Showing the changes to python (3 of 3 files). Show all
Unified · Split
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | import numpy |
| 2 | 2 | from _aubio import * |
| 3 | +from midiconv import * | |
| 3 | 4 | |
| 4 | 5 | class fvec(numpy.ndarray): |
| 5 | 6 | |
| @@ -0,0 +1,37 @@ | ||
| 1 | +# -*- encoding: utf8 -*- | |
| 2 | + | |
| 3 | +def note2midi(note): | |
| 4 | + " convert a note name to a midi note value " | |
| 5 | + # from C-2 to G8, though we do accept everything in the upper octave | |
| 6 | + _valid_notenames = {'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11} | |
| 7 | + _valid_modifiers = {None: 0, u'♮': 0, '#': +1, u'♯': +1, u'\udd2a': +2, 'b': -1, u'♭': -1, u'\ufffd': -2} | |
| 8 | + _valid_octaves = range(-1, 10) | |
| 9 | + if not (1 < len(note) < 5): | |
| 10 | + raise ValueError, "string of 2 to 4 characters expected, got %d (%s)" % (len(note), note) | |
| 11 | + notename, modifier, octave = [None]*3 | |
| 12 | + | |
| 13 | + if len(note) == 4: | |
| 14 | + notename, modifier, octave_sign, octave = note | |
| 15 | + octave = octave_sign + octave | |
| 16 | + elif len(note) == 3: | |
| 17 | + notename, modifier, octave = note | |
| 18 | + if modifier == '-': | |
| 19 | + octave = modifier + octave | |
| 20 | + modifier = None | |
| 21 | + else: | |
| 22 | + notename, octave = note | |
| 23 | + | |
| 24 | + notename = notename.upper() | |
| 25 | + octave = int(octave) | |
| 26 | + | |
| 27 | + if notename not in _valid_notenames: | |
| 28 | + raise ValueError, "%s is not a valid note name" % notename | |
| 29 | + if modifier not in _valid_modifiers: | |
| 30 | + raise ValueError, "only # and b are acceptable modifiers, not %s" % modifier | |
| 31 | + if octave not in _valid_octaves: | |
| 32 | + raise ValueError, "%s is not a valid octave" % octave | |
| 33 | + | |
| 34 | + midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier] | |
| 35 | + if midi > 127: | |
| 36 | + raise ValueError, "%s is outside of the range C-2 to G8" % note | |
| 37 | + return midi | |
| @@ -0,0 +1,54 @@ | ||
| 1 | +# -*- encoding: utf8 -*- | |
| 2 | + | |
| 3 | +from aubio import note2midi | |
| 4 | +import unittest | |
| 5 | + | |
| 6 | +list_of_known_notes = ( | |
| 7 | + ( 'C-1', 0 ), | |
| 8 | + ( 'C#-1', 1 ), | |
| 9 | + ( 'd2', 38 ), | |
| 10 | + ( 'C3', 48 ), | |
| 11 | + ( 'B3', 59 ), | |
| 12 | + ( 'B#3', 60 ), | |
| 13 | + ( 'A4', 69 ), | |
| 14 | + ( 'A#4', 70 ), | |
| 15 | + ( 'G8', 115 ), | |
| 16 | + ( u'G♯8', 116 ), | |
| 17 | + ( u'G♭9', 126 ), | |
| 18 | + ( 'G9', 127 ), | |
| 19 | + ( u'G\udd2a2', 45 ), | |
| 20 | + ( u'B\ufffd2', 45 ), | |
| 21 | + ( u'A♮2', 45 ), | |
| 22 | + ) | |
| 23 | + | |
| 24 | +class TestNote2MidiGoodValues(unittest.TestCase): | |
| 25 | + | |
| 26 | + def test_note2midi_known_values(self): | |
| 27 | + " known values are correctly converted " | |
| 28 | + for note, midi in list_of_known_notes: | |
| 29 | + self.assertEqual ( note2midi(note), midi ) | |
| 30 | + | |
| 31 | +class TestNote2MidiWrongValues(unittest.TestCase): | |
| 32 | + | |
| 33 | + def test_note2midi_missing_octave(self): | |
| 34 | + " fails when passed only one character" | |
| 35 | + self.assertRaises(ValueError, note2midi, 'C') | |
| 36 | + | |
| 37 | + def test_note2midi_wrong_modifier(self): | |
| 38 | + " fails when passed an invalid note name" | |
| 39 | + self.assertRaises(ValueError, note2midi, 'C.1') | |
| 40 | + | |
| 41 | + def test_note2midi_wronge_midifier_again(self): | |
| 42 | + " fails when passed a wrong modifier" | |
| 43 | + self.assertRaises(ValueError, note2midi, 'CB-3') | |
| 44 | + | |
| 45 | + def test_note2midi_wrong_octave(self): | |
| 46 | + " fails when passed a wrong octave" | |
| 47 | + self.assertRaises(ValueError, note2midi, 'CBc') | |
| 48 | + | |
| 49 | + def test_note2midi_out_of_range(self): | |
| 50 | + " fails when passed a non-existing note" | |
| 51 | + self.assertRaises(ValueError, note2midi, 'A9') | |
| 52 | + | |
| 53 | +if __name__ == '__main__': | |
| 54 | + unittest.main() | |