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