initial (incomplete) framework for DiskIOPoint manipulation
[ardour.git] / scripts / vamp_audio_to_midi.lua
1 ardour {
2         ["type"] = "EditorAction",
3         name = "Polyphonic Audio to MIDI",
4         license     = "MIT",
5         author      = "Ardour Team",
6 description = [[
7 Analyze audio from the selected audio region to a selected MIDI region.
8
9 A MIDI region on the target track will have to be created first (use the pen tool).
10
11 This script uses the Polyphonic Transcription VAMP plugin from Queen Mary Univ, London.
12 The plugin works best at 44.1KHz input sample rate, and is tuned for piano and guitar music. Velocity is not estimated.
13 ]]
14 }
15
16 function factory () return function ()
17         local sel = Editor:get_selection ()
18         local sr = Session:nominal_frame_rate ()
19         local tm = Session:tempo_map ()
20         local vamp = ARDOUR.LuaAPI.Vamp ("libardourvampplugins:qm-transcription", sr)
21         local midi_region
22         local audio_regions = {}
23         local start_time = Session:current_end_frame ()
24         local end_time = Session:current_start_frame ()
25         for r in sel.regions:regionlist ():iter () do
26                 if r:to_midiregion():isnil() then
27                         local st = r:position()
28                         local ln = r:length()
29                         local et = st + ln
30                         if st < start_time then
31                                 start_time = st
32                         end
33                         if et > end_time then
34                                 end_time = et
35                         end
36                         table.insert(audio_regions, r)
37                 else
38                         midi_region = r:to_midiregion()
39                 end
40         end
41         assert (audio_regions and midi_region)
42         midi_region:set_initial_position(start_time)
43         midi_region:set_length(end_time - start_time, 0)
44
45         for i,ar in pairs(audio_regions) do
46                 local a_off = ar:position ()
47                 local b_off = midi_region:quarter_note () - midi_region:start_beats ()
48
49                 vamp:analyze (ar:to_readable (), 0, nil)
50                 local fl = vamp:plugin ():getRemainingFeatures ():at (0)
51                 if fl and fl:size() > 0 then
52                         local mm = midi_region:midi_source(0):model()
53                         local midi_command = mm:new_note_diff_command ("Audio2Midi")
54                         for f in fl:iter () do
55                                 local ft = Vamp.RealTime.realTime2Frame (f.timestamp, sr)
56                                 local fd = Vamp.RealTime.realTime2Frame (f.duration, sr)
57                                 local fn = f.values:at (0)
58
59                                 local bs = tm:exact_qn_at_frame (a_off + ft, 0)
60                                 local be = tm:exact_qn_at_frame (a_off + ft + fd, 0)
61
62                                 local pos = Evoral.Beats (bs - b_off)
63                                 local len = Evoral.Beats (be - bs)
64                                 local note = ARDOUR.LuaAPI.new_noteptr (1, pos, len, fn + 1, 0x7f)
65                                 midi_command:add (note)
66                         end
67                         mm:apply_command (Session, midi_command)
68                 end
69         end
70 end end
71
72 function icon (params) return function (ctx, width, height, fg)
73         local txt = Cairo.PangoLayout (ctx, "ArdourMono ".. math.ceil(width * .7) .. "px")
74         txt:set_text ("\u{2669}") -- quarter note symbol UTF8
75         local tw, th = txt:get_pixel_size ()
76         ctx:set_source_rgba (ARDOUR.LuaAPI.color_to_rgba (fg))
77         ctx:move_to (.5 * (width - tw), .5 * (height - th))
78         txt:show_in_cairo_context (ctx)
79 end end