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
2222 elif params.mode in ['default']:
2323 pass
2424 else:
25− print("unknown mode {:s}".format(params.mode))
25+ raise ValueError("unknown mode {:s}".format(params.mode))
2626 # manual settings
2727 if 'samplerate' in params:
2828 samplerate = params.samplerate
@@ -69,9 +69,9 @@ if __name__ == '__main__': · 40 unmodified lines
6969 parser = argparse.ArgumentParser()
7070 parser.add_argument('-m', '--mode',
7171 help="mode [default|fast|super-fast]",
72− dest="mode")
72+ dest="mode", default='default')
7373 parser.add_argument('sources',
74− nargs='*',
74+ nargs='+',
7575 help="input_files")
7676 args = parser.parse_args()
7777 for f in args.sources:
python/ext/aubiomodule.c+12−4
@@ -117,7 +117,9 @@ Py_bintomidi (PyObject * self, PyObject * args) · 116 unmodified lines
117117 smpl_t input, samplerate, fftsize;
118118 smpl_t output;
119119
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)) {
121123 return NULL;
122124 }
123125
@@ -132,7 +134,9 @@ Py_miditobin (PyObject * self, PyObject * args) · 8 unmodified lines
132134 smpl_t input, samplerate, fftsize;
133135 smpl_t output;
134136
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)) {
136140 return NULL;
137141 }
138142
@@ -147,7 +151,9 @@ Py_bintofreq (PyObject * self, PyObject * args) · 8 unmodified lines
147151 smpl_t input, samplerate, fftsize;
148152 smpl_t output;
149153
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)) {
151157 return NULL;
152158 }
153159
@@ -162,7 +168,9 @@ Py_freqtobin (PyObject * self, PyObject * args) · 8 unmodified lines
162168 smpl_t input, samplerate, fftsize;
163169 smpl_t output;
164170
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)) {
166174 return NULL;
167175 }
168176
python/ext/py-filterbank.c+3−3
@@ -94,7 +94,7 @@ Py_filterbank_do(Py_filterbank * self, PyObject * args) · 93 unmodified lines
9494
9595 if (self->vec.length != self->win_s / 2 + 1) {
9696 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",
9898 self->vec.length, self->win_s / 2 + 1);
9999 return NULL;
100100 }
@@ -139,7 +139,7 @@ Py_filterbank_set_triangle_bands (Py_filterbank * self, PyObject *args) · 38 unmodified lines
139139 &(self->freqs), samplerate);
140140 if (err > 0) {
141141 PyErr_SetString (PyExc_ValueError,
142− "error when setting filter to A-weighting");
142+ "error when running set_triangle_bands");
143143 return NULL;
144144 }
145145 Py_RETURN_NONE;
@@ -158,7 +158,7 @@ Py_filterbank_set_mel_coeffs_slaney (Py_filterbank * self, PyObject *args) · 12 unmodified lines
158158 err = aubio_filterbank_set_mel_coeffs_slaney (self->o, samplerate);
159159 if (err > 0) {
160160 PyErr_SetString (PyExc_ValueError,
161− "error when setting filter to A-weighting");
161+ "error when running set_mel_coeffs_slaney");
162162 return NULL;
163163 }
164164 Py_RETURN_NONE;
python/lib/aubio/cmd.py+30−1
@@ -101,6 +101,8 @@ def parser_add_subcommand_notes(subparsers): · 100 unmodified lines
101101 help='estimate midi-like notes (monophonic)')
102102 subparser.add_input()
103103 subparser.add_buf_hop_size()
104+ subparser.add_silence()
105+ subparser.add_release_drop()
104106 subparser.add_time_format()
105107 subparser.add_verbose_help()
106108 subparser.set_defaults(process=process_notes)
@@ -207,6 +209,12 @@ class AubioArgumentParser(argparse.ArgumentParser): · 100 unmodified lines
207209 action="store", dest="silence", default=-70,
208210 help="silence threshold")
209211
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+
210218 def add_minioi(self, default="12ms"):
211219 self.add_argument("-M", "--minioi",
212220 metavar = "<value>", type=str,
@@ -382,6 +390,10 @@ class process_notes(default_process): · 169 unmodified lines
382390 def __init__(self, args):
383391 self.parse_options(args, self.valid_opts)
384392 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)
385397 super(process_notes, self).__init__(args)
386398 def __call__(self, block):
387399 return self.notes(block)
@@ -502,7 +514,24 @@ class process_cut(process_onset): · 114 unmodified lines
502514
503515 def main():
504516 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()
506535 if 'show_version' in args and args.show_version:
507536 sys.stdout.write('aubio version ' + aubio.version + '\n')
508537 sys.exit(0)
python/lib/aubio/midiconv.py+38−9
@@ -1,9 +1,11 @@
11 # -*- coding: utf-8 -*-
22 """ utilities to convert midi note number to and from note names """
33
4−__all__ = ['note2midi', 'midi2note', 'freq2note']
4+__all__ = ['note2midi', 'midi2note', 'freq2note', 'note2freq']
55
66 import sys
7+from ._aubio import freqtomidi, miditofreq
8+
79 py3 = sys.version_info[0] == 3
810 if py3:
911 str_instances = str
@@ -63,10 +65,11 @@ def note2midi(note): · 53 unmodified lines
6365 }
6466 _valid_octaves = range(-1, 10)
6567 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)))
6770 if len(note) not in range(2, 5):
68− raise ValueError("string of 2 to 4 characters expected, got %d (%s)" \
69− % (len(note), note))
71+ msg = "string of 2 to 4 characters expected, got {:d} ({:s})"
72+ raise ValueError(msg.format(len(note), note))
7073 notename, modifier, octave = [None]*3
7174
7275 if len(note) == 4:
@@ -90,7 +93,8 @@ def note2midi(note): · 17 unmodified lines
9093 if octave not in _valid_octaves:
9194 raise ValueError("%s is not a valid octave" % octave)
9295
93− midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier]
96+ midi = 12 + octave * 12 + _valid_notenames[notename] \
97+ + _valid_modifiers[modifier]
9498 if midi > 127:
9599 raise ValueError("%s is outside of the range C-2 to G8" % note)
96100 return midi
@@ -129,8 +133,10 @@ def midi2note(midi): · 32 unmodified lines
129133 if not isinstance(midi, int_instances):
130134 raise TypeError("an integer is required, got %s" % midi)
131135 if midi not in range(0, 128):
132− raise ValueError("an integer between 0 and 127 is excepted, got %d" % midi)
133− _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
136+ msg = "an integer between 0 and 127 is excepted, got {:d}"
137+ raise ValueError(msg.format(midi))
138+ _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#',
139+ 'A', 'A#', 'B']
134140 return _valid_notenames[midi % 12] + str(int(midi / 12) - 1)
135141
136142 def freq2note(freq):
@@ -153,5 +159,28 @@ def freq2note(freq): · 16 unmodified lines
153159 >>> aubio.freq2note(220.1)
154160 'A3'
155161 """
156− from aubio import freqtomidi
157− return midi2note(int(freqtomidi(freq)))
162+ nearest_note = int(freqtomidi(freq) + .5)
163+ return midi2note(nearest_note)
164+
165+def 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
1919 class aubio_cmd_utils(TestCase):
2020
2121 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")
2324
2425 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")
2628
2729 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")
2932
3033 if __name__ == '__main__':
3134 main()
python/tests/test_note2midi.py+19−2
@@ -3,7 +3,7 @@ · 2 unmodified lines
33
44 from __future__ import unicode_literals
55
6−from aubio import note2midi, freq2note
6+from aubio import note2midi, freq2note, note2freq, float_type
77 from nose2.tools import params
88 import unittest
99
@@ -111,10 +111,27 @@ class note2midi_wrong_values(unittest.TestCase): · 101 unmodified lines
111111
112112 class freq2note_simple_test(unittest.TestCase):
113113
114− def test_freq2note(self):
114+ def test_freq2note_above(self):
115115 " make sure freq2note(441) == A4 "
116116 self.assertEqual("A4", freq2note(441))
117117
118+ def test_freq2note_under(self):
119+ " make sure freq2note(439) == A4 "
120+ self.assertEqual("A4", freq2note(439))
121+
122+class 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+
118135 if __name__ == '__main__':
119136 import nose2
120137 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
55 from aubio import notes
66
77 AUBIO_DEFAULT_NOTES_SILENCE = -70.
8+AUBIO_DEFAULT_NOTES_RELEASE_DROP = 10.
89 AUBIO_DEFAULT_NOTES_MINIOI_MS = 30.
910
1011 class aubio_notes_default(TestCase):
@@ -38,6 +39,19 @@ class aubio_notes_params(TestCase): · 27 unmodified lines
3839 self.o.set_silence(val)
3940 assert_equal (self.o.get_silence(), val)
4041
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+
4155 from .utils import list_all_sounds
4256 list_of_sounds = list_all_sounds('sounds')
4357
python/tests/test_slicing.py+2−2
@@ -34,13 +34,13 @@ class aubio_slicing_test_case(TestCase): · 33 unmodified lines
3434
3535 def test_slice_start_every_blocksize(self):
3636 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)]
3838 slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir,
3939 hopsize = 200)
4040
4141 def test_slice_start_every_half_blocksize(self):
4242 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)]
4444 slice_source_at_stamps(self.source_file, regions_start,
4545 output_dir = self.output_dir, hopsize = 200)
4646

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