Assign colors to buttons according to button text

Hi
I'm sorry to ask this Q again, but I can't find any valid information here or at VI-Control.
It's still the same problem:
Upon selecting a MIDI track in Cubase a MIDI message CC 127 val 1 is send to OSC. Here a script is validating the data, and if it really is CC 127, OSC returns a MIDI message '/control, 1,126,1. This in return makes the selected track send a NEW MIDI message to OSC: '/control, 1, 117, 1. This message is coded via the last two units (117,1), to ID this track as ex. a VSL Piccolo track. Quite logic considering that the Piccolo flute is the "first" instrument in the Orchestra.
Inside the .js script there are these lists of articulation names:


Here the piccolo - just assigned to CC119 value103!!

Now OSC has the information to "populate" the articulations buttons with the names of the articulations, in this instance there are 27 (!) different articulations. So what I need is "a little help" to colorize the buttons according to the name. I imagine a switch statement with cases could be use to evaluate the name and assign a color.

Years ago I coded in GFA Basic on Atari and I have picked up some knowledge of the matter, but I can't find my way in this.

This is the code - created by Mihkel Zilmer, modified by me:

I understand line 1063 - 1082 but after that it's getting difficult. Especially 1084, 1085 and 1090 is problematic.
Any help much appreciated, could also be a reference to information.
Regards Stig Christensen MUSICMIND

Hello Stigc56,
I am also interested in the solution. I asked the same question in a post last year...

I was trying to do the same thing again last night without success!
my knowledge in code is light.
I think we have to declare a color variable for each articulation type before the oscInfilter. Something like:

  var artcolor = {
'Staccato': {
  color: 'red',
},
'Portato Short': {
  color: 'blue',
  // etc
}  }

But then, I don't know how to make the link between the displayed articulations and the colors in the buttons.Probably in the receiveOsc field but how? Does anyone have the solution?

Hi, i cant see line numbers in the screenshot..?
One of my next topics is changing colors via custom modules, so i don't have a blueprint ready now.

As for which color to choose and how, i would opt for an logic where to find a specific string in the name -> value.includes('portato')

There are so many articulations out hre,
sooner or later i will investigate time in this interesting topic..

Abstrus, Thanks for your answer.
If it helps, here is a file that works perfectly with cubase to display articulations in OSC. Custom-module-color.js (3.8 KB)

An idea could be to list all the articulations by typology (I added lines 35 to 43). It should be easy then when you enter a new instrument to systematically reference its colors articulations.

Firstly OSC reads the corresponding articulation list and generates the texts. (currently it works).
Secondly it should colorize the button (or the text of the button) according to what it finds in correspondence in the color variable.

Can't wait to read your next topic with the solution!
Zig

Sorry: Here they are:

to @abstrus I had this idea my self, but I want to use VST maps from Babylonwaves, and they come with a strict color code system. My plan is to make the color-coding work by numbers as in Cubase and to persuade Marc (from Babylonwaves) to help decoding the endless XML files.


Only if he can't help I will consider the solution to valuate the string to assign a color.

But I simply need to fully understand what this is:

receiveOsc({address: Object.values(buttons)[i], args: [{type: 'i', value: 1}]}) // assign values to buttons
receiveOsc({address: Object.values(labels)[i], args: [{type: 's', value: label}]})

receiveOSC is a function? If so why isn't it defined?

I have just taken a 3.5 hour long course in Javascript! :wink:

Good to know that we now are 3 persons interested in this, now we just needs the wizards!

Stig Christensen MUSICMIND

receiveOSC is a function? If so why isn't it defined?

receiveOsc() is an old implementation of receive(), it still works for compatibility reasons but the latter should be used. The difference is that It's slightly simpler (specifying the arguments' types is not mandatory).

Thanks a lot.
So I could replace recieveOsc with receive?

Maybe we could have a artColor variabel attached to each articulation like this:

0:{ 'trackname':'Violon 1', 'trackarticulations':['Sustain',1, 'Tremolo',3,'Harmonic',3, 'Staccato',2,'Spiccato',2]},

