MIDImyAPP
is a free programmable UNIX command-line tool (32/64bit Intel-based) for Mac OSX 10.5 or higher (old ppc version here) to remote your Mac and send user-defined MIDI events (including SysEx messages) triggered by any MIDI events sent on the MIDI bus.
For remoting your Mac you can specify any shell commands (a script [Shell, Ruby, Perl, Java, AppleScript, Python, etc.] or an UNIX command [open, say, etc.]) which will be executed if a defined MIDI event occured. It is also possible to send user-defined MIDI events triggerd by other MIDI events coming from the MIDI bus.
In addition MIDImyAPP is able to control basic functions of GarageBand (start MIDImyAPP with option -g
):
MIDIMyApp also ships with two other command-line tools to play and stop a sound or MIDI file.
MIDImyAPP rescans the MIDI configuration for each change on the global MIDI settings automatically.
MIDImyAPP is written in Carbon-C++ entirely to decrease the latency time as much as possible. For live performances it is recommended to use at least a double-core Intel Mac with 2GHz.
Simply download and decompress the ZIP archive to any location on your Mac.
download MIDImyAPP (93kB)
MIDImyAPP is an UNIX shell command which runs in the Terminal.
cd ~/Desktop/MIDImyAPP
./MIDImyAPP
and press RETURNx
and press RETURNAn other option to start MIDImyAPP is to double-click at startMIDImyAPP
from Finder.
If there is the need to run MIDImyAPP in the background you can double-click at startMIDImyAPPBG
and close the Terminal afterwards. To stop MIDImyAPP double-click at stopMIDImyAPP
Once you invoked MIDImyAPP (not hidden) you should see the sent MIDI events in the Terminal window (a kind of MIDIlogger).
Inside the MIDImyAPP folder there is a default configuration file called config.plist
. This file is a standard XML Mac Property List file (plist) which can be edited with the “Property List Editor”, XCode (if installed), or a plain text editor.
The internal structure is quite simple:
If you open it in a text editor you will see:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>THE MIDI EVENT</key>
<string>SHELL COMMAND</string>
</dict>
</plist>
Hints:
< > &
you have to write < > &
(only relevant while editing in a text editor); all other ASCII characters are allowed including new_line
tell application "Safari" to activate
you can avoid calling it via osascript
if you write into the configuration file as SHELL COMMAND tell application "Safari" to activate
; any SHELL COMMAND which begins with tell app
will be executed internally by MIDImyAPP in order to speed up the execution timeIf MIDImyAPP starts it creates a so-called pipe named sendMIDI
located in the MIDImyAPP directory. This allows other programs or scripts to send commands back to MIDImyAPP. Supported commands are:
As default MIDImyAPP makes usage of the coreMIDI function MIDIReceived()
to send the passed event to the bus. This will exclude virtual MIDI devices as IAC (see Audio MIDI Setup). You can toggle that mode by using the program option -i
or the run-time command i
. In the so-called IAC mode MIDImyAPP send the passed event to all found destination by using coreMIDI’s MIDISend()
function. Please make sure in Mac’s “Audio MIDI Setup” that the IAC device is ‘online’.
From another Terminal you can execute this bash command:
echo m903c66 > ./sendMIDI
if the Terminal runs in the same directory as MIDImyAPP, ohterwise you have to specify the full absolute path to the pipe sendMIDI
.
Hint mXX and wXX are also avaiable as run-time commands.
If MIDIMyApp sends a MIDI event by using mXX
it adds 4 bytes 0x00 in front of the event in order to be able to recognize that a received event was sent by MIDImyAPP itself and to avoid an eternal loop. This adding don’t change the actual event.
For instance, you specified that MIDI events 90XXXX
should call a script which is changing the velocity and sending that changed event back to the MIDI bus then without header the sent MIDI event would trigger the 90XXXX
again; instead MIDImyAPP sends 0000000090xxxx
.
MIDImyAPP, if started with the command-line option -g
creates an internal bridge to GarageBand in order to be able to execute some basic commands much faster. So far the supported commands which has to be used as SHELL COMMAND in the configuration file are:
.gb_play
.gb_stop
.gb_start
.gb_forward
.gb_rewind
.gb_cycle_on
.gb_cycle_off
.gb_record
.gb_mute_current_track
.gb_solo_current_track
.gb_play_toggle
.gb_prev_track
.gb_next_track
.gb_set_master_vol
.gb_set_tempo
B06DXX
SHELL COMMAND: .gb_set_master_vol
If you press for instance a key the velocity is passed as variable (last byte), if you control a slider, drawbar, or knob the actual value is passed as variable. To ignore or use that variable follow this workflow:
XX
as KEY in the plist file%@
as place holder%@
will be replaced internally by the decimal value (in general 0-127)XXXX
as KEY in the plist file%@
as place holder(s)%@
will be replaced internally by the decimal value (in general 0-127)say "%@ and %@"
=> say "1 and 2"
say "%@ "
=> say "1"
for only one place holder the second last byte will passed onlythe release of key A5 on MIDI channel 4 should open the PDF file “test.pdf”:
935D00
SHELL COMMAND: open "test.pdf"
the hitting of key A5 on channel 4 should open the movie file “test.mov”:
935DXX
SHELL COMMAND: open "test.mov"
935D00
to " "
the hitting of key A5 on channel 4 should open a text document (TextEdit) containing the velocity times 100 plus the text “ speed”:
935DXX
SHELL COMMAND: echo "`perl -e 'print @%*100'` speed" | open -f
the hitting of key A5 on channel 4 should play the sound file “test.aif” (inside the MIDImyAPP folder) looped with the volume given by the passed velocity and stop it on release A5:
935DXX
SHELL COMMAND: ./play -l -v %@ test.aif
935D00
SHELL COMMAND: ./stop test.aif
play
and stop
see Appendixany Note On event played on channel 1 will be played additionally with the maximum velocity:
90XXXX
SHELL COMMAND: T=%@;export $T;[[ %@ > 0 ]] && echo $(printf "m90%%X7F" $T)> sendMIDI &
Hint Have a look at the config.plist shipped with MIDImyAPP for further examples.
The configuration file config.plist
will be used as default. MIDImyAPP accepts the option -p FILE
to load an other configuration file. To use for instance the configuration file “My first gig.plist” located on the Desktop start MIDImyAPP from Terminal via:
./MIDImyAPP -p "$HOME/Desktop/My first gig.plist"
It is possible to use MIDImyAPP as slave to send each MIDI event to an other script or file. In that mode MIDImyAPP does not make usage of a configuration file.
Examples
./MIDImyAPP -e "echo %@ >> ~/events.txt"
will append each event to the file ~/events.txt
./MIDImyAPP -e "echo %@ > ~/midi_pipe"
will send each event to the named pipe ~/midi_pipe (useful if a script is listening on that pipe to do something with these events)
The following runtime commands are available:
Hans-Jörg Bibiko mail@bibiko.de
MIDImyAPP is totally free. The only condition is to give feedback about usability, bugs, suggestions, etc.
t
to translate a MIDI event to human-readable messagemXX
or wXX
) on run-time manuallysendMIDI
(same folder) to be able to send MIDI events from other scripts/programs via mXX
or wXX
, to reload another configuration file via rFILE
, and to pause/resume MIDImyAPP via p
-g
to support GarageBand.gb_...
pre-defined function to remote GarageBand-i
(IAC mode) to send all MIDImyAPP MIDI events to all destinations via coreMIDI’s MIDISend, otherwise it uses coreMIDI’s MIDIReceive; make sure if the IAC driver is online (Audio MIDI Setup)Inside the MIDImyAPP folder there are two tiny command-line utilities play
and stop
.
./play {-l -v VOL} SOUND_FILE
plays a passed sound file
./stop SOUND_FILE
stops the SOUND_FILE which is playing back by ./play
./stop
only works inside the configuration file if ./play
was called (literally)