--- /dev/null
+# -*- encoding: utf8 -*-
+
+def note2midi(note):
+ " convert a note name to a midi note value "
+ # from C-2 to G8, though we do accept everything in the upper octave
+ _valid_notenames = {'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11}
+ _valid_modifiers = {None: 0, u'♮': 0, '#': +1, u'♯': +1, u'\udd2a': +2, 'b': -1, u'♭': -1, u'\ufffd': -2}
+ _valid_octaves = range(-1, 10)
+ if not (1 < len(note) < 5):
+ raise ValueError, "string of 2 to 4 characters expected, got %d (%s)" % (len(note), note)
+ notename, modifier, octave = [None]*3
+
+ if len(note) == 4:
+ notename, modifier, octave_sign, octave = note
+ octave = octave_sign + octave
+ elif len(note) == 3:
+ notename, modifier, octave = note
+ if modifier == '-':
+ octave = modifier + octave
+ modifier = None
+ else:
+ notename, octave = note
+
+ notename = notename.upper()
+ octave = int(octave)
+
+ if notename not in _valid_notenames:
+ raise ValueError, "%s is not a valid note name" % notename
+ if modifier not in _valid_modifiers:
+ raise ValueError, "only # and b are acceptable modifiers, not %s" % modifier
+ if octave not in _valid_octaves:
+ raise ValueError, "%s is not a valid octave" % octave
+
+ midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier]
+ if midi > 127:
+ raise ValueError, "%s is outside of the range C-2 to G8" % note
+ return midi
--- /dev/null
+# -*- encoding: utf8 -*-
+
+from aubio import note2midi
+import unittest
+
+list_of_known_notes = (
+ ( 'C-1', 0 ),
+ ( 'C#-1', 1 ),
+ ( 'd2', 38 ),
+ ( 'C3', 48 ),
+ ( 'B3', 59 ),
+ ( 'B#3', 60 ),
+ ( 'A4', 69 ),
+ ( 'A#4', 70 ),
+ ( 'G8', 115 ),
+ ( u'G♯8', 116 ),
+ ( u'G♭9', 126 ),
+ ( 'G9', 127 ),
+ ( u'G\udd2a2', 45 ),
+ ( u'B\ufffd2', 45 ),
+ ( u'A♮2', 45 ),
+ )
+
+class TestNote2MidiGoodValues(unittest.TestCase):
+
+ def test_note2midi_known_values(self):
+ " known values are correctly converted "
+ for note, midi in list_of_known_notes:
+ self.assertEqual ( note2midi(note), midi )
+
+class TestNote2MidiWrongValues(unittest.TestCase):
+
+ def test_note2midi_missing_octave(self):
+ " fails when passed only one character"
+ self.assertRaises(ValueError, note2midi, 'C')
+
+ def test_note2midi_wrong_modifier(self):
+ " fails when passed an invalid note name"
+ self.assertRaises(ValueError, note2midi, 'C.1')
+
+ def test_note2midi_wronge_midifier_again(self):
+ " fails when passed a wrong modifier"
+ self.assertRaises(ValueError, note2midi, 'CB-3')
+
+ def test_note2midi_wrong_octave(self):
+ " fails when passed a wrong octave"
+ self.assertRaises(ValueError, note2midi, 'CBc')
+
+ def test_note2midi_out_of_range(self):
+ " fails when passed a non-existing note"
+ self.assertRaises(ValueError, note2midi, 'A9')
+
+if __name__ == '__main__':
+ unittest.main()