Showing the changes to python/lib (4 of 28 files). Show all
Unified · Split
| @@ -255,6 +255,9 @@ class AubioArgumentParser(argparse.ArgumentParser): · 254 unmodified lines | ||
| 255 | 255 | metavar = "<slices>", |
| 256 | 256 | action = "store", dest = "cut_until_nslices", default = None, |
| 257 | 257 | help="how many extra slices should be added at the end of each slice") |
| 258 | + self.add_argument("--create-first", | |
| 259 | + action = "store_true", dest = "create_first", default = False, | |
| 260 | + help="always include first slice") | |
| 258 | 261 | |
| 259 | 262 | # some utilities |
| 260 | 263 | |
| @@ -511,7 +514,24 @@ class process_cut(process_onset): · 250 unmodified lines | ||
| 511 | 514 | |
| 512 | 515 | def main(): |
| 513 | 516 | parser = aubio_parser() |
| 514 | − 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() | |
| 515 | 535 | if 'show_version' in args and args.show_version: |
| 516 | 536 | sys.stdout.write('aubio version ' + aubio.version + '\n') |
| 517 | 537 | sys.exit(0) |
| @@ -101,7 +101,7 @@ def _cut_analyze(options): · 100 unmodified lines | ||
| 101 | 101 | |
| 102 | 102 | s = source(source_uri, samplerate, hopsize) |
| 103 | 103 | if samplerate == 0: |
| 104 | − samplerate = s.get_samplerate() | |
| 104 | + samplerate = s.samplerate | |
| 105 | 105 | options.samplerate = samplerate |
| 106 | 106 | |
| 107 | 107 | if options.beat: |
| @@ -150,7 +150,8 @@ def _cut_slice(options, timestamps): · 42 unmodified lines | ||
| 150 | 150 | slice_source_at_stamps(options.source_uri, |
| 151 | 151 | timestamps, timestamps_end = timestamps_end, |
| 152 | 152 | output_dir = options.output_directory, |
| 153 | − samplerate = options.samplerate) | |
| 153 | + samplerate = options.samplerate, | |
| 154 | + create_first = options.create_first) | |
| 154 | 155 | |
| 155 | 156 | def main(): |
| 156 | 157 | parser = aubio_cut_parser() |
| @@ -1,9 +1,11 @@ | ||
| 1 | 1 | # -*- coding: utf-8 -*- |
| 2 | 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 | |
| 6 | 6 | import sys |
| 7 | +from ._aubio import freqtomidi, miditofreq | |
| 8 | + | |
| 7 | 9 | py3 = sys.version_info[0] == 3 |
| 8 | 10 | if py3: |
| 9 | 11 | str_instances = str |
| @@ -24,10 +26,11 @@ def note2midi(note): · 14 unmodified lines | ||
| 24 | 26 | } |
| 25 | 27 | _valid_octaves = range(-1, 10) |
| 26 | 28 | if not isinstance(note, str_instances): |
| 27 | − raise TypeError("a string is required, got %s (%s)" % (note, str(type(note)))) | |
| 29 | + msg = "a string is required, got {:s} ({:s})" | |
| 30 | + raise TypeError(msg.format(str(type(note)), repr(note))) | |
| 28 | 31 | if len(note) not in range(2, 5): |
| 29 | − raise ValueError("string of 2 to 4 characters expected, got %d (%s)" \ | |
| 30 | − % (len(note), note)) | |
| 32 | + msg = "string of 2 to 4 characters expected, got {:d} ({:s})" | |
| 33 | + raise ValueError(msg.format(len(note), note)) | |
| 31 | 34 | notename, modifier, octave = [None]*3 |
| 32 | 35 | |
| 33 | 36 | if len(note) == 4: |
| @@ -51,7 +54,8 @@ def note2midi(note): · 17 unmodified lines | ||
| 51 | 54 | if octave not in _valid_octaves: |
| 52 | 55 | raise ValueError("%s is not a valid octave" % octave) |
| 53 | 56 | |
| 54 | − midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier] | |
| 57 | + midi = 12 + octave * 12 + _valid_notenames[notename] \ | |
| 58 | + + _valid_modifiers[modifier] | |
| 55 | 59 | if midi > 127: |
| 56 | 60 | raise ValueError("%s is outside of the range C-2 to G8" % note) |
| 57 | 61 | return midi |
| @@ -61,11 +65,36 @@ def midi2note(midi): · 3 unmodified lines | ||
| 61 | 65 | if not isinstance(midi, int_instances): |
| 62 | 66 | raise TypeError("an integer is required, got %s" % midi) |
| 63 | 67 | if midi not in range(0, 128): |
| 64 | − raise ValueError("an integer between 0 and 127 is excepted, got %d" % midi) | |
| 65 | − _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] | |
| 68 | + msg = "an integer between 0 and 127 is excepted, got {:d}" | |
| 69 | + raise ValueError(msg.format(midi)) | |
| 70 | + _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', | |
| 71 | + 'A', 'A#', 'B'] | |
| 66 | 72 | return _valid_notenames[midi % 12] + str(int(midi / 12) - 1) |
| 67 | 73 | |
| 68 | 74 | def freq2note(freq): |
| 69 | 75 | " convert frequency in Hz to nearest note name, e.g. [0, 22050.] -> [C-1, G9] " |
| 70 | − from aubio import freqtomidi | |
| 71 | − return midi2note(int(freqtomidi(freq))) | |
| 76 | + nearest_note = int(freqtomidi(freq) + .5) | |
| 77 | + return midi2note(nearest_note) | |
| 78 | + | |
| 79 | +def note2freq(note): | |
| 80 | + """Convert note name to corresponding frequency, in Hz. | |
| 81 | + | |
| 82 | + Parameters | |
| 83 | + ---------- | |
| 84 | + note : str | |
| 85 | + input note name | |
| 86 | + | |
| 87 | + Returns | |
| 88 | + ------- | |
| 89 | + freq : float [0, 23000[ | |
| 90 | + frequency, in Hz | |
| 91 | + | |
| 92 | + Example | |
| 93 | + ------- | |
| 94 | + >>> aubio.note2freq('A4') | |
| 95 | + 440 | |
| 96 | + >>> aubio.note2freq('A3') | |
| 97 | + 220.1 | |
| 98 | + """ | |
| 99 | + midi = note2midi(note) | |
| 100 | + return miditofreq(midi) | |
| @@ -6,19 +6,22 @@ from aubio import source, sink · 5 unmodified lines | ||
| 6 | 6 | _max_timestamp = 1e120 |
| 7 | 7 | |
| 8 | 8 | def slice_source_at_stamps(source_file, timestamps, timestamps_end=None, |
| 9 | − output_dir=None, samplerate=0, hopsize=256): | |
| 9 | + output_dir=None, samplerate=0, hopsize=256, | |
| 10 | + create_first=False): | |
| 10 | 11 | """ slice a sound file at given timestamps """ |
| 11 | 12 | |
| 12 | 13 | if timestamps is None or len(timestamps) == 0: |
| 13 | 14 | raise ValueError("no timestamps given") |
| 14 | 15 | |
| 15 | − if timestamps[0] != 0: | |
| 16 | + if timestamps[0] != 0 and create_first: | |
| 16 | 17 | timestamps = [0] + timestamps |
| 17 | 18 | if timestamps_end is not None: |
| 18 | 19 | timestamps_end = [timestamps[1] - 1] + timestamps_end |
| 19 | 20 | |
| 20 | 21 | if timestamps_end is not None: |
| 21 | − if len(timestamps_end) != len(timestamps): | |
| 22 | + if len(timestamps_end) == len(timestamps) - 1: | |
| 23 | + timestamps_end = timestamps_end + [_max_timestamp] | |
| 24 | + elif len(timestamps_end) != len(timestamps): | |
| 22 | 25 | raise ValueError("len(timestamps_end) != len(timestamps)") |
| 23 | 26 | else: |
| 24 | 27 | timestamps_end = [t - 1 for t in timestamps[1:]] + [_max_timestamp] |
| @@ -48,7 +51,7 @@ def slice_source_at_stamps(source_file, timestamps, timestamps_end=None, · 23 unmodified lines | ||
| 48 | 51 | # get hopsize new samples from source |
| 49 | 52 | vec, read = _source.do_multi() |
| 50 | 53 | # if the total number of frames read will exceed the next region start |
| 51 | − if len(regions) and total_frames + read >= regions[0][0]: | |
| 54 | + while len(regions) and total_frames + read >= regions[0][0]: | |
| 52 | 55 | #print "getting", regions[0], "at", total_frames |
| 53 | 56 | # get next region |
| 54 | 57 | start_stamp, end_stamp = regions.pop(0) |
| @@ -75,12 +78,15 @@ def slice_source_at_stamps(source_file, timestamps, timestamps_end=None, · 20 unmodified lines | ||
| 75 | 78 | if remaining > start: |
| 76 | 79 | # write remaining samples from current region |
| 77 | 80 | _sink.do_multi(vec[:, start:remaining], remaining - start) |
| 78 | − #print "closing region", "remaining", remaining | |
| 81 | + #print("closing region", "remaining", remaining) | |
| 79 | 82 | # close this file |
| 80 | 83 | _sink.close() |
| 81 | 84 | elif read > start: |
| 82 | 85 | # write all the samples |
| 83 | 86 | _sink.do_multi(vec[:, start:read], read - start) |
| 84 | 87 | total_frames += read |
| 88 | + # remove old slices | |
| 89 | + slices = list(filter(lambda s: s['end_stamp'] > total_frames, | |
| 90 | + slices)) | |
| 85 | 91 | if read < hopsize: |
| 86 | 92 | break |