So
for( i=0 ; i < len; i+=2) // every unequal value will give the artColor.

....

The really hard point here beside finding a way to colorize the buttons, is to generate the Articulation maps themselves AND to create the articulation strings that goes in the .js file. If we can use Babylonwaves for the maps then I know of the X-DAW utility that can create strings out of the vst-maps and they can be combined with all the necessary brackets and commas.

The ultimate solution would be have a script that could "filter" the gigantic XML files to get 'artName' and artColor.

Hope we will succeed.

Regards Stigc56

puh, i don't wanna make false hopes on a solution.(i would like to make somekind of listing of instruments and finding them -> parsing kontakts files and folders)

as for xml parsing, i am sure there exists a nodejs module for this that could help out.
I think this is definitly possible.

receive is used to update the gui (or better said a widget) you specify the id of the widget a self choosen name and the value itself(you find examples in the forum too)

possible tries..

Hi all,
I find some solution for the problem but I still need help.
I found the way to send color to the buttons using OSC{/colored/@{parent.variables.n}, default, false} in the colorWidget field.
I made a loop to populate buttons with colors but there is a bug :

var oscPort = '8080';
var bank, patch, buttonGrid, labelTexts;

var buttons = {
	'b1':'/b1/show','b2':'/b2/show','b3':'/b3/show','b4':'/b4/show','b5':'/b5/show',
}

var labels = {
	'b1':'/b1/label','b2':'/b2/label','b3':'/b3/label','b4':'/b4/label','b5':'/b5/label',
}
	var instruments = {
	0:{ 'trackname':'Violon 1', 'trackarticulations':['A1', 'A2','A3', 'A4','A5']},
	1:{ 'trackname':'Orchestral Ukulele', 'trackarticulations':['B1','B2','B3','B4','B5', 'B6']},
}

var colors = ['red', 'yellow']
var colortrack = { 
'red': ['A1','A4','B3'],
'yellow': ['A2','A3','B1']
}
module.exports = {
oscInFilter:function(data)
{
    var {address, args, host, port} = data

if (address !=='/control') return {address, args, host, port}
	if (args[1].value < 117) return {address, args, host, port}
	if (args[1].value == 127) 
		{
		send('midi','OSCtoDAW','/control', 1,126,1)
	return {address, args, host, port}
		}
	else
		{
		bank = (args[1].value - 117)     
		patch = (bank * 128) + args[2].value

		labelTexts = instruments[patch].trackarticulations
		var len = labelTexts.length
		for (i = 0; i < len; i++)
			{
			receive(Object.values(buttons)[i], {type:'i', value: 1})
			receive(Object.values(labels)[i], {type:'s', value: labelTexts[i]}) // populate name
			
// Loop that color the buttons ( I NEED HELP HERE ! )
			for(z of colors){
				for(y of colortrack[z]){
					if(labelTexts[i] = y) {
						var colorcode = z
                       // Log the button with the corresponding color
						console.log(labelTexts[i] + ' is colored in ' + z) 
					}
				}
			}
			// Don't know what tracknumber is but it doesn't work without it
			var tracknumber = address.split('/')[2]
			receive("/colored/"+ tracknumber, colorcode);
			
			}
			var len2=Object.values(buttons).length
		for (i = len; i < len2; i++)
			{
			receive(Object.values(buttons)[i], {type:'i', value: 0})					
			}
	
// SHOW SELECTED INSTRUMENT			
		receive('/EDIT', 'button_container_id', {html:'Selected instrument : '+ instruments[patch].trackname})
	    return
		}
	return {address, args, host, port}
},
}

In the console I get this for each buttons and all the buttons get the last value (yellow in this case) :

(DEBUG, OSC) In: { address: '/b5/show', args: 1 } From: undefined:undefined
(DEBUG, OSC) In: { address: '/b5/label', args: 'B1' } From: undefined:undefined
A1 is colored in red
A4 is colored in red
B3 is colored in red
A2 is colored in yellow
A3 is colored in yellow
B1 is colored in yellow
(DEBUG, OSC) In: { address: '/colored/undefined', args: 'yellow' } From: undefined:undefined

