I have what seems to me to me to be a fairly simple goal. I want to have a Template Project where I have several tracks pre-configured with a selection of my favorite sounds that I can select using MIDI Program Change messages from my hardware controller. To be clear I mean that each track has a range of sounds (not one sound per track). For example the Bass track has say 10 bass sounds to choose from, the the lead track has 5 lead sounds, the beat track has 7 drum kits, etc. The workflow is that I would start a new track with my template, I would arm a track, send a Program Change message to choose a sound, record 1 or more MIDI clips, and then arm a different track and repeat the process. I also want to be able to change to a different sound on the same track and have the Program Change be recorded as automation.
OK Great! The Instrument Selector should be able to do this right?! So I set up an an Instrument Selector on each track, I set it's "Mode" to "Program Change" and I'm off to the races right? WRONG. There is an absolutely show-stopping problem with the design of the Instrument Selector. All of the modes other than "Manual" not only are NOT recorded as automation, but the state of the Instrument Selector IS NOT EVEN SAVED IN THE PROJECT! That means that, for any Instrument selector whose mode is set to anything other than "manual" (eg: Program Change), when you save and reload that project the Insutrment Selector will be reset to the first instrument in the bank. So in my workflow outlined above, when I finish my session and save the project, and then later re-open the project to continue work, all of the sounds are wrong and I have to go to each instrument selector on each track and remember which instrument was selected. This is totally bizarre, and completely unusable.
OK so the only usable mode of the Insutrment Selector, if you want the selected instrument recorded as automation and saved with the project, is "manual". Alright.. I can deal with this, I can control it via a script instead.
So I created a script which scans through my tracks on init(), creates a cursorDevice on each track and then a chainSelector from each cursor and then stores them for later. Then when a Program Change message come into the script, it recalls the chainSelector for the currently armed track and passes the Program Change number straight to chainSelector.activeChainIndex().set(). Hurray it works! And it records as automation, and it's saved in the project! Huzzah! I've been using this for a couple of weeks now, and it's great.
But now I want to add an Arpeggiator device on some channels, and I want this to go BEFORE the Instrument Selector so that the arpeggiator is independant of the selected instrument. Now my Program Change Instrument Selector code breaks because the Instrument Selector is no longer the first device on the channel. "No problem" I thought, I'll just scan through the devices on the Track to find the Instrument Selector instead of just assuming it's the first one. And this is where I ran into some really weird problems with the design of the Bitwig API.
In short, I can't introspect the Device chain from a script due to this weird chicken-and-egg problem where I can't inspect anything that I didn't markInterested() in init(), but in init() I can't actually use deviceBanks or cursorDevices to find devices to markInterested() because the actual data behind Bank and cursor objects is not populated until AFTER initialisation. In other words there is no data to introspect in the device chain during init(), but afterwards I can't introspect the device chain because I did not call markInterested() on the data. Insert Jackie Chan Confused meme here.... This means that introspecting the device chain to find the device i want is a non starter.
So then I decided to put both the Arpeggiator and the Instrument Selector inside a Chain device, and then map the Instrument Selector's chain selector onto a Preset Parameter on the chain device. It shows up on the Chain's Preset Page as a SelectBox with each of the chain names enumerated. Nice! Now we are back to having our selector on the first device on the channel which means all I need to do from here is to change my script to have the Program Change messages control that Preset Parameter via a cursorRemoteControlPage, right?! Not so fast...
The problem here is that I want my incoming Program Change number (1, 2, 3, etc) to select the corresponding entry in the list (eg: PC 1 selects item 1 on the parameter's list, PC 2 selects item 2, etc), but the Preset API doesn't allow for direct selection in this way. Instead it maps the set of possible values into a set of ranges betwen 0 and 1. So if you have 3 items in the list then values from 0 to 0.33 select item 1, 0.34 t0 0.66 selects item 2, and 0.67 to 1.0 selects item 3. OK, I can deal with this too, all I need to do is divide my incoming Program Change number by the total number of entries in the list! 1 / 3 = 0.33 should select the first item in the list, right?! Here comes the BUT.... It's not possible to actually get the max value of the range that the Parameter is mapping, so it's not possible to do that calculation because I'm missing one of the numbers. I could only make this work if I made sure that all of my Instrument selectors had a fixed number of chains, and then I hard code that number in my script. I suppose this is not an impossible solution, but it's ugly.
Then I heard that the latest API version has a new DeviceMatcher API that seems to be able to do what I want. I should be able to set up a DeviceMatcher on a DeviceBank to find the Instrument Selector so I can set it's chain index. So I enabled the "can-copy-device-and-param-ids" in config.json, got the UUID string for the Instrument Selector and called createBitwigDeviceMatcher with the UUID, but it won't accept it because it's a string and not a java.util.uuid object. But I am coding in Javascript, and there seems to be no provision in the API to create "UUID" object and no advice for any other way to provide the UUID so that it will become a java.util.uuid in the back end....
So... I'm stumped... Looks like I'm going to have to go with the "hardcoded max-range" solution for the parameter control.
I'm a senior software engineer with 20 years experience so I can say with some confidence that this API design is VERY confusing and poorly documented. The jopurney of trying to achieve this relatively simple task has been 100x harder than it should have been.
If anyone has any suggestions for how I could solve any of the problems in any of the approaches listed above I would be extremely grateful. To recap, the particular issues I am looking to solve are:
1. Instrument Selector state is not saved in project, ore recorded as automation when mode is not manual.
2. DeviceBanks, cursors, values of sub-items, etc. are all unpopulated during init() and so I can't actually reach device objects and therefore cannot do markInterested(), which means I then also cannot reach or use them after init()
3. Device Parameter's mapped to a selection list do not permit direct selection of list item by index and it's not possible to work around this because the SettableRange's maximum value is not available via the API
4. There seems to be no way to provide a UUID to createBitwigDeviceMatcher() via the Javascript API
Thanks for your time in reading such a long post.
My insane journey of trying to control an Instrument Selector via program change messages
-
- KVRer
- 16 posts since 7 Apr, 2010 from Newcastle, Australia
- KVRAF
- 9563 posts since 6 Jan, 2017 from Outer Space
Did you write to support for your first attempt without script?
It should work as you expected. If not its a severe bug which needs to be fixed. This would not be a feature request, its a requirement for any DAW...
It should work as you expected. If not its a severe bug which needs to be fixed. This would not be a feature request, its a requirement for any DAW...
- KVRAF
- 4898 posts since 13 May, 2004
Sounds like a bug to me. But I am not sure if this is seen as a performance feature only. Report to Bitwig.Sam_K wrote: Sun Jul 26, 2020 4:47 am 1. Instrument Selector state is not saved in project, ore recorded as automation when mode is not manual.
Can you give an example what you are trying to do (code)? Didn't have a problem in that area so far.Sam_K wrote: Sun Jul 26, 2020 4:47 am 2. DeviceBanks, cursors, values of sub-items, etc. are all unpopulated during init() and so I can't actually reach device objects and therefore cannot do markInterested(), which means I then also cannot reach or use them after init()
Yes, that is an issue. Should be at least fixable for Bitwig devices. But it got me thinking and this is what I came up as a workaround:Sam_K wrote: Sun Jul 26, 2020 4:47 am 3. Device Parameter's mapped to a selection list do not permit direct selection of list item by index and it's not possible to work around this because the SettableRange's maximum value is not available via the API
Code: Select all
var maxValue = -1;
function getMaxValue ()
{
var val = parameter.value ();
println ("Raw: " + val.getRaw ());
val.setImmediately (1);
host.scheduleTask (function () {
maxValue = val.getRaw ();
println ("Maximum: " + maxValue);
}, 100);
}
Yes, known issue.Sam_K wrote: Sun Jul 26, 2020 4:47 am 4. There seems to be no way to provide a UUID to createBitwigDeviceMatcher() via the Javascript API
-
- KVRer
- Topic Starter
- 16 posts since 7 Apr, 2010 from Newcastle, Australia
Thanks, TJ Shredder and Moss.
I had not reported the bug to Bitwig when you replied, but I have now done so. Here's the main part of the message I wrote them.
Cheers
I had not reported the bug to Bitwig when you replied, but I have now done so. Here's the main part of the message I wrote them.
Moss thank you for your responses regarding the scripting. I have started work on an isolated example script to more clearly demonstrate point 2, and to trial your suggested solution to point 3. I should have something to post in a couple of days.With the release of Bitwig version 3.2 a major change was made to the functionality of the Instrument Selector with the introduction of the “mode” feature. This new feature has a major bug, and also introduces a regression where desirable behavior exhibited byu the Instrument Selector in prior versions can now no longer be re-created with the new version.
The Bug. If the mode of the Instrument Selector is “Program Change” or “Key Switch” then the current selection state is not saved with the Bitwig project. If the project is saved, closed and then re-opened, then the Instrument Selector will always revert to the first instrument in the list.
The Feature Regression: In Bitwig 3.1 the Instrument Selector responded to Program Change messages IN ADDITION to allowing manual selection via the UI and allowing control via, and recording of, automation of the selected instrument. Program Change messages were automatically translated to Instrument Selector automation. This was a very useful feature set that I depended on.
Since Bitwig 3.2, this feature set has been split between “Manual” mode and “Program Change” mode and it is now not possible to have both features at once. I need the “Program Change” functionality, but I also need to have all of the “Manual” mode functionality as well.
If I could have the design I wanted, then they would not be modes at all. I would have the “manual” features (manual selection via UI, and automation) be ALWAYS working and then the Keyswitch and Program Change functionality are additional, non-exclusive features that I can enable and configure. Then I could have an instrument selector where I can choose instrument via UI buttons, Program Change and/or Keyswitches, and then also always have the ability of recording selection changes as automation regardless of the control source.
Cheers
