// Numark Mixtrack Mapping Script Functions // 26/06/2011 - v1.0b // Matteo // With contributions from // uncleeugene // RAWRR function NumarkMixTrack() {} NumarkMixTrack.init = function(id) { // called when the MIDI device is opened & set up NumarkMixTrack.id = id; // Store the ID of this device for later use NumarkMixTrack.directoryMode = false; NumarkMixTrack.scratchMode = [false, false]; NumarkMixTrack.scratching = [false, false]; NumarkMixTrack.KeyIsLocked = [false,false]; NumarkMixTrack.manualLooping = [false, false]; NumarkMixTrack.leds = [ // Common { "directory": 0x73, "file": 0x72 }, // Deck 1 { "rate": 0x70, "scratchMode": 0x48, "keylock": 0x51, "manualLoop": 0x61, "loopIn": 0x53, "loopOut": 0x54, "reLoop": 0x55 }, // Deck 2 { "rate": 0x71, "scratchMode": 0x50, "keylock": 0x52, "manualLoop": 0x62, "loopIn": 0x56, "loopOut": 0x57, "reLoop": 0x58 } ]; NumarkMixTrack.setLED(NumarkMixTrack.leds[0]["file"], true); } NumarkMixTrack.shutdown = function(id) { // called when the MIDI device is closed var lowestLED = 0x30; var highestLED = 0x73; for (var i=lowestLED; i<=highestLED; i++) { NumarkMixTrack.setLED(i, false); // Turn off all the lights } } NumarkMixTrack.groupToDeck = function(group) { var matches = group.match(/^\[Channel(\d+)\]$/); if (matches == null) { return -1; } else { return matches[1]; } } NumarkMixTrack.samplesPerBeat = function(group) { // FIXME: Get correct channels for current deck var sampleRate = engine.getValue(group, "track_samplerate"); var channels = 2; var bpm = engine.getValue(group, "file_bpm"); var ret=channels * sampleRate * 60 / bpm; return channels * sampleRate * 60 / bpm; } NumarkMixTrack.setLED = function(value, status) { if (status) { status = 0x64; } else { status = 0x00; } midi.sendShortMsg(0x90, value, status); } NumarkMixTrack.selectKnob = function(channel, control, value, status, group) { if (value > 63) { value = value - 128; } if (NumarkMixTrack.directoryMode) { if (value < 0) { for (var i = 0; i < -value; i++) { engine.setValue(group, "SelectNextPlaylist", 1); } } else { for (var i = 0; i < value; i++) { engine.setValue(group, "SelectPrevPlaylist", 1); } } } else { engine.setValue(group, "SelectTrackKnob", -value); } } NumarkMixTrack.loopIn = function(channel, control, value, status, group) { var deck = NumarkMixTrack.groupToDeck(group); if (value) { if(NumarkMixTrack.manualLooping[deck-1]) { // Cut loop to Half var start = engine.getValue(group, "loop_start_position"); var end = engine.getValue(group, "loop_end_position"); if((start != -1) && (end != -1)) { var len = (end - start) / 2; engine.setValue(group, "loop_end_position", start + len); } } else { if (engine.getValue(group, "loop_enabled")) { engine.setValue(group, "reloop_exit", 1); NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["reLoop"],false); } engine.setValue(group, "loop_in", 1); engine.setValue(group, "loop_end_position", -1); NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["loopIn"],true); NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["loopOut"],false); } } } NumarkMixTrack.loopOut = function(channel, control, value, status, group) { var deck = NumarkMixTrack.groupToDeck(group); if (value) { var start = engine.getValue(group, "loop_start_position"); var end = engine.getValue(group, "loop_end_position"); if(NumarkMixTrack.manualLooping[deck-1]) { // Set loop to current Bar var bar = NumarkMixTrack.samplesPerBeat(group); start = Math.ceil((engine.getValue(group, "playposition")*engine.getValue(group, "track_samples")/bar)-1)*bar; engine.setValue(group,"loop_start_position",start); engine.setValue(group,"loop_end_position", start + bar); engine.setValue(group, "reloop_exit",1); NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["loopIn"],true); NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["loopOut"],true); } else { if (start != -1) { if (end != -1) { // Loop In and Out set -> call Reloop/Exit engine.setValue(group, "reloop_exit", 1); NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["loopIn"],true); NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["loopOut"],true); NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["reLoop"],true); } else { // Loop In set -> call Loop Out engine.setValue(group, "loop_out", 1); NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["loopOut"],true); } } } } } NumarkMixTrack.reLoop = function(channel, control, value, status, group) { var deck = NumarkMixTrack.groupToDeck(group); if (value) { if(NumarkMixTrack.manualLooping[deck-1]) { // Multiply Loop by Two var start = engine.getValue(group, "loop_start_position"); var end = engine.getValue(group, "loop_end_position"); if((start != -1) && (end != -1)) { var len = (end - start) * 2; engine.setValue(group, "loop_end_position", start + len); } } else { if (engine.getValue(group, "loop_enabled")) { NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["reLoop"],false); } else { var start = engine.getValue(group, "loop_start_position"); var end = engine.getValue(group, "loop_end_position"); if( (start != -1) && (end != -1)) { // Loop is set ! Light the led NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["reLoop"],true); } } engine.setValue(group, "reloop_exit", 1); } } } NumarkMixTrack.jogWheel = function(channel, control, value, status, group) { var deck = NumarkMixTrack.groupToDeck(group); var adjustedJog = parseFloat(value); var posNeg = 1; if (adjustedJog > 63) { // Counter-clockwise posNeg = -1; adjustedJog = value - 128; } if (NumarkMixTrack.scratching[deck-1]) { engine.scratchTick(deck, adjustedJog); } else { var gammaInputRange = 23; // Max jog speed var maxOutFraction = 0.5; // Where on the curve it should peak; 0.5 is half-way var sensitivity = 0.5; // Adjustment gamma var gammaOutputRange = 3; // Max rate change if (engine.getValue(group,"play")) { adjustedJog = posNeg * gammaOutputRange * Math.pow(Math.abs(adjustedJog) / (gammaInputRange * maxOutFraction), sensitivity); } else { adjustedJog = gammaOutputRange * adjustedJog / (gammaInputRange * maxOutFraction); } engine.setValue(group, "jog", adjustedJog); } } NumarkMixTrack.toggleDirectoryMode = function(channel, control, value, status, group) { // Toggle setting and light if (value) { if (NumarkMixTrack.directoryMode) { NumarkMixTrack.directoryMode = false; } else { NumarkMixTrack.directoryMode = true; } NumarkMixTrack.setLED(NumarkMixTrack.leds[0]["directory"], NumarkMixTrack.directoryMode); NumarkMixTrack.setLED(NumarkMixTrack.leds[0]["file"], !NumarkMixTrack.directoryMode); } } NumarkMixTrack.toggleScratchMode = function(channel, control, value, status, group) { var deck = NumarkMixTrack.groupToDeck(group); // Toggle setting and light if (value) { if (NumarkMixTrack.scratchMode[deck-1]) { NumarkMixTrack.scratchMode[deck-1] = false; } else { NumarkMixTrack.scratchMode[deck-1] = true; } NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["scratchMode"], NumarkMixTrack.scratchMode[deck-1]); } } NumarkMixTrack.WheelTouch = function (channel, control, value, status, group) { var deck = NumarkMixTrack.groupToDeck(group); if (NumarkMixTrack.scratchMode[deck-1]) { if (value) { // Wheel touched engine.scratchEnable(deck, 512, 33+1/3, 0.2, (0.2)/32); NumarkMixTrack.scratching[deck-1] = true; } else { // Wheel left engine.scratchDisable(deck); NumarkMixTrack.scratching[deck-1] = false; } } } NumarkMixTrack.toggleManualLooping = function(channel, control, value, status, group) { var deck = NumarkMixTrack.groupToDeck(group); // Toggle setting and light if (value) { if (NumarkMixTrack.manualLooping[deck-1]) { NumarkMixTrack.manualLooping[deck-1] = false; } else { NumarkMixTrack.manualLooping[deck-1] = true; } NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["manualLoop"], NumarkMixTrack.manualLooping[deck-1]); } } NumarkMixTrack.ToggleKeylock = function(channel, control, value, status, group) { var deck = NumarkMixTrack.groupToDeck(group); // Toggle setting and light if (value) { if (NumarkMixTrack.KeyIsLocked[deck-1]) { engine.setValue(group, "keylock", 0); NumarkMixTrack.KeyIsLocked[deck-1] = false; } else { engine.setValue(group, "keylock", 1); NumarkMixTrack.KeyIsLocked[deck-1] = true; } NumarkMixTrack.setLED(NumarkMixTrack.leds[deck]["keylock"], NumarkMixTrack.KeyIsLocked[deck-1]); } }