summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2017-12-05 16:09:19 +0100
committerRobin Gareus <robin@gareus.org>2017-12-05 16:09:52 +0100
commitc0f34653049d255640f76484dfa50700629ad90d (patch)
treecd33e4951c4961e0272944c014e28dd5515a98dd /scripts
parent4a66edd48074a1e1fdbe7fc464b59860b185bdd4 (diff)
Add example Lua script to send raw MIDI (sysex) from file
Diffstat (limited to 'scripts')
-rw-r--r--scripts/_tx_raw_midi_from_file.lua110
1 files changed, 110 insertions, 0 deletions
diff --git a/scripts/_tx_raw_midi_from_file.lua b/scripts/_tx_raw_midi_from_file.lua
new file mode 100644
index 0000000000..36cbdc1a39
--- /dev/null
+++ b/scripts/_tx_raw_midi_from_file.lua
@@ -0,0 +1,110 @@
+ardour {
+ ["type"] = "EditorAction",
+ name = "Send Raw MIDI from File",
+ license = "MIT",
+ author = "Ardour Team",
+ description = [[Read raw binary midi (.syx) from file and send it to a control port]]
+}
+
+function factory () return function ()
+
+ function portlist ()
+ local rv = {}
+ local a = Session:engine()
+ local _, t = a:get_ports (ARDOUR.DataType("midi"), ARDOUR.PortList())
+ for p in t[2]:iter() do
+ local amp = p:to_asyncmidiport ()
+ if amp:isnil() or not amp:sends_output() then goto continue end
+ rv[amp:name()] = amp
+ print (amp:name(), amp:sends_output())
+ ::continue::
+ end
+ return rv
+ end
+
+ local dialog_options = {
+ { type = "file", key = "file", title = "Select .syx MIDI file" },
+ { type = "dropdown", key = "port", title = "Target Port", values = portlist () }
+ }
+
+ local rv = LuaDialog.Dialog ("Select Taget", dialog_options):run ()
+ dialog_options = nil -- drop references (ports, shared ptr)
+ collectgarbage () -- and release the references immediately
+
+ if not rv then return end -- user cancelled
+
+ local f = io.open (rv["file"], "rb")
+
+ if not f then
+ LuaDialog.Message ("Raw MIDI Tx", "File Not Found", LuaDialog.MessageType.Error, LuaDialog.ButtonType.Close):run ()
+ goto out
+ end
+
+ do -- scope for 'local'
+ local size = f:seek("end") -- determine file size
+ f:seek("set", 0)
+
+ if size > 1048576 then
+ local ok = LuaDialog.Message ("Raw MIDI Tx",
+ string.format ("File is larger than 1MB.\nFile-size = %.1f kB\n\nContinue?", size / 1024),
+ LuaDialog.MessageType.Question, LuaDialog.ButtonType.Yes_No):run ()
+ if ok ~= LuaDialog.Response.Yes then
+ f:close ()
+ goto out
+ end
+ end
+ end
+
+ do -- scope for 'local'
+ local midi_byte_count = 0
+ local total_read = 0
+ local message_count = 0
+ local long_message = false
+
+ local async_midi_port = rv["port"] -- reference to port
+ local parser = ARDOUR.RawMidiParser () -- construct a MIDI parser
+
+ while true do
+ -- read file in 64byte chunks
+ local bytes = f:read (64)
+ if not bytes then break end
+ total_read = total_read + #bytes
+
+ -- parse MIDI data byte-by-byte
+ for i = 1, #bytes do
+ if parser:process_byte (bytes:byte (i)) then
+ if parser:buffer_size () > 127 then
+ long_message = true
+ print ("WARNING -- single large message > 127, bytes: ", parser:buffer_size ())
+ end
+ -- parsed complete normalized MIDI message, send it
+ async_midi_port:write (parser:midi_buffer (), parser:buffer_size (), 0)
+
+ -- Physical MIDI is sent at 31.25kBaud.
+ -- Every message is sent as 10bit message on the wire,
+ -- so every MIDI byte needs 320usec.
+ ARDOUR.LuaAPI.usleep (400 * parser:buffer_size ())
+
+ -- count msgs and valid bytes sent
+ midi_byte_count = midi_byte_count + parser:buffer_size ()
+ message_count = message_count + 1
+ if 0 == message_count % 50 then
+ -- print() wakes up the GUI, prevent stalling the event loop
+ print ("Sent", message_count, "messages, bytes so far: ", midi_byte_count)
+ end
+ end
+ end
+ end
+
+ f:close ()
+ print ("Sent", message_count, "messages, total bytes: ", midi_byte_count, "/", total_read)
+
+ if long_message then
+ LuaDialog.Message ("Raw MIDI Tx", "Dataset contained messages longer than 127 bytes. Which may or may not have been transmitted successfully.", LuaDialog.MessageType.Warning, LuaDialog.ButtonType.Close):run ()
+ end
+ end
+
+ ::out::
+ rv = nil
+ collectgarbage ()
+end end