def test_chord_progression_add_remove(self): c1 = Chord.from_ident("A1 Major") c2 = Chord.from_ident("A2 Major") c3 = Chord.from_ident("A3 Major") cs1 = ChordProgression(c1, c2, c3) mock = unittest.mock.Mock() self.MEL.add_handler(mock, cs1) self.assertTrue(self.MEL.handlers) self.MEL.clear_handlers() self.assertFalse(self.MEL.handlers)
def test_multiple_callbacks_same_chord(self): mock1 = unittest.mock.Mock() mock2 = unittest.mock.Mock() c1 = Chord(Note(20), Note(40), Note(60)) c2 = Chord(Note(20), Note(40), Note(60)) self.MEL.add_handler(mock1, c1) self.MEL.add_handler(mock2, c2) press_chord(self.loopback, c1) mock1.assert_called() mock2.assert_called()
def test_get_semitones_from_chord_name(self): self.assertEqual(Chord._get_semitones_from_chord_name("Major"), [0, 4, 7]) self.assertEqual( Chord._get_semitones_from_chord_name("Harmonic seventh"), [0, 4, 7, 10]) self.assertEqual( Chord._get_semitones_from_chord_name("Augmented sixth"), [0, 6, 10]) # Multiple possible chord, should select 1st with self.assertRaises(ValueError): Chord._get_semitones_from_chord_name("test")
def test_chord_progression_callback(self): c1 = Chord.from_ident("A1 Major") c2 = Chord.from_ident("A2 Major") c3 = Chord.from_ident("A3 Major") cs1 = ChordProgression(c1, c2, c3) mock = unittest.mock.Mock() self.MEL.add_handler(mock, cs1) press_chord(self.loopback, c1) press_chord(self.loopback, c2) press_chord(self.loopback, c3) time.sleep(TEST_CHORD_DELAY) mock.assert_called()
def test_equality(self): c1 = Chord(Note(69), Note(73), Note(76)) c2 = Chord(Note(69), Note(73), Note(76)) self.assertEqual(c1, c2) nl_ordered = NoteList(Note(69), Note(73), Note(76)) # Pre-ordered self.assertEqual(nl_ordered, c1) nl_unordered = NoteList(Note(73), Note(69), Note(76)) # Un-ordered self.assertEqual(nl_unordered, c1) seq1 = Sequence(Note(69), Note(73), Note(76)) self.assertNotEqual(c1, seq1) # Different note list lengths should automatically be not equal c3 = Chord(Note(69), Note(73), Note(76), Note(100)) self.assertNotEqual(c1, c3)
def test_trigger_on_custom_chord(self): mock = unittest.mock.Mock() chord = Chord.from_midi_list([20, 40, 60]) self.assertFalse(self.MEL.handlers) # Empty check self.MEL.add_handler(mock, chord) press_chord(self.loopback, chord) mock.assert_called()
def test_chord_and_sequence(self): chord_mock = unittest.mock.Mock() sequence_mock = unittest.mock.Mock() c1 = Chord(Note(1), Note(2), Note(3)) seq1 = Sequence(Note(1), Note(2), Note(3)) self.MEL.add_handler(chord_mock, c1) self.MEL.add_handler(sequence_mock, seq1) press_chord(self.loopback, c1) # Should trigger both chord_mock.assert_called() sequence_mock.assert_called()
def test_chord_handlers_add_remove(self): mock1 = unittest.mock.Mock() mock2 = unittest.mock.Mock() c1 = Chord.from_ident("C4 Major") c2 = Chord.from_ident("C5 Minor") self.assertFalse(self.MEL.handlers) # Empty self.MEL.add_handler(mock1, c1) self.assertTrue(self.MEL.handlers) # Not empty self.MEL.clear_handlers() self.assertFalse(self.MEL.handlers) # Now test a single removal self.MEL.add_handler(mock1, c1) self.MEL.add_handler(mock2, c2) self.assertTrue(self.MEL.handlers) # Not empty self.assertIn(c1, self.MEL.handlers) self.assertIn(c2, self.MEL.handlers) self.MEL.clear_handlers(c1) self.assertNotIn(c1, self.MEL.handlers) self.assertIn(c2, self.MEL.handlers)
def _callback(self, msg): if msg.type == "note_on" and msg.velocity > 0: # Key down self.recent_notes.append(msg.note) self.down_notes.add(msg.note) self.recent_chords.append(Chord.from_midi_list(self.down_notes)) logger.debug(f"Note {msg.note} on") self._check_handlers() elif msg.type == "note_off" or (msg.type == "note_on" and msg.velocity == 0): # Key up self.down_notes.remove(msg.note) logger.debug(f"Note {msg.note} off")
def test_from_ident(self): c1 = Chord(Note(69), Note(73), Note(76)) c2 = Chord.from_ident("A4 Major") self.assertEqual(c1, c2) with self.assertRaises(AssertionError): Chord.from_ident("") with self.assertRaises(ValueError): Chord.from_ident("test test") with self.assertRaises( ValueError ): # This is a different error message in _get_semitones_from_chord_name Chord.from_ident("A4 test")
def test_decorator_string(self): mock = unittest.mock.Mock() self.assertFalse(self.MEL.handlers) # Empty @self.MEL.on_notes("C4 Major") def sub(): # pragma: no cover mock() self.assertTrue(self.MEL.handlers) # Not empty press_chord(self.loopback, Chord.from_ident("C4 Major")) mock.assert_called()
def test_handler_remove_class(self): mock1 = unittest.mock.Mock() mock2 = unittest.mock.Mock() c1 = Chord.from_ident("C4 Major") s1 = Sequence.from_midi_list([1, 2, 3]) self.MEL.add_handler(mock1, c1) self.MEL.add_handler(mock2, s1) self.assertIn(c1, self.MEL.handlers) self.assertIn(s1, self.MEL.handlers) self.MEL.clear_handlers(Chord) self.assertNotIn(c1, self.MEL.handlers) self.assertIn(s1, self.MEL.handlers)
def test_decorator_chord(self): mock = unittest.mock.Mock() self.assertFalse(self.MEL.handlers) # Empty c1 = Chord(Note(5), Note(10), Note(15)) @self.MEL.on_notes(c1) def sub(): mock() self.assertTrue(self.MEL.handlers) # Not empty press_chord(self.loopback, c1) mock.assert_called()
def test_chord_progression_multiple_callback(self): c1 = Chord.from_ident("A1 Major") c2 = Chord.from_ident("A2 Major") c3 = Chord.from_ident("A3 Major") c4 = Chord.from_ident("C1 Major") c5 = Chord.from_ident("C2 Major") c6 = Chord.from_ident("C3 Major") cs1 = ChordProgression(c1, c2, c3) cs2 = ChordProgression(c4, c5, c6) mock1 = unittest.mock.Mock() mock2 = unittest.mock.Mock() self.MEL.add_handler(mock1, cs1) self.MEL.add_handler(mock2, cs2) press_chord(self.loopback, c1) press_chord(self.loopback, c2) press_chord(self.loopback, c3) time.sleep(TEST_CHORD_DELAY) mock1.assert_called() press_chord(self.loopback, c4) press_chord(self.loopback, c5) press_chord(self.loopback, c6) time.sleep(TEST_CHORD_DELAY) mock2.assert_called()
def test_from_note_chord(self): c1 = Chord(Note(69), Note(73), Note(76)) c2 = Chord.from_note_chord(Note(69), "Major") self.assertEqual(c1, c2)
def test_get_semitones(self): c1 = Chord.from_ident("A4 Major") self.assertEqual(c1._get_semitones(), [0, 4, 7])
def test_identify(self): c1 = Chord.from_ident("A4 Major") self.assertIn("A4 Major", c1.identify()) c2 = Chord() self.assertEqual(c2.identify(), None)
def _resolve_notes_obj(notes_obj): if isinstance(notes_obj, str): notes_obj = Chord.from_ident(notes_obj) if not (isinstance(notes_obj, Chord) or isinstance(notes_obj, Sequence) or isinstance(notes_obj, ChordProgression)): raise TypeError("Expected a Sequence or Chord") return notes_obj
def test_hash(self): c1 = Chord(Note(69), Note(73), Note(76)) self.assertEqual(hash(c1), 643362958232848345) self.assertEqual(Chord.__hash__, NoteList.__hash__)
def test_string(self): self.assertEqual(str(Chord.from_ident("A4 Major")), "Chord(A4, C#5, E5)")
def test_eq_chord(self): notes = (Note(15), Note(10), Note(20)) seq1 = Sequence(notes) c1 = Chord(notes) self.assertNotEqual(seq1, c1) # Chord should sort the notes, while Sequence doesn't