Any idea how to make the loop working ?

Z

There should be two equal signs here (Equality (==) - JavaScript | MDN).

var colorcode = z

You should initialize the variable before the loop and assign only once the condition are met, and then add a break statement to prevent the value to be overridden at the loop's next iteration.

@jean-emmanuel Thank you for your help, now it works. I also understood how to send (with receive function) the color in the json file with the right syntax.
I'm going to clean the code and will share it here soon.

@jean-emmanuel
My Cubase/Nuendo template is almost finished... and I must say that I love OSC, so powerful!.
Before sharing it, I need help to fix this problem.
Strangely, this part of the js works perfectly but I still get an error message... why? :

(ERROR) A JavaScript error occurred in the main process:
TypeError: Cannot read property 'trackarticulations' of undefined
at CustomModule.oscInFilter (/Users/zig/Desktop/OSC Project/ZIG_Custom_module_color_BUG.js:55:36)
at OscServer.oscInFilter (/Applications/open-stage-control v1.8.15.app/Contents/Resources/app/server/open-stage-control-server.js:75100:38)
at MidiConverter.receiveOsc (/Applications/open-stage-control v1.8.15.app/Contents/Resources/app/server/open-stage-control-server.js:75136:25)
at Function.parseIpc (/Applications/open-stage-control v1.8.15.app/Contents/Resources/app/server/open-stage-control-server.js:74813:22)
at PythonShell. (/Applications/open-stage-control v1.8.15.app/Contents/Resources/app/server/open-stage-control-server.js:74790:27)
at PythonShell.emit (events.js:203:13)
at /Applications/open-stage-control v1.8.15.app/Contents/Resources/app/server/open-stage-control-server.js:53052:22
at Array.forEach ()
at PythonShell.receiveInternal (/Applications/open-stage-control v1.8.15.app/Contents/Resources/app/server/open-stage-control-server.js:53050:15)
at PythonShell.receive (/Applications/open-stage-control v1.8.15.app/Contents/Resources/app/server/open-stage-control-server.js:53024:21)

Here is the js (I removed all the other useless functions in this version) If I understand correctly, the problem comes from the line 55 : labelTexts = instruments[patch].trackarticulations

var oscPort = '8080';
var bank, patch, labelTexts;

//define the target for each button (show/hide)
var buttons = {
	'b1':'/b1/show','b2':'/b2/show'
}

//define the target for each button (name/text)
var labels = {
	'b1':'/b1/label','b2':'/b2/label'
}

//define the target for each button (color)
var labelscolor = {
	'b1':'/b1/color','b2':'/b2/color'
}	

//define trackname and articulations 
var instruments = {
	0:{ 'trackname':'CSS - Chabada', 'trackarticulations':['A','B']},
	1:{ 'trackname':'SCSS - Orchestral Ukulele', 'trackarticulations':['C','D']},

	// etc... (put your own here!)
} 

//define colors and color associated with articulations (put here your own!)
var colors = ['red', 'yellow','green'] // etc
var colortrack = { 
	'red': ['A','C'], // put articulation here
	'yellow': ['B','D'],
	'green':['Spiccato', 'Spiccato feathered', 'Staccato', 'Staccato dig', 'Staccato CS'],
	// etc
}

