MidiPipe app (which supports AppleScript)

Hello,

I am trying to do the following example with the Mac app, MidiPipe (http://www.subtlesoft.square7.net/MidiPipe.html):

To map the C5 key on my midi piano keyboard, upon pressing it, to play both a C3 and C5 simultaneously, but to have C5 trigger several milliseconds after C3.

I got MidiPipe to work to have a C5 key play both a C3 and C5 simultaneously using Remap. However I need that several milliseconds delay until C3 is “pressed” …

Midipipe does support custom AppleScript via the “AppleScript” trigger / feature in the app.

I’d be grateful for some guidance here… for if you have ideas.

The reason I want to be able to do this… is… I have a Kontakt Virtual Instrument where one uses lower piano keys (such as C3) to switch between different sounds… and higher keys (such as C5 to execute/play the sound). However if they are fired simultaneously without the slight delay for the higher key, the wrong sound is played unless I re-press the C5 again. Hopefully I’m making sense :).

Thanks in advance for your help!
Shawn

Hi Shawn. Welcome to MacScripter.

I think this may be doable with AppleScript’s ‘delay’ command, but I’m not sure how precise 'delay’s timing is. I was surprised to find it even attempted intervals as short as a few milliseconds (in El Capitan), but it seems to do so.

In your second paragraph, it says that the C5 has to trigger several milliseconds after the C3, but in the next, it’s the C3 which has to be delayed. I’ve gone with C5 below, but you can easily change the note number in the code

So. This script’s intended for use in a MidiPipe AppleScript Trigger tool. Leave the tool’s “pass through” option unchecked so that the script controls the throughput. The script checks each message coming down its pipe and delays any C5 note-on messages by a few milliseconds. The MIDI channel isn’t considered, but it can be if needed. Play about with the ‘delay’ time to see what works for you — or even if it works for you. :wink: I’m not a MidiPipe expert. I just downloaded it recently to help someone else with a script.

on runme(message)
	if ((beginning of message) div 16 is 9) and (item 2 of message is 84) then
		-- If this is a note-on message for note number 84 (C5), wait a few milliseconds and then pass on the message.
		delay 0.007 -- Delay (approx) 7 milliseconds.
		return message
	else
		-- Otherwise pass the message immediately.
		return message
	end if
end runme

Nigel,

Thanks so much for your kindness in helping me and for the welcome!

So, if I wanted to modify your script to be able to handle multiple keys to be delayed… do I just do something like:


on runme(message)
   if ((beginning of message) div 16 is 9) and (item 2 of message is 84) and (item 2 of message is 85) and (item 2 of message is 86) then
       -- If this is a note-on message for note number 84 (C5), wait a few milliseconds and then pass on the message.
       delay 0.007 -- Delay (approx) 7 milliseconds.
       return message
   else
       -- Otherwise pass the message immediately.
       return message
   end if
end runme

Many thanks,
Shawn

Hi Shawn.

Not quite. That way, item 2 of message would have to be 84, 85, and 86 at the same time! The logic of the ‘if’ line should be:

if ((beginning of message) div 16 is 9) and ((item 2 of message is 84) or (item 2 of message is 85) or (item 2 of message is 86)) then

But depending on how many different keys you wanted to delay and what they were, it might be more efficient and/or convenient to do something like:

if ((beginning of message) div 16 is 9) and (item 2 of message ≥ 84) and (item 2 of message ≤ 86) then

Or:

if ((beginning of message) div 16 is 9) and (item 2 of message is in {84, 85, 86}) then

Thanks so much, I think this is going to do the trick!

What specifically does this part of the code mean?

if ((beginning of message) div 16 is 9)

In other words, what is “div 16”?

As you probably know, MIDI messages are streamed as byte values — a byte consisting of eight binary digits or “bits”. MidiPipe feeds each message to the script as an array (a “list” in AppleScript parlance) containing the bytes’ numeric values in the order they occur in the message. The variable used to hold the list is called ‘message’ in this script and ‘beginning of message’ is one way of referring to the first item in the list.

The first four bits of the first byte in a message denote the kind of message it is and the other four bits are the channel number minus 1. The first byte of a note-on message on channel 1 has the binary value 10010000 (144 in decimal) — 1001 for “note on” and 0000 for channel 1 minus 1. The first byte of a note-on message on channel 16 has the binary value 10011111 (159 in decimal).

The AppleScript operator ‘div’ divides by the number which follows it and returns just the whole-number part of the result. If we ‘div’ the first byte’s value by 16, we’re left with just the value of the first four bits, which in a note-on message is 9.

I hope this makes sense. It’s half past two in the morning here! :wink: