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) |
---|
51 | return int(second2tick(sec, ticks_per_beat, tempo)) |
---|
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]), |
---|
66 | velocity=127, time=0) |
---|
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) |
---|