def __sub__(self, expr): '''Offset taken from offset returns duration: :: >>> durationtools.Offset(2) - durationtools.Offset(1, 2) Duration(3, 2) Duration taken from offset returns another offset: :: >>> durationtools.Offset(2) - durationtools.Duration(1, 2) Offset(3, 2) Coerce `expr` to offset when `expr` is neither offset nor duration: :: >>> durationtools.Offset(2) - Fraction(1, 2) Duration(3, 2) Returns duration or offset. ''' if isinstance(expr, type(self)): return Duration(Duration.__sub__(self, expr)) elif isinstance(expr, Duration): return Duration.__sub__(self, expr) else: expr = type(self)(expr) return self - expr
def test_state_hashing(self): note = HashableNote(NamedPitch("A3"), Duration(1, 4)) duplicate_note = HashableNote(NamedPitch("A3"), Duration(1, 4)) state = CompositionState(Duration(0), (note, duplicate_note), None) duplicate_state = CompositionState(Duration(0), (duplicate_note, note), None) self.assertEqual(state, duplicate_state) self.assertEqual(hash(state), hash(duplicate_state))
def test_action_hashing(self): note = HashableNote(NamedPitch("A3"), Duration(1, 4)) duplicate_note = HashableNote(NamedPitch("A3"), Duration(1, 4)) action = CompositionAction((note, duplicate_note)) duplicate_action = CompositionAction((duplicate_note, note)) self.assertEqual(action, duplicate_action) self.assertEqual(hash(action), hash(duplicate_action))
def __mul__(self, *args): r'''Multiplier times duration gives duration. Returns duration. ''' if len(args) == 1 and type(args[0]) is Duration: return Duration(Duration.__mul__(self, *args)) else: return Duration.__mul__(self, *args)
def test_state_value_function(self): state = CompositionState(Duration(0), (self.allowed_note, None), None) state_two = CompositionState(Duration(0), (self.allowed_note, self.allowed_note), None) self.assertEqual( 0.0, self.value_function.actionvalue(state, self.allowed_action)) self.value_function.setactionvalue(state, self.allowed_action, 1.0) self.assertEqual( 1.0, self.value_function.actionvalue(state, self.allowed_action)) self.assertEqual( 0.0, self.value_function.actionvalue(state_two, self.allowed_action))
def __new__(class_, *args, **kwargs): grace_displacement = None for arg in args: if hasattr(arg, 'grace_displacement'): grace_displacement = getattr(arg, 'grace_displacement') break grace_displacement = grace_displacement or kwargs.get( 'grace_displacement') if grace_displacement is not None: grace_displacement = Duration(grace_displacement) grace_displacement = grace_displacement or None if len(args) == 1 and isinstance(args[0], Duration): args = args[0].pair self = Duration.__new__(class_, *args) self._grace_displacement = grace_displacement return self
def _generate_actions(self): possible_pitches_per_voice = [] for name, voice_range in self.composition_parameters.desired_voices: pitch_set = self.composition_parameters.scale.create_named_pitch_set_in_pitch_range( voice_range) possible_pitches_per_voice.append(pitch_set) possible_durations_per_voice = [[Duration(4, 4)] for _ in range( self.composition_parameters.number_of_voices_to_generate)] actions = [] notes_per_voice = [] for i in range( self.composition_parameters.number_of_voices_to_generate): notes_per_voice.append([]) for pitch, duration in itertools.product( possible_pitches_per_voice[i], possible_durations_per_voice[i]): notes_per_voice[i].append(HashableNote(pitch, duration)) index_to_action = dict() action_to_index = dict() i = 0 for notes in itertools.product(*notes_per_voice): action = CompositionAction(notes) actions.append(action) index_to_action[i] = action action_to_index[action] = i i += 1 return actions, index_to_action, action_to_index
def generate_environment() -> Tuple[Domain, Task]: composition_parameters = CompositionParameters( [("contrapuntal", soprano_range), ("cantus", tenor_range)], meter, scale, Duration(11)) domain = CompositionEnvironment(composition_parameters, history_length=history_length, position_invariant=position_invariant) task = task_class(domain) return domain, task
def reward(self, state, action, state_prime): if not self.differential: if state_prime.preceding_duration == Duration(11): return self.grade_composition(self.domain) else: return 0 if self.prev_duration == state_prime.preceding_duration: assert False return elif self.prev_duration < state_prime.preceding_duration: new_grade = self.grade_composition(self.domain) reward = new_grade - self.prev_grade self.prev_grade = new_grade elif self.prev_duration > state_prime.preceding_duration: # This should only be the first step reward = self.grade_composition(self.domain) self.prev_grade = reward self.prev_duration = state_prime.preceding_duration return reward
def __init__(self, composition_parameters: CompositionParameters, given_voices: List[Voice] = list(), history_length=1, position_invariant=False): self.given_voices = given_voices self.composition_parameters = composition_parameters self.history_length = history_length self.voices = [ Voice("", name=name) for name, pitch_range in self.composition_parameters.desired_voices ] self.current_duration = Duration(0) actionslist, index_to_action, action_to_index = self._generate_actions( ) self.actions = actionslist self.index_to_action = index_to_action self.action_to_index = action_to_index self.position_invariant = position_invariant
def save_composition(name: str, agent_name: str, composition: CompositionEnvironment, out_dir: str): score = Score() staff_group = scoretools.StaffGroup([], context_name='StaffGroup') for voice in composition.voices + composition.given_voices: staff = Staff([voice]) if voice.name == "cantus": attach(Clef("alto"), staff) attach(composition.composition_parameters.scale.key_signature, staff) staff_group.append(staff) tempo = Tempo(Duration(4, 4), 60) attach(tempo, staff_group[0]) score.append(staff_group) score.add_final_bar_line() lilypond_file = lilypondfiletools.make_basic_lilypond_file(score) lilypond_file.header_block.composer = markuptools.Markup(agent_name) lilypond_file.header_block.title = markuptools.Markup(name) lilypond_file.header_block.tagline = markuptools.Markup() midi_block = lilypondfiletools.Block(name="midi") context_block = lilypondfiletools.Block(name="context") channel_mapping = lilypondfiletools.Block(name="score") # channel_mapping.midiChannelMapping = "instrument" # context_block.items.append(channel_mapping) # midi_block.items.append(context_block) lilypond_file.score_block.items.append(midi_block) layout_block = lilypondfiletools.Block(name="layout") lilypond_file.score_block.items.append(layout_block) filename = name + ".ly" if not os.path.exists(out_dir): os.makedirs(out_dir) out_path = os.path.join(out_dir, filename) with open(out_path, mode="w") as f: f.write(format(lilypond_file))
def __init__(self, domain: CompositionEnvironment, differential: bool = True): super().__init__(domain) self.domain = domain self.differential = differential self.prev_duration = Duration(0) self.prev_grade = 0.0
def __gt__(self, arg): r'''Is true when offset is greater than `arg`. Otherwise false. .. container:: example **Example 1.** With equal numerators, denominators and grace displacements: :: >>> offset_1 = Offset((1, 4), grace_displacement=(-1, 16)) >>> offset_2 = Offset((1, 4), grace_displacement=(-1, 16)) :: >>> offset_1 > offset_1 False >>> offset_1 > offset_2 False >>> offset_2 > offset_1 False >>> offset_2 > offset_2 False .. container:: example **Example 2.** With equal numerators and denominators but differing grace displacements: :: >>> offset_1 = Offset((1, 4), grace_displacement=(-1, 8)) >>> offset_2 = Offset((1, 4), grace_displacement=(-1, 16)) :: >>> offset_1 > offset_1 False >>> offset_1 > offset_2 False >>> offset_2 > offset_1 True >>> offset_2 > offset_2 False .. container:: example **Example 3.** With differing numerators and denominators. Ignores grace displacements: :: >>> offset_1 = Offset((1, 4)) >>> offset_2 = Offset((1, 2), grace_displacement=(-99)) :: >>> offset_1 > offset_1 False >>> offset_1 > offset_2 False >>> offset_2 > offset_1 True >>> offset_2 > offset_2 False Returns true or false. ''' if isinstance(arg, type(self)) and self.pair == arg.pair: return self._get_grace_displacement() > \ arg._get_grace_displacement() return Duration.__gt__(self, arg)
def setUp(self): self.allowed_note = HashableNote(NamedPitch("A3"), Duration(1, 4)) self.allowed_action = CompositionAction( (self.allowed_note, self.allowed_note)) self.value_function = StateActionValueTable( actions=[self.allowed_action])
def test_hashable_note_hashing(self): note = HashableNote(NamedPitch("A3"), Duration(1, 4)) duplicate_note = HashableNote(NamedPitch("A3"), Duration(1, 4)) self.assertEqual(note, duplicate_note) self.assertEqual(hash(note), hash(duplicate_note))
def reset(self): self.voices = [ Voice("") for _ in range( self.composition_parameters.number_of_voices_to_generate) ] self.current_duration = Duration(0)