Open Sound Control (OSC) Teensy Audio Library Implementation

Live edit of array/class is currently not supported as I still struggling with the group export
I have faith you'll figure it out! I just realised that there could be problem with "mutual nesting": if you have Tab A and Tab B, each can import [an array of] the other. I imagine this could cause Bad Things to occur... but maybe you already noticed the possibility?

have also implemented the navigator map (taken direct from node-red)
available at the zoom controls corner
That's useful - I just found a bunch of orphan buttons I didn't even know were there!

I did some changes how the group export behaves
If there is many tabs selected as "Audio Main":
1. If current selected tab is a "Audio Main" then that is used
2. If current selected tab is not a "Audio Main" then the first "Audio Main" in the tab order is used
Need to read up on what an "Audio Main" does for me. Pretty sure I remember there being a note about it in your main GUI++ thread.

while I did this I accidentally did
Code:
if (nns.workspaces[wi].id = RED.view.activeWorkspace) {
    mainSelected = wi;
}
instead of
Code:
if (nns.workspaces[wi].id == RED.view.activeWorkspace) {
    mainSelected = wi;
}
this resulted in a huge mess and my current design got lost into a 25MB json file
good is that I had recently saved a json, so it was not so much loss, and I could "kind of"(the interface was really slow) look at the old design to make a new one in firefox.

Because of that I have now implemented some safe guards:
1. always making a copy of the workspace when doing exports
2. implemented a save on "page reload" setting @ settings-global-"Auto Download JSON"
this can be a good thing to use while doing huge and important stuff
Ouch - sounds painful. Glad you got it sorted out.

I have now fixed so that the initial / always are included.
Thanks. I think I'll still try to keep the option to leave it out, as at the moment I can't see a reason not to, and people will presumably use other tools to build and operate dynamic audio applications. But it reminds me I really ought to do a proper job of managing string parameters - maybe now is the moment, it's all very inconsistent right now.
 
I just realized that there could be problem with "mutual nesting"
I have been thinkin of that for a very long time, node-red have that functionality
Have now imported that function, and did some changes to make it work with the current structure.
So now you can try to do "circular reference" and see what happens.


Need to read up on what an "Audio Main" does for me. Pretty sure I remember there being a note about it in your main GUI++ thread.
First I did use the existing "Main Tab" setting
but have now implemented a separate for defining the "Audio Main"
(both are available at tab/workspace edit "Rename Sheet")

The "Audio Main" defines the tab, that the export starts with (the entry point)

I could determine that tab by searching for I/O objects (i2sIn,i2sOut,usbin,usbout etc.)
but that could be nondeterministic as one could have inputs on one tab and outputs on another.
which one should then be the "main" entry.
MainEntry.png

The "Audio Main" is currently only used by the OSC export.

