Store/Retrieve more than one variable in Clipboard using an Array?

Thank you! :lol:

But you’ll be gratified to hear that your idea does actually work — provided the terms are preceded by ‘my’ or ‘AppleScript’s’ in each script. I’ve tried so far with various types of value in ‘pi’, ‘minutes’, and ‘text item delimiters’. Once they’re changed in a script in one pipe, the changes are visible to a script in another. I think you’ve cracked it, Carruthers. Or cracked something, anyway. :wink:

I’m a guitar player/singer that uses bass pedals and a laptop. I’ve created a pretty convoluted process, but it works.

You probably know about arranger keyboards, you can play the keyboard or bass pedals and the program plays short accompaniment loops. When you press a footswitch, the arranger waits until the beginning of the next bar and then does something - changes the loop, add extra instruments etc.

Arranger song files (called styles) use obscure non MIDI info, they are difficult to program. I have found a way to do more or less the same thing using my MIDI sequencer program.

Currently I CAN switch parts, but the action happens WHEN I press a footswitch. As this is usually the same time (the beginning of a bar) I have to play a bass note (and perhaps do something else with my feet), I really can’t do it. I need to be able to press the footswitch ahead of time and have the switching action occur at the beginning of the next bar.

The footswitch is connected to the circuit board matrix from a USB keyboard’s number pad, which generates MIDI notes (using another app called MIDIkeys), which goe to MIDIpipe. MIDIpipe then uses applescript to write a specific “part number” to the clipboard based on the MIDI note in.

However, due to MIDIpipe’s limited functioning, in order to be able to press the footswitch early and have the part change happen on the new bar, I would have to do three separate processes.

1, Press the footswitch, set clipboard first number to the Mix number.

  1. Have a special “trigger” MIDI note sent from the sequencer to MIDIPipe on the first beat of the bar, which then uses Applescript to set the second character of the clipboard string to a boolean 1.

  2. Then the MID switching part, which says, read the clipboard, if the second character is 1, switch to part 1-5.

The lat process would be in a loop that runs for every MIDI event passing through the “pipe,” so speed might be an issue. If there is a slight lag, I haven’y yet noticed, and also I can adjust the timing of the trigger note to compensate anyway.

And finally, I would like to expand the use this “delay till next bar” function for other foot triggered events, as I am pretty clumsy ha ha… I would just add more “positions” to the string (list?) stored on the clipboard.

BTW I am in Hawaii which is literally the other side of the world from you guys in Europe.

Thanks again.

Sorry, I got carried away. Back to the code.

If I understand you correctly, certain well labeled properties can be set with a numerical value in one script and referenced in another:

my print depth
my print length
my pi
my seconds
my text item delimiters

I will give them a go.

Thank you.

Hi.

That’s right. They’re properties of the AppleScript instance being used by MidiPipe and are shared by every script it’s running. Any changes made to their values remain in force across all the scripts until either further changes are made or MidiPipe is quit. However, using them like this is a hack and you have to be sure not to use any labels that your scripts may need to use in the normal way!

Triggered scripts, by the way, can declare their own individual properties in which they can store data for their own use on subsequent triggerings. This is of course ideal for the script that’s waiting for the “first beat of the bar” cue.

Is it feasible in your set-up to send the footswitch signal(s) down the same pipe as the other stuff but on a different channel? That way you’d only need one script.

As the footswitch is really a keyboard, connected to MIDIKeys (which outputs the notes to be processed in MIDIpipe), then yes, I can set MIDIkeys to an unused MIDI channel.

However, being a novice, I am balking at all those nested if statements :wink:

As I have MIDI events flying in and out of MIDIpipe in several directions at once, a lot of nice simple pipes are preferable to fewer more complicated ones. At least, until I get better at scripting.

I googled for the complete list of the properties above, but didn’t find anything. I guess this is a hack so they are undocumented. Are there any more (I’m getting greedy…)

Mahalo.

Peter

It’s definitely a hack, but they’re not undocumented. They’re often referred to as global constants, because generally it makes no sense to change their value. But you can – you just need to make sure you then never use them with the expectation that they contain what’s written on the tin.