module.exports = {  
oscInFilter:function(data)
{
    var {address, args, host, port} = data

if (address !=='/control') return {address, args, host, port}
	if (args[1].value < 116) return {address, args, host, port}
	if (args[1].value == 127) 
		{
		send('midi','OSCtoDAW','/control', 1,126,1)
	return {address, args, host, port}
		}

// ARTICULATION SECTION
	else
		{
		bank = (args[1].value - 117)     
		patch = (bank * 128) + args[2].value

		labelTexts = instruments[patch].trackarticulations // <<<< PROBLEM HERE ?
		var len = labelTexts.length // Find the occurence in trackarticulations
		for (i = 0; i < len; i++) // Increment
			{
			receive(Object.values(buttons)[i], {type:'i', value: 1}) // populate buttons
			receive(Object.values(labels)[i], {type:'s', value: labelTexts[i]}) // populate name
			
			//color buttons
			for(z of colors){
				for(y of colortrack[z]){
					if(labelTexts[i] == y) {
						var colorcode = z
						receive(Object.values(labelscolor)[i], colorcode); // populate color
					}
				}
			}
			}
		var len2 = Object.values(buttons).length
		for (i = len; i < len2; i++) {
			receive(Object.values(buttons)[i], {type:'i', value: 0})					
		} 

// display selected instrument in top panel
		var panelarticulation = "#007aa5"	// <<<< define panel text color here
		receive('/panelart', panelarticulation); // color selected instrument (top of the panel)
		receive('/EDIT', 'button_container_id', {html:'Selected instrument : '+ instruments[patch].trackname}) // set selected instrument name
	    return
		}      
	return {address, args, host, port}
},
}

Thanks for your help.

Z

TypeError: Cannot read property 'trackarticulations' of undefined

labelTexts = instruments[patch].trackarticulations // <<<< PROBLEM HERE ?

The error occurs because under some conditions instruments[patch] is not defined (ie patch has a value that's not found in instruments' keys). you should add some console.log statements to understand what value causes your code to fail.

Thank you for taking the time to answer.
I have console log every iteration of labelTexts and it logs the correct names :roll_eyes: :slight_smile:
Sorry for my noob question but what (where ) exactly is undefined in this case?

[ 'D', 'C' ]
D
(DEBUG, OSC) In:  { address: '/b1/show', args: 1 } From: undefined:undefined
(DEBUG, OSC) In:  { address: '/b1/label', args: 'D' } From: undefined:undefined
(DEBUG, OSC) In:  { address: '/b1/color', args: 'yellow' } From: undefined:undefined
C
(DEBUG, OSC) In:  { address: '/b2/show', args: 1 } From: undefined:undefined
(DEBUG, OSC) In:  { address: '/b2/label', args: 'C' } From: undefined:undefined
(DEBUG, OSC) In:  { address: '/b2/color', args: 'red' } From: undefined:undefined
(DEBUG, OSC) In:  { address: '/panelart', args: '#007aa5' } From: undefined:undefined
(DEBUG, OSC) In:  {
  address: '/EDIT',
  args: [
    'button_container_id',
    '{"html":"Selected instrument : SCSS - Orchestral Ukulele"}'
  ]
} From: undefined:undefined
(DEBUG, MIDI) in: CONTROL_CHANGE: channel=1, cc=116, value=0 From: midi:DAWtoOSC
(ERROR) A JavaScript error occurred in the main process:
TypeError: Cannot read property 'trackarticulations' of undefined
    at CustomModule.oscInFilter (/Users/zig/Desktop/OSC Project/ZIG_Custom_module_color_BUG.js:55:36)`
var someObject = {
  1: 'A',
  2: 'B'
}

console.log(someObject[1]) // 'A'
console.log(someObject[2]) // 'B'
console.log(someObject[3]) // undefined

Hi there All,

I have just stumbled across this thread - sorry I’ve not seen it earlier.

I’ve implemented the solutions you’re trying to make work above. And additionally used custom classes to easily assign button Color’s with images to the articulations buttons.

Further - I’ve amended the custom module so that it will also work for instrument tracks in cubase as well as midi tracks (albeit limited to only 127 tracks), and have created a set of templates that map quick controls and midi cc faders to the vsti (working on the assumption that an expression map will only be used for a certain plugin vsti).

Final hurdle tho, I’m getting there on this I think is to get the custom module to automatically populate the object variables from the xml expression maps. If I can get this to work it will avoid having to manually edit the custom module every time I amend or create a new expression map.

Let me know how you’re getting on.