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
midi_scripting [2019/07/08 09:08]
swiftb0y Finished Color API description so the PR can be merged.
midi_scripting [2019/11/24 12:10] (current)
kobx Added references to script.deckFromGroup to scratch how to
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 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 449: Line 466:
 The color API features two methods: The color API features two methods:
  
-  * **predefinedColorFromID**(//​id//​) - returns a single color object by the provided ID. +  * **color.predefinedColorFromID**(//​id//​) - returns a 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.+  * **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: 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:
Line 460: Line 477:
   * **id** - internal ID of the color.   * **id** - internal ID of the color.
  
-Since these Methods might seem a bit confusing, we provide hotcuebutton class via [Components JS], which is able to take care of the color feature automatically (see [component js hotcue button color]). +Since these Methods might seem a bit confusing, we 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]]).
-===== Helper functions =====+
  
-Here is a list of functions available to you from the always-loaded common-controller-scripts.js file:+===== Helper functions ===== 
 +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.1562591339.txt.gz · Last modified: 2019/07/08 09:08 by swiftb0y