Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

score.py - ValueError: math domain error #5

Open
kjcole opened this issue Mar 2, 2022 · 4 comments
Open

score.py - ValueError: math domain error #5

kjcole opened this issue Mar 2, 2022 · 4 comments

Comments

@kjcole
Copy link

kjcole commented Mar 2, 2022

I was revisiting code that I don't recall giving this error before. I recently updated to SCAMP version 0.8.9.5.

You may recall helping me with a pseudo-Celtic random song generator. That's what's crapping out. It plays the tune, but upon finishing it yields the following when trying to generate the score:

Traceback (most recent call last):
  File "./celtic.py", line 99, in <module>
    main()
  File "./celtic.py", line 93, in main
    performance.to_score(title="Beating the Cat",
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/performance.py", line 1094, in to_score
    return Score.from_performance(
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 934, in from_performance
    return Score.from_quantized_performance(
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 956, in from_quantized_performance
    staff_group = StaffGroup.from_quantized_performance_part(part)
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 1344, in from_quantized_performance_part
    return StaffGroup._from_measure_voice_grid(
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 1559, in _from_measure_voice_grid
    [
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 1560, in <listcomp>
    Staff._from_measure_bins_of_voice_lists(
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 1654, in _from_measure_bins_of_voice_lists
    return cls([Measure.from_list_of_performance_voices(measure_content, time_signature, show_time_signature)
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 1654, in <listcomp>
    return cls([Measure.from_list_of_performance_voices(measure_content, time_signature, show_time_signature)
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 1762, in from_list_of_performance_voices
    voices.append(Voice.from_performance_voice(*voice_content))
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 1926, in from_performance_voice
    processed_contents = Voice._recombine_processed_beats(processed_beats, measure_quantization)
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 2163, in _recombine_processed_beats
    recombined_division_points = Voice._try_all_sub_recombinations(
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 2185, in _try_all_sub_recombinations
    recombo, _ = _get_best_recombination_given_beat_hierarchy(
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 216, in _get_best_recombination_given_beat_hierarchy
    best_subgroup_option, best_subgroup_score = _get_best_subgroup_recombination_option(
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 242, in _get_best_subgroup_recombination_option
    assert all(_is_single_note_viable_grouping(x, max_dots=engraving_settings.max_dots_allowed)
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 242, in <genexpr>
    assert all(_is_single_note_viable_grouping(x, max_dots=engraving_settings.max_dots_allowed)
  File "/home/kjcole/.local/lib/python3.8/site-packages/scamp/score.py", line 175, in _is_single_note_viable_grouping
    if Fraction(math.log2(length_in_subdivisions / dot_multiplier)).limit_denominator().denominator == 1:
ValueError: math domain error
@MarcTheSpark
Copy link
Owner

Hey Kevin!

Can you post the script that's not working? It's a little hard to tell without seeing your code, but it looks like somehow it's getting a negative note length or something.

@kjcole
Copy link
Author

kjcole commented Mar 4, 2022

GitHub doesn't like Python attachments. (I suppose I could have just changed the extension, but here it is.)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# "Beating the Cat"
# Decomposed by Kevin Cole <[email protected]> 2021.02.19 (kjc)
#
# Tuning info courtesy of http://www.hotpipes.com/tuning.html
#
# Sorta 6/8?
#

from random import choice, randint, shuffle, sample, uniform
from scamp  import *
from scamp_extensions.pitch import Scale

s = Session(tempo=120)

woodblock = s.new_part("woodblock")
bagpipe   = s.new_part("bagpipe")
bodhran   = s.new_part("bodhran",
                       soundfont="soundfonts/Bodhran")  # Bodhran.sf2

#          G4  A4  B4  C#5 D5  E5  F#5 G5  A5
chanter = (67, 69, 71, 73, 74, 76, 78, 79, 81)  # A4 is the "key note"
scale   = Scale.from_pitches(chanter)


def rickity(duration=32, shift=0):
    """Clickity-clackity, rickity-tickity, pseudo-bones"""
    pitches = (  75,   73,   67,   77,   70,   65)
    volumes = ( 0.75,  0.75,  0.75,  1.0,  0.75,  0.75)
    lengths = ((1.0 / 3.0),) * 6  # 0.333333..., 0.333333..., ...
    while current_clock().beat() < duration:
        for pitch, volume, length in zip(pitches, volumes, lengths):
            woodblock.play_note(pitch + shift, volume, length)


def boombah(duration=32):
    """Boom-bah of the bodhran"""
    notes = ((60, 58, 58, 60, 58, 58),
             (60, 58) * 2,
             (60, 58))
    vols  = ((0.75,  0.75,  0.75,  1.0,  0.75,  0.75),
             (1.0,   0.75,) * 2,
             (1.0,   0.75))
    durs  = (((1.0 / 3.0),)             * 6,  # 0.3333..., 0.3333..., ...
             ((2.0 / 3.0), (1.0 / 3.0)) * 2,  # 0.6666..., 0.3333..., 0.6666...
             ((4.0 / 3.0), (2.0 / 3.0)))      # 1.3333..., 0.6666
    wait(4)
    while current_clock().beat() < duration:
        pattern = randint(0, 2)
        for note, vol, dur in zip(notes[pattern],
                                  vols[pattern],
                                  durs[pattern]):
            bodhran.play_note(note, vol, dur)


def pipe(duration=32):
    """The pipes, the pipes, are droning"""
    # Drones chord
    #
    drones = (57, 57, 45)  # A2, A2, A3 (tenor, tenor, bass)
    wait(8)
    drone = bagpipe.start_chord(drones, 0.8)
    wait(4)
    note = choice(chanter)
    while current_clock().beat() < duration:
        dur  = randint(1, 6) * (1.0 / 3.0)
        bagpipe.play_note(note, 1.0, dur)
        leading = note
        while abs(note - leading) in (0, 1, 2, 3, 6, 8, 10, 11, 13, 14, 15):
            note = choice(chanter)

    # Deflate the bag
    #
    drone.end()

    bagpipe.play_note([81, 76], [0.6, 0], 1.0, blocking=False)
    bagpipe.play_note([57, 52], [0.6, 0], 1.0, blocking=False)
    bagpipe.play_note([45, 40], [0.8, 0], 1.0)


def main():
    """The main attraction"""
    s.start_transcribing()
    s.fork(rickity, args=(42, 30,))
    s.fork(boombah, args=(44,))
    s.fork(pipe,    args=(40,))
    s.wait_for_children_to_finish()

    if s.is_transcribing():
        performance = s.stop_transcribing()
        performance.to_score(title="Beating the Cat",
                             composer="Decomposer: Kevin Cole",
                             time_signature="6/8").show_xml()


if __name__ == "__main__":
    main()

@MarcTheSpark
Copy link
Owner

Well, I tracked down the source of the issue! You're doing something very strange by accident here: the boombah part is using triplets, but in the context of 6/8 time. This creates a weird situation for the quantizer, since it's trying to make sense of 4/3 of a quarter note within dotted-quarter-note beats. I need to fix something here for sure, but I'm guessing that the triplets may not be what you're really intending?

@kjcole
Copy link
Author

kjcole commented Mar 8, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants