History

Merge branch 'master' into feature/docstrings

Paul Brossier committed 8 years ago

Commit ed596f72 parents f9400d0 4bc10e228 files · +322 −92Browse files

Showing the changes to python (9 of 28 files). Show all

Unified · Split

9 files
  1. python/demos/demo_bpm_extract.py +3 −3
  2. python/ext/aubiomodule.c +12 −4
  3. python/ext/py-filterbank.c +3 −3
  4. python/lib/aubio/cmd.py +30 −1
  5. python/lib/aubio/midiconv.py +38 −9
  6. python/tests/test_aubio_cmd.py +6 −3
  7. python/tests/test_note2midi.py +19 −2
  8. python/tests/test_notes.py +14 −0
  9. python/tests/test_slicing.py +2 −2
python/demos/demo_bpm_extract.py+3−3
@@ -22,7 +22,7 @@ def get_file_bpm(path, params=None): · 21 unmodified lines
22 elif params.mode in ['default']:22 elif params.mode in ['default']:
23 pass23 pass
24 else:24 else:
25 print("unknown mode {:s}".format(params.mode))25 raise ValueError("unknown mode {:s}".format(params.mode))
26 # manual settings26 # manual settings
27 if 'samplerate' in params:27 if 'samplerate' in params:
28 samplerate = params.samplerate28 samplerate = params.samplerate
@@ -69,9 +69,9 @@ if __name__ == '__main__': · 40 unmodified lines
69 parser = argparse.ArgumentParser()69 parser = argparse.ArgumentParser()
70 parser.add_argument('-m', '--mode',70 parser.add_argument('-m', '--mode',
71 help="mode [default|fast|super-fast]",71 help="mode [default|fast|super-fast]",
72 dest="mode")72 dest="mode", default='default')
73 parser.add_argument('sources',73 parser.add_argument('sources',
74 nargs='*',74 nargs='+',
75 help="input_files")75 help="input_files")
76 args = parser.parse_args()76 args = parser.parse_args()
77 for f in args.sources:77 for f in args.sources:
python/ext/aubiomodule.c+12−4
@@ -117,7 +117,9 @@ Py_bintomidi (PyObject * self, PyObject * args) · 116 unmodified lines
117 smpl_t input, samplerate, fftsize;117 smpl_t input, samplerate, fftsize;
118 smpl_t output;118 smpl_t output;
119 119
120 if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {120 if (!PyArg_ParseTuple (args,
121 "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
122 &input, &samplerate, &fftsize)) {
121 return NULL;123 return NULL;
122 }124 }
123 125
@@ -132,7 +134,9 @@ Py_miditobin (PyObject * self, PyObject * args) · 8 unmodified lines
132 smpl_t input, samplerate, fftsize;134 smpl_t input, samplerate, fftsize;
133 smpl_t output;135 smpl_t output;
134 136
135 if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {137 if (!PyArg_ParseTuple (args,
138 "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
139 &input, &samplerate, &fftsize)) {
136 return NULL;140 return NULL;
137 }141 }
138 142
@@ -147,7 +151,9 @@ Py_bintofreq (PyObject * self, PyObject * args) · 8 unmodified lines
147 smpl_t input, samplerate, fftsize;151 smpl_t input, samplerate, fftsize;
148 smpl_t output;152 smpl_t output;
149 153
150 if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {154 if (!PyArg_ParseTuple (args,
155 "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
156 &input, &samplerate, &fftsize)) {
151 return NULL;157 return NULL;
152 }158 }
153 159
@@ -162,7 +168,9 @@ Py_freqtobin (PyObject * self, PyObject * args) · 8 unmodified lines
162 smpl_t input, samplerate, fftsize;168 smpl_t input, samplerate, fftsize;
163 smpl_t output;169 smpl_t output;
164 170
165 if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {171 if (!PyArg_ParseTuple (args,
172 "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
173 &input, &samplerate, &fftsize)) {
166 return NULL;174 return NULL;
167 }175 }
168 176
python/ext/py-filterbank.c+3−3
@@ -94,7 +94,7 @@ Py_filterbank_do(Py_filterbank * self, PyObject * args) · 93 unmodified lines
94 94
95 if (self->vec.length != self->win_s / 2 + 1) {95 if (self->vec.length != self->win_s / 2 + 1) {
96 PyErr_Format(PyExc_ValueError,96 PyErr_Format(PyExc_ValueError,
97 "input cvec has length %d, but fft expects length %d",97 "input cvec has length %d, but filterbank expects length %d",
98 self->vec.length, self->win_s / 2 + 1);98 self->vec.length, self->win_s / 2 + 1);
99 return NULL;99 return NULL;
100 }100 }
@@ -139,7 +139,7 @@ Py_filterbank_set_triangle_bands (Py_filterbank * self, PyObject *args) · 38 unmodified lines
139 &(self->freqs), samplerate);139 &(self->freqs), samplerate);
140 if (err > 0) {140 if (err > 0) {
141 PyErr_SetString (PyExc_ValueError,141 PyErr_SetString (PyExc_ValueError,
142 "error when setting filter to A-weighting");142 "error when running set_triangle_bands");
143 return NULL;143 return NULL;
144 }144 }
145 Py_RETURN_NONE;145 Py_RETURN_NONE;
@@ -158,7 +158,7 @@ Py_filterbank_set_mel_coeffs_slaney (Py_filterbank * self, PyObject *args) · 12 unmodified lines
158 err = aubio_filterbank_set_mel_coeffs_slaney (self->o, samplerate);158 err = aubio_filterbank_set_mel_coeffs_slaney (self->o, samplerate);
159 if (err > 0) {159 if (err > 0) {
160 PyErr_SetString (PyExc_ValueError,160 PyErr_SetString (PyExc_ValueError,
161 "error when setting filter to A-weighting");161 "error when running set_mel_coeffs_slaney");
162 return NULL;162 return NULL;
163 }163 }
164 Py_RETURN_NONE;164 Py_RETURN_NONE;
python/lib/aubio/cmd.py+30−1
@@ -101,6 +101,8 @@ def parser_add_subcommand_notes(subparsers): · 100 unmodified lines
101 help='estimate midi-like notes (monophonic)')101 help='estimate midi-like notes (monophonic)')
102 subparser.add_input()102 subparser.add_input()
103 subparser.add_buf_hop_size()103 subparser.add_buf_hop_size()
104 subparser.add_silence()
105 subparser.add_release_drop()
104 subparser.add_time_format()106 subparser.add_time_format()
105 subparser.add_verbose_help()107 subparser.add_verbose_help()
106 subparser.set_defaults(process=process_notes)108 subparser.set_defaults(process=process_notes)
@@ -207,6 +209,12 @@ class AubioArgumentParser(argparse.ArgumentParser): · 100 unmodified lines
207 action="store", dest="silence", default=-70,209 action="store", dest="silence", default=-70,
208 help="silence threshold")210 help="silence threshold")
209 211
212 def add_release_drop(self):
213 self.add_argument("-d", "--release-drop",
214 metavar = "<value>", type=float,
215 action="store", dest="release_drop", default=10,
216 help="release drop threshold")
217
210 def add_minioi(self, default="12ms"):218 def add_minioi(self, default="12ms"):
211 self.add_argument("-M", "--minioi",219 self.add_argument("-M", "--minioi",
212 metavar = "<value>", type=str,220 metavar = "<value>", type=str,
@@ -382,6 +390,10 @@ class process_notes(default_process): · 169 unmodified lines
382 def __init__(self, args):390 def __init__(self, args):
383 self.parse_options(args, self.valid_opts)391 self.parse_options(args, self.valid_opts)
384 self.notes = aubio.notes(**self.options)392 self.notes = aubio.notes(**self.options)
393 if args.silence is not None:
394 self.notes.set_silence(args.silence)
395 if args.release_drop is not None:
396 self.notes.set_release_drop(args.release_drop)
385 super(process_notes, self).__init__(args)397 super(process_notes, self).__init__(args)
386 def __call__(self, block):398 def __call__(self, block):
387 return self.notes(block)399 return self.notes(block)
@@ -502,7 +514,24 @@ class process_cut(process_onset): · 114 unmodified lines
502 514
503def main():515def main():
504 parser = aubio_parser()516 parser = aubio_parser()
505 args = parser.parse_args()517 if sys.version_info[0] != 3:
518 # on py2, create a dummy ArgumentParser to workaround the
519 # optional subcommand issue. See https://bugs.python.org/issue9253
520 # This ensures that:
521 # - version string is shown when only '-V' is passed
522 # - help is printed if '-V' is passed with any other argument
523 # - any other argument get forwarded to the real parser
524 parser_root = argparse.ArgumentParser(add_help=False)
525 parser_root.add_argument('-V', '--version', help="show version",
526 action="store_true", dest="show_version")
527 args, extras = parser_root.parse_known_args()
528 if args.show_version == False: # no -V, forward to parser
529 args = parser.parse_args(extras, namespace=args)
530 elif len(extras) != 0: # -V with other arguments, print help
531 parser.print_help()
532 sys.exit(1)
533 else: # in py3, we can simply use parser directly
534 args = parser.parse_args()
506 if 'show_version' in args and args.show_version:535 if 'show_version' in args and args.show_version:
507 sys.stdout.write('aubio version ' + aubio.version + '\n')536 sys.stdout.write('aubio version ' + aubio.version + '\n')
508 sys.exit(0)537 sys.exit(0)
python/lib/aubio/midiconv.py+38−9
@@ -1,9 +1,11 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2""" utilities to convert midi note number to and from note names """2""" utilities to convert midi note number to and from note names """
3 3
4__all__ = ['note2midi', 'midi2note', 'freq2note']4__all__ = ['note2midi', 'midi2note', 'freq2note', 'note2freq']
5 5
6import sys6import sys
7from ._aubio import freqtomidi, miditofreq
8
7py3 = sys.version_info[0] == 39py3 = sys.version_info[0] == 3
8if py3:10if py3:
9 str_instances = str11 str_instances = str
@@ -63,10 +65,11 @@ def note2midi(note): · 53 unmodified lines
63 }65 }
64 _valid_octaves = range(-1, 10)66 _valid_octaves = range(-1, 10)
65 if not isinstance(note, str_instances):67 if not isinstance(note, str_instances):
66 raise TypeError("a string is required, got %s (%s)" % (note, str(type(note))))68 msg = "a string is required, got {:s} ({:s})"
69 raise TypeError(msg.format(str(type(note)), repr(note)))
67 if len(note) not in range(2, 5):70 if len(note) not in range(2, 5):
68 raise ValueError("string of 2 to 4 characters expected, got %d (%s)" \71 msg = "string of 2 to 4 characters expected, got {:d} ({:s})"
69 % (len(note), note))72 raise ValueError(msg.format(len(note), note))
70 notename, modifier, octave = [None]*373 notename, modifier, octave = [None]*3
71 74
72 if len(note) == 4:75 if len(note) == 4:
@@ -90,7 +93,8 @@ def note2midi(note): · 17 unmodified lines
90 if octave not in _valid_octaves:93 if octave not in _valid_octaves:
91 raise ValueError("%s is not a valid octave" % octave)94 raise ValueError("%s is not a valid octave" % octave)
92 95
93 midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier]96 midi = 12 + octave * 12 + _valid_notenames[notename] \
97 + _valid_modifiers[modifier]
94 if midi > 127:98 if midi > 127:
95 raise ValueError("%s is outside of the range C-2 to G8" % note)99 raise ValueError("%s is outside of the range C-2 to G8" % note)
96 return midi100 return midi
@@ -129,8 +133,10 @@ def midi2note(midi): · 32 unmodified lines
129 if not isinstance(midi, int_instances):133 if not isinstance(midi, int_instances):
130 raise TypeError("an integer is required, got %s" % midi)134 raise TypeError("an integer is required, got %s" % midi)
131 if midi not in range(0, 128):135 if midi not in range(0, 128):
132 raise ValueError("an integer between 0 and 127 is excepted, got %d" % midi)136 msg = "an integer between 0 and 127 is excepted, got {:d}"
133 _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']137 raise ValueError(msg.format(midi))
138 _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#',
139 'A', 'A#', 'B']
134 return _valid_notenames[midi % 12] + str(int(midi / 12) - 1)140 return _valid_notenames[midi % 12] + str(int(midi / 12) - 1)
135 141
136def freq2note(freq):142def freq2note(freq):
@@ -153,5 +159,28 @@ def freq2note(freq): · 16 unmodified lines
153 >>> aubio.freq2note(220.1)159 >>> aubio.freq2note(220.1)
154 'A3'160 'A3'
155 """161 """
156 from aubio import freqtomidi162 nearest_note = int(freqtomidi(freq) + .5)
157 return midi2note(int(freqtomidi(freq)))163 return midi2note(nearest_note)
164
165def note2freq(note):
166 """Convert note name to corresponding frequency, in Hz.
167
168 Parameters
169 ----------
170 note : str
171 input note name
172
173 Returns
174 -------
175 freq : float [0, 23000[
176 frequency, in Hz
177
178 Example
179 -------
180 >>> aubio.note2freq('A4')
181 440
182 >>> aubio.note2freq('A3')
183 220.1
184 """
185 midi = note2midi(note)
186 return miditofreq(midi)
python/tests/test_aubio_cmd.py+6−3
@@ -19,13 +19,16 @@ class aubio_cmd(TestCase): · 18 unmodified lines
19class aubio_cmd_utils(TestCase):19class aubio_cmd_utils(TestCase):
20 20
21 def test_samples2seconds(self):21 def test_samples2seconds(self):
22 self.assertEqual(aubio.cmd.samples2seconds(3200, 32000), "0.100000\t")22 self.assertEqual(aubio.cmd.samples2seconds(3200, 32000),
23 "0.100000\t")
23 24
24 def test_samples2milliseconds(self):25 def test_samples2milliseconds(self):
25 self.assertEqual(aubio.cmd.samples2milliseconds(3200, 32000), "100.000000\t")26 self.assertEqual(aubio.cmd.samples2milliseconds(3200, 32000),
27 "100.000000\t")
26 28
27 def test_samples2samples(self):29 def test_samples2samples(self):
28 self.assertEqual(aubio.cmd.samples2samples(3200, 32000), "3200\t")30 self.assertEqual(aubio.cmd.samples2samples(3200, 32000),
31 "3200\t")
29 32
30if __name__ == '__main__':33if __name__ == '__main__':
31 main()34 main()
python/tests/test_note2midi.py+19−2
@@ -3,7 +3,7 @@ · 2 unmodified lines
3 3
4from __future__ import unicode_literals4from __future__ import unicode_literals
5 5
6from aubio import note2midi, freq2note6from aubio import note2midi, freq2note, note2freq, float_type
7from nose2.tools import params7from nose2.tools import params
8import unittest8import unittest
9 9
@@ -111,10 +111,27 @@ class note2midi_wrong_values(unittest.TestCase): · 101 unmodified lines
111 111
112class freq2note_simple_test(unittest.TestCase):112class freq2note_simple_test(unittest.TestCase):
113 113
114 def test_freq2note(self):114 def test_freq2note_above(self):
115 " make sure freq2note(441) == A4 "115 " make sure freq2note(441) == A4 "
116 self.assertEqual("A4", freq2note(441))116 self.assertEqual("A4", freq2note(441))
117 117
118 def test_freq2note_under(self):
119 " make sure freq2note(439) == A4 "
120 self.assertEqual("A4", freq2note(439))
121
122class note2freq_simple_test(unittest.TestCase):
123
124 def test_note2freq(self):
125 " make sure note2freq('A3') == 220"
126 self.assertEqual(220, note2freq("A3"))
127
128 def test_note2freq_under(self):
129 " make sure note2freq(A4) == 440"
130 if float_type == 'float32':
131 self.assertEqual(440, note2freq("A4"))
132 else:
133 self.assertLess(abs(note2freq("A4")-440), 1.e-12)
134
118if __name__ == '__main__':135if __name__ == '__main__':
119 import nose2136 import nose2
120 nose2.main()137 nose2.main()
python/tests/test_notes.py+14−0
@@ -5,6 +5,7 @@ from numpy.testing import TestCase, assert_equal, assert_almost_equal · 4 unmodified lines
5from aubio import notes5from aubio import notes
6 6
7AUBIO_DEFAULT_NOTES_SILENCE = -70.7AUBIO_DEFAULT_NOTES_SILENCE = -70.
8AUBIO_DEFAULT_NOTES_RELEASE_DROP = 10.
8AUBIO_DEFAULT_NOTES_MINIOI_MS = 30.9AUBIO_DEFAULT_NOTES_MINIOI_MS = 30.
9 10
10class aubio_notes_default(TestCase):11class aubio_notes_default(TestCase):
@@ -38,6 +39,19 @@ class aubio_notes_params(TestCase): · 27 unmodified lines
38 self.o.set_silence(val)39 self.o.set_silence(val)
39 assert_equal (self.o.get_silence(), val)40 assert_equal (self.o.get_silence(), val)
40 41
42 def test_get_release_drop(self):
43 assert_equal (self.o.get_release_drop(), AUBIO_DEFAULT_NOTES_RELEASE_DROP)
44
45 def test_set_release_drop(self):
46 val = 50
47 self.o.set_release_drop(val)
48 assert_equal (self.o.get_release_drop(), val)
49
50 def test_set_release_drop_wrong(self):
51 val = -10
52 with self.assertRaises(ValueError):
53 self.o.set_release_drop(val)
54
41from .utils import list_all_sounds55from .utils import list_all_sounds
42list_of_sounds = list_all_sounds('sounds')56list_of_sounds = list_all_sounds('sounds')
43 57
python/tests/test_slicing.py+2−2
@@ -34,13 +34,13 @@ class aubio_slicing_test_case(TestCase): · 33 unmodified lines
34 34
35 def test_slice_start_every_blocksize(self):35 def test_slice_start_every_blocksize(self):
36 hopsize = 20036 hopsize = 200
37 regions_start = [i*hopsize for i in range(1, n_slices)]37 regions_start = [i*hopsize for i in range(0, n_slices)]
38 slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir,38 slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir,
39 hopsize = 200)39 hopsize = 200)
40 40
41 def test_slice_start_every_half_blocksize(self):41 def test_slice_start_every_half_blocksize(self):
42 hopsize = 20042 hopsize = 200
43 regions_start = [i*hopsize//2 for i in range(1, n_slices)]43 regions_start = [i*hopsize//2 for i in range(0, n_slices)]
44 slice_source_at_stamps(self.source_file, regions_start,44 slice_source_at_stamps(self.source_file, regions_start,
45 output_dir = self.output_dir, hopsize = 200)45 output_dir = self.output_dir, hopsize = 200)
46 46

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t