diff --git a/src/app/devices/controller.device.ts b/src/app/devices/controller.device.ts index 7a68a6d..c3b18e8 100644 --- a/src/app/devices/controller.device.ts +++ b/src/app/devices/controller.device.ts @@ -450,19 +450,67 @@ Object.defineProperty (controllerDevice, 'isMultipleMode', { }); controllerDevice.setLayerMode = function () { - this.attachButtonsToNeuron (); + this.initializeLayerMode (); + this.attachButtonsToLayer (); this.attachControlsToLayer (); }; -controllerDevice.attachControlsToLayer = function (): void { - const neurons = networkState.neurons[networkState.selectedLayerIndex]; - +controllerDevice.initializeLayerMode = function () { + // all nodes this.playNotes ({ firstNote: this.settings.lights.first, lastNote: this.settings.lights.last, color: this.settings.colorByState.layerMode, }); + // color enabled neurons in green + setTimeout (() => { + const neurons = networkState.neurons[networkState.selectedLayerIndex]; + neurons.forEach ((neuron) => { + if (neuron.isEnabled === true) { + const { neuronIndex } = networkState.getNeuronAndLayerIndexes (parseInt (neuron.id)); + this.playNote ({ + note: this.settings.rows.firstButtons[neuronIndex - 1], + color: this.settings.colorByState.selectMode, + }); + this.playNote ({ + note: this.settings.rows.secondButtons[neuronIndex - 1], + color: this.settings.colorByState.selectMode, + }); + } + }); + }, this.settings.time.wait); +}; + +controllerDevice.attachButtonsToLayer = function (): void { + this.addNoteListener ('on', (e) => { + const inputNote = parseInt (e.note.number); + const index = this.settings.rows.secondButtons.indexOf (inputNote); + if (index !== -1) { + this.shifted[index] = true; + this.playNote ({ + note: inputNote, + color: this.settings.colorByState.shift, + }); + } + }); + + this.addNoteListener ('off', (e) => { + const inputNote = parseInt (e.note.number); + const index = this.settings.rows.secondButtons.indexOf (inputNote); + if (index !== -1) { + this.shifted[index] = false; + this.playNote ({ + note: inputNote, + color: this.settings.colorByState.layerMode, + }); + } + }); +}; + +controllerDevice.attachControlsToLayer = function (): void { + const neurons = networkState.neurons[networkState.selectedLayerIndex]; + this.addControlListener ((e) => { const inputNote = e.controller.number; @@ -484,7 +532,7 @@ controllerDevice.attachControlsToLayer = function (): void { ); const learningRate = selectCardUi.options.learningRate[learningRateOptionIndex]; - + if (learningRate !== neurons[index].learningRate) { networkState.setLearningRate (parseInt (neurons[index].id), learningRate); layerCardUi.setLearningRate (index, learningRate); diff --git a/src/app/devices/known-devices/known-devices.ts b/src/app/devices/known-devices/known-devices.ts index eb45171..2acbc26 100644 --- a/src/app/devices/known-devices/known-devices.ts +++ b/src/app/devices/known-devices/known-devices.ts @@ -1,8 +1,10 @@ import { Controller, Selector } from '../device/device.types'; import { novationLaunchpadX } from './novation-launchpad-x'; import { novationLaunchControlXl } from './novation-launch-control-xl'; +import { novationLaunchpadMini } from './novation-launchpad-mini'; export const knownDevices: (Selector|Controller)[] = [ novationLaunchpadX, novationLaunchControlXl, + novationLaunchpadMini, ]; diff --git a/src/app/devices/known-devices/novation-launchpad-mini.ts b/src/app/devices/known-devices/novation-launchpad-mini.ts new file mode 100644 index 0000000..aef2157 --- /dev/null +++ b/src/app/devices/known-devices/novation-launchpad-mini.ts @@ -0,0 +1,73 @@ +import { Selector, DeviceCategory } from '../device/device.types'; + +/** + * Novation Launchpad Mini + * + * @see http://leemans.ch/latex/doc_launchpad-programmers-reference.pdf + */ +export const novationLaunchpadMini: Selector = { + category: DeviceCategory.select, + manufacturer: 'Focusrite A.E. Ltd', + name: 'Launchpad Mini', + channels: { + input: 'all', + output: 1, + }, + lights: { + first: 0, + last: 120, + }, + grid: [ + // describe columns + // top down then left to right + [0, 16, 32, 48, 64, 80, 96, 112], + [1, 17, 33, 49, 65, 81, 97, 113], + [2, 18, 34, 50, 66, 82, 98, 114], + [3, 19, 35, 51, 67, 83, 99, 115], + [4, 20, 36, 52, 68, 84, 100, 116], + [5, 21, 37, 53, 69, 85, 101, 117], + [6, 22, 38, 54, 70, 86, 102, 118], + [7, 23, 39, 55, 71, 87, 103, 119], + ], + functionKeys: { + firstRow: [91, 92, 93, 94, 95, 96, 97, 98], // not available + lastColumn: [8, 24, 40, 56, 72, 88, 104, 120], + }, + colors: { + black: 0, + off: 0, + red: 15, + amber: 63, + yellow: 62, + green: 60, + }, + get colorByState () { + return { + inputOn: this.colors.red, + inputOff: this.colors.black, + neuronOn: this.colors.green, + neuronOff: this.colors.black, + neuronSelected: this.colors.yellow, + outputWeightOn: this.colors.red, + outputWeightOff: this.colors.black, + playbackOn: this.colors.green, + playbackOff: this.colors.red, + layerOn: this.colors.amber, + layerOff: this.colors.black, + }; + }, + time: { + wait: 200, + defaultDuration: 500, + longClick: 400, + }, + get bootSequence () { + return { + color: this.colors.red, + sysex: { + manufacturer: 0, + data: [32, 41, 2, 12, 14, 1], + }, + }; + }, +}; diff --git a/src/app/devices/selector.device.ts b/src/app/devices/selector.device.ts index 2dd99dd..9b624f1 100644 --- a/src/app/devices/selector.device.ts +++ b/src/app/devices/selector.device.ts @@ -336,8 +336,14 @@ selectorDevice.attachLayers = function () { // clear clearTimeout (clickTimer); clickTimer = null; - // payload networkState.toggleLayer (index); + if (networkState.selectedLayerIndex !== null) { + networkState.resetLayerSelection (); + this.renderLayers (); + controllerDevice.updateMode (); + layerCardUi.updateCard (); + playgroundUi.renderLayers (); + } }, this.settings.time.longClick); } @@ -369,6 +375,10 @@ selectorDevice.updateLightPlayback = function () { }; selectorDevice.renderLayers = function () { + if (!this.isInitialized) { + return; + } + const layerPads = this.settings.functionKeys.firstRow.slice (1, -1); const index = networkState.selectedLayerIndex; diff --git a/src/app/state/network.state.ts b/src/app/state/network.state.ts index 97c7192..adfca3f 100644 --- a/src/app/state/network.state.ts +++ b/src/app/state/network.state.ts @@ -317,3 +317,7 @@ networkState.setLayer = function (index: number) { } return this.selectedLayerIndex; }; + +networkState.resetLayerSelection = function () { + this.selectedLayerIndex = null; +}; diff --git a/src/app/ui/playground.ui.ts b/src/app/ui/playground.ui.ts index abcb286..bf21280 100644 --- a/src/app/ui/playground.ui.ts +++ b/src/app/ui/playground.ui.ts @@ -4,6 +4,7 @@ import { mappingsUi } from './mappings.ui'; import { networkState } from '../state/network.state'; import { layerCardUi } from './layer-card.ui'; import { selectorDevice } from '../devices/selector.device'; +import { controllerDevice } from '../devices/controller.device'; export const playgroundUi = Object.create (null); @@ -120,6 +121,7 @@ playgroundUi.attachLayers = function () { this.renderLayers (); layerCardUi.updateCard (); selectorDevice.renderLayers (); + controllerDevice.updateMode (); }; }); };