f503dc0a58862a9751f9ea71318b4e61cee9b94b
[aubio.git] / python / demos / demo_wav2midi.py
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     tick = int(second2tick(sec, ticks_per_beat, tempo))
52     return tick
53
54 sec = 7
55 previous_note = None
56
57 last_time = 0
58
59 # total number of frames read
60 total_frames = 0
61 while True:
62     samples, read = s()
63     new_note = notes_o(samples)
64     if (new_note[0] != 0):
65         note_str = ' '.join(["%.2f" % i for i in new_note])
66         print("%.6f" % (total_frames/float(samplerate)), new_note)
67         delta = frames2tick(total_frames) - last_time
68         if new_note[2] > 0:
69             track.append(Message('note_off', note=int(new_note[2]),
70                 velocity=127, time=0)
71                 )
72         track.append(Message('note_on',
73             note=int(new_note[0]),
74             velocity=int(new_note[1]),
75             time=delta)
76             )
77         last_time = frames2tick(total_frames)
78     total_frames += read
79     if read < hop_s: break
80
81 mid.save(midioutput)