here is my current test setup (it's not doing anything special just for testing the export)
CurrentTestSetup.png
note. the three last cases are currently not supported

the last will probably never be supported as it's both a array of class and also each class have a array item output, which will be hard to determine and match specially if the input count of the second array wfmD don't match the outputs of arrayoutput[2]
also I don't find any use case for it anyway.

also note that if a class has a array output object connected to it's output
the mixer will take care of that and also include each of them
the mixer in the example will be expanded into 18 inputs
(1+2+1+1*2+2+2*2+2+2+2)

and here is a link to the design
Code:
https://raw.githubusercontent.com/manicken/manicken.github.io/master/examples/OSCexportTests.json
 
Last edited:
I was a little hasty
Have now found some bugs in the OSC group export
when having something as simple as
main:
A_simpleMainWithArray.png

monoVoiceWithArray:
A_simpleMonoVoiceWithArray.png

monoVoice without array:
A_simpleMonoVoice.png

It's working good at the top level when having a mixer
taking a lot of different sources

but when having a mixer inside a class messes everything up

here is the failing 'output' when using monoVoiceWithArray (errors marked in red)
Code:
("/teensy*/dynamic/crCo", "ss", "wav_0_i0_i0_mixer_0_i0", "/mav/i0")
("/teensy*/audio/mav/i0/wav_0_i0_i0_mixer_0_i0/co", "sisi", "/mav/i0/wav/i0", 0, "/mav/i0/mixer", 0)
("/teensy*/dynamic/crCo", "ss", "wav_0_i0_i1_mixer_1_i0", "/mav/i0")
("/teensy*/audio/mav/i0/wav_0_i0_i1_mixer_1_i0/co", "sisi", "/mav/i0/wav/i1", 0, "/mav/i0/mixer", 1)

("/teensy*/dynamic/crCo", "ss", "wav_0_i1_i0_mixer_[COLOR="#FF0000"]2[/COLOR]_i1", "/mav/i1")
("/teensy*/audio/mav/i1/wav_0_i1_i0_mixer_[COLOR="#FF0000"]2[/COLOR]_i1/co", "sisi", "/mav/i1/wav/i0", 0, "/mav/i1/mixer", [COLOR="#FF0000"]2[/COLOR])
("/teensy*/dynamic/crCo", "ss", "wav_0_i1_i1_mixer_[COLOR="#FF0000"]3[/COLOR]_i1", "/mav/i1")
("/teensy*/audio/mav/i1/wav_0_i1_i1_mixer_[COLOR="#FF0000"]3[/COLOR]_i1/co", "sisi", "/mav/i1/wav/i1", 0, "/mav/i1/mixer", [COLOR="#FF0000"]3[/COLOR])

here is the failing 'output' when using monoVoice Without Array (errors marked in red)

Code:
("/teensy*/dynamic/crCo", "ss", "wavA_0_i0_mixer_0_i0", "/mv/i0")
("/teensy*/audio/mv/i0/wavA_0_i0_mixer_0_i0/co", "sisi", "/mv/i0/wavA", 0, "/mv/i0/mixer", 0)
("/teensy*/dynamic/crCo", "ss", "wavB_0_i0_mixer_1_i0", "/mv/i0")
("/teensy*/audio/mv/i0/wavB_0_i0_mixer_1_i0/co", "sisi", "/mv/i0/wavB", 0, "/mv/i0/mixer", 1)

("/teensy*/dynamic/crCo", "ss", "wavA_0_i1_mixer_[COLOR="#FF0000"]1[/COLOR]_i1", "/mv/i1")
("/teensy*/audio/mv/i1/wavA_0_i1_mixer_[COLOR="#FF0000"]1[/COLOR]_i1/co", "sisi", "/mv/i1/wavA", 0, "/mv/i1/mixer", [COLOR="#FF0000"]1[/COLOR])
("/teensy*/dynamic/crCo", "ss", "wavB_0_i1_mixer_[COLOR="#FF0000"]2[/COLOR]_i1", "/mv/i1")
("/teensy*/audio/mv/i1/wavB_0_i1_mixer_[COLOR="#FF0000"]2[/COLOR]_i1/co", "sisi", "/mv/i1/wavB", 0, "/mv/i1/mixer", [COLOR="#FF0000"]2[/COLOR])
 
ok think I fixed the above problem

there is still a problem when trying to connect a multi output class/object to the mixer
i.e. when connecting two or more outputs
so no stereo mixer support yet.

then I found another problem, the paths are all messed up when doing subsubitems
And by looking at the c++ export code I know why,
so gonna rewrite that.
 
Great. Today has mostly been about tidying up: I've removed almost all the horrible "50 byte temporary string buffer - should be enough" code, with a side effect that the initial / can be omitted by the user and will be inserted by the library if needed. I also got sidetracked onto "can we save code space by having a special copy of the Audio library with unnecessary object types removed?". Answer, after a bit of work, is Yes! Given that I was getting to 82% usage on a Teensy 3.5, and a modest cull got me down to 69%, I'm happy in principle. Oh, and the ReadMe.md is updated. So, not very exciting, and you don't need to update, though as ever it would be good to get someone else's view of whether it's working OK.

Just tried to create a circular reference ... :D

I think I'm just putting off trying to start writing an example /subscribe module, really.
 
Good work!

I have made the 'circular reference check' error notification output the path,
also made the notifications animation faster + fast close by clicking them

Fixed so that it's possible to use Stereo Mixer like this now:

StereoMixer.png

input order is like this (short version):
M1 M2 L1 L2 R1 R2 FL1 FL2 FR1 FR2 RL1 RL2 RR1 RR2

I'm thinking of sorting them like this (it's more logical):
M1 M2 L1 R1 L2 R2 FL1 FR1 RL2 RR2 FL2 FR2 RL2 RR2

then I need to implement the BusWire variant
 
Good work!

I have made the 'circular reference check' error notification output the path,
also made the notifications animation faster + fast close by clicking them

Fixed so that it's possible to use Stereo Mixer like this now:

View attachment 27290

input order is like this (short version):
M1 M2 L1 L2 R1 R2 FL1 FL2 FR1 FR2 RL1 RL2 RR1 RR2

I'm thinking of sorting them like this (it's more logical):
M1 M2 L1 R1 L2 R2 FL1 FR1 RL2 RR2 FL2 FR2 RL2 RR2

then I need to implement the BusWire variant
Likewise!

I'm not sure I see how that input list fits with the image: I think I can see M1 to M4, (SVL1 and SVR1) to (SVL4 and SVR4), and (QVA1, QVB1, QVC1, QVD1) to (QVA4, QVB4, QVC4, QVD4), so mixerStereoF has 20 (mono) inputs and mixerStereoR has 8.

But I agree that keeping L and R next to one another makes more sense from the user's point of view, if it's possible for you to do.
 
I've done a bit of restructuring within OSCAudio to pull out some useful functionality into a separate OSCUtils library, and then built an OSCSubscription library using that. I've branched it in case it's broken, and you can find that branch here. The ReadMe is updated, and there's a new demo sketch OSCAudioMIDIsubsFS.ino.

  • User needs to create an OSCSubscription object, and call its update() function regularly
  • The object needs a routeFunction() provided, which will be used to route messages when their subscription fires
  • The update() function needs an OSCBundle parameter to collect any responses: the user should then send() them to the client
  • OSCMessages sent to /subscribe address should be routed to OSCSubscription::route for your object: this provides methods /subscribe, /renew and /unsubscribe
I've used /subEvt as the response messages' address pattern (similar to /reply for directly-addressed OSCAudio messages). In my example I just used my normal processMessage() function as the routeFunction(); this could get weird if a subscription fires messages that get picked up by the subscription engine! At the moment there are no checks for duplicates, and no way to determine what subscriptions currently exist.

For example, /teensy*/subscribe/subscribe,iis<250><10000></teensy1/audio/voi*/i*/env/isAc> will result in a bundle being generated every 250ms for the next 10s, containing which envelopes are active in all instances of all voices. If the lifetime is set to zero the subscription doesn't expire. Expired subscriptions are deleted and cannot be recovered internally; the client has to resend them.

As part of this, I decided that the "target" datum in /reply or /subEvt messages wasn't very useful: if you use /teensy1/audio/voi*/i*/env/isAc to find which envelopes are active, the targets just came back with the "leaf name" env, N times for an N-voice synth. So I've changed that and you still get N messages, but with target names of /voice1/i0/env up to /voice1/iN/env, for example. It makes the messages bigger, but much more useful for maintaining a UI. You can always cut back your naming to /v1/i0/e if you think it helps...

EDIT: still at 82% on a Teensy 3.5!
 
Now I have done some restructuring of the code again, it's the third time now
but now the output order is more structured and easier to read, also it follows the design better.
Also fixed some naming bugs, while connecting a multi output object to a dynMixer

And finally the grouping of signals coming from a multi output class object
going to either AudioMixer or AudioStereoMixer.

Is like this:
L1 R1 L2 R2 ....


I have also changed the structure/order of the OSC menu items

now the 'Export Group' is renamed to 'Export' and moved to the top
that will be the only option when it's working flawless


Now it's time to add support for the bus wire
so that we don't have to connect multiple wires to the mixer
and the design would look nicer
 
This is all looking great! I've managed to crash my test application doing live editing, so need to investigate that... My current simple testbed is this:
Code:
{"version":1,"settings":{"main":{},"arduino":{"ProjectName":"TestToneArray","Board":{"Platform":"","Board":"","Options":""}},"BiDirDataWebSocketBridge":{},"workspaces":{},"sidebar":{"autoSwitchTabToInfoTab":false},"palette":{},"editor":{},"devTest":{},"IndexedDBfiles":{"testFileNames":"testFile.txt"},"NodeDefGenerator":{},"NodeDefManager":{},"NodeHelpManager":{},"OSC":{"UseDebugLinkName":true}},"workspaces":[{"type":"tab","id":"3629fcd9.ccc604","label":"Main","inputs":0,"outputs":0,"export":true,"isMain":false,"mainNameType":"tabName","mainNameExt":".ino","isAudioMain":true,"generateCppDestructor":false,"extraClassDeclarations":"","settings":{"workspaceBgColor":"#EDFFDF","scaleFactor":0.8,"showGridHminor":false,"showGridHmajor":false,"showGridVminor":false,"showGridVmajor":false,"useCenterBasedPositions":false},"nodes":[{"id":"Main_Piano3","type":"UI_Piano","isClass":false,"name":"Piano - waves/i0/wav1","tag":"waves/i0/wav1","comment":"","w":210,"h":130,"textSize":14,"midiCh":"0","midiId":"0","octave":4,"sendCommand":"// this table goes to octave -1\nvar noteFreqs = [8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602, 21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032, 5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85];\nvar freq = noteFreqs[(d.octave+1)*12 + d.keyIndex];\n\n// send in bundle with two commands frequency and noteOn/Off\nvar bundle = OSC.CreateBundle(0);\nbundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'/be',\"ffi\",0.95, freq,0));\n//bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'2/be',\"ffi\",0.5, freq/2,2));\n//if (d.pressed === true)\n//    bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.parentGroup.name+'/noteOn',\"\"));\n//else\n//    bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.parentGroup.name+'/noteOf*',\"\"));\n\nOSC.SendData(OSC.CreateBundleData(bundle));\n\n","headerHeight":30,"whiteKeysColor":"#FFFFFF","blackKeysColor":"#A0A0A0","blackKeysWidthDiff":6,"x":60,"y":270,"blackKeyLabelsVisible":true,"whiteKeyLabelsVisible":true,"parentGroup":"Main_group2","z":"3629fcd9.ccc604","bgColor":"#F6F8BC","wires":[]},{"id":"Main_Button9","type":"UI_Button","isClass":false,"name":"enable","tag":"enabl","comment":"","w":100,"h":34,"textSize":14,"midiCh":"0","midiId":"0","pressAction":"","repeatPressAction":false,"releaseAction":"","repeatReleaseAction":false,"local":"true","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/\"+d.tag+\"*\";\nOSC.SendData(OSC.CreateMessageData(addr,''));","parentGroup":"Main_group7","x":955,"y":110,"z":"3629fcd9.ccc604","bgColor":"#F6F8BC","wires":[]},{"id":"Main_Slider15","type":"UI_Slider","isClass":false,"name":"volume","tag":"vol","comment":"","w":30,"h":200,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":46,"divVal":1,"fval":46,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/\"+d.tag+\"*\";\nOSC.SendData(OSC.CreateMessageData(addr,'f',d.val/d.maxVal));","parentGroup":"Main_group7","x":990,"y":180,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_group2","type":"group","isClass":false,"name":"envA","tag":"waveform1","comment":"","w":449,"h":182,"textSize":14,"nodes":["Main_Piano3","Main_Piano1"],"border_color":"rgba(153,153,153,1)","individualListBoxMode":true,"exportAsClass":true,"x":50,"y":230,"z":"3629fcd9.ccc604","bgColor":"rgba(221,255,187,1)","wires":[]},{"id":"Main_Piano1","type":"UI_Piano","isClass":false,"name":"Piano - waves/i0/wav2","tag":"waves/i0/wav2","comment":"","w":210,"h":130,"textSize":14,"midiCh":"0","midiId":"0","octave":4,"sendCommand":"// this table goes to octave -1\nvar noteFreqs = [8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602, 21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032, 5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85];\nvar freq = noteFreqs[(d.octave+1)*12 + d.keyIndex];\n\n// send in bundle with two commands frequency and noteOn/Off\nvar bundle = OSC.CreateBundle(0);\n//bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'1/be',\"ffi\",0.8, freq,0));\nbundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'/be',\"ffi\",0.95, freq/2,0));\n//if (d.pressed === true)\n//    bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.parentGroup.name+'/noteOn',\"\"));\n//else\n//    bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.parentGroup.name+'/noteOf*',\"\"));\n\nOSC.SendData(OSC.CreateBundleData(bundle));\n\n","headerHeight":30,"whiteKeysColor":"#FFFFFF","blackKeysColor":"#A0A0A0","blackKeysWidthDiff":6,"x":275,"y":270,"blackKeyLabelsVisible":true,"whiteKeyLabelsVisible":true,"parentGroup":"Main_group2","z":"3629fcd9.ccc604","bgColor":"#F6F8BC","wires":[]},{"id":"Main_Slider1","type":"UI_Slider","isClass":false,"name":"pan 1","tag":"0","comment":"","w":172,"h":34,"textSize":14,"midiCh":"0","midiId":"0","orientation":"h","label":"d.val","minVal":-100,"maxVal":100,"val":-83,"divVal":1,"fval":-83,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/pan\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":544.25,"y":184.5,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_group1","type":"group","isClass":false,"name":"mixerStereo","tag":"","comment":"","w":386,"h":283,"textSize":14,"nodes":["Main_Slider1","Main_Slider2","Main_Slider3","Main_Slider4","Main_Slider5"],"border_color":"rgba(153,153,153,1)","individualListBoxMode":true,"exportAsClass":true,"x":535,"y":130,"z":"3629fcd9.ccc604","bgColor":"rgba(221,255,187,1)","wires":[]},{"id":"Main_Slider2","type":"UI_Slider","isClass":false,"name":"pan 2","tag":"1","comment":"","w":172,"h":34,"textSize":14,"midiCh":"0","midiId":"0","orientation":"h","label":"d.val","minVal":-100,"maxVal":100,"val":62,"divVal":1,"fval":62,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/pan\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":739.25,"y":184.5,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider3","type":"UI_Slider","isClass":false,"name":"gain","tag":"","comment":"","w":86,"h":129,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":72,"divVal":1,"fval":72,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/gain\";\nOSC.SendData(OSC.CreateMessageData(addr,'f',d.val/d.maxVal));","parentGroup":"Main_group1","x":685,"y":250,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_group7","type":"group","isClass":false,"name":"sgtl5000","comment":"","w":119,"h":336,"textSize":14,"nodes":["Main_Button9","Main_Slider15"],"border_color":"rgba(153,153,153,1)","individualListBoxMode":true,"exportAsClass":true,"x":945,"y":75,"z":"3629fcd9.ccc604","bgColor":"rgba(221,255,187,1)","wires":[]},{"id":"Main_Slider4","type":"UI_Slider","isClass":false,"name":"gainL","tag":"0","comment":"","w":56,"h":129,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":44,"divVal":1,"fval":44,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/gain\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":555,"y":250,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider5","type":"UI_Slider","isClass":false,"name":"gainR","tag":"1","comment":"","w":56,"h":129,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":41,"divVal":1,"fval":41,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/gain\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":840,"y":250,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_waves1","type":"waves","isClass":true,"name":"waves[2]","x":40,"y":140,"z":"3629fcd9.ccc604","bgColor":"#CCFFCC","wires":[["Main_mixerStereo1:0"],["Main_mixerStereo1:1"]]},{"id":"Main_mixerStereo1","type":"AudioMixerStereo","isClass":false,"name":"mixerStereo","comment":"","inputs":2,"x":195,"y":140,"z":"3629fcd9.ccc604","bgColor":"#E6E0F8","wires":[["Main_dacs1:0","Main_i2s1:0"],["Main_dacs1:1","Main_i2s1:1"]]},{"id":"Main_i2s1","type":"AudioOutputI2S","isClass":false,"name":"i2s","comment":"","x":390,"y":105,"z":"3629fcd9.ccc604","bgColor":"#E6E0F8","wires":[]},{"id":"Main_dacs1","type":"AudioOutputAnalogStereo","isClass":false,"name":"dac","comment":"","x":390,"y":175,"z":"3629fcd9.ccc604","bgColor":"#E6E0F8","wires":[]},{"id":"Main_sgtl5000_1","type":"AudioControlSGTL5000","isClass":false,"name":"sgtl5000","comment":"","x":815,"y":65,"z":"3629fcd9.ccc604","bgColor":"#E6E0F8","wires":[]}]},{"type":"tab","id":"22723e47.b3e4f2","label":"waves","inputs":0,"outputs":0,"export":true,"isMain":false,"mainNameType":"tabName","mainNameExt":".ino","isAudioMain":false,"generateCppDestructor":false,"extraClassDeclarations":"","settings":{"guiEditMode":false,"workspaceBgColor":"#EDFFDF","scaleFactor":0.8,"showGridHminor":false,"showGridHmajor":false,"showGridVminor":false,"showGridVmajor":false,"useCenterBasedPositions":false},"nodes":[{"id":"waves_Out2","type":"TabOutput","isClass":false,"name":"Out","comment":"","inputs":1,"x":500,"y":230,"z":"22723e47.b3e4f2","bgColor":"#cce6ff","wires":[]},{"id":"waves_Out3","type":"TabOutput","isClass":false,"name":"Out","comment":"","inputs":1,"x":500,"y":290,"z":"22723e47.b3e4f2","bgColor":"#cce6ff","wires":[]},{"id":"waves_waveform2","type":"AudioSynthWaveform","isClass":false,"name":"wav1","comment":"","x":319,"y":225.75,"z":"22723e47.b3e4f2","bgColor":"#E6E0F8","wires":[["waves_Out2:0"]]},{"id":"waves_waveform3","type":"AudioSynthWaveform","isClass":false,"name":"wav2","comment":"","x":319,"y":285.75,"z":"22723e47.b3e4f2","bgColor":"#E6E0F8","wires":[["waves_Out3:0"]]}]}],"nodeAddons":{}
}
which shows a few odd items:
Code:
("/teensy*/dynamic/clearAl*")
("//**************************")
("//*** create all objects ***")
("//**************************")
("/teensy*/dynamic/crGrp", "ss", "waves", "/")
("/teensy*/dynamic/crGrp", "ss", "i0", "/waves")
("/teensy*/dynamic/crGrp", "ss", "i1", "/waves")
("/teensy*/dynamic/crOb", "sss", "AudioSynthWaveform", "wav1", "/waves/i*")
("/teensy*/dynamic/crOb", "sss", "AudioSynthWaveform", "wav2", "/waves/i*")
("/teensy*/dynamic/crOb", "ssi", "AudioMixerStereo", "mixerStereo", 4)
("/teensy*/dynamic/crOb", "ss", "AudioOutputI2S", "i2s")
("/teensy*/dynamic/crOb", "ss", "AudioOutputAnalogStereo", "dac")
("/teensy*/dynamic/crOb", "ss", "AudioControlSGTL5000", "sgtl5000")
("//************************************")
("//*** create all audio connections ***")
("//************************************")
("//********************************************")
("//  /waves/i0")
("//********************************************")
[COLOR="#FF0000"]("//********************************************")
("//  /waves/i0")
("//********************************************")[/COLOR]
("/teensy*/dynamic/crCo", "s", "[COLOR="#FF0000"]waves_[/COLOR]wav1_0_[COLOR="#FF0000"]i0_[/COLOR]mixerStereo_0")
("/teensy*/audio/waves_wav1_0_i0_mixerStereo_0/co", "sisi", "/waves/i0/wav1", 0, "/mixerStereo", 0)
("/teensy*/dynamic/crCo", "s", "[COLOR="#FF0000"]waves_[/COLOR]wav2_0_[COLOR="#FF0000"]i0_[/COLOR]mixerStereo_1")
("/teensy*/audio/waves_wav2_0_i0_mixerStereo_1/co", "sisi", "/waves/i0/wav2", 0, "/mixerStereo", 1)
("//********************************************")
("//  /waves/i1")
("//********************************************")
("//********************************************")
("//  /waves/i1")
("//********************************************")
("/teensy*/dynamic/crCo", "s", "waves_wav1_0_i1_mixerStereo_2")
("/teensy*/audio/waves_wav1_0_i1_mixerStereo_2/co", "sisi", "/waves/i1/wav1", 0, "/mixerStereo", 2)
("/teensy*/dynamic/crCo", "s", "waves_wav2_0_i1_mixerStereo_3")
("/teensy*/audio/waves_wav2_0_i1_mixerStereo_3/co", "sisi", "/waves/i1/wav2", 0, "/mixerStereo", 3)
("//********************************************")
("//  /mixerStereo")
("//********************************************")
("/teensy*/dynamic/crCo", "s", "mixerStereo_0_i2s_0[COLOR="#FF0000"]_i2s[/COLOR]")
("/teensy*/audio/mixerStereo_0_i2s_0_i2s/co", "sisi", "/mixerStereo", 0, "/i2s", 0)
("/teensy*/dynamic/crCo", "s", "mixerStereo_1_i2s_1[COLOR="#FF0000"]_i2s[/COLOR]")
("/teensy*/audio/mixerStereo_1_i2s_1_i2s/co", "sisi", "/mixerStereo", 1, "/i2s", 1)
("/teensy*/dynamic/crCo", "s", "mixerStereo_0_dac_0")
("/teensy*/audio/mixerStereo_0_dac_0/co", "sisi", "/mixerStereo", 0, "/dac", 0)
("/teensy*/dynamic/crCo", "s", "mixerStereo_1_dac_1")
("/teensy*/audio/mixerStereo_1_dac_1/co", "sisi", "/mixerStereo", 1, "/dac", 1)

Total AudioObjects:9
Total AudioConnections: 15.5

RAW data (size 1804 bytes):
#bundle[00][e5][9c][1a][83][ab][85] [00][00][00][00] /teensy*/dynamic/clearAl*[00][00][00],[00][00][00][00][00][00](/teensy*/dynamic/crGrp[00][00],ss[00]waves[00][00][00]/[00][00][00][00][00][00](/teensy*/dynamic/crGrp[00][00],ss[00]i0[00][00]/waves[00][00][00][00][00](/teensy*/dynamic/crGrp[00][00],ss[00]i1[00][00]/waves[00][00][00][00][00]H/teensy*/dynamic/crOb[00][00][00],sss[00][00][00][00]AudioSynthWaveform[00][00]wav1[00][00][00][00]/waves/i*[00][00][00][00][00][00]H/teensy*/dynamic/crOb[00][00][00],sss[00][00][00][00]AudioSynthWaveform[00][00]wav2[00][00][00][00]/waves/i*[00][00][00][00][00][00]D/teensy*/dynamic/crOb[00][00][00],ssi[00][00][00][00]AudioMixerStereo[00][00][00][00]mixerStereo[00][00][00][00][04][00][00][00]0/teensy*/dynamic/crOb[00][00][00],ss[00]AudioOutputI2S[00][00]i2s[00][00][00][00]8/teensy*/dynamic/crOb[00][00][00],ss[00]AudioOutputAnalogStereo[00]dac[00][00][00][00]@/teensy*/dynamic/crOb[00][00][00],ss[00]AudioControlSGTL5000[00][00][00][00]sgtl5000[00][00][00][00][00][00][00]</teensy*/dynamic/crCo[00][00][00],s[00][00]waves_wav1_0_i0_mixerStereo_0[00][00][00][00][00][00]`/teensy*/audio/waves_wav1_0_i0_mixerStereo_0/co[00],sisi[00][00][00]/waves/i0/wav1[00][00][00][00][00][00]/mixerStereo[00][00][00][00][00][00][00][00][00][00][00]</teensy*/dynamic/crCo[00][00][00],s[00][00]waves_wav2_0_i0_mixerStereo_1[00][00][00][00][00][00]`/teensy*/audio/waves_wav2_0_i0_mixerStereo_1/co[00],sisi[00][00][00]/waves/i0/wav2[00][00][00][00][00][00]/mixerStereo[00][00][00][00][00][00][00][01][00][00][00]</teensy*/dynamic/crCo[00][00][00],s[00][00]waves_wav1_0_i1_mixerStereo_2[00][00][00][00][00][00]`/teensy*/audio/waves_wav1_0_i1_mixerStereo_2/co[00],sisi[00][00][00]/waves/i1/wav1[00][00][00][00][00][00]/mixerStereo[00][00][00][00][00][00][00][02][00][00][00]</teensy*/dynamic/crCo[00][00][00],s[00][00]waves_wav2_0_i1_mixerStereo_3[00][00][00][00][00][00]`/teensy*/audio/waves_wav2_0_i1_mixerStereo_3/co[00],sisi[00][00][00]/waves/i1/wav2[00][00][00][00][00][00]/mixerStereo[00][00][00][00][00][00][00][03][00][00][00]4/teensy*/dynamic/crCo[00][00][00],s[00][00]mixerStereo_0_i2s_0_i2s[00][00][00][00]T/teensy*/audio/mixerStereo_0_i2s_0_i2s/co[00][00][00],sisi[00][00][00]/mixerStereo[00][00][00][00][00][00][00][00]/i2s[00][00][00][00][00][00][00][00][00][00][00]4/teensy*/dynamic/crCo[00][00][00],s[00][00]mixerStereo_1_i2s_1_i2s[00][00][00][00]T/teensy*/audio/mixerStereo_1_i2s_1_i2s/co[00][00][00],sisi[00][00][00]/mixerStereo[00][00][00][00][00][00][00][01]/i2s[00][00][00][00][00][00][00][01][00][00][00]0/teensy*/dynamic/crCo[00][00][00],s[00][00]mixerStereo_0_dac_0[00][00][00][00]P/teensy*/audio/mixerStereo_0_dac_0/co[00][00][00],sisi[00][00][00]/mixerStereo[00][00][00][00][00][00][00][00]/dac[00][00][00][00][00][00][00][00][00][00][00]0/teensy*/dynamic/crCo[00][00][00],s[00][00]mixerStereo_1_dac_1[00][00][00][00]P/teensy*/audio/mixerStereo_1_dac_1/co[00][00][00],sisi[00][00][00]/mixerStereo[00][00][00][00][00][00][00][01]/dac[00][00][00][00][00][00][00][01]
  • doubled comment blocks for the connection creation in sub-groups
  • strangely placed group path elements in the "group to root" connection names (I'd expect waves_i0_wav1_0_mixerStereo_0, for example)
  • extra _i2s on the I2S input connections (but not the DAC, oddly)
Of course, you may have had very good reasons for doing things the way you have, and I've failed to spot them!
 
I was just to say that bus wires is now supported coming out from classes

but spotted some duplicate connection names in the output at class inputs.

the get link name function is a mess
need to clean/fix that up
 
Now the connection names are generated like this
which at least don't generate any doubles
need to fix these as most of the time the paths are not needed
because the connections are created in a path,
they don't need the path to generate unique names.

Code:
var dbg = RED.OSC.settings.UseDebugLinkName;
var sourcePath = l.sourcePath!=undefined?(l.sourcePath.replaceAllVal("/", (dbg?"_":""))):"";
var targetPath = l.targetPath!=undefined?(l.targetPath.replaceAllVal("/", (dbg?"_":""))):"";
var sourceName = l.sourceName.replaceAllVal("/", (dbg?"_":""));
var targetName = l.targetName.replaceAllVal("/", (dbg?"_":""));;
var sourceId = sourcePath + (dbg?"_":"") + sourceName + (dbg?"_":"") + l.sourcePort;
var targetId = targetPath + (dbg?"_":"") + targetName + (dbg?"_":"") + l.targetPort;
if (RED.OSC.settings.HashLinkNames == true)
   var name = RED.OSC.settings.HashLinkNamesHeader||"L" + (cyrb53(sourceId + (dbg?"_":"") + targetId)).toString(16);
else
   var name = (sourceId + (dbg?"_":"") + targetId);
as you can see I have now included the option to generate the link names as a hash
this make short names, that don't take up so much memory.

note. the 'live update' generated link names don't use the paths at the moment
this is because I make copies of the original links (to not mess things up)

To make live update work with classes/arrays I would need to do some restructuring.



Here is a bus wires example:
BusWireSupport.png

MonoArrayVoice (array is because it have a array at the input)
MonoArrayVoice.png

StereoVoice
with one bus wire output
StereoVoice.png

QuadVoice
with two bus wire outputs
QuadVoice.png


Here are some variants that is not supported:
"quadvoice4"
UnsupportedQuadVoice.png
"quadvoice5"
UnsupportedQuadVoice2.png
usage:
UnsupportedQuadVoiceUsage.png

everything is in this design:
Code:
https://raw.githubusercontent.com/manicken/manicken.github.io/master/examples/OSCexportTests.json
note. there are some examples that is not supported.
they have comments inside their tabs

also
there is this new button (taken from node-red)
TabsListAndSearchButton.png
this lists all tabs, and can also be used to search for nodes/objects
 
Last edited:
Will take a look at this soon.

I've been chasing down the live-editing crash, and I think it was due to addresses longer than I allowed for: "unfortunately" (i.e. "due to an omission which renders the library nearly unusable"...) there's no native getAddressLength() function in the OSC library. I've bodged around it for now, but it's getting close to the point where I'm going to have to dive in to fix some essential elements and put in a PR. Not hopeful on that front, as there are ones in there that are two years old, and the last maintenance was done 9 months ago.

Anyway, having fixed that (new commit here), I've found an issue with live re-sizing of mixers. Here's part of the output log:
Code:
mixerStereo node inputs changed from 2 to 4
removed link (waves[2], 0, mixerStereo, 0)
removed link (waves[2], 1, mixerStereo, 1)
removed link (mixerStereo, 0, dac, 0)
removed link (mixerStereo, 0, i2s, 0)
removed link (mixerStereo, 1, dac, 1)
removed link (mixerStereo, 1, i2s, 1)
{"timeTag":{"raw":[3852356044,648540160]},"packets":[
{"address":"/teensy*/dynamic/d*","args":[{"type":"s","value":"[COLOR="#FF0000"]undefined_waves_0_undefined_mixerStereo_0[/COLOR]"}]},
{"address":"/teensy*/dynamic/d*","args":[{"type":"s","value":"undefined_waves_1_undefined_mixerStereo_1"}]},
{"address":"/teensy*/dynamic/d*","args":[{"type":"s","value":"undefined_mixerStereo_0_undefined_dac_0"}]},
{"address":"/teensy*/dynamic/d*","args":[{"type":"s","value":"undefined_mixerStereo_0_undefined_i2s_0"}]},
{"address":"/teensy*/dynamic/d*","args":[{"type":"s","value":"undefined_mixerStereo_1_undefined_dac_1"}]},
{"address":"/teensy*/dynamic/d*","args":[{"type":"s","value":"undefined_mixerStereo_1_undefined_i2s_1"}]},
{"address":"/teensy*/dynamic/d*","args":[{"type":"s","value":"mixerStereo"}]},
{"address":"/teensy*/dynamic/crOb","args":[{"type":"s","value":"AudioMixerStereo"},{"type":"s","value":"mixerStereo"},{"type":"i","value":4}]},
{"address":"/teensy*/dynamic/crCo","args":[{"type":"s","value":"[COLOR="#FF0000"]undefined_waves_0_undefined_mixerStereo_0[/COLOR]"}]},
{"address":"/teensy*/audio/undefined_waves_0_undefined_mixerStereo_0/co","args":[{"type":"s","value":"[COLOR="#FF0000"]waves[2][/COLOR]"},{"type":"i","value":0},{"type":"s","value":"mixerStereo"},{"type":"i","value":"0"}]},
{"address":"/teensy*/dynamic/crCo","args":[{"type":"s","value":"undefined_waves_1_undefined_mixerStereo_1"}]},
{"address":"/teensy*/audio/undefined_waves_1_undefined_mixerStereo_1/co","args":[{"type":"s","value":"waves[2]"},{"type":"i","value":1},{"type":"s","value":"mixerStereo"},{"type":"i","value":"1"}]},
{"address":"/teensy*/dynamic/crCo","args":[{"type":"s","value":"undefined_mixerStereo_0_undefined_dac_0"}]},
{"address":"/teensy*/audio/undefined_mixerStereo_0_undefined_dac_0/co","args":[{"type":"s","value":"mixerStereo"},{"type":"i","value":0},{"type":"s","value":"dac"},{"type":"i","value":"0"}]},
{"address":"/teensy*/dynamic/crCo","args":[{"type":"s","value":"undefined_mixerStereo_0_undefined_i2s_0"}]},
{"address":"/teensy*/audio/undefined_mixerStereo_0_undefined_i2s_0/co","args":[{"type":"s","value":"mixerStereo"},{"type":"i","value":0},{"type":"s","value":"i2s"},{"type":"i","value":"0"}]},
{"address":"/teensy*/dynamic/crCo","args":[{"type":"s","value":"undefined_mixerStereo_1_undefined_dac_1"}]},
{"address":"/teensy*/audio/undefined_mixerStereo_1_undefined_dac_1/co","args":[{"type":"s","value":"mixerStereo"},{"type":"i","value":1},{"type":"s","value":"dac"},{"type":"i","value":"1"}]},
{"address":"/teensy*/dynamic/crCo","args":[{"type":"s","value":"undefined_mixerStereo_1_undefined_i2s_1"}]},
{"address":"/teensy*/audio/undefined_mixerStereo_1_undefined_i2s_1/co","args":[{"type":"s","value":"mixerStereo"},{"type":"i","value":1},{"type":"s","value":"i2s"},{"type":"i","value":"1"}]}]}

packets:
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/d*"},{"type":"s","value":"/undefined_waves_0_undefined_mixerStereo_0"},{"type":"i","value":0},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/d*"},{"type":"s","value":"/undefined_waves_1_undefined_mixerStereo_1"},{"type":"i","value":0},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/d*"},{"type":"s","value":"/undefined_mixerStereo_0_undefined_dac_0"},{"type":"i","value":0},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/d*"},{"type":"s","value":"/undefined_mixerStereo_0_undefined_i2s_0"},{"type":"i","value":0},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/d*"},{"type":"s","value":"/undefined_mixerStereo_1_undefined_dac_1"},{"type":"i","value":0},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/d*"},{"type":"s","value":"/undefined_mixerStereo_1_undefined_i2s_1"},{"type":"i","value":0},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/d*"},{"type":"s","value":"/mixerStereo"},{"type":"i","value":1},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/crOb"},{"type":"s","value":"/mixerStereo"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/crCo"},{"type":"s","value":"/undefined_waves_0_undefined_mixerStereo_0"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/audio/undefined_waves_0_undefined_mixerStereo_0/co"},{"type":"s","value":"[COLOR="#FF0000"]Bad path(s): /waves_2, /mixerStereo[/COLOR]"},{"type":"i","value":1}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/crCo"},{"type":"s","value":"/undefined_waves_1_undefined_mixerStereo_1"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/audio/undefined_waves_1_undefined_mixerStereo_1/co"},{"type":"s","value":"Bad path(s): /waves_2, /mixerStereo"},{"type":"i","value":1}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/crCo"},{"type":"s","value":"/undefined_mixerStereo_0_undefined_dac_0"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/audio/undefined_mixerStereo_0_undefined_dac_0/co"},{"type":"s","value":"/mixerStereo:0 -> /dac:0 (0)"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/crCo"},{"type":"s","value":"/undefined_mixerStereo_0_undefined_i2s_0"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/audio/undefined_mixerStereo_0_undefined_i2s_0/co"},{"type":"s","value":"/mixerStereo:0 -> /i2s:0 (0)"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/crCo"},{"type":"s","value":"/undefined_mixerStereo_1_undefined_dac_1"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/audio/undefined_mixerStereo_1_undefined_dac_1/co"},{"type":"s","value":"/mixerStereo:1 -> /dac:1 (0)"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/dynamic/crCo"},{"type":"s","value":"/undefined_mixerStereo_1_undefined_i2s_1"},{"type":"i","value":0}]}
{"address":"/reply","args":[{"type":"s","value":"/teensy*/audio/undefined_mixerStereo_1_undefined_i2s_1/co"},{"type":"s","value":"/mixerStereo:1 -> /i2s:1 (0)"},{"type":"i","value":0}]}
OK
Essentially it seems to be down to using different code to generate the connection names: the ones it tries to delete were actually called something like _waves_i0_wav1_0__mixerStereo_0. Maybe it would make sense for you to store the connection's name at construction time, altering it as needed when the source and destination objects are renamed? Or just have a single function responsible for generating the names, of course.

As an aside, I have internal sanitise() and trimUnderscores() functions - I think we discussed those several pages back. They're applied in that order, and trimUnderscores() removes leading and trailing underscores, and compresses runs of them into one, so the name actually used will end up being waves_i0_wav1_0_mixerStereo_0 (note the subtle removal of one underscore between 0 and mixerStereo). I think this probably doesn't matter, as longs as my code always applies the rules consistently.
 
But Paul have a OSC fork, isn't that what we are using?
If so then the needed updates could be pushed to that instead?
At least for the moment.

The naming of links actually only use one function, but that function obviously still have some problems :(
I know about the leading and double '_':s but that was a quick and dirty fix to get it working.
 
But Paul have a OSC fork, isn't that what we are using?
If so then the needed updates could be pushed to that instead?
At least for the moment.
I'm using the upstream CNMAT repository. Paul's fork is 65 commits behind that, and only ahead because he's fixed some warnings back in 2017 and again in 2020 (I don't think I get warnings, so they're probably fixed upstream as well). I'd rather contribute to the original repository: routine maintenance and keeping up with PRs doesn't seem to be something PJRC have a policy of staying on top of. If they adopt dynamic audio and OSCAudio and GUI++, they can bring their OSC library up to date then.
The naming of links actually only use one function, but that function obviously still have some problems :(
I know about the leading and double '_':s but that was a quick and dirty fix to get it working.
Turns out I was wrong about it not mattering! They create OK, but connecting them doesn't work, because I can't apply trimUnderscores() to the (untrimmed) address you send the connect request to. It all works if I turn off the "Use debug link names" option.
 
@adrianfreed, I've forked the OSC library, done some fixes and issued a PR. Would be good to know if there's a chance it'll be merged :)
 
I have been thinking, no matter what I have said before.
Would it not be better if you:
1. always trim leading/trailing spaces
2a. Replace all invalid characters "/ #*,?[]{}" with underscores, and just leave them there (no trimming of additional _)
2b. (alternative) just reply with 'invalid name'-error if name contains unsupported characters "/ #*,?[]{}"

I would vote for 2b as from a user perspective that
would be the most convenient, as how else would they know if they did something unsupported, and how the resulting name is,
(ok now when I think about it, the standard reply maybe contains the trimmed name?)

Also if anyone want to have leading/trailing underscores they should be able to have that, even if that look ugly.

I will of course fix the link names generation anyway,
but that's mostly because I think it's ugly and only generate long names. Also the undefined part needs to go away (but that's more a bug)
JavaScript have some problems, if for example
I write to check if str is 'not undefined' (i.e. defined)
Code:
var str="";
var result=str?str:"hello"
One would expect it to return a empty string, but instead it returns "hello"

Instead you need to write it like this:
Code:
var str="";
var result=(str!=undefined)?str:"hello"

That problem above did introduce many bugs and problems in the generator code.
 
I don't know if you have noticed but I have implemented a strict naming scheme on both AudioObject names and specially class names.

AudioObject names can only be named to valid c/c++(and similar) names (including ending with [*] to define arrays)

Class names must begin with a uppercase letter (A-Z) and can only contain underscores(as the only special char)

Both Class and Objects can contain numbers but not begin with that.

However when making copies of array defined objects the new names won't change.
 
Think this could solve your getMessageAddressLen
At least you don't have to buffer a stupid amount of data to get the address size.
Code:
int padSize(int _bytes){
    int space = (_bytes + 3) / 4;
    space *= 4;
	return space - _bytes;
}
size_t OSCUtils::getMessageAddressLen(OSCMessage& msg)
{
int dataCount = msg->size();
int totalDataSize =0;
for (int i = 0; i < dataCount; i++){
        OSCData * datum = msg->getOSCData(i);
        totalDataSize+=datum->bytes;
        totalDataSize += padSize(datum->bytes);
    }
return msg-bytes() - totalDataSize; 
}
It at least returns the minimum amount of space needed to get a address.
 
They create OK, but connecting them doesn't work, because I can't apply trimUnderscores() to the (untrimmed) address you send the connect request to. It all works if I turn off the "Use debug link names" option.

Have now fixed leading/double '_':s

Also did removed unnecessary path:s when creating links inside a 'class'

so instead of having extreme link names like this:
quadvoice4_stereovoice_mvL_wav1_0_quadvoice4_stereovoice_mvL_mixer_0
quadvoice4_stereovoice_mvL_wav_i0_0_quadvoice4_stereovoice_mvL_mixer_1

it's now:
wav1_0_mixer_0
wav_i0_0_mixer_1
 
Apologies for the radio silence, I have the house to myself this weekend so can maximise bug fixing and new features!

  • should now be hard / difficult to create I/O resource clashes via OSC*
  • new /system address: implements /reset, /heap, /stack, /usage and /max functions, currently echoed to the terminal
  • you now get an error code if a connection can't be made, e.g. if its target input is in use
  • fixed a memory leak if OSCMessages are received rather than bundles
* the GUI flags these with warning signs, but if a create message does get sent, e.g. creating both an I2S and PT8211 object, you should get an IN_USE response and the second object is not created. Not that with the current state of the dynamic audio library, it is not possible to destroy an I/O object fully once it's been created, as I can't figure out the necessary steps to e.g. remove DMA use safely. Hence they remain present in a "dormant" state, and can be re-started by "re-creating" them. So you can create I2S, delete it, attempt to create PT8211 (which fails), and create the I2S again (which succeeds, rising from the ashes of the supposedly deleted one!). [I did my first test with a TDM output, which failed - I think the "number of inputs" parameter confused the OSCAudio library. I've raised it with myself as an issue on github.]

One thing I spotted when trying live editing is that bus connections confuse the GUI. I had this design:
Code:
{"version":1,"settings":{"main":{},"arduino":{"ProjectName":"TestToneBussed","Board":{"Platform":"","Board":"","Options":""}},"BiDirDataWebSocketBridge":{},"workspaces":{},"sidebar":{"autoSwitchTabToInfoTab":false},"palette":{},"editor":{},"devTest":{},"IndexedDBfiles":{"testFileNames":"testFile.txt"},"NodeDefGenerator":{},"NodeDefManager":{},"NodeHelpManager":{},"OSC":{"LiveUpdate":false,"UseDebugLinkName":true}},"workspaces":[{"type":"tab","id":"3629fcd9.ccc604","label":"Main","inputs":0,"outputs":0,"export":true,"isMain":false,"mainNameType":"tabName","mainNameExt":".ino","isAudioMain":true,"generateCppDestructor":false,"extraClassDeclarations":"","settings":{"workspaceBgColor":"#EDFFDF","scaleFactor":0.8,"showGridHminor":false,"showGridHmajor":false,"showGridVminor":false,"showGridVmajor":false,"useCenterBasedPositions":false},"nodes":[{"id":"Main_Piano3","type":"UI_Piano","isClass":false,"name":"Piano - waves/i0/wav1","tag":"waves/i0/wav1","comment":"","w":210,"h":130,"textSize":14,"midiCh":"0","midiId":"0","octave":3,"sendCommand":"// this table goes to octave -1\nvar noteFreqs = [8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602, 21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032, 5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85];\nvar freq = noteFreqs[(d.octave+1)*12 + d.keyIndex];\n\n// send in bundle with two commands frequency and noteOn/Off\nvar bundle = OSC.CreateBundle(0);\nbundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'/be',\"ffi\",0.95, freq,0));\n//bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'2/be',\"ffi\",0.5, freq/2,2));\n//if (d.pressed === true)\n//    bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.parentGroup.name+'/noteOn',\"\"));\n//else\n//    bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.parentGroup.name+'/noteOf*',\"\"));\n\nOSC.SendData(OSC.CreateBundleData(bundle));\n\n","headerHeight":30,"whiteKeysColor":"#FFFFFF","blackKeysColor":"#A0A0A0","blackKeysWidthDiff":6,"x":60,"y":270,"blackKeyLabelsVisible":true,"whiteKeyLabelsVisible":true,"parentGroup":"Main_group2","z":"3629fcd9.ccc604","bgColor":"#F6F8BC","wires":[]},{"id":"Main_Button9","type":"UI_Button","isClass":false,"name":"enable","tag":"enabl","comment":"","w":100,"h":34,"textSize":14,"midiCh":"0","midiId":"0","pressAction":"","repeatPressAction":false,"releaseAction":"","repeatReleaseAction":false,"local":"true","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/\"+d.tag+\"*\";\nOSC.SendData(OSC.CreateMessageData(addr,''));","parentGroup":"Main_group7","x":1110,"y":170,"z":"3629fcd9.ccc604","bgColor":"#F6F8BC","wires":[]},{"id":"Main_Slider15","type":"UI_Slider","isClass":false,"name":"volume","tag":"vol","comment":"","w":30,"h":200,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":46,"divVal":1,"fval":46,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/\"+d.tag+\"*\";\nOSC.SendData(OSC.CreateMessageData(addr,'f',d.val/d.maxVal));","parentGroup":"Main_group7","x":1145,"y":240,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_group2","type":"group","isClass":false,"name":"envA","tag":"waveform1","comment":"","w":449,"h":338,"textSize":14,"nodes":["Main_Piano3","Main_Piano1","Main_Piano2","Main_Piano4"],"border_color":"rgba(153,153,153,1)","individualListBoxMode":true,"exportAsClass":true,"x":50,"y":230,"z":"3629fcd9.ccc604","bgColor":"rgba(221,255,187,1)","wires":[]},{"id":"Main_Piano1","type":"UI_Piano","isClass":false,"name":"Piano - waves/i0/wav2","tag":"waves/i0/wav2","comment":"","w":210,"h":130,"textSize":14,"midiCh":"0","midiId":"0","octave":4,"sendCommand":"// this table goes to octave -1\nvar noteFreqs = [8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602, 21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032, 5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85];\nvar freq = noteFreqs[(d.octave+1)*12 + d.keyIndex];\n\n// send in bundle with two commands frequency and noteOn/Off\nvar bundle = OSC.CreateBundle(0);\n//bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'1/be',\"ffi\",0.8, freq,0));\nbundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'/be',\"ffi\",0.95, freq,3));\n//if (d.pressed === true)\n//    bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.parentGroup.name+'/noteOn',\"\"));\n//else\n//    bundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.parentGroup.name+'/noteOf*',\"\"));\n\nOSC.SendData(OSC.CreateBundleData(bundle));\n\n","headerHeight":30,"whiteKeysColor":"#FFFFFF","blackKeysColor":"#A0A0A0","blackKeysWidthDiff":6,"x":275,"y":270,"blackKeyLabelsVisible":true,"whiteKeyLabelsVisible":true,"parentGroup":"Main_group2","z":"3629fcd9.ccc604","bgColor":"#F6F8BC","wires":[]},{"id":"Main_group7","type":"group","isClass":false,"name":"sgtl5000","comment":"","w":119,"h":336,"textSize":14,"nodes":["Main_Button9","Main_Slider15"],"border_color":"rgba(153,153,153,1)","individualListBoxMode":true,"exportAsClass":true,"x":1100,"y":135,"z":"3629fcd9.ccc604","bgColor":"rgba(221,255,187,1)","wires":[]},{"id":"Main_Piano2","type":"UI_Piano","isClass":false,"name":"Piano - waves/i1/wav1","tag":"waves/i1/wav1","comment":"","w":210,"h":130,"textSize":14,"midiCh":"0","midiId":"0","octave":5,"sendCommand":"// this table goes to octave -1\nvar noteFreqs = [8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602, 21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032, 5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85];\nvar freq = noteFreqs[(d.octave+1)*12 + d.keyIndex];\n\n// send in bundle with two commands frequency and noteOn/Off\nvar bundle = OSC.CreateBundle(0);\nbundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'/be',\"ffi\",0.95, freq,9));\n\nOSC.SendData(OSC.CreateBundleData(bundle));\n\n","headerHeight":30,"whiteKeysColor":"#FFFFFF","blackKeysColor":"#A0A0A0","blackKeysWidthDiff":6,"x":60,"y":425,"blackKeyLabelsVisible":true,"whiteKeyLabelsVisible":true,"parentGroup":"Main_group2","z":"3629fcd9.ccc604","bgColor":"#F6F8BC","wires":[]},{"id":"Main_Piano4","type":"UI_Piano","isClass":false,"name":"Piano - waves/i1/wav2","tag":"waves/i1/wav2","comment":"","w":210,"h":130,"textSize":14,"midiCh":"0","midiId":"0","octave":6,"sendCommand":"// this table goes to octave -1\nvar noteFreqs = [8.176, 8.662, 9.177, 9.723, 10.301, 10.913, 11.562, 12.25, 12.978, 13.75, 14.568, 15.434, 16.352, 17.324, 18.354, 19.445, 20.602, 21.827, 23.125, 24.5, 25.957, 27.5, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735, 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533, 2093.005, 2217.461, 2349.318, 2489.016, 2637.02, 2793.826, 2959.955, 3135.963, 3322.438, 3520, 3729.31, 3951.066, 4186.009, 4434.922, 4698.636, 4978.032, 5274.041, 5587.652, 5919.911, 6271.927, 6644.875, 7040, 7458.62, 7902.133, 8372.018, 8869.844, 9397.273, 9956.063, 10548.08, 11175.3, 11839.82, 12543.85];\nvar freq = noteFreqs[(d.octave+1)*12 + d.keyIndex];\n\n// send in bundle with two commands frequency and noteOn/Off\nvar bundle = OSC.CreateBundle(0);\nbundle.packets.push(OSC.CreatePacket(RED.OSC.settings.RootAddress + '/audio/'+d.tag+'/be',\"ffi\",0.95, freq,11));\n\n\nOSC.SendData(OSC.CreateBundleData(bundle));\n\n","headerHeight":30,"whiteKeysColor":"#FFFFFF","blackKeysColor":"#A0A0A0","blackKeysWidthDiff":6,"x":275,"y":425,"blackKeyLabelsVisible":true,"whiteKeyLabelsVisible":true,"parentGroup":"Main_group2","z":"3629fcd9.ccc604","bgColor":"#F6F8BC","wires":[]},{"id":"Main_group1","type":"group","isClass":false,"name":"mixerStereo","tag":"","comment":"","w":532,"h":437,"textSize":14,"nodes":["Main_Slider3","Main_Slider1","Main_Slider2","Main_Slider4","Main_Slider5","Main_Slider6","Main_Slider7","Main_Slider8","Main_Slider9"],"border_color":"rgba(153,153,153,1)","individualListBoxMode":true,"exportAsClass":true,"x":530,"y":130,"z":"3629fcd9.ccc604","bgColor":"rgba(221,255,187,1)","wires":[]},{"id":"Main_Slider1","type":"UI_Slider","isClass":false,"name":"pan 1","tag":"0","comment":"","w":172,"h":34,"textSize":14,"midiCh":"0","midiId":"0","orientation":"h","label":"d.val","minVal":-100,"maxVal":100,"val":81,"divVal":1,"fval":81,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/pan\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":550,"y":240,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider2","type":"UI_Slider","isClass":false,"name":"pan 2","tag":"1","comment":"","w":172,"h":34,"textSize":14,"midiCh":"0","midiId":"0","orientation":"h","label":"d.val","minVal":-100,"maxVal":100,"val":-59,"divVal":1,"fval":-59,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/pan\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":550,"y":330,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider3","type":"UI_Slider","isClass":false,"name":"gain","tag":"","comment":"","w":86,"h":129,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":31,"divVal":1,"fval":31,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/gain\";\n//var addr = RED.OSC.settings.RootAddress + \"/audio/mixerStereo/gain\";\nOSC.SendData(OSC.CreateMessageData(addr,'f',d.val/d.maxVal));\n","parentGroup":"Main_group1","x":950,"y":405,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider4","type":"UI_Slider","isClass":false,"name":"gainL","tag":"0","comment":"","w":56,"h":129,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":66,"divVal":1,"fval":66,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/gain\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":555.75,"y":405.5,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider5","type":"UI_Slider","isClass":false,"name":"gainR","tag":"1","comment":"","w":56,"h":129,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":41,"divVal":1,"fval":41,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/gain\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":650,"y":405,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider6","type":"UI_Slider","isClass":false,"name":"pan 1","tag":"2","comment":"","w":172,"h":34,"textSize":14,"midiCh":"0","midiId":"0","orientation":"h","label":"d.val","minVal":-100,"maxVal":100,"val":49,"divVal":1,"fval":49,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/pan\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":760,"y":240,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider7","type":"UI_Slider","isClass":false,"name":"pan 2","tag":"3","comment":"","w":172,"h":34,"textSize":14,"midiCh":"0","midiId":"0","orientation":"h","label":"d.val","minVal":-100,"maxVal":100,"val":84,"divVal":1,"fval":84,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/pan\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":760,"y":330,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider8","type":"UI_Slider","isClass":false,"name":"gainL","tag":"2","comment":"","w":56,"h":129,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":20,"divVal":1,"fval":20,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/gain\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":765.75,"y":405.5,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_Slider9","type":"UI_Slider","isClass":false,"name":"gainR","tag":"3","comment":"","w":56,"h":129,"textSize":14,"midiCh":"0","midiId":"0","orientation":"v","label":"d.val","minVal":0,"maxVal":100,"val":8,"divVal":1,"fval":8,"sendMode":"r","autoReturn":false,"returnValue":"mid","barFGcolor":"#F6F8BC","sendFormat":"","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/audio/\"+d.parentGroup.name+\"/gain\";\nOSC.SendData(OSC.CreateMessageData(addr,'if',d.tag,d.val/d.maxVal));","parentGroup":"Main_group1","x":860,"y":405,"z":"3629fcd9.ccc604","bgColor":"#808080","wires":[]},{"id":"Main_TextBox1","type":"UI_TextBox","isClass":false,"name":"","tag":"","comment":"waves[1] controls                         waves[2] controls","w":324,"h":34,"textSize":14,"x":590,"y":170,"z":"3629fcd9.ccc604","bgColor":"#DDFFBB","wires":[]},{"id":"Main_Button1","type":"UI_Button","isClass":false,"name":"heap","tag":"enabl","comment":"","w":100,"h":34,"textSize":14,"midiCh":"0","midiId":"0","pressAction":"","repeatPressAction":false,"releaseAction":"","repeatReleaseAction":false,"local":"true","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/system/heap\";\nOSC.SendData(OSC.CreateMessageData(addr,''));","x":710,"y":590,"z":"3629fcd9.ccc604","bgColor":"#22B2F8","wires":[]},{"id":"Main_Button2","type":"UI_Button","isClass":false,"name":"reset","tag":"enabl","comment":"","w":100,"h":34,"textSize":14,"midiCh":"0","midiId":"0","pressAction":"","repeatPressAction":false,"releaseAction":"","repeatReleaseAction":false,"local":"true","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/system/reset\";\nOSC.SendData(OSC.CreateMessageData(addr,''));","x":960,"y":590,"z":"3629fcd9.ccc604","bgColor":"#F85218","wires":[]},{"id":"Main_Button3","type":"UI_Button","isClass":false,"name":"max usage","tag":"enabl","comment":"","w":100,"h":34,"textSize":14,"midiCh":"0","midiId":"0","pressAction":"","repeatPressAction":false,"releaseAction":"","repeatReleaseAction":false,"local":"true","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/system/max\";\nOSC.SendData(OSC.CreateMessageData(addr,'T'));","x":835,"y":590,"z":"3629fcd9.ccc604","bgColor":"#22B2F8","wires":[]},{"id":"Main_Button4","type":"UI_Button","isClass":false,"name":"stack","tag":"enabl","comment":"","w":100,"h":34,"textSize":14,"midiCh":"0","midiId":"0","pressAction":"","repeatPressAction":false,"releaseAction":"","repeatReleaseAction":false,"local":"true","sendCommand":"var addr = RED.OSC.settings.RootAddress + \"/system/stack\";\nOSC.SendData(OSC.CreateMessageData(addr,''));","x":590,"y":590,"z":"3629fcd9.ccc604","bgColor":"#22B2F8","wires":[]},{"id":"Main_waves1","type":"waves","isClass":true,"name":"waves[2]","x":50,"y":120,"z":"3629fcd9.ccc604","bgColor":"#CCFFCC","wires":[["Main_mixerStereo1:0"]]},{"id":"Main_noise1","type":"AudioSynthNoiseWhite","isClass":false,"name":"noise","comment":"","x":70,"y":165,"z":"3629fcd9.ccc604","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_mixerStereo1","type":"AudioMixerStereo","isClass":false,"name":"mixerStereo","comment":"","inputs":2,"x":195,"y":140,"z":"3629fcd9.ccc604","bgColor":"#E6E0F8","wires":[["Main_dacs1:0","Main_i2s1:0"],["Main_dacs1:1","Main_i2s1:1"]]},{"id":"Main_i2s1","type":"AudioOutputI2S","isClass":false,"name":"i2s","comment":"","x":390,"y":105,"z":"3629fcd9.ccc604","bgColor":"#E6E0F8","wires":[]},{"id":"Main_dacs1","type":"AudioOutputAnalogStereo","isClass":false,"name":"dac","comment":"","x":390,"y":175,"z":"3629fcd9.ccc604","bgColor":"#E6E0F8","wires":[]},{"id":"Main_sgtl5000_1","type":"AudioControlSGTL5000","isClass":false,"name":"sgtl5000","comment":"","x":1105,"y":485,"z":"3629fcd9.ccc604","bgColor":"#E6E0F8","wires":[]}]},{"type":"tab","id":"22723e47.b3e4f2","label":"waves","inputs":0,"outputs":0,"export":true,"isMain":false,"mainNameType":"tabName","mainNameExt":".ino","isAudioMain":false,"generateCppDestructor":false,"extraClassDeclarations":"","settings":{"guiEditMode":false,"workspaceBgColor":"#EDFFDF","scaleFactor":0.8,"showGridHminor":false,"showGridHmajor":false,"showGridVminor":false,"showGridVmajor":false,"useCenterBasedPositions":false},"nodes":[{"id":"waves_Out1","type":"TabOutput","isClass":false,"name":"Out","comment":"","inputs":2,"x":480,"y":265,"z":"22723e47.b3e4f2","bgColor":"#cce6ff","wires":[]},{"id":"waves_waveform2","type":"AudioSynthWaveform","isClass":false,"name":"wav1","comment":"","x":319,"y":225.75,"z":"22723e47.b3e4f2","bgColor":"#E6E0F8","wires":[["waves_Out1:0"]]},{"id":"waves_waveform1","type":"AudioSynthWaveform","isClass":false,"name":"wav2","comment":"","x":319,"y":300.75,"z":"22723e47.b3e4f2","bgColor":"#E6E0F8","wires":[["waves_Out1:1"]]}]}],"nodeAddons":{}
}
When I try to live-connect the noise output to the apparently second but actually fifth mixer input, the GUI tries to connect to the (in use) second mixer input, which fails.

Further back in time ... I'll see if Adrian comes back about my PR into the OSC library before getting even trickier with the address length stuff. I was too lazy to write the code you did, there's plenty of stack and it's only used for a very short time! Going forward, even if getAddressLength() doesn't make it to the official library, I think we can justify saying it should be in the PJRC fork, which needs updating anyway. But I don't want anyone playing with this stuff now to be dependent on too many libraries; as it is they already need changed core files, the dynamic audio library and the OSCAudio library.

Even further back in time ... I think I agree with you about sanitising and trimming invalid names, i.e. don't do it and return an error. I'll leave it in for now, as it's been useful, but maybe make it a run-time or compile-time option in the future.
 
I did my first test with a TDM output, which failed - I think the "number of inputs" parameter confused the OSCAudio library. I've raised it with myself as an issue on github.
That's my fault, I have now corrected it with using a special def. parameter called dynInputs which is only defined on the dynamic input mixers at the moment.

Before I did have it but removed it to be replaced by def.defaults.inputs which is always on objects having user selectable input count,
this was a mistake as I have made it possible to change the visually input count on other objects as well(to make the design tidier), for example the TDM.

When I try to live-connect the noise output to the apparently second but actually fifth mixer input, the GUI tries to connect to the (in use) second mixer input, which fails.

Ok now it gets the correct index using my getDynInputDynSizePortStartIndex function

I was too lazy to write the code you did
I did copy the most of it from the msg-bytes() function


I have also now implemented a new version notification
that should be shown when versions arrive,
this makes it easier to see that it's the new version that is running
Also this can show version specific changes.

edit.
Latest Updates @ menu now shows the complete history (at least from now and forward)
 
Last edited:
Definitely better, but (;)):
  • if I upload the design without input 4 connected, the mixer is only created with 4 inputs (0 to 3): there's nowhere to connect the noise generator
  • if I create with the connection, then try to delete it, the name used is incorrect (mixer input 1 again), so it doesn't get deleted on the Teensy, only in the GUI, so...
  • ...when I try to reconnect, input 4 is still in use. I can get round this by...
  • ...deleting the noise object, then hitting Ctrl-Z to undo: the re-created connection has the wrong name, but it's accessible, although...
  • ...the original connection still exists in memory, just not connected to anything
  • similarly, attempting to rename noise to noiseX causes problems, because GUI++ generates a non-existent connection to rename

I forgot to ask earlier, is it possible to send boolean values from the GUI? They're a bit weird in that they have a type of either T or F, but no associated data. I've tried:
Code:
var addr = RED.OSC.settings.RootAddress + "/system/max";
OSC.SendData(OSC.CreateMessageData(addr,'T'));
This gives me a "length mismatch count" error in the output log; if I put a dummy 0 parameter in this goes away, and I think the correct message gets sent, though unfortunately it crashes the Teensy (pretty sure that's my fault...).
 
Back
Top