You could use minutes and weeks, I suppose.

These should be reasonably safe to use when only MIDI-watching:

These aren’t mentioned as constants in ASLG, but appear to be settable:

This is a settable constant in some contexts — such as when preceded by ‘my’ — but the return command in others:

This isn’t a settable constant, but with ‘my’ or ‘Applescript’s’ in front of it, does appear to be a settable AppleScript property.

  1. Don’t use any other constants you may discover — at least, not without checking here first.
  2. Always include the ‘my’.
  3. Make sure your scripts are thoroughly commented so that you always know which values are supposed to go in which properties!

By the way, a non-hack solution to this in Yosemite or later would be:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set alpha to {property1:4, property2:"oops", property3:{1, 2, 3, 4, 5}, property4:{a:"aardvark"}, property5:Tuesday}
set the clipboard to alpha
delay 0.2

set maybe to (the clipboard as list)
set values to {}
set keys to {}
repeat with i from 1 to (count maybe) by 2
	set end of keys to item i of maybe
	set end of values to item (i + 1) of maybe
end repeat
set beta to (current application's class "NSDictionary"'s dictionaryWithObjects:(values) forKeys:(keys)) as record

Or if you still wanted it to look awful:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set alpha to {property1:4, property2:"oops", property3:{1, 2, 3, 4, 5}, property4:{a:"aardvark"}, property5:Tuesday}
set the clipboard to alpha
delay 0.2

tell {the clipboard as list, {{}, {}}}
	repeat with i from 1 to (count beginning) by 2
		set end's beginning's end to beginning's item i
		set end's end's end to beginning's item (i + 1)
	end repeat
	set beta to (current application's class "NSDictionary"'s dictionaryWithObjects:(end's end) forKeys:(end's beginning)) as record
end tell

Or speed things up a little:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set alpha to {property1:4, property2:"oops", property3:{1, 2, 3, 4, 5}, property4:{a:"aardvark"}, property5:Tuesday}
set theDict to current application's NSDictionary's dictionaryWithDictionary:alpha
set theData to current application's NSKeyedArchiver's archivedDataWithRootObject:theDict
set thePasteboard to current application's NSPasteboard's generalPasteboard()
thePasteboard's clearContents()
thePasteboard's setData:theData forType:"myVeryOwnType"
delay 0.2
set theData to thePasteboard's dataForType:"myVeryOwnType"
set beta to (current application's NSKeyedUnarchiver's unarchiveObjectWithData:theData) as record

:wink:

:cool:

Here’s how I think a one-pipe/multi-channel solution might look. It’s not a fully working script as I don’t know the numbers involved and can’t test it anyway. Just a demo of how it might be structured. The script module’s “pass through” option would be left unchecked so that the script controlled both output and throughput.

-- Footswitch signal channel. (16 here. Channels are numbered 0-15 in the transmitted data.)
property footSignalChannel : 16 - 1
-- MIDI Note On and Control Change event codes.
property noteOn : 9
property controlChange : 11
-- MIDI number of a note reserved for marking the first beat of every bar. Set as required.
property barlineNote : 60
-- List of Control Change messages for the mixes to be used. Set as required. The actual channel(s) will be set before they're transmitted.
property mixChangePresets : {{176, 60, 80}, {176, 60, 81}} -- etc.
-- Mix change message waiting to be sent, when there is one.
property mixChangeMessage : missing value
-- Flag to indicate if a mix change is waiting.
property mixChangeWaiting : false

