User Tools

Site Tools


midi_scripting

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Next revision Both sides next revision
midi_scripting [2019/07/08 08:40]
swiftb0y inserted draft for color API
midi_scripting [2020/02/04 22:49]
mevsme [Soft-takeover]
Line 1: Line 1:
  ​====== Controller Scripting ======  ​====== Controller Scripting ======
  
-In order to support the features of many MIDI controllers,​ Mixxx offers what we call MIDI Scripting (introduced in Mixxx v1.7.0). It enables MIDI controls to be mapped to [[http://​doc.trolltech.com/​4.5/​qtscript.html|QtScript]] (also known as [[http://​en.wikipedia.org/​wiki/​JavaScript_syntax|Javascript]]/​[[http://​www.ecma-international.org/​publications/​standards/​Ecma-262.htm|EMCAScript]]) functions, allowing mappings to manage complex behaviors. These user-created functions can then do anything desired with the MIDI event info such as affect different controls depending on whether another button is pressed, adjust incoming control values to work better with Mixxx (i.e. for [[#​scratching]]),​ send messages to LED displays on the controller, or even [[#turning a 2 deck controller into a 4 deck controller|turn a 2 deck controller into a 4 deck controller]].+In order to support the features of many MIDI controllers,​ Mixxx offers what we call MIDI Scripting (introduced in Mixxx v1.7.0). It enables MIDI controls to be mapped to [[http://​doc.trolltech.com/​4.5/​qtscript.html|QtScript]] (also known as [[http://​en.wikipedia.org/​wiki/​JavaScript_syntax|Javascript]]/​[[http://​www.ecma-international.org/​publications/​standards/​Ecma-262.htm|EMCAScript]]) functions, allowing mappings to manage complex behaviors. These user-created functions can then do anything desired with the MIDI event info such as affect different controls depending on whether another button is pressed, adjust incoming control values to work better with Mixxx (i.e. for [[#Scratching and jog wheels|scratching]]),​ send messages to LED displays on the controller, or even [[#turning a 2 deck controller into a 4 deck controller|turn a 2 deck controller into a 4 deck controller]].
  
 If you would like your mapping included in Mixxx, please see the coding guidelines on the [[Contributing Mappings]] page. If you would like your mapping included in Mixxx, please see the coding guidelines on the [[Contributing Mappings]] page.
Line 43: Line 43:
 You can add as many <​file>​ tags as you like, but be sure to specify the appropriate functionprefix in every one. These will all be loaded when the controller is activated. You can add as many <​file>​ tags as you like, but be sure to specify the appropriate functionprefix in every one. These will all be loaded when the controller is activated.
  
-There is a default script function file called ''​common-controller-scripts.js''​ which contains functions common to all controllers and is always loaded. See [[#available common ​functions]] below for information on these functions.+There is a default script function file called ''​common-controller-scripts.js''​ which contains functions common to all controllers and is always loaded. See [[#Helper ​functions]] below for information on these functions.
  
 ==== Script file header ==== ==== Script file header ====
Line 74: Line 74:
 </​code>​ </​code>​
  
-The ID parameter of the init function is the ''​controller id''​ attribute from the XML file. This can be used to identify the particular controller instance in print statements. The ''​debugging''​ parameter is set to '​true'​ if the user specified the %%--mididebug%% parameter on the command line.+The ID parameter of the init function is the ''​controller id''​ attribute from the XML file. 
 +This can be used to identify the particular controller instance in print statements. 
 +The ''​debugging''​ parameter is set to '​true'​ if the user specified the ''​%%--controllerDebug%%'' ​parameter on the command line (''​%%--midiDebug%%''​ until Mixxx 1.10).
  
 **Note**: Instead of using global variables, define properties of your controller object (''​MyController''​ in this example) to avoid name collisions with other scripts that may be loaded. **Note**: Instead of using global variables, define properties of your controller object (''​MyController''​ in this example) to avoid name collisions with other scripts that may be loaded.
Line 247: Line 249:
  
 Generally, you should not call ''​midi.sendShortMsg''​ or ''​midi.sendSysexMsg''​ directly from functions that handle MIDI input. Instead, the input function should change the state of a [[MixxxControls|Mixxx Control]] and you should call ''​midi.sendShortMsg''/''​midi.sendSysexMsg''​ in a callback function that reacts to changes in that Mixxx Control. Refer to the section above for details. This way, the state of the controller will always be in sync with what Mixxx is actually doing, even if the user manipulates Mixxx with the keyboard, mouse, or another controller. If the MIDI input handling function only changes the state of script variables but not Mixxx Controls, then it would be appropriate to call ''​midi.sendShortMsg''/''​midi.sendSysexMsg''​ from the input handling function. Generally, you should not call ''​midi.sendShortMsg''​ or ''​midi.sendSysexMsg''​ directly from functions that handle MIDI input. Instead, the input function should change the state of a [[MixxxControls|Mixxx Control]] and you should call ''​midi.sendShortMsg''/''​midi.sendSysexMsg''​ in a callback function that reacts to changes in that Mixxx Control. Refer to the section above for details. This way, the state of the controller will always be in sync with what Mixxx is actually doing, even if the user manipulates Mixxx with the keyboard, mouse, or another controller. If the MIDI input handling function only changes the state of script variables but not Mixxx Controls, then it would be appropriate to call ''​midi.sendShortMsg''/''​midi.sendSysexMsg''​ from the input handling function.
 +
 +===== Debugging your mappings =====
 +As mentioned above, you don't have to restart Mixxx, when you're testing your scripts.
 +Every time you save your file, Mixxx will reload it immediately.
 +Additionally if you specify ''​%%--controllerDebug%%''​ (or ''​%%--midiDebug%%''​ prior to verion 1.11),
 +Mixxx then logs all incoming and outgoing MIDI messages.
 +Also you can use ''​print()''​ in your script to output further messages.
 +The second parameter passed to your ''​init()''​ functions specifies if the controller debug mode is enabled.
  
 ===== Components library ===== ===== Components library =====
 Now that you understand the basics, it is suggested to use the [[Components JS]] library for new mappings. Now that you understand the basics, it is suggested to use the [[Components JS]] library for new mappings.
 +
 ===== Soft-takeover ===== ===== Soft-takeover =====
 To prevent sudden wide parameter changes when the on-screen control diverges from a hardware control, use soft-takeover. While it's active on a particular parameter, manipulating the control on the hardware will have no effect until the position of the hardware control is close to that of the software, at which point it will take over and operate as usual. You can enable and disable it at any point, and it operates on each MixxxControl independently. Typically, for each control that has physical limits (typically, knobs and sliders) on your controller, you would enable soft-takeover in the ''​init()''​ script function and just leave it enabled. To prevent sudden wide parameter changes when the on-screen control diverges from a hardware control, use soft-takeover. While it's active on a particular parameter, manipulating the control on the hardware will have no effect until the position of the hardware control is close to that of the software, at which point it will take over and operate as usual. You can enable and disable it at any point, and it operates on each MixxxControl independently. Typically, for each control that has physical limits (typically, knobs and sliders) on your controller, you would enable soft-takeover in the ''​init()''​ script function and just leave it enabled.
Line 265: Line 276:
 Note that this only works for controls manipulated through ''​engine.setValue()''​ or ''​engine.setParameter()''​ in a script. It does not work for controls mapped in an XML file. Note that this only works for controls manipulated through ''​engine.setValue()''​ or ''​engine.setParameter()''​ in a script. It does not work for controls mapped in an XML file.
  
-If you change the function ​of an absolute control (one that has hard stops at max and min positionsthat is controlling ​MixxxControls with soft-takeover enabled, you will need to tell Mixxx each time you change what the physical ​control is manipulating ​to avoid an abrupt jump when switching the physical control ​back. Do this with the following function, supplying the MixxxControl you're switching control //away// from:+If you change the functionality ​of an absolute control (one that has hard stopsmax and min position, not infinite encoderwhich is controlling ​[[mixxxcontrols]] and has soft-takeover enabled, you will need to tell Mixxx each time you change ​its functionality (e.g. press //shift// button) ​what physical ​rotary you are manipulating. This will prevent ​an abrupt jump to its current value from the old one, when switching the old functionality ​back (i.e. //​unshift//​). Do this with the following function, supplying the MixxxControl you're switching control //away// from:
 <code javascript>​ <code javascript>​
 engine.softTakeoverIgnoreNextValue("​[Channel1]",​ "​rate"​);​ engine.softTakeoverIgnoreNextValue("​[Channel1]",​ "​rate"​);​
Line 277: Line 288:
 engine.scratchTick(int deck, int interval); engine.scratchTick(int deck, int interval);
 engine.scratchDisable(int deck, bool ramp); engine.scratchDisable(int deck, bool ramp);
-bool engine.isScratching(int deck);</​code>​+bool engine.isScratching(int deck); 
 +</​code>​
  
 Here is how to use them: Here is how to use them:
Line 293: Line 305:
     * the movement value (typically 1 for one "​tick"​ forwards, -1 for one "​tick"​ backwards)     * the movement value (typically 1 for one "​tick"​ forwards, -1 for one "​tick"​ backwards)
   - When you're done scratching (like when the wheel is released,) just call ''​engine.scratchDisable()''​ with the number of the virtual deck to stop scratching and whether you want Mixxx to ramp up to the play speed or jump to it instantly. (Default is to ramp which also allows spin-backs with wheels.)   - When you're done scratching (like when the wheel is released,) just call ''​engine.scratchDisable()''​ with the number of the virtual deck to stop scratching and whether you want Mixxx to ramp up to the play speed or jump to it instantly. (Default is to ramp which also allows spin-backs with wheels.)
 +
 +**Note:** You can use ''​script.deckFromGroup(group)''​ to get the virtual deck number from the group string.
 +See [[#Helper functions]] for more information.
  
 Here is an example for the two most common types of wheels. Click the tab labeled '​scratchingExample.js'​ below to open this example as a file in your text editor. Here is an example for the two most common types of wheels. Click the tab labeled '​scratchingExample.js'​ below to open this example as a file in your text editor.
Line 298: Line 313:
 // The button that enables/​disables scratching // The button that enables/​disables scratching
 MyController.wheelTouch = function (channel, control, value, status, group) { MyController.wheelTouch = function (channel, control, value, status, group) {
 +    var deckNumber = script.deckFromGroup(group);​
     if ((status & 0xF0) === 0x90) {    // If button down     if ((status & 0xF0) === 0x90) {    // If button down
   //if (value === 0x7F) {  // Some wheels send 0x90 on press and release, so you need to check the value   //if (value === 0x7F) {  // Some wheels send 0x90 on press and release, so you need to check the value
Line 326: Line 342:
     ​     ​
     // In either case, register the movement     // In either case, register the movement
 +    var deckNumber = script.deckFromGroup(group);​
     if (engine.isScratching(deckNumber)) {     if (engine.isScratching(deckNumber)) {
         engine.scratchTick(deckNumber,​ newValue); // Scratch!         engine.scratchTick(deckNumber,​ newValue); // Scratch!
     } else {     } else {
-        engine.setValue('​[Channel'​+deckNumber+'​]'​, '​jog',​ newValue); // Pitch bend+        engine.setValue(group, '​jog',​ newValue); // Pitch bend
     }     }
 } }
Line 445: Line 462:
 ===== Color API ===== ===== Color API =====
  
-As most DJing applications,​ mixxx is capable of colored hotcues. There are several ways of accessing and processing color information in scripts. To keep compability with color limited hardware, we provide a [ncolors colorpalette:​ [Insert here]. +As most DJing applications,​ mixxx is capable of colored hotcues. There are several ways of accessing and processing color information in scripts. To keep compability with color limited hardware, we provide a [[hotcue_colors|8 color colorpalette]]. 
-Each of those colors has a unique ID. This ID can be retrieved via the engine.getValue('​[ChannelN]',​ '​hotcue_X_color_id'​) (where N and X are the respective Deck and hotcue whose information is being accessed). +Each of those colors has a unique ID. This ID can be retrieved via the ''​engine.getValue('​[ChannelN]',​ '​hotcue_X_color_id'​)'' ​(where N and X are the respective Deck and hotcue whose information is being accessed). 
-To prevent some code duplication and to provide a more robust API, a new color object was created. It features methods that return ​a struct/​hashmap/​dictionary which contain the properties of the colors in the Color palette. It contains the following properties:+The color API features two methods: 
 + 
 +  * **color.predefinedColorFromID**(//​id//​) - returns a single color object by the provided ID. 
 +  * **color.predefinedColorsList**() - returns the whole color palette in the form of a color object array. Since controllers handle colors differently from model to model, it is up to you to interpret the color and send it to the controller. 
 + 
 +To prevent some code duplication and to provide a more robust API, a new color object was created. It can be retrieved by using ''​color.predefinedColorFromID(id)''​ and it returns ​a struct/​hashmap/​dictionary which contain the properties of the colors in the Color palette. It contains the following properties:
  
   * **red** - red color channel (//8-bit precision//​).   * **red** - red color channel (//8-bit precision//​).
Line 455: Line 477:
   * **id** - internal ID of the color.   * **id** - internal ID of the color.
  
-The color API features two methods: +Since these Methods might seem bit confusingwe provide hotcuebutton class via [[components_js|Components JS]], which is able to take care of the color feature ​automatically ​(see [[components_js#​hotcuebutton|Components JS Hotcue]]).
- +
-  * **predefinedColorFromID(//​id//​)** - returns ​single color object by the provided ID. +
-  * **predefinedColorsList()** - returns the whole color palette in the form of a color object array. Since controllers handle colors differently from model to model, it is up to you to interpret the color and send it to the controller. however, [Components JS] has a hotcuebutton component that is able to take care of the color feature (see [component js hotcue button color]). +
  
 ===== Helper functions ===== ===== Helper functions =====
- +Here is a list of functions available to you from the always-loaded ​''​common-controller-scripts.js'' ​file:
-Here is a list of functions available to you from the always-loaded common-controller-scripts.js file:+
   * **nop**() - Does nothing (No OPeration.) Empty function you can use as a place-holder while developing to avoid errors.   * **nop**() - Does nothing (No OPeration.) Empty function you can use as a place-holder while developing to avoid errors.
   * **print**(//​string//​) - Prints the passed in string to the console.   * **print**(//​string//​) - Prints the passed in string to the console.
midi_scripting.txt · Last modified: 2020/03/25 15:47 by be.ing