[3c6a3c4] | 1 | #! /usr/bin/env python |
---|
| 2 | |
---|
| 3 | # Simple demo to extract notes from a sound file, and store them in a midi file |
---|
| 4 | # using mido. |
---|
| 5 | # |
---|
| 6 | # Install mido: `pip instal mido` |
---|
| 7 | # |
---|
| 8 | # Documentation: https://mido.readthedocs.io/ |
---|
| 9 | |
---|
| 10 | import sys |
---|
| 11 | from aubio import source, notes |
---|
| 12 | from mido import Message, MetaMessage, MidiFile, MidiTrack, second2tick, bpm2tempo |
---|
| 13 | |
---|
| 14 | if len(sys.argv) < 3: |
---|
| 15 | print("Usage: %s <filename> <output> [samplerate]" % sys.argv[0]) |
---|
| 16 | sys.exit(1) |
---|
| 17 | |
---|
| 18 | filename = sys.argv[1] |
---|
| 19 | midioutput = sys.argv[2] |
---|
| 20 | |
---|
| 21 | downsample = 1 |
---|
| 22 | samplerate = 44100 // downsample |
---|
| 23 | if len( sys.argv ) > 3: samplerate = int(sys.argv[3]) |
---|
| 24 | |
---|
| 25 | win_s = 512 // downsample # fft size |
---|
| 26 | hop_s = 256 // downsample # hop size |
---|
| 27 | |
---|
| 28 | s = source(filename, samplerate, hop_s) |
---|
| 29 | samplerate = s.samplerate |
---|
| 30 | |
---|
| 31 | tolerance = 0.8 |
---|
| 32 | |
---|
| 33 | notes_o = notes("default", win_s, hop_s, samplerate) |
---|
| 34 | |
---|
| 35 | print("%8s" % "time","[ start","vel","last ]") |
---|
| 36 | |
---|
| 37 | # create a midi file |
---|
| 38 | mid = MidiFile() |
---|
| 39 | track = MidiTrack() |
---|
| 40 | mid.tracks.append(track) |
---|
| 41 | |
---|
| 42 | ticks_per_beat = mid.ticks_per_beat # default: 480 |
---|
| 43 | bpm = 120 # default midi tempo |
---|
| 44 | |
---|
| 45 | tempo = bpm2tempo(bpm) |
---|
| 46 | track.append(MetaMessage('set_tempo', tempo=tempo)) |
---|
| 47 | track.append(MetaMessage('time_signature', numerator=4, denominator=4)) |
---|
| 48 | |
---|
| 49 | def frames2tick(frames, samplerate=samplerate): |
---|
| 50 | sec = frames / float(samplerate) |
---|
[34dca87] | 51 | return int(second2tick(sec, ticks_per_beat, tempo)) |
---|
[3c6a3c4] | 52 | |
---|
| 53 | last_time = 0 |
---|
| 54 | |
---|
| 55 | # total number of frames read |
---|
| 56 | total_frames = 0 |
---|
| 57 | while True: |
---|
| 58 | samples, read = s() |
---|
| 59 | new_note = notes_o(samples) |
---|
| 60 | if (new_note[0] != 0): |
---|
| 61 | note_str = ' '.join(["%.2f" % i for i in new_note]) |
---|
| 62 | print("%.6f" % (total_frames/float(samplerate)), new_note) |
---|
| 63 | delta = frames2tick(total_frames) - last_time |
---|
| 64 | if new_note[2] > 0: |
---|
| 65 | track.append(Message('note_off', note=int(new_note[2]), |
---|
[f55630c] | 66 | velocity=127, time=delta) |
---|
[3c6a3c4] | 67 | ) |
---|
| 68 | track.append(Message('note_on', |
---|
| 69 | note=int(new_note[0]), |
---|
| 70 | velocity=int(new_note[1]), |
---|
| 71 | time=delta) |
---|
| 72 | ) |
---|
| 73 | last_time = frames2tick(total_frames) |
---|
| 74 | total_frames += read |
---|
| 75 | if read < hop_s: break |
---|
| 76 | |
---|
| 77 | mid.save(midioutput) |
---|