on runme(message)
	-- Get the value of this message's first byte, which contains the event code and channel number.
	set eventAndChannel to item 1 of message
	-- Extract the channel number
	set messageChannel to eventAndChannel mod 16
	-- Is it the footswitch signal channel?
	if (messageChannel is footSignalChannel) then
		-- If so, is the message a Note On event with a velocity > 0?
		if (eventAndChannel div 16 is noteOn) and (item 3 of message > 0) then
			-- If so, set up a mix change to be actioned on the next bar line.
			-- I've assumed here is that note #60 should set the first mix, note #61 the next, and so on.
			set mixChangeMessage to item ((item 2 of message) - 59) of mixChangePresets
			set mixChangeWaiting to true
		end if
		-- Since this channel's only used for the footswitch signal, it doesn't matter if the message is passed through or not.
		
		-- Otherwise assume this message is on the sequencer channel.
		-- Is there a mix change waiting to be actioned?
	else if (mixChangeWaiting) then
		-- If so, is this message the trigger note indicating the first beat of the bar?
		if (eventAndChannel div 16 is noteOn) and (item 2 of message is barlineNote) and (item 3 of message > 0) then
			-- If so, cancel the change-waiting flag and output the change message on the original channel.
			set mixChangeWaiting to false
			set item 1 of mixChangeMessage to controlChange * 16 + messageChannel
			return mixChangeMessage
		else
			-- Not a trigger note. Pass the original message.
			return message
		end if
	else
		-- No mix change waiting. Pass the original message.
		return message
	end if
end runme

Well, being able to use 8 or more globals will be a boolean playground…

When I used the clipboard as storage, I was able to see the value of the variable, so I could check the “signal flow.”

How can I observe the values of the globals? As I understand it now, they are global to all applescript(s), so perhaps I can run something in “real” applescript to display them?

Thank you for the more advanced code ideas, I am learning a lot. I’m still at 10.9.5 though. 10.10 was a music software breakpoint, so I’m desperately holding on.

Ooops just re-read the thread. The globals only persist in the MIDIpipe Applescript instance.

How can I display them?

Well. If you’re going to fool with the record before it goes on the clipboard:

set alpha to {property1:4, property2:"oops", property3:{1, 2, 3, 4, 5}, property4:{a:"aardvark"}, property5:Tuesday, date:(current date)}
set the clipboard to {alpha}
delay 0.2

set beta to beginning of (the clipboard as list)
-- Or:
set beta to (the clipboard as list) as record

:slight_smile:

I don’t know how or what you were displaying before. There’s no obvious way to show what’s going on in real time without holding things up. You can get a script to ‘say’ the value of a variable as long as the value’s text, a number, or a boolean:

set my print depth to "aardvark"
say my print depth

Or it can say when the flow’s entered a certain block of code:

if (footswitchSignalReceived) then
	say "footswitch signal"
	-- Relevant handling code here.
end if

Or, as Yvan suggested, you can set the properties of a record to several variables of interest and put the record on the ciipboard. You can then read the clipboard with a script in Script Editor and see the result in the Result pane. Obviously this only shows record that’s on the clipboard when it’s read, but it may be useful. The advantage of a record over a list is that you can give the properties meaningful labels, making it easy to identify which value’s which.

If you’re really desperate and need a message-by-message breakdown of the entire performance, you can get the script(s) to write running logs to a text file or editor. But that’s potentially a hell of a lot of data — as well as a considerable amount of extra code!

One can view the contents of the clipboard either with one of several apps. or in the Finder, under Edit, View Clipboard. The Finder window is not real time though, you need to refresh the window.

Anyway, I’m sure have enough info now. Many thanks to all who commented.

Peter

For anyone who Googled and got this MIDIpipe thread, this little pipe reveals the status of the “my” variables listed above:

on runme(message)

if (whatever MIDI trigger message is input) then

tell application “Finder”
say my minutes
end tell
end if
end runme

I have the logic working perfectly thanks to everyone here.

FYI I am monitoring the globals by having Applescript tell the finder to say them. Very cool.

The final problem. I need to block the MIDI from going through each specific pipe. I thought this would work as a MIDI on off switch, but it does not

on runme(message)
if (my hours = (1)) then
return (message)
end if
end runme

The script still passes MIDI. And, when “if = True”, it doubles the notes.

Stublito

Hi stublito.

Have you unchecked the “pass through” option beneath the script window?

Thanks for the quick reply.

Yes, I’ve unchecked that.

It’s definitely “leaking” through each pipe, and not from somewhere else, if I disable the input tool in any pipe, it mutes correctly.

FYI I have 13 of these being switched by the logic.