def test_copy_from(self): state_a = sol.State() state_b = sol.State() state_a.notes = {42: 0} state_a.message = object() state_a.velocity = 43 state_a.pitch_bend == 45 state_a.pressure == 46 for n in range(128): state_a._cc[n] = n state_b.copy_from(state_a) assert state_b.message is state_a.message assert state_b.note == state_a.note assert state_b.velocity == state_a.velocity assert state_b.pitch_bend == state_a.pitch_bend assert state_b.pressure == state_a.pressure for n in range(128): assert state_b.cc(n) == state_a.cc(n) # Check for deep copy state_a.notes = {43: 0} assert state_b.note != state_a.note state_a._cc[0] = 100 assert state_b.cc(0) != state_a.cc(0)
def test_process_midi_types_pressure(self): s = sol.Sol() state = sol.State() msg = make_message(smolmidi.CHANNEL_PRESSURE, 64) s._process_midi(msg, state) assert math.isclose(state.pressure, 0.5, rel_tol=0.01)
def test_process_midi_types_cc(self): s = sol.Sol() state = sol.State() msg = make_message(smolmidi.CC, 42, 64) s._process_midi(msg, state) assert math.isclose(state.cc(42), 0.5, rel_tol=0.01)
def test_default_state(self): state = sol.State() assert state.message is None assert state.note is None assert state.velocity == 0 assert state.pitch_bend == 0 assert state.pressure == 0 for n in range(128): assert state._cc[n] == 0
def test_process_midi_types_pitch_bend(self): s = sol.Sol() state = sol.State() msg = make_message(smolmidi.PITCH_BEND, 0x00, 0x40) s._process_midi(msg, state) assert state.pitch_bend == 0 msg = make_message(smolmidi.PITCH_BEND, 0x00, 0x00) s._process_midi(msg, state) assert state.pitch_bend == -1 msg = make_message(smolmidi.PITCH_BEND, 0x00, 0x80) s._process_midi(msg, state) assert state.pitch_bend == 1
def test_process_midi_types_note_on_off(self): s = sol.Sol() state = sol.State() msg = make_message(smolmidi.NOTE_ON, 42, 64) s._process_midi(msg, state) assert state.note == 42 assert math.isclose(state.velocity, 0.5, rel_tol=0.01) msg = make_message(smolmidi.NOTE_OFF, 42, 0) s._process_midi(msg, state) assert state.note is None assert state.velocity == 0 # Note on with 0 velocity should be treated as Note Off msg = make_message(smolmidi.NOTE_ON, 42, 0) s._process_midi(msg, state) assert state.note is None assert state.velocity == 0
def test_empty(self): state = sol.State() assert state.latest_note is None assert state.oldest_note is None assert state.highest_note is None assert state.lowest_note is None
def make_state(self): state = sol.State() state.notes = {40: 4, 41: 3, 43: 2, 44: 1} return state
def test_poly_note_stealing(monotonic_ns): state = sol.State() outputs = sol.Outputs() p = poly.Poly() # No notes, all outputs should be default states. monotonic_ns.return_value = 0 p.update(state, outputs) assert outputs.cv_a == 0 assert outputs.cv_b == 0 assert outputs.cv_c == 0 assert outputs.cv_d == 0 assert outputs.gate_1 is False assert outputs.gate_2 is False assert outputs.gate_3 is False assert outputs.gate_4 is False # Play one note, assert that it gets assigned. state.message = make_message(smolmidi.NOTE_ON, 40, 127) p.update(state, outputs) assert outputs.cv_a == helpers.note_to_volts_per_octave(40) assert outputs.cv_b == 0 assert outputs.cv_c == 0 assert outputs.cv_d == 0 assert outputs.gate_1 is True assert outputs.gate_2 is False assert outputs.gate_3 is False assert outputs.gate_4 is False # Release the note, assert that it's gate gets released. monotonic_ns.return_value = 1 * _NS_TO_S state.message = make_message(smolmidi.NOTE_OFF, 40) p.update(state, outputs) assert outputs.gate_1 is False # Play four notes, assert that they all get assigned. monotonic_ns.return_value = 1 * _NS_TO_S state.message = make_message(smolmidi.NOTE_ON, 40, 127) p.update(state, outputs) monotonic_ns.return_value = 2 * _NS_TO_S state.message = make_message(smolmidi.NOTE_ON, 41, 127) p.update(state, outputs) monotonic_ns.return_value = 3 * _NS_TO_S state.message = make_message(smolmidi.NOTE_ON, 42, 127) p.update(state, outputs) monotonic_ns.return_value = 4 * _NS_TO_S state.message = make_message(smolmidi.NOTE_ON, 43, 127) p.update(state, outputs) assert outputs.cv_a == helpers.note_to_volts_per_octave(40) assert outputs.cv_b == helpers.note_to_volts_per_octave(41) assert outputs.cv_c == helpers.note_to_volts_per_octave(42) assert outputs.cv_d == helpers.note_to_volts_per_octave(43) assert outputs.gate_1 is True assert outputs.gate_2 is True assert outputs.gate_3 is True assert outputs.gate_4 is True # Play one more note, it should replace the oldest (first) # note. state.message = make_message(smolmidi.NOTE_ON, 44, 127) p.update(state, outputs) assert outputs.cv_a == helpers.note_to_volts_per_octave(44) # This should cause retrigger, so it should go False briefly # then go to True. step() must be called to update the gate # retrigger logic. assert outputs.gate_1 is False monotonic_ns.return_value = 5 * _NS_TO_S outputs.step() assert outputs.gate_1 is True # Release one of the notes in the middle. It should create # a "hole". state.message = make_message(smolmidi.NOTE_OFF, 42) p.update(state, outputs) assert outputs.gate_3 is False # Now, play another note. It should get assigned to the # "hole". state.message = make_message(smolmidi.NOTE_ON, 45, 127) p.update(state, outputs) assert outputs.cv_c == helpers.note_to_volts_per_octave(45) assert outputs.gate_3 is True