Skip to content

Commit e8ce290

Browse files
authored
Merge pull request #20 from brummbrum/MoreButtonLights
More button lights
2 parents feaeabf + afb0f52 commit e8ce290

File tree

1 file changed

+54
-15
lines changed

1 file changed

+54
-15
lines changed

src/niMidi.cpp

+54-15
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ const unsigned char CMD_CHANGE_SEL_TRACK_VOLUME = 0x64;
8181
const unsigned char CMD_CHANGE_SEL_TRACK_PAN = 0x65;
8282
const unsigned char CMD_TOGGLE_SEL_TRACK_MUTE = 0x66;
8383
const unsigned char CMD_TOGGLE_SEL_TRACK_SOLO = 0x67;
84-
const unsigned char CMD_SEL_TRACK_AVAILABLE = 0x68; // ToDo: ?
85-
const unsigned char CMD_SEL_TRACK_MUTED_BY_SOLO = 0x69; // ToDo: ?
84+
const unsigned char CMD_SEL_TRACK_AVAILABLE = 0x68;
85+
const unsigned char CMD_SEL_TRACK_MUTED_BY_SOLO = 0x69;
8686

8787
const unsigned char TRTYPE_UNSPEC = 1;
8888
const unsigned char TRTYPE_MASTER = 6;
@@ -97,6 +97,7 @@ const bool HIDE_MUTED_BY_SOLO = false;
9797
static int g_trackInFocus = 0;
9898
static bool g_anySolo = false;
9999
static int g_soloStateBank[BANK_NUM_TRACKS] = { 0 };
100+
static bool g_muteStateBank[BANK_NUM_TRACKS] = { false };
100101

