2017-12-05 10:09:19 -05:00
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. \n File-size = %.1f kB \n \n Continue? " , 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
2017-12-19 11:42:24 -05:00
if parser : buffer_size ( ) > 255 then
2017-12-05 10:09:19 -05:00
long_message = true
2017-12-19 11:42:24 -05:00
print ( " WARNING -- single large message > 255, bytes: " , parser : buffer_size ( ) )
2017-12-05 10:09:19 -05:00
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