Soft-Takeover on Parameters in Controller Script

Official support for: bitwig.com
Post Reply New Topic
RELATED
PRODUCTS

Post

Hi Everyone!

Is there maybe anyone out there who has already integrated a self-scripted "Soft Takeover" for (automation) parameters?
Because I am stuck getting an observer reading the current values, comparing them to the values currently on the controller, and only changing them in Bitwig when they are within a range.

Maybe someone can help me out? (First things first: setting up an observer, reading 8 macro controller knob values...)

Post

http://blog.thomashelzle.de/2014/06/bit ... observers/

Many controller scripts do this, so you may want to check some of them out.
One example is my TouchOSC script:
https://github.com/ThomasHelzle/TouchOSC-Bitwig
It does a lot but has a rather simple structure.

The Arturia KeyLab script in the factory location is a bit more current but also a bit more complex.

Cheers,

Tom
"Out beyond the ideas of wrongdoing and rightdoing, there is a field. I’ll meet you there." - Rumi
ScreenDream Instagram Mastodon

Post

Thanks for your answer,
but now I am stuck,....

Here is my work in progress script,

Code: Select all

loadAPI(1);
// original oxygen 29 script
host.defineController("M-Audio", "Oxygen 49", "1.0", "2B6AB540-B75A-11E3-A5E2-0300200C9A66");

host.defineMidiPorts(1, 1);

host.addDeviceNameBasedDiscoveryPair(["Oxygen 49"], ["Oxygen 49"]);
// Main variable:
var tOSC;

var DEVICE_START_CC = 102;
var DEVICE_END_CC = 109;

function TouchOSC() {
  tOSC = this;
  this.cMacro = [];
  this.currentVolume = 0;
  this.FADERS = 118; // Start of Fader Range - 8 x track volume + 1 x master volume
  this.MACROS = 102; // Start of Device Macro Range - 8 macro knobs on the cursor device
  	this.trackVolume = [];
	this.trackVolumeHasChanged = [];
		// Macros:
	this.deviceMacro = [];
	this.deviceMacroHasChanged = [];
		// Initializations:
	for (var i=0; i<8; i++) {
		this.trackVolume[i] = 0;
		this.trackVolumeHasChanged[i] = false;
		
		this.deviceMacro[i] = 0;
		this.deviceMacroHasChanged[i] = false;
		
		this.cTrack = host.createCursorTrack(1, 0);
		this.cDevice = tOSC.cTrack.getPrimaryDevice();
		
	}
	this.tracks = host.createMainTrackBank(8, 0, 0);
	
	
	this.cTrack.getVolume().addValueDisplayObserver(8, "None", function(value) {
      this.currentVolume = value;
      if(this.trackVolumeHasChanged) {
         // do something
      }
	  
	  })
	  
  }

// Search after different naming-schemes for autodetection
for ( var i = 1; i < 9; i++)
{
	var name = i.toString() + "- Oxygen 49";
	host.addDeviceNameBasedDiscoveryPair([name], [name]);
	host.addDeviceNameBasedDiscoveryPair(["Oxygen 49 MIDI " + i.toString()], ["Oxygen 49 MIDI " + i.toString()]);
}

var CC =
{   
    PREV_PRESET : 57,
    NEXT_PRESET : 58,
	PREV_TRACK : 59,
	NEXT_TRACK : 60,
	LOOP       : 20,
	REWIND     : 21,
	FORWARD    : 22,
	STOP       : 23,
	PLAY       : 24,
	RECORD     : 25,
	SLIDER     : 118,
};

var LOWEST_CC = 2;
var HIGHEST_CC = 101;

function isInDeviceParametersRange(cc)
{
	return cc >= DEVICE_START_CC && cc <= 105;
}

function isInDeviceParametersRange2(cc)
{
	return cc >= 106 && cc <= DEVICE_END_CC;
}