101102
signed char convertSignedMidiValue(unsigned char value) {
102103
// Convert a signed 7 bit MIDI value to a signed char.
@@ -154,6 +155,8 @@ class NiMidiSurface: public BaseSurface {
154155
NiMidiSurface(int inDev, int outDev)
155156
: BaseSurface(inDev, outDev) {
156157
this->_sendCc(CMD_HELLO, 0);
158+
this->_sendCc(CMD_UNDO, 1);
159+
this->_sendCc(CMD_REDO, 1);
157160
}
158161

159162
virtual ~NiMidiSurface() {
@@ -200,7 +203,7 @@ class NiMidiSurface: public BaseSurface {
200203
}
201204
}
202205

203-
// ToDo: add more button lights: AUTO, tbd: undo/redo, clear, quantize, tempo
206+
// ToDo: add more button lights: AUTO, clear, quantize, 4D encoder navigation (blue LEDs)
204207

205208
virtual void SetTrackListChange() override {
206209
// If tracklist changes update Mixer View and ensure sanity of track and bank focus
@@ -229,27 +232,43 @@ class NiMidiSurface: public BaseSurface {
229232
// SetSurfaceSelected() is less economical because it will be called multiple times (also for unselecting tracks).
230233
// However, SetSurfaceSelected() is the more robust choice because of: https://forum.cockos.com/showpost.php?p=2138446&postcount=15
231234

232-
// Note: SetSurfaceSelected is also called on project tab change
235+
// Note: SetSurfaceSelected is also called on project tab change or when record arming. However, <selected> will only be true if a track selection has changed.
233236
this->_metronomeUpdate(); //check if metronome status has changed when switching project tabs
237+
// Track selection has changed:
234238
if (selected) {
235239
int id = CSurf_TrackToID(track, false);
236240
int numInBank = id % BANK_NUM_TRACKS;
237241
int oldBankStart = this->_bankStart;
238242
this->_bankStart = id - numInBank;
239243
if (this->_bankStart != oldBankStart) {
240244
// Update everything
241-
this->_allMixerUpdate();
245+
this->_allMixerUpdate(); // Note: this will also update the g_muteStateBank and g_soloStateBank caches
242246
}
243247
else {
244248
// Update track names
245249
this->_namesMixerUpdate();
246250
}
247251
// Let Keyboard know about changed track selection
248252
this->_sendSysex(CMD_TRACK_SELECTED, 1, numInBank);
249-
// Set KK Instance Focus
250253
g_trackInFocus = id;
251-
this->_sendSysex(CMD_SET_KK_INSTANCE, 0, 0,
252-
getKkInstanceName(track));
254+
if (g_trackInFocus != 0) {
255+
// Mark selected track as available and update Mute and Solo Button lights
256+
this->_sendSysex(CMD_SEL_TRACK_AVAILABLE, 1, 0);
257+
this->_sendSysex(CMD_TOGGLE_SEL_TRACK_MUTE, g_muteStateBank[numInBank] ? 1 : 0, 0);
258+
this->_sendSysex(CMD_TOGGLE_SEL_TRACK_SOLO, g_soloStateBank[numInBank], 0);
259+
if (g_anySolo) {
260+
this->_sendSysex(CMD_SEL_TRACK_MUTED_BY_SOLO, (g_soloStateBank[numInBank] == 0) ? 1 : 0, 0);
261+
}
262+
else {
263+
this->_sendSysex(CMD_SEL_TRACK_MUTED_BY_SOLO, 0, 0);
264+
}
265+
}
266+
else {
267+
// Master track not available for Mute and Solo
268+
this->_sendSysex(CMD_SEL_TRACK_AVAILABLE, 0, 0);
269+
}
270+
// Set KK Instance Focus
271+
this->_sendSysex(CMD_SET_KK_INSTANCE, 0, 0, getKkInstanceName(track));
253272
}
254273
}
255274

@@ -278,28 +297,46 @@ class NiMidiSurface: public BaseSurface {
278297
virtual void SetSurfaceMute(MediaTrack* track, bool mute) override {
279298
int id = CSurf_TrackToID(track, false);
280299
if (id == g_trackInFocus) {
281-
this->_sendCc(CMD_TOGGLE_SEL_TRACK_MUTE, mute ? 1 : 0); // ToDo: does not work yet - why? Is an extra track_available required? Or instance? Or SysEx?
300+
this->_sendSysex(CMD_TOGGLE_SEL_TRACK_MUTE, mute ? 1 : 0, 0);
282301
}
283302
if ((id >= this->_bankStart) && (id <= this->_bankEnd)) {
284303
int numInBank = id % BANK_NUM_TRACKS;
304+
g_muteStateBank[numInBank] = mute;
285305
this->_sendSysex(CMD_TRACK_MUTED, mute ? 1 : 0, numInBank);
286306
}
287307
}
288308

289309
virtual void SetSurfaceSolo(MediaTrack* track, bool solo) override {
290310
// Note: Solo in Reaper can have different meanings (Solo In Place, Solo In Front and much more -> Reaper Preferences)
291311
int id = CSurf_TrackToID(track, false);
292-
// Ignore solo on master, id = 0 is only used as an "any track is soloed" indicator
312+
313+
// Ignore solo on master, id = 0 is only used as an "any track is soloed" change indicator
293314
if (id == 0) {
294315
// If g_anySolo state has changed update the tracks' muted by solo states within the current bank
295316
if (g_anySolo != solo) {
296317
g_anySolo = solo;
297318
this->_allMixerUpdate(); // Everything needs to be updated, not good enough to just update muted_by_solo states
298319
}
320+
// If any track is soloed the currently selected track will be muted by solo unless it is also soloed
321+
if (g_trackInFocus > 0) {
322+
if (g_anySolo) {
323+
MediaTrack* track = CSurf_TrackFromID(g_trackInFocus, false);
324+
if (!track) {
325+
return;
326+
}
327+
int soloState = *(int*)GetSetMediaTrackInfo(track, "I_SOLO", nullptr);
328+
this->_sendSysex(CMD_SEL_TRACK_MUTED_BY_SOLO, (soloState == 0) ? 1 : 0, 0);
329+
}
330+
else {
331+
this->_sendSysex(CMD_SEL_TRACK_MUTED_BY_SOLO, 0, 0);
332+
}
333+
}
299334
return;
300335
}
336+
337+
// Solo state has changed on individual tracks:
301338
if (id == g_trackInFocus) {
302-
this->_sendCc(CMD_TOGGLE_SEL_TRACK_SOLO, solo ? 1 : 0); // ToDo: Button light does not work yet - why? Is an extra track_available required? Or instance? Or SysEx?
339+
this->_sendSysex(CMD_TOGGLE_SEL_TRACK_SOLO, solo ? 1 : 0, 0);
303340
}
304341
if ((id >= this->_bankStart) && (id <= this->_bankEnd)) {
305342
int numInBank = id % BANK_NUM_TRACKS;
@@ -340,7 +377,6 @@ class NiMidiSurface: public BaseSurface {
340377
void _onMidiEvent(MIDI_event_t* event) override {
341378
if (event->midi_message[0] != MIDI_CC) {
342379
return;
343-
// ToDo: Analyze other incoming MIDI messages too, like Sysex, MCU etc
344380
}
345381
unsigned char& command = event->midi_message[1];
346382
unsigned char& value = event->midi_message[2];
@@ -413,6 +449,7 @@ class NiMidiSurface: public BaseSurface {
413449
// ToDo: Scrubbing very slow. Rather than just amplifying this value
414450
// have to evaluate incoming MIDI stream to allow for both fine as well
415451
// coarse scrubbing
452+
// Or move to next beat, bar etc
416453
CSurf_ScrubAmt(convertSignedMidiValue(value));
417454
break;
418455
case CMD_TRACK_SELECTED:
@@ -513,7 +550,7 @@ class NiMidiSurface: public BaseSurface {
513550
}
514551
// If no tracks are soloed then muted tracks shall show no peaks
515552
else {
516-
if (*(bool*)GetSetMediaTrackInfo(track, "B_MUTE", nullptr)) {
553+
if (g_muteStateBank[numInBank]) {
517554
peakBank[j] = 1;
518555
peakBank[j + 1] = 1;
519556
}
@@ -526,8 +563,8 @@ class NiMidiSurface: public BaseSurface {
526563
}
527564
}
528565
else {
529-
// Tracks muted by solo show peaks but they appear greyed out. Muted tracks that are NOT soloed shall show no peaks.
530-
if ((g_soloStateBank[numInBank] == 0) && (*(bool*)GetSetMediaTrackInfo(track, "B_MUTE", nullptr))) {
566+
// Muted tracks that are NOT soloed shall show no peaks. Tracks muted by solo show peaks but they appear greyed out.
567+
if ((g_soloStateBank[numInBank] == 0) && (g_muteStateBank[numInBank])) {
531568
peakBank[j] = 1;
532569
peakBank[j + 1] = 1;
533570
}
@@ -553,6 +590,7 @@ class NiMidiSurface: public BaseSurface {
553590
this->_bankEnd = this->_bankStart + BANK_NUM_TRACKS - 1; // avoid ambiguity: track counting always zero based
554591
int numTracks = CSurf_NumTracks(false);
555592
// Set bank select button lights
593+
// ToDo: Consider optimizing this piece of code
556594
int bankLights = 3; // left and right on
557595
if (numTracks < BANK_NUM_TRACKS) {
558596
bankLights = 0; // left and right off
@@ -613,6 +651,7 @@ class NiMidiSurface: public BaseSurface {
613651
int selected = *(int*)GetSetMediaTrackInfo(track, "I_SELECTED", nullptr);
614652
this->_sendSysex(CMD_TRACK_SELECTED, selected, numInBank);
615653
bool muted = *(bool*)GetSetMediaTrackInfo(track, "B_MUTE", nullptr);
654+
g_muteStateBank[numInBank] = muted;
616655
this->_sendSysex(CMD_TRACK_MUTED, muted ? 1 : 0, numInBank);
617656
double volume = *(double*)GetSetMediaTrackInfo(track, "D_VOL", nullptr);
618657
char volText[64];

0 commit comments

Comments
 (0)