Skip to content

Commit

Permalink
Merge pull request #3 from elafarge/etienne/add-nested-device-navigation
Browse files Browse the repository at this point in the history
Add double-click feature to quick-select a device
  • Loading branch information
elafarge committed Sep 2, 2015
2 parents 7e93116 + e7aee33 commit bf6337d
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 7 deletions.
9 changes: 5 additions & 4 deletions TODO List.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
TODO List
---------

Feel free to pick up a task and implementing if you don't have anything else to do :)
Feel free to pick up a task and implement it.

New Features
============
Expand All @@ -16,11 +16,12 @@ New Features
Launchcontrol). That would be cool for a mixing session where one might want to be able to
switch between effects only. Extending the existing UserMode should be a good approach.
* Track navigation synchronized with the Novation Launchpad (make a PR against their repo).
* Scroll in sends (should work out of the box the the Bitwig 1.1 minor release).
* Scroll in sends: investigate what doesn't work and fix it
* Save the state of the launchpad when the script is exited and retrieve it when it wakes up
(state = physical values of all the knobs and faders for a direct takeover when starting the
script). Apparently the new Bitwig API has bindings to write on disk, otherwise a TCP
service will be required.
script). Since Bitwig's API doesn't seem to provide a good way to write on DIsk, I was thinking
of hiding the state in controller parameters on `exit()` and to fetch them on `start()` and then
get them deleted to stop the end user from witnessing this dirty trick in the UI.


Code improvements
Expand Down
13 changes: 13 additions & 0 deletions launchcontrolxl/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ Controller = function(bw_host){
this.boards = [];
this.current_board_number = -1;

// Let's set the notification levels
log_info("Setting notification settings");
this.notification_settings = this.host.getNotificationSettings();
this.notification_settings.getUserNotificationsEnabled().set(true);
this.notification_settings.setShouldShowSelectionNotifications(false);
this.notification_settings.setShouldShowChannelSelectionNotifications(false);
this.notification_settings.setShouldShowTrackSelectionNotifications(false);
this.notification_settings.setShouldShowDeviceSelectionNotifications(false);
this.notification_settings.setShouldShowDeviceLayerSelectionNotifications(false);
this.notification_settings.setShouldShowPresetNotifications(false);
this.notification_settings.setShouldShowMappingNotifications(false);
this.notification_settings.setShouldShowValueNotifications(false);

// Unfortunately we can have only one control section per controller so we
// have to create it here once and for all for the 8 user channels
this.user_control_count = Board.CONTROL_COUNT*8 + 2*LiveBoard.USER_CONTROL_COUNT;
Expand Down
41 changes: 39 additions & 2 deletions launchcontrolxl/device_board.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ DeviceBoard = function(controller, channel){
}
};

this.slot_names = [];
this.select_slot = -1;
this.cursor_slot = null;

// Let's register our observers
var board = this;
for(var i=0; i<8; i++){
Expand Down Expand Up @@ -104,6 +108,22 @@ DeviceBoard = function(controller, channel){
SoftTakeoverBoard.prototype.valueChangedCallback.call(board, ["buttons", 0, 4],
yes? 127 : 0);
});

// Callbacks for navigation accross slots
this.controller.cursor_device.addSlotsObserver(function(slots){
board.slot_names = slots;
});

this.controller.cursor_device.hasSlots().addValueObserver(function(has_slots){
if(has_slots) {
board.selected_slot = 0;
board.cursor_slot = board.controller.cursor_device.getCursorSlot();
board.cursor_slot.selectSlot(board.slot_names[board.selected_slot]);
} else {
board.selected_slot = -1;
board.cursor_slot = null;
}
});
}
};

Expand Down Expand Up @@ -175,6 +195,25 @@ DeviceBoard.prototype.onMidi = function(status, data1, data2){
}
}

// Nested navigation
if(path[0] == "action" && Math.floor(status/16) != 8 && this.cursor_slot !== null){
switch(path[1]){
case "mute":
this.controller.cursor_device.selectParent();
break;
case "solo":
this.controller.cursor_device.selectFirstInSlot(
this.slot_names[this.selected_slot]);
break;
case "record":
this.selected_slot++;
if(this.selected_slot >= this.slot_names.length)
this.selected_slot = 0;
this.cursor_slot.selectSlot(this.slot_names[this.selected_slot]);
break;
}
}

// Tweak the right control
if(this.hasControl(path)){
if(path[0] == "faders"){
Expand Down Expand Up @@ -275,8 +314,6 @@ DeviceBoard.prototype.getWeakColorBits = function(path){
}
}

// TODO: Action buttons

// The buttons
if(path[0] == "buttons"){
if (path[2] < 4)
Expand Down
26 changes: 25 additions & 1 deletion launchcontrolxl/mixer_board.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ MixerBoard = function(controller, channel){

this.device_mode = false;
this.selected_track_index = 0;
this.last_hit = null;
this.consecutive_hits = 0;

this.button_states = {
"mute": [false, false, false, false, false, false, false, false],
Expand Down Expand Up @@ -177,7 +179,12 @@ MixerBoard.prototype.onMidi = function(status, data1, data2){
}

if(path[0] == "buttons" && path[1] === 0 && Math.floor(status/16) != 8){
this.controller.track_bank.getTrack(path[2]).select();
if(this.last_hit !== null && this.last_hit === path[2])
this.enableDeviceMode();
else {
this.controller.track_bank.getTrack(path[2]).select();
this.bowLastHitString(path[2]);
}
}

// And let's update the "hasControl" (in case we caught up)
Expand All @@ -202,6 +209,21 @@ MixerBoard.prototype.disable = function(){
Board.prototype.disable.call(this);
};

MixerBoard.prototype.bowLastHitString = function(button_number){
if(this.last_hit === button_number)
this.consecutive_hits++;
else
this.consecutive_hits = 1;
this.last_hit = button_number;
var board = this;
this.controller.host.scheduleTask(function(btn_nb){
if(board.last_hit === btn_nb)
board.consecutive_hits--;
if(board.consecutive_hits === 0)
board.last_hit = null;
}, [button_number], 500);
};

////////////////////////////////////////////////////////////////////////////////
///////////// Led color and manipulations ///////////////
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -300,6 +322,7 @@ MixerBoard.prototype.showSelectedMode = function(){

MixerBoard.prototype.enableDeviceMode = function(){
this.setSoftValue(["action", "device"], 127);
this.updateLed(["action", "device"]);
this.disableAssignmentVisualFeedback();
this.device_mode = true;
this.enableAssignmentVisualFeedback();
Expand All @@ -308,6 +331,7 @@ MixerBoard.prototype.enableDeviceMode = function(){

MixerBoard.prototype.enableMixerMode = function(){
this.setSoftValue(["action", "device"], 0);
this.updateLed(["action", "device"]);
this.disableAssignmentVisualFeedback();
this.device_mode = false;
this.enableAssignmentVisualFeedback();
Expand Down

0 comments on commit bf6337d

Please sign in to comment.