function init()
{

// instantiate a new TouchOSC Object:
	new TouchOSC()  
	// Creating Observers, indications etc.:
		
for (var i=0; i<8; i++) {
		// Volume
		tOSC.tracks.getTrack(i).getVolume().setIndication(true);
		tOSC.tracks.getTrack(i).getVolume().addValueObserver(127, getTrackValueFunc(i, tOSC.trackVolume, tOSC.trackVolumeHasChanged));
		// Macro
		tOSC.cMacro[i] = tOSC.cDevice.getMacro(i);
		tOSC.cMacro[i].getAmount().setIndication(true);
		tOSC.cMacro[i].getAmount().addValueObserver(127, getTrackValueFunc(i, tOSC.deviceMacro, tOSC.deviceMacroHasChanged));

	}
	
	

cursorTrack2 = host.createCursorTrackSection(3, 0);
device = host.createCursorDevice();
transport = host.createTransport();
primaryInstrument = cursorTrack2.getPrimaryInstrument();

	for ( var i = 0; i < 8; i++)
	{
		var p = primaryInstrument.getMacro(i).getAmount();
		p.setIndication(true);

	}
	
	// Register callbacks for midi- and sysex-events
	host.getMidiInPort(0).setMidiCallback(onMidi);

	noteIn = host.getMidiInPort(0).createNoteInput("Oxygen 25 Keyboard");

	// Make CCs 0-109 freely mappable
	userControls = host.createUserControls(HIGHEST_CC);

	for(var i=LOWEST_CC; i<=HIGHEST_CC; i++)
	{
		userControls.getControl(i - LOWEST_CC).setLabel("CC" + i);
	}

	// The cursor track view follows the track selection in the application GUI
	cursorTrack = host.createCursorTrack(4, 4);
	
	
}

function onMidi(status, data1, data2)
{
	//printMidi(status, data1, data2);

	if (isChannelController(status))
	{
		// Handle transport-buttons and trackselection
		if ((data1 >= 20 && data1 <= 60 && data1 != 112) && data2 >= 0)
		{
			switch(data1) {
				case CC.PREV_TRACK:
				cursorTrack.selectPrevious();
				break;
				case CC.PREV_PRESET:
				device.switchToPreviousPreset();
				break;
				case CC.NEXT_PRESET:
				{
				device.switchToNextPreset();
				}
				break;
			case CC.NEXT_TRACK:
				cursorTrack.selectNext();
				break;
			case CC.LOOP:
				transport.toggleLoop();
				break;
			case CC.REWIND:
				transport.rewind();
				break;
			case CC.FORWARD:
				transport.fastForward();
				break;
			case CC.STOP:
				transport.stop();
				break;
			case CC.PLAY:
				transport.play();
				break;
			case CC.RECORD:
				cursorTrack.getArm().toggle();
				transport.record();
				break;
			}
		}
		else
		{
		if (isInDeviceParametersRange(data1))
		{
			var index = data1 - DEVICE_START_CC;
			if (index == 0) index = 4;
			if (index == 1) index = 5;
			if (index == 2) index = 6;
			if (index == 3) index = 7;
			primaryInstrument.getMacro(index).getAmount().set(data2, 128);
		}
		if (isInDeviceParametersRange2(data1))
		{
			var index = data1 - DEVICE_START_CC;
			if (index == 4) index = 0;
			if (index == 5) index = 1;
			if (index == 6) index = 2;
			if (index == 7) index = 3;
			primaryInstrument.getMacro(index).getAmount().set(data2, 128);
		}
			// Handle slider for trackvolume
			if (data1 == CC.SLIDER)
			{
			 var oldVolVal = this.currentVolume;
	  
	         var newVolVal  = tOSC.trackVolume[0];
	       //  printMidi(oldVolVal,newVolVal);
	         var ok = false;
	         if (newVolVal != oldVolVal) ok = true;
				if (ok == true) {
				cursorTrack.getVolume().set(data2, 128);
				}
			}
			else
			{
				// Handle CC 02 - 109
				if (data1 >= LOWEST_CC && data1 <= HIGHEST_CC)
				{
					var index = data1 - LOWEST_CC;
					userControls.getControl(index).set(data2, 128);
				}
			}
		}
	}
}

function flush()
{
	// Check if transport has changed and if yes, update all of the controlls:

	 // Go through an 8-step Loop to check for all the stuff that could have changed:
	 for (var k=0; k<8; k++) {
	 var oldVolVal = this.currentVolume;
	  
	 var newVolVal  = tOSC.trackVolume[k];
	 
	 var ok = false;
	 if (newVolVal == oldVolVal) ok = true;
	 
			if (tOSC.trackVolumeHasChanged[k] && ok == true) {
			     
				 sendChannelController(0, tOSC.FADERS + k, tOSC.trackVolume[k]);
				
				 tOSC.trackVolumeHasChanged[k] = false;
			}

			if (tOSC.deviceMacroHasChanged[k]) {
				 sendChannelController(0, tOSC.MACROS + k, tOSC.deviceMacro[k]);
				 tOSC.deviceMacroHasChanged[k] = false;
			}

		}
}

function exit()
{
}


// different functions from other script, maybe dont need


function onSysex(data)
{
	//printSysex(data);
}

// A function to create an indexed function for the Observers
function getValueObserverFunc(index, varToStore)
{
   return function(value)
   {
      varToStore[index] = value;
   }
}

// A function to create an indexed function for the Observers with an added state variable:
function getTrackValueFunc(index, varToStore, varToSet)
{
   return function(value)
   {
      varToStore[index] = value;
			varToSet[index] = true;
   }
}

// A function to create an indexed function for the Observers for Clips including a Color-Update:
function getClipValueFunc(slot, varToStore)
{
   return function(index, value)
   {
      varToStore[slot+index*4] = value;
			
   }
}

I am now stuck at comparing a dB value to an midi data...
-37.4 dB and 74
of course they will not be the same in any way - so I need to convert one to the other - but how?

Can you help? Thanks!

Post

I am actually working on a soft take over implementation for a script I am writing. If you are still around next week, I will post some code that might be able to help you.

Mike
Michael Schmalle
http://www.teotigraphix.com
Surfing on sine waves

Maschine4Bitwig - Studio, MK2, MikroMK2, MK1
http://www.teotigraphix.com/bitwig/maschine

Post

You can observe either the scaled value with addValueObserver, then you give it an integer range to which the value is scaled (for instance 128 for the typical Midi controller), or you can observe the raw internal value (the value that Bitwig Studio uses internally to represent the value) with addRawValueObserver, check what you get and do your own scaling.
The same is true for set/setRaw and inc/incRaw.
Does that make sense?

I personally will wait for the BWS-native takeover implementation, but there is no date for that yet.

Cheers,

Tom
"Out beyond the ideas of wrongdoing and rightdoing, there is a field. I’ll meet you there." - Rumi
ScreenDream Instagram Mastodon

Post

ThomasHelzle wrote:You can observe either the scaled value with addValueObserver, then you give it an integer range to which the value is scaled (for instance 128 for the typical Midi controller), or you can observe the raw internal value (the value that Bitwig Studio uses internally to represent the value) with addRawValueObserver, check what you get and do your own scaling.
The same is true for set/setRaw and inc/incRaw.
Does that make sense?

I personally will wait for the BWS-native takeover implementation, but there is no date for that yet.

Cheers,

Tom
You say this but are we talking 1.2, or "have no idea". I would love to use the native impl and not waste time doing it right now. :)

Mike
Michael Schmalle
http://www.teotigraphix.com
Surfing on sine waves

Maschine4Bitwig - Studio, MK2, MikroMK2, MK1
http://www.teotigraphix.com/bitwig/maschine

Post

My hope is that it's 1.1.x, but no, I have no idea yet, since it involves several areas of the application.

Cheers,

Tom
"Out beyond the ideas of wrongdoing and rightdoing, there is a field. I’ll meet you there." - Rumi
ScreenDream Instagram Mastodon

Post Reply

Return to “Bitwig”