├── Controller Scripts ├── icontrol.control.js ├── softstep │ ├── KMI_softstep.control.js │ ├── KMI_softstep.html │ ├── README.md │ ├── clip_page.png │ ├── ctrl_page.png │ ├── prm_page.png │ └── tran_page.png └── yamaha_mx49_mx61 │ └── Yamaha-MX49-MX61.control.js ├── LICENSE ├── README.md └── sfz2multisample ├── pom.xml └── src └── main └── java └── net └── localguru └── sfz2multisample └── Sfz2Multisample.java /Controller Scripts/icontrol.control.js: -------------------------------------------------------------------------------- 1 | loadAPI(1); 2 | 3 | host.defineController( "M-Audio", "iControl", "1.0", "336185fb-7e4b-46e5-9954-fd7100c3b99b"); 4 | 5 | host.defineMidiPorts(1,1); 6 | host.addDeviceNameBasedDiscoveryPair(["iControl"],["iControl"]); 7 | host.addDeviceNameBasedDiscoveryPair(["iControl MIDI 1"],["iControl MIDI 1"]); 8 | 9 | var CC = { 10 | REC: 106, 11 | START: 107, 12 | REV: 108, 13 | PLAY: 109, 14 | FF: 110, 15 | LOOP: 111, 16 | 17 | SEL1 : 88, 18 | SEL8 : 95, 19 | 20 | ARM1: 64, 21 | ARM8: 71, 22 | 23 | MUTE1: 80, 24 | MUTE8: 87, 25 | 26 | SOLO1: 72, 27 | SOLO8: 79, 28 | 29 | KNOB1: 16, 30 | KNOB8: 23, 31 | } 32 | 33 | var MODE = { 34 | VOL:97, 35 | PAN:98, 36 | SEND1:99, 37 | SEND2:100, 38 | MACRO1:101, 39 | MACRO2:102, 40 | MACRO3:103, 41 | } 42 | 43 | var currentMode = MODE.VOL; 44 | 45 | function getTrackObserver( track ) { 46 | return function( on ) { 47 | sendMidi( 176, CC.SEL1 + track, on ? 127 : 0 ); 48 | } 49 | } 50 | function getArmObserver( track ) { 51 | return function( on ) { 52 | sendMidi( 176, CC.ARM1 + track, on ? 127 : 0 ); 53 | } 54 | } 55 | function getSoloObserver( track ) { 56 | return function( on ) { 57 | sendMidi( 176, CC.SOLO1 + track, on ? 127 : 0 ); 58 | } 59 | } 60 | function getMuteObserver( track ) { 61 | return function( on ) { 62 | sendMidi( 176, CC.MUTE1 + track, on ? 127 : 0 ); 63 | } 64 | } 65 | 66 | function changeMode( mode ) { 67 | for ( var i = MODE.VOL; i<=MODE.MACRO3; i++) { 68 | sendMidi( 176, i, 0); 69 | } 70 | sendMidi( 176, mode, 127); 71 | currentMode = mode; 72 | } 73 | 74 | function init() { 75 | host.getMidiInPort(0).setMidiCallback(onMidi); 76 | transport = host.createTransportSection(); 77 | transport.addIsPlayingObserver(function(on) { 78 | isPlay = on; 79 | sendMidi( 176, CC.PLAY, isPlay ? 127 : 0 ); 80 | }); 81 | 82 | transport.addIsLoopActiveObserver( function(on ) { sendMidi( 176, CC.LOOP, on ? 127 : 0 ); }); 83 | transport.addIsRecordingObserver( function(on ) { sendMidi( 176, CC.REC, on ? 127 : 0 ); }); 84 | 85 | masterTrack = host.createMasterTrackSection(0); 86 | 87 | trackBank = host.createTrackBank(8,1,0); 88 | for( var i=0; i<8; i++) { 89 | var t = trackBank.getTrack(i) 90 | t.addIsSelectedObserver( getTrackObserver( i )); 91 | t.getMute().addValueObserver( getMuteObserver( i )); 92 | t.getSolo().addValueObserver( getSoloObserver( i )); 93 | t.getArm().addValueObserver( getArmObserver( i )); 94 | } 95 | 96 | changeMode( MODE.VOL ); 97 | } 98 | 99 | 100 | 101 | function onMidi( status, data1, data2 ) { 102 | if ( status == 176 ) { 103 | if ( data1 == 24 ) { 104 | if ( data2 < 64 ) { 105 | transport.incPosition( data2/4, false ); 106 | } else { 107 | transport.incPosition( (data2-128)/4, false ); 108 | } 109 | }else if ( data1 == 7 ) { 110 | masterTrack.getVolume().set(data2, 128); 111 | } else if ( withinRange( data1, CC.SEL1, CC.SEL8 )) { 112 | if ( data2 == 127 ) { 113 | trackBank.getTrack( data1 - CC.SEL1 ).select(); 114 | } 115 | } else if ( withinRange( data1, CC.MUTE1, CC.MUTE8 )) { 116 | if ( data2 == 127 ) { 117 | trackBank.getTrack( data1 - CC.MUTE1 ).getMute().toggle(); 118 | } 119 | } else if ( withinRange( data1, CC.ARM1, CC.ARM8 )) { 120 | if ( data2 == 127 ) { 121 | trackBank.getTrack( data1 - CC.ARM1 ).getArm().toggle(); 122 | } 123 | } else if ( withinRange( data1, CC.SOLO1, CC.SOLO8 )) { 124 | if ( data2 == 127 ) { 125 | trackBank.getTrack( data1 - CC.SOLO1 ).getSolo().toggle(); 126 | } 127 | } else if ( withinRange( data1, CC.KNOB1, CC.KNOB8 )) { 128 | var value; 129 | if ( currentMode == MODE.PAN ) { 130 | value = trackBank.getTrack( data1 - CC.KNOB1 ).getPan(); 131 | } else if ( currentMode == MODE.SEND1 ) { 132 | value = trackBank.getTrack( data1 - CC.KNOB1 ).getSend(0); 133 | } else if ( currentMode == MODE.SEND2 ) { 134 | value = trackBank.getTrack( data1 - CC.KNOB1 ).getSend(1); 135 | } else if ( currentMode == MODE.MACRO1 ) { 136 | value = trackBank.getTrack( data1 - CC.KNOB1 ).getPrimaryDevice().getMacro(0).getAmount(); 137 | } else if ( currentMode == MODE.MACRO2 ) { 138 | value = trackBank.getTrack( data1 - CC.KNOB1 ).getPrimaryDevice().getMacro(1).getAmount(); 139 | } else if ( currentMode == MODE.MACRO3 ) { 140 | value = trackBank.getTrack( data1 - CC.KNOB1 ).getPrimaryDevice().getMacro(2).getAmount(); 141 | 142 | 143 | } else { 144 | value = trackBank.getTrack( data1 - CC.KNOB1 ).getVolume(); 145 | } 146 | 147 | value.inc( (data2 < 64 ? data2 : data2 - 128), 128 ); 148 | 149 | } else if ( withinRange( data1, MODE.VOL, MODE.MACRO3 )) { 150 | if ( data2 == 127 ) { 151 | changeMode( data1 ); 152 | } 153 | } else { 154 | if ( data2 == 127 ) { 155 | switch(data1) { 156 | case CC.REC: 157 | transport.record(); 158 | break; 159 | case CC.START: 160 | transport.setPosition(0); 161 | break; 162 | case CC.REV: 163 | transport.rewind(); 164 | break; 165 | case CC.PLAY: 166 | transport.play(); 167 | break; 168 | case CC.FF: 169 | transport.fastForward(); 170 | break; 171 | case CC.LOOP: 172 | transport.toggleLoop(); 173 | break; 174 | } 175 | } 176 | } 177 | } 178 | 179 | 180 | } 181 | 182 | function exit() { 183 | } 184 | -------------------------------------------------------------------------------- /Controller Scripts/softstep/KMI_softstep.control.js: -------------------------------------------------------------------------------- 1 | loadAPI(4); 2 | 3 | host.defineController("Keith McMillen", "Softstep 2", "1.0", "dd426d62-43f4-4f42-a3cc-2255086109c7"); 4 | 5 | host.defineMidiPorts(1, 1); 6 | host.addDeviceNameBasedDiscoveryPair(["SSCOM MIDI 1"], ["SSCOM MIDI 1"]); 7 | Color = { 8 | GREEN:0, 9 | RED:1, 10 | YELLOW:2 11 | } 12 | 13 | Led = { 14 | OFF:0, 15 | ON:1, 16 | BLINK:2, 17 | FAST_BLINK:3, 18 | FLASH:4 19 | } 20 | 21 | Pages = { 22 | TRAN:0, 23 | PRM:1, 24 | CTRL:2, 25 | CLIP:3 26 | } 27 | 28 | pages = ['TRAN', 'PRM', 'CTRL', 'CLIP'] 29 | current_page = 0 30 | 31 | buttons = [44,52,60,68,76,40,48,56,64,72] 32 | state = [0,0,0,0,0,0,0,0,0,0] 33 | state_fine = [ 34 | 0,0,0,0, 35 | 0,0,0,0, 36 | 0,0,0,0, 37 | 0,0,0,0, 38 | 0,0,0,0, 39 | 0,0,0,0, 40 | 0,0,0,0, 41 | 0,0,0,0, 42 | 0,0,0,0, 43 | 0,0,0,0, 44 | ] 45 | 46 | pressure = [ 47 | 0,0,0,0, 48 | 0,0,0,0, 49 | 0,0,0,0, 50 | 0,0,0,0, 51 | 0,0,0,0, 52 | 0,0,0,0, 53 | 0,0,0,0, 54 | 0,0,0,0, 55 | 0,0,0,0, 56 | 0,0,0,0, 57 | ] 58 | 59 | 60 | 61 | param_values = [0,0,0,0,0,0,0,0] 62 | 63 | ledstates=[ 64 | [[Color.GREEN,Led.OFF],[Color.GREEN,Led.OFF],[Color.GREEN,Led.OFF],[Color.GREEN,Led.OFF],[Color.GREEN,Led.OFF], 65 | [Color.GREEN,Led.OFF],[Color.GREEN,Led.OFF],[Color.GREEN,Led.OFF],[Color.GREEN,Led.OFF],[Color.GREEN,Led.OFF]], 66 | [[Color.GREEN,Led.ON],[Color.GREEN,Led.ON],[Color.GREEN,Led.ON],[Color.GREEN,Led.ON],[Color.YELLOW,Led.ON], 67 | [Color.GREEN,Led.ON],[Color.GREEN,Led.ON],[Color.GREEN,Led.ON],[Color.GREEN,Led.ON],[Color.YELLOW,Led.ON]], 68 | [[Color.RED,Led.ON],[Color.RED,Led.ON],[Color.RED,Led.ON],[Color.RED,Led.ON],[Color.RED,Led.ON], 69 | [Color.RED,Led.ON],[Color.RED,Led.ON],[Color.RED,Led.ON],[Color.RED,Led.ON],[Color.RED,Led.ON]], 70 | [[Color.YELLOW,Led.ON],[Color.YELLOW,Led.ON],[Color.YELLOW,Led.ON],[Color.YELLOW,Led.ON],[Color.YELLOW,Led.ON], 71 | [Color.YELLOW,Led.ON],[Color.YELLOW,Led.ON],[Color.YELLOW,Led.ON],[Color.YELLOW,Led.ON],[Color.YELLOW,Led.ON]], 72 | ] 73 | 74 | function init() { 75 | host.getMidiInPort(0).setMidiCallback(onMidi); 76 | notificationSettings = host.getNotificationSettings(); 77 | notificationSettings.setShouldShowTrackSelectionNotifications(true); 78 | notificationSettings.setShouldShowChannelSelectionNotifications(true); 79 | 80 | generic = host.getMidiInPort(0).createNoteInput("Softstep", "91????","81????"); 81 | generic.setShouldConsumeEvents(true); 82 | out = host.getMidiOutPort(0) 83 | 84 | out.sendSysex("f0 00 1b 48 7a 01 00 00 00 00 00 00 00 00 00 00 00 01 00 09 00 0b 2b 3a 00 10 04 01 00 00 00 00 00 00 00 2f 7e 00 00 00 00 02 f7") //Standalone 85 | out.sendSysex("f0 00 1b 48 7a 01 00 00 00 00 00 00 00 00 00 00 00 01 00 09 00 0b 2b 3a 00 10 03 00 00 00 00 00 00 00 00 50 07 00 00 00 00 00 f7"); // Tether 86 | out.sendSysex("f0 00 1b 48 7a 01 00 00 00 00 00 00 00 00 00 00 00 01 00 04 00 05 08 25 01 20 00 00 7b 2c 00 00 00 0c f7") // backlight 87 | 88 | cursorTrack = host.createCursorTrack(1, 1); 89 | primaryDevice = cursorTrack.createCursorDevice() 90 | primaryDevice.exists().markInterested(); 91 | remoteControls = primaryDevice.createCursorRemoteControlsPage(8); 92 | 93 | userControls = host.createUserControlsSection(10); 94 | for( var b = 0; b<10; b++) { 95 | userControls.getControl(b).setLabel("Pad " + (b+1)); 96 | } 97 | 98 | 99 | for( var i=0; i<8; i++) { 100 | remoteControls.getParameter( i ).value().addValueObserver(128,getValueObserver( i )); 101 | } 102 | 103 | transport = host.createTransportSection(); 104 | 105 | transport.addIsPlayingObserver( function(value) { 106 | if (value) { 107 | println("playing"); 108 | led(Pages.TRAN,0,Color.RED,Led.OFF); 109 | led(Pages.TRAN,1,Color.GREEN,Led.ON); 110 | } else { 111 | println("stoped"); 112 | led(Pages.TRAN,0,Color.RED,Led.ON); 113 | led(Pages.TRAN,1,Color.GREEN,Led.OFF); 114 | } 115 | }) 116 | 117 | transport.addIsRecordingObserver(function(on) { 118 | led(Pages.TRAN,2,Color.RED, on ? Led.ON : Led.OFF ); 119 | }) 120 | 121 | transport.addClickObserver(function(on) { 122 | led(Pages.TRAN,5,Color.YELLOW, on ? Led.ON : Led.OFF ); 123 | }); 124 | 125 | transport.addIsLoopActiveObserver(function(on) { 126 | led(Pages.TRAN,6,Color.GREEN, on ? Led.ON : Led.OFF ); 127 | }); 128 | 129 | transport.addIsWritingArrangerAutomationObserver(function(on) { 130 | led(Pages.TRAN,7,Color.YELLOW, on ? Led.ON : Led.OFF ); 131 | }); 132 | 133 | transport.addOverdubObserver(function(on) { 134 | led(Pages.TRAN,8,Color.RED, on ? Led.ON : Led.OFF ); 135 | }); 136 | 137 | transport.addLauncherOverdubObserver(function(on) { 138 | led(Pages.TRAN,9,Color.RED, on ? Led.ON : Led.OFF ); 139 | }); 140 | 141 | trackBank = host.createMainTrackBank(1, 0, 9); 142 | track = trackBank.getTrack(0); 143 | slotBank = track.getClipLauncherSlots() 144 | slotBank.addHasContentObserver(function(idx, value) { 145 | led(Pages.CLIP, idx, Color.GREEN, value ? Led.ON : Led.OFF ); 146 | }); 147 | display(pages[current_page]) 148 | updateLeds(); 149 | } 150 | 151 | function exit() { 152 | 153 | out.sendSysex("f0 00 1b 48 7a 01 00 00 00 00 00 00 00 00 00 00 00 01 00 04 00 05 08 25 00 20 00 00 4c 1c 00 00 00 0c f7"); // backlight 154 | display(" "); 155 | resetLeds(); 156 | 157 | out.sendSysex("f0 00 1b 48 7a 01 00 00 00 00 00 00 00 00 00 00 00 01 00 09 00 0b 2b 3a 00 10 04 00 00 00 00 00 00 00 00 17 1f 00 00 00 00 00 f7"); // standalone 158 | out.sendSysex("f0 00 1b 48 7a 01 00 00 00 00 00 00 00 00 00 00 00 01 00 09 00 0b 2b 3a 00 10 03 01 00 00 00 00 00 00 00 68 66 00 00 00 00 00 f7"); // tether 159 | } 160 | 161 | function onMidi(status, data1, data2) { 162 | // printMidi(status, data1, data2); 163 | 164 | change = [0,0,0,0,0,0,0,0,0,0]; 165 | change_fine = [ 166 | 0,0,0,0, 167 | 0,0,0,0, 168 | 0,0,0,0, 169 | 0,0,0,0, 170 | 0,0,0,0, 171 | 0,0,0,0, 172 | 0,0,0,0, 173 | 0,0,0,0, 174 | 0,0,0,0, 175 | 0,0,0,0, 176 | ] 177 | 178 | if ( status == 176 && data1 == 80 && data2 == 0 ) { 179 | setPage(current_page - 1) 180 | } 181 | if ( status == 176 && data1 == 81 && data2 == 0 ) { 182 | setPage(current_page + 1) 183 | } 184 | 185 | for (var b=0; b<10; b++) { 186 | for( var i=0; i<4; i++) { 187 | if ( status == 176 && data1 == buttons[b]+i) { 188 | pressure[4*b+i]=data2; 189 | } 190 | 191 | if ( status == 176 && data1 == buttons[b]+i && data2 >= 20 ) { 192 | if ( state[b] == 0 ) { 193 | state[b] = buttons[b]+i; 194 | // println( "button " + b + " pressed"); 195 | change[b]=1 196 | } 197 | if (state_fine[4*b+i] == 0 ) { 198 | state_fine[4*b+i] = 4*b+i 199 | // println( "button " + b + " sub " + i + " pressed"); 200 | change_fine[4*b+i] = 1; 201 | } 202 | } 203 | if ( status == 176 && data1 == buttons[b]+i && data2 < 10 ) { 204 | if ( state[b] == buttons[b]+i ) { 205 | state[b] = 0; 206 | // println( "button " + b + " released"); 207 | change[b]=-1 208 | } 209 | if (state_fine[4*b+i] == 4*b+i) { 210 | state_fine[4*b+i] = 0; 211 | // println( "button " + b + " sub " + i + " released"); 212 | change_fine[4*b+i] = -1; 213 | } 214 | } 215 | } 216 | } 217 | 218 | 219 | if (current_page == Pages.TRAN ) { 220 | if ( change[0]==-1 ) { 221 | transport.stop(); 222 | } 223 | if ( change[1]==-1) { 224 | transport.play(); 225 | } 226 | if ( change[2]==-1) { 227 | transport.record(); 228 | } 229 | if ( change[3]==-1) { 230 | transport.tapTempo(); 231 | } 232 | if (change[4] == -1) { 233 | if (primaryDevice.exists().get()) { 234 | primaryDevice.browseToReplaceDevice(); 235 | } else { 236 | cursorTrack.browseToInsertAtStartOfChain(); 237 | } 238 | } 239 | if (change[5] == -1 ) { 240 | transport.toggleClick(); 241 | } 242 | if (change[6] == -1 ) { 243 | transport.toggleLoop(); 244 | } 245 | if (change[7] == -1 ) { 246 | transport.toggleWriteArrangerAutomation(); 247 | } 248 | if (change[8] == -1 ) { 249 | transport.toggleOverdub(); 250 | } 251 | if (change[9] == -1 ) { 252 | transport.toggleLauncherOverdub(); 253 | } 254 | 255 | } else if (current_page == Pages.PRM ) { 256 | pi = [5,6,7,8,0,1,2,3] 257 | for (var i=0; i<8; i++) { 258 | idx = pi[i] 259 | if (change_fine[4*idx] == -1) { 260 | changeValue(i,+10); 261 | } 262 | if (change_fine[4*idx+1] == -1) { 263 | changeValue(i,+1); 264 | } 265 | if (change_fine[4*idx+2] == -1) { 266 | changeValue(i,-1); 267 | } 268 | if (change_fine[4*idx+3] == -1) { 269 | changeValue(i,-10); 270 | } 271 | } 272 | 273 | if (change_fine[4*9+1] == -1) { 274 | remoteControls.selectNext(); 275 | } 276 | if (change_fine[4*9+2] == -1) { 277 | remoteControls.selectPrevious(); 278 | } 279 | if (change_fine[4*4+1] == -1) { 280 | primaryDevice.selectNext(); 281 | primaryDevice.selectInEditor(); 282 | } 283 | if (change_fine[4*4+2] == -1) { 284 | primaryDevice.selectPrevious(); 285 | primaryDevice.selectInEditor(); 286 | } 287 | } else if (current_page == Pages.CTRL ) { 288 | // map pressure to cotroller 289 | for (var x=0; x<10; x++) { 290 | v = 0; 291 | for( var i=0; i<4; i++) { 292 | v = v > pressure[4*x+i] ? v : pressure[4*x+i]; 293 | } 294 | if (v > 0) { 295 | println( "control " + x + " " + v); 296 | userControls.getControl(x).set(v, 64); 297 | } 298 | } 299 | } else if (current_page == Pages.CLIP ) { 300 | for (var i=0; i<9; i++) { 301 | if (change[i] == -1 ) { 302 | slotBank.launch(i); 303 | } 304 | } 305 | 306 | if (change_fine[4*9+1] == -1) { 307 | trackBank.scrollForwards(); 308 | track.selectInMixer(); 309 | } 310 | if (change_fine[4*9+2] == -1) { 311 | trackBank.scrollBackwards(); 312 | track.selectInMixer(); 313 | } 314 | 315 | if (change_fine[4*9+3] == -1) { 316 | slotBank.stop() 317 | } 318 | } 319 | } 320 | 321 | function setPage(m) { 322 | println("set page "+ m); 323 | if ( m < 0 ) { 324 | current_page = pages.length-1; 325 | } else if ( m > pages.length-1) { 326 | current_page = 0; 327 | } else { 328 | current_page = m 329 | } 330 | display(pages[current_page]); 331 | updateLeds(); 332 | host.showPopupNotification( pages[current_page]); 333 | } 334 | 335 | 336 | function led(page, number, color, mode ) { 337 | ledstates[page][number] = [color,mode]; 338 | if (page == current_page) { 339 | for( var c=0; c<3; c++) { 340 | setLed(number,c,Led.OFF); 341 | } 342 | setLed(number, color, mode); 343 | } 344 | } 345 | 346 | /** 347 | * Sets led number (numbered from 1 to 10) to given color and mode 348 | */ 349 | function setLed(number, color, mode) { 350 | out.sendMidi(0xB0,40,number) // select led, numbered from 0 351 | out.sendMidi(0xB0,41,color) // green = 0, red = 1, yellow = 2 352 | out.sendMidi(0xB0,42,mode) // range(x) = (off, on, blink, fast, flash) 353 | out.sendMidi(0xB0,0,0) 354 | out.sendMidi(0xB0,0,0) 355 | out.sendMidi(0xB0,0,0) 356 | } 357 | 358 | /** 359 | * Switch all leds off 360 | */ 361 | function resetLeds() { 362 | for( var l= 0; l<10; l++) { 363 | for( var c=0; c<3; c++) { 364 | setLed(l,c,Led.OFF); 365 | } 366 | } 367 | } 368 | 369 | function updateLeds() { 370 | ls = ledstates[current_page]; 371 | for( var l= 0; l<10; l++) { 372 | for( var c=0; c<3; c++) { 373 | setLed(l,c,Led.OFF); 374 | } 375 | setLed(l,ls[l][0],ls[l][1]); 376 | } 377 | } 378 | 379 | /** 380 | * Sets the text on the device's display. The text gets truncated to 4 chars 381 | */ 382 | function display(text) { 383 | for( var i=0; i<4; i++) { 384 | var cc = i < text.length ? text.charCodeAt(i) : 0x20; 385 | out.sendMidi(176,50+i,cc); 386 | } 387 | } 388 | 389 | function changeValue(p,v) { 390 | param_values[p] += v 391 | if (param_values[p] < 0) { param_values[p] = 0; } 392 | if (param_values[p] > 127) { param_values[p] = 127; } 393 | println( "set value " + p + " to " + param_values[p]); 394 | remoteControls.getParameter( p ).value().set(param_values[p], 128); 395 | } 396 | 397 | function getValueObserver( i ) { 398 | return function( value ) { 399 | param_values[i] = value 400 | } 401 | } 402 | 403 | -------------------------------------------------------------------------------- /Controller Scripts/softstep/KMI_softstep.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | KMI Softstep2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 |
19 | 24 |
25 |
26 |

Global

27 |
28 |

29 | The controller script for the KMI Softstep 2 uses several pages which can be cycled 30 | throu using the left and right navigation buttons 31 |

32 |

33 | the name of the current page is shown on the display and when switching between pages its also shown on the screen, so you 34 | don't have to look down to your controller panel when switching pages. 35 |

36 |

This control-script is based on the python program Foococo by 37 | Matthieu Amiguet. Many thanks for figuring out how to switch the Softstep 38 | into hostmode and controling the Screen

39 |
40 |
41 |
42 |

Transport Mode

43 |
44 |
45 | LaunchPad 46 |
47 |

48 | In this mode the buttons can be used to start and stop the current project, activate loop mode and toggle various recording modes. 49 | You can also start the device/clip/sample/preset-browser or tap your tempo. 50 |

51 |
52 |
53 | 54 |
55 |

Parameter Mode

56 | 57 |
58 |
59 | LaunchPad 60 |
61 | 62 |

in parameter mode you can change values of the currently selected device by usin the arrow keys on your softstep 2. Each softstep 63 | button is mapped to one parameter, the up and down key of the button can be used to increase or decrease the values by 10 and the 64 | left and right buttons can be used to increase and decrease the value by 1 - this is usefull if a parameter is mapped to a descret 65 | value like a program change on a hardware synth for example

66 |

The button number 5 can be used to switch between parameter banks on the selected devcie and button 0 is used to navigate between 67 | devices in the currently selected channel.

68 |
69 |
70 |
71 |

Controller Mode

72 |
73 |
74 | LaunchPad 75 |
76 | 77 |

In controller mode the pressure value of each button is mapped to a usercontroller that can be mapped to any controllable parameter 78 | you like using the midi-learn function

79 |
80 |
81 |
82 |

Clip Launch Mode

83 |
84 |
85 | LaunchPad 86 |
87 | 88 |

in clip launcher mode, the first 9 buttons trigger start, stop or record on the first 9 clips of the selected track - the leds are 89 | lit green if a slot contains a clip. If you hit a empty clip recording starts on this slot (and the led turns red). Botton 0 is used 90 | to select a track in the mixer.

91 |
92 |
93 |
94 | 98 |
99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /Controller Scripts/softstep/README.md: -------------------------------------------------------------------------------- 1 | A Bitwig Studio Controller Script for the KMI Softstep 2 2 | 3 | I wrote a [Blogpost about it](https://www.local-guru.net/blog/2018/11/30/Bitwig-Studio-Controllerscript-for-SoftStep2-) 4 | 5 | and here is the [download link to the zip file](https://www.local-guru.net/projects/softstep/softstep.zip) if you are in a hurry or don't want to read manuals 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Controller Scripts/softstep/clip_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngradwohl/bitwig_scripts/626162797855ae3f032c898503f0024fac3b8800/Controller Scripts/softstep/clip_page.png -------------------------------------------------------------------------------- /Controller Scripts/softstep/ctrl_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngradwohl/bitwig_scripts/626162797855ae3f032c898503f0024fac3b8800/Controller Scripts/softstep/ctrl_page.png -------------------------------------------------------------------------------- /Controller Scripts/softstep/prm_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngradwohl/bitwig_scripts/626162797855ae3f032c898503f0024fac3b8800/Controller Scripts/softstep/prm_page.png -------------------------------------------------------------------------------- /Controller Scripts/softstep/tran_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngradwohl/bitwig_scripts/626162797855ae3f032c898503f0024fac3b8800/Controller Scripts/softstep/tran_page.png -------------------------------------------------------------------------------- /Controller Scripts/yamaha_mx49_mx61/Yamaha-MX49-MX61.control.js: -------------------------------------------------------------------------------- 1 | 2 | loadAPI(2); 3 | 4 | const RGB_COLORS = 5 | [ 6 | [ 0.3294117748737335 , 0.3294117748737335 , 0.3294117748737335 , "Dark Gray"], 7 | [ 0.47843137383461 , 0.47843137383461 , 0.47843137383461 , "Gray"], 8 | [ 0.7882353067398071 , 0.7882353067398071 , 0.7882353067398071 , "Light Gray"], 9 | [ 0.5254902243614197 , 0.5372549295425415 , 0.6745098233222961 , "Silver"], 10 | [ 0.6392157077789307 , 0.4745098054409027 , 0.26274511218070984, "Dark Brown"], 11 | [ 0.7764706015586853 , 0.6235294342041016 , 0.43921568989753723, "Brown"], 12 | [ 0.34117648005485535, 0.3803921639919281 , 0.7764706015586853 , "Dark Blue"], 13 | [ 0.5176470875740051 , 0.5411764979362488 , 0.8784313797950745 , "Purplish Blue"], 14 | [ 0.5843137502670288 , 0.2862745225429535 , 0.7960784435272217 , "Purple"], 15 | [ 0.8509804010391235 , 0.21960784494876862, 0.4431372582912445 , "Pink"], 16 | [ 0.8509804010391235 , 0.18039216101169586, 0.1411764770746231 , "Red"], 17 | [ 1 , 0.34117648005485535, 0.0235294122248888 , "Orange"], 18 | [ 0.8509804010391235 , 0.615686297416687 , 0.062745101749897 , "Light Orange"], 19 | [ 0.45098039507865906, 0.5960784554481506 , 0.0784313753247261 , "Green"], 20 | [ 0 , 0.615686297416687 , 0.27843138575553894, "Cold Green"], 21 | [ 0 , 0.6509804129600525 , 0.5803921818733215 , "Bluish Green"], 22 | [ 0 , 0.6000000238418579 , 0.8509804010391235 , "Blue"], 23 | [ 0.7372549176216125 , 0.4627451002597809 , 0.9411764740943909 , "Light Purple"], 24 | [ 0.8823529481887817 , 0.4000000059604645 , 0.5686274766921997 , "Light Pink"], 25 | [ 0.9254902005195618 , 0.3803921639919281 , 0.34117648005485535, "Skin"], 26 | [ 1 , 0.5137255191802979 , 0.24313725531101227, "Redish Brown"], 27 | [ 0.8941176533699036 , 0.7176470756530762 , 0.30588236451148987, "Light Brown"], 28 | [ 0.6274510025978088 , 0.7529411911964417 , 0.2980392277240753 , "Light Green"], 29 | [ 0.24313725531101227, 0.7333333492279053 , 0.3843137323856354 , "Grass Green"], 30 | [ 0.26274511218070984, 0.8235294222831726 , 0.7254902124404907 , "Light Blue"], 31 | [ 0.2666666805744171 , 0.7843137383460999 , 1 , "Greenish Blue"], 32 | ]; 33 | 34 | 35 | host.defineController("Yamaha", "MX49/MX61", "1.0", "fadd4e99-a961-4237-9c97-478321ea072e") 36 | host.defineMidiPorts(5, 5); 37 | host.addDeviceNameBasedDiscoveryPair( 38 | ["Yamaha MX49/MX61 MIDI 1", 39 | "Yamaha MX49/MX61 MIDI 2", 40 | "Yamaha MX49/MX61 MIDI 3", 41 | "Yamaha MX49/MX61 MIDI 4", 42 | "Yamaha MX49/MX61 MIDI 5"], 43 | 44 | ["Yamaha MX49/MX61 MIDI 1", 45 | "Yamaha MX49/MX61 MIDI 2", 46 | "Yamaha MX49/MX61 MIDI 3", 47 | "Yamaha MX49/MX61 MIDI 4", 48 | "Yamaha MX49/MX61 MIDI 5"]); 49 | 50 | function init() { 51 | host.getMidiInPort(0).setMidiCallback(onMidi0); 52 | host.getMidiInPort(1).setMidiCallback(onMidi1); 53 | 54 | host.getMidiInPort(4).setMidiCallback(onMidi5); 55 | host.getMidiInPort(4).setSysexCallback(onSysex5); 56 | 57 | generic = host.getMidiInPort(0).createNoteInput("Yamaha MX49/MX61"); 58 | out1 = host.getMidiOutPort(0) 59 | 60 | out2 = host.getMidiOutPort(1) 61 | out3 = host.getMidiOutPort(2) 62 | out4 = host.getMidiOutPort(3) 63 | out5 = host.getMidiOutPort(4) 64 | 65 | trackBank = host.createTrackBank(64,1,1); 66 | 67 | generic.setShouldConsumeEvents(false); 68 | 69 | out5.sendSysex("F0 43 10 7F 17 01 20 00 00 F7") 70 | 71 | sendTemplateName( "Bitwig"); 72 | sendName(8, "Vol") 73 | sendName(9, "Pan") 74 | sendName(10, "Send 1") 75 | sendName(11, "Send 2") 76 | 77 | for( var i= 0; i<8; i++) { 78 | sendValue( i, 0, macromapped[i] ); 79 | } 80 | 81 | transport = host.createTransportSection(); 82 | application = host.createApplication(); 83 | 84 | cursorTrack = host.createCursorTrack(1, 1); 85 | 86 | //primaryDevice = cursorTrack.getPrimaryDevice(); 87 | primaryDevice = cursorTrack.createCursorDevice() 88 | primaryDevice.exists().markInterested(); 89 | remoteControls = primaryDevice.createCursorRemoteControlsPage(8); 90 | 91 | primaryDevice.addNameObserver( 15, "Device", function( name ) { 92 | sendTemplateName( name ); 93 | out5.sendSysex("F0 43 10 7F 17 01 20 00 00 F7") 94 | 95 | }) 96 | 97 | for( var i=0; i<8; i++) { 98 | remoteControls.getParameter( i ).name().addValueObserver(getMacroNameObserver(i)) 99 | remoteControls.getParameter( i ).value().addValueObserver(100,getValueObserver( i )); 100 | } 101 | primaryDevice.getChannel().getVolume().addValueObserver(100,getValueObserver(8)); 102 | primaryDevice.getChannel().getPan().addValueObserver(100,getValueObserver(9)); 103 | 104 | browser = host.createPopupBrowser(); 105 | resultColumn = browser.resultsColumn(); 106 | cursorResult = resultColumn.createCursorItem(); 107 | cursorResult.addValueObserver(100, "", getSelectedNameObserver() ); 108 | cursorResultBank = resultColumn.createItemBank(1000); 109 | 110 | for (var i=0; i= 8 || macromapped[idx]); 198 | 199 | if ( idx < 8 ) { 200 | remoteControls.getParameter( idx ).value().set(data2, 128); 201 | 202 | } else if ( idx == 8 ) { 203 | primaryDevice.getChannel().getVolume().set( data2, 128 ); 204 | } else if ( idx == 9 ) { 205 | primaryDevice.getChannel().getPan().set( data2, 128 ); 206 | } else if ( idx == 10) { 207 | if ( primaryDevice.getChannel().getSend(0) != null ) { 208 | primaryDevice.getChannel().getSend(0).set( data2, 128 ); 209 | } 210 | } else if ( idx == 11 ) { 211 | if ( primaryDevice.getChannel().getSend(1) != null ) { 212 | primaryDevice.getChannel().getSend(1).set( data2, 128 ); 213 | } 214 | } 215 | } 216 | if (status == 144) { 217 | if ( data1 == 93 && data2 == 127 ) { 218 | transport.stop(); 219 | } else if ( data1 == 94 && data2 == 127 ) { 220 | transport.play(); 221 | 222 | } else if ( data1 == 60 && data2 == 127 ) { 223 | setTrackColor(10); 224 | } else if ( data1 == 61 && data2 == 127 ) { 225 | setTrackColor(11); 226 | 227 | } else if ( data1 == 62 && data2 == 127 ) { 228 | setTrackColor(13); 229 | 230 | } else if ( data1 == 63 && data2 == 127 ) { 231 | setTrackColor(23); 232 | 233 | } else if ( data1 == 64 && data2 == 127 ) { 234 | setTrackColor(6); 235 | 236 | } else if ( data1 == 65 && data2 == 127 ) { 237 | setTrackColor(16); 238 | 239 | 240 | } else if ( data1 == 118 && data2 == 127 ) { 241 | application.createAudioTrack(0); 242 | host.scheduleTask( function() { 243 | trackBank.scrollToChannel(0); 244 | c = RGB_COLORS[Math.floor(Math.random()*RGB_COLORS.length)] 245 | trackBank.getChannel(0).color().set(c[0], c[1], c[2]) 246 | },100); 247 | 248 | } else if ( data1 == 119 && data2 == 127 ) { 249 | application.createInstrumentTrack(0); 250 | host.scheduleTask( function() { 251 | trackBank.scrollToChannel(0); 252 | c = RGB_COLORS[Math.floor(Math.random()*RGB_COLORS.length)] 253 | trackBank.getChannel(0).color().set(c[0], c[1], c[2]) 254 | },100); 255 | 256 | } else if ( data1 == 54 && data2 == 127 ) { 257 | createSpecialTrack("HW Instrument"); 258 | } else if ( data1 == 55 && data2 == 127 ) { 259 | createSpecialTrack("ACE.64"); 260 | } else if ( data1 == 56 && data2 == 127 ) { 261 | createSpecialTrack("Repro-1.64"); 262 | } else if ( data1 == 57 && data2 == 127 ) { 263 | createSpecialTrack("Polysynth"); 264 | } else if ( data1 == 58 && data2 == 127 ) { 265 | createSpecialTrack("Drum Machine"); 266 | } else if ( data1 == 59 && data2 == 127 ) { 267 | if (primaryDevice.exists().get()) { 268 | primaryDevice.browseToReplaceDevice(); 269 | } else { 270 | cursorTrack.browseToInsertAtStartOfChain(); 271 | } 272 | 273 | } 274 | // generic.sendRawMidiEvent( status, data1, data2 ); 275 | } 276 | } 277 | 278 | function createSpecialTrack(pluginName) { 279 | application.createInstrumentTrack(0); 280 | 281 | host.scheduleTask( function() { 282 | trackBank.scrollToChannel(0); 283 | c = RGB_COLORS[Math.floor(Math.random()*RGB_COLORS.length)] 284 | trackBank.getChannel(0).color().set(c[0], c[1], c[2]) 285 | trackBank.getChannel(0).browseToInsertAtStartOfChain(); 286 | application.arrowKeyDown(); 287 | host.scheduleTask( function() { 288 | for (var i=0; i " +item.name().getValue()); 293 | if (name == pluginName) break; 294 | } 295 | browser.commit(); 296 | t = trackBank.getChannel(0); 297 | t.selectInMixer(); 298 | 299 | }, 300); 300 | }, 100); 301 | 302 | } 303 | 304 | function setTrackColor(color) { 305 | c = RGB_COLORS[color] 306 | cursorTrack.color().set(c[0], c[1], c[2]) 307 | } 308 | 309 | function exit() 310 | { 311 | } 312 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 ngradwohl 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bitwig_scripts 2 | ============== 3 | 4 | Scripts For Bitwig 5 | -------------------------------------------------------------------------------- /sfz2multisample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | net.localguru.sfz2multisample 5 | Sfz2Multisample 6 | jar 7 | 1.0.2 8 | Sfz2Multsample 9 | 10 | 11 | local jar 12 | file://${basedir}/repo 13 | 14 | 15 | 16 | UTF-8 17 | 18 | 19 | 20 | junit 21 | junit 22 | 3.8.1 23 | test 24 | 25 | 26 | 27 | 28 | 29 | org.codehaus.mojo 30 | exec-maven-plugin 31 | 1.2 32 | 33 | net.localguru.sfz2multisample.Sfz2Multisample 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-shade-plugin 39 | 1.4 40 | 41 | 42 | package 43 | 44 | shade 45 | 46 | 47 | 48 | 49 | 50 | net.localguru.sfz2multisample.Sfz2Multisample 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-compiler-plugin 61 | 2.1 62 | 63 | 1.6 64 | 1.6 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /sfz2multisample/src/main/java/net/localguru/sfz2multisample/Sfz2Multisample.java: -------------------------------------------------------------------------------- 1 | package net.localguru.sfz2multisample; 2 | import java.io.*; 3 | import java.util.*; 4 | import java.util.zip.*; 5 | import java.util.StringTokenizer; 6 | import javax.sound.sampled.*; 7 | import javax.sound.sampled.spi.*; 8 | 9 | public class Sfz2Multisample { 10 | public static void main( String args[] ) { 11 | Sfz2Multisample main = new Sfz2Multisample(); 12 | 13 | String sfz_name = args[0]; 14 | String multi_name = sfz_name.replace("sfz", "multisample"); 15 | String sfz = main.loadSfz( sfz_name ); 16 | System.out.println( sfz_name ); 17 | 18 | // System.out.println( sfz ); 19 | 20 | String xml = "\n"+ 21 | "\n" + 22 | "Bitwig Studio\n" + 23 | "\n"+ 24 | "SFZ2Multisample\n"+ 25 | "\n"+ 26 | "\n"+ 27 | "\n"; 28 | 29 | StringTokenizer tok = new StringTokenizer( sfz, "<[^>]*>" ); 30 | List sampleNames = new ArrayList(); 31 | String default_path=""; 32 | 33 | String mode = ""; 34 | while ( tok.hasMoreTokens()) { 35 | String res = tok.nextToken(); 36 | if ( "region".equals( res ) || "group".equals( res ) || "control".equals( res )) { 37 | mode = res; 38 | continue; 39 | } 40 | String[] tmp = res.trim().split(" "); 41 | Map attributes = new HashMap(); 42 | String sample = "" ; 43 | boolean s =false; 44 | String key = ""; 45 | for ( String t : tmp ) { 46 | if ( t.indexOf("=") == -1 && s ) { 47 | sample += t + " "; 48 | continue; 49 | } 50 | // System.out.println( "T: " + t ); 51 | String[] data = t.split("="); 52 | if (data[0].trim().equals("")) continue; 53 | key = data[0]; 54 | if (!data[0].trim().equals( "sample") && !data[0].trim().equals("default_path")) { 55 | attributes.put(data[0].trim(), data[1].trim()); 56 | } else { 57 | sample = data[1].trim() + " "; 58 | s = true; 59 | } 60 | } 61 | if ( "default_path".equals( key )) { 62 | default_path = sample.trim(); 63 | System.out.println( "DP: " + default_path ); 64 | } 65 | if ( default_path != null && !"".equals( default_path )) { 66 | sample = default_path + sample; 67 | } 68 | sample = sample.trim().replace("\\","/"); 69 | if ( "sample".equals(key)) { 70 | attributes.put( "sample", sample); 71 | sampleNames.add( sample); 72 | } 73 | 74 | if ( attributes.get("key") != null ) { 75 | String k = attributes.get("key"); 76 | attributes.put("hikey", k); 77 | attributes.put("lokey", k); 78 | attributes.put("pitch_keycenter", k); 79 | 80 | } 81 | 82 | if ( mode.equals( "region" )) { 83 | if ( attributes.get("sample") == null ) { 84 | attributes.put( "sample", sample); 85 | sampleNames.add( sample); 86 | } 87 | float end = 1000F; 88 | try { 89 | System.out.println( "Sample: " + attributes.get("sample")); 90 | AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(sample)); 91 | long len = audioInputStream.getFrameLength(); 92 | AudioFormat format = audioInputStream.getFormat(); 93 | float fr = format.getFrameRate(); 94 | end = len; 95 | 96 | } catch ( Exception e ) { 97 | e.printStackTrace(); 98 | } 99 | String[] parts = sample.split("/"); 100 | 101 | xml+="\n"; 102 | xml+="\n"; 103 | xml+="\n"; 104 | xml+="\n"; 105 | xml+="\n"; 106 | } 107 | } 108 | xml+="\n"; 109 | xml+="\n"; 110 | 111 | List sampleNamesSeen = new ArrayList(); 112 | 113 | try { 114 | ZipOutputStream result = new ZipOutputStream( new BufferedOutputStream( new FileOutputStream( multi_name ))); 115 | for ( String name: sampleNames ) { 116 | if ( sampleNamesSeen.contains( name )) { 117 | continue; 118 | } 119 | sampleNamesSeen.add( name ); 120 | try { 121 | BufferedInputStream fis = new BufferedInputStream( new FileInputStream( name ), 4096); 122 | String[] parts = name.split("/"); 123 | System.out.println(name); 124 | result.putNextEntry( new ZipEntry( parts[ parts.length-1])); 125 | int count = 0; 126 | byte[] data = new byte[4096]; 127 | while((count=fis.read( data, 0, 4096 )) != -1 ) { 128 | result.write( data,0,count); 129 | } 130 | fis.close(); 131 | } catch ( Exception e ) { 132 | e.printStackTrace(); 133 | } 134 | } 135 | 136 | result.putNextEntry( new ZipEntry( "multisample.xml")); 137 | byte[] data = xml.getBytes( "UTF-8"); 138 | 139 | result.write( data, 0, data.length); 140 | 141 | 142 | result.close(); 143 | } catch ( Exception ioe ) { 144 | ioe.printStackTrace(); 145 | } 146 | 147 | 148 | 149 | 150 | } 151 | 152 | public String loadSfz( String filename ) { 153 | StringBuilder b = new StringBuilder(); 154 | try { 155 | BufferedReader reader = new BufferedReader( new InputStreamReader( new FileInputStream( filename ))); 156 | String l = null; 157 | while ((l = reader.readLine()) != null ) { 158 | String content[] = l.split("//"); 159 | if ( content.length > 0 ) { 160 | System.out.println( content[0] ); 161 | b.append(content[0]); 162 | b.append(" "); 163 | } 164 | } 165 | reader.close(); 166 | } catch ( IOException ioe ) { 167 | ioe.printStackTrace(); 168 | } 169 | return b.toString(); 170 | } 171 | 172 | 173 | } 174 | --------------------------------------------------------------------------------