Skip to content

Commit

Permalink
Allow selection of custom row offset instead of octave row offset.
Browse files Browse the repository at this point in the history
  • Loading branch information
gbevin committed Mar 28, 2016
1 parent 8b499e9 commit 204722c
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 16 deletions.
9 changes: 6 additions & 3 deletions linnstrument-firmware.ino
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,9 @@ char* OSVersionBuild = ".028";
#define COLOR_BLACK 7

// Special row offset values, for legacy reasons
#define ROWOFFSET_NOOVERLAP 0x00
#define ROWOFFSET_ZERO 0x7f
#define ROWOFFSET_NOOVERLAP 0x00
#define ROWOFFSET_OCTAVECUSTOM 0x0c
#define ROWOFFSET_ZERO 0x7f

#define LED_FLASH_DELAY 50000 // the time before a led is turned off when flashing or pulsing, in microseconds

Expand Down Expand Up @@ -420,7 +421,8 @@ enum DisplayMode {
displayPromo,
displayEditAudienceMessage,
displaySleep,
displaySleepConfig
displaySleepConfig,
displayRowOffset
};
DisplayMode displayMode = displayNormal;

Expand Down Expand Up @@ -620,6 +622,7 @@ struct GlobalSettings {
int mainNotes[12]; // bitmask array that determines which notes receive "main" lights
int accentNotes[12]; // bitmask array that determines which notes receive accent lights (octaves, white keys, black keys, etc.)
byte rowOffset; // interval between rows. 0 = no overlap, 1-12 = interval, 13 = guitar
byte customRowOffset; // the custom row offset that can be configured at the location of the octave setting
VelocitySensitivity velocitySensitivity; // See VelocitySensitivity values
unsigned short minForVelocity; // 1-127
unsigned short maxForVelocity; // 1-127
Expand Down
20 changes: 18 additions & 2 deletions ls_displayModes.ino
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ displayPromo : display promotion animation
displayEditAudienceMessage : edit an audience message
displaySleep : sleeping
displaySleepConfig : sleep mode configuration
displayRowOffset : custom row offset selection
These routines handle the painting of these display modes on LinnStument's 208 LEDs.
**************************************************************************************************/
Expand Down Expand Up @@ -160,6 +161,9 @@ void updateDisplay() {
case displaySleepConfig:
paintSleepConfig();
break;
case displayRowOffset:
paintRowOffset();
break;
}

updateSwitchLeds();
Expand Down Expand Up @@ -822,6 +826,11 @@ void paintSleepConfig() {
}
}

void paintRowOffset() {
clearDisplay();
paintNumericDataDisplay(globalColor, Global.customRowOffset, 0, false);
}

void paintMinUSBMIDIIntervalDisplay() {
clearDisplay();
paintNumericDataDisplay(globalColor, Device.minUSBMIDIInterval, 0, true);
Expand Down Expand Up @@ -1155,8 +1164,8 @@ void paintGlobalSettingsDisplay() {
case 7: // +7
lightLed(5, 2);
break;
case 12: // +octave
lightLed(6, 2);
case ROWOFFSET_OCTAVECUSTOM: // +octave or custom
setLed(6, 2, getRowOffsetColor(), cellOn);
break;
case 13: // guitar tuning
lightLed(6, 3);
Expand Down Expand Up @@ -1261,6 +1270,13 @@ void paintGlobalSettingsDisplay() {
#endif
}

byte getRowOffsetColor() {
if (Global.customRowOffset != 12) {
return globalAltColor;
}
return globalColor;
}

byte getSwitchCC65Color() {
if (Global.ccForSwitch != 65) {
return globalAltColor;
Expand Down
71 changes: 68 additions & 3 deletions ls_extstorage.ino
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,32 @@ struct DeviceSettingsV5 {
boolean operatingLowPower; // whether low power mode is active or not
boolean leftHanded; // whether to orient the X axis from right to left instead of from left to right
};
struct GlobalSettingsV6 {
void setSwitchAssignment(byte, byte);

byte splitPoint; // leftmost column number of right split (0 = leftmost column of playable area)
byte currentPerSplit; // controls which split's settings are being displayed
byte activeNotes; // controls which collection of note lights presets is active
int mainNotes[12]; // bitmask array that determines which notes receive "main" lights
int accentNotes[12]; // bitmask array that determines which notes receive accent lights (octaves, white keys, black keys, etc.)
byte rowOffset; // interval between rows. 0 = no overlap, 1-12 = interval, 13 = guitar
VelocitySensitivity velocitySensitivity; // See VelocitySensitivity values
unsigned short minForVelocity; // 1-127
unsigned short maxForVelocity; // 1-127
unsigned short valueForFixedVelocity; // 1-127
PressureSensitivity pressureSensitivity; // See PressureSensitivity values
boolean pressureAftertouch; // Indicates whether pressure should behave like traditional piano keyboard aftertouch or be continuous from the start
byte switchAssignment[4]; // The element values are ASSIGNED_*. The index values are SWITCH_*.
boolean switchBothSplits[4]; // Indicate whether the switches should operate on both splits or only on the focused one
unsigned short ccForSwitch; // 0-127
byte midiIO; // 0 = MIDI jacks, 1 = USB
ArpeggiatorDirection arpDirection; // the arpeggiator direction that has to be used for the note sequence
ArpeggiatorStepTempo arpTempo; // the multiplier that needs to be applied to the current tempo to achieve the arpeggiator's step duration
signed char arpOctave; // the number of octaves that the arpeggiator has to operate over: 0, +1, or +2
SustainBehavior sustainBehavior; // the way the sustain pedal influences the notes
};
struct PresetSettingsV6 {
GlobalSettings global;
GlobalSettingsV6 global;
SplitSettings split[NUMSPLITS];
};
struct ConfigurationV7 {
Expand Down Expand Up @@ -501,6 +525,7 @@ void copyConfigurationV1(void* target, void* source) {
t->preset[p].global.currentPerSplit = g->currentPerSplit;
copyGlobalSettingsNoteLights(&t->preset[p].global, g->mainNotes, g->accentNotes);
t->preset[p].global.rowOffset = g->rowOffset;
t->preset[p].global.customRowOffset = 12;
t->preset[p].global.velocitySensitivity = g->velocitySensitivity;
t->preset[p].global.minForVelocity = 0;
t->preset[p].global.maxForVelocity = DEFAULT_MAX_VELOCITY;
Expand Down Expand Up @@ -680,6 +705,7 @@ void copyPresetSettingsOfConfigurationV2(void* target, void* source) {
t->preset[p].global.currentPerSplit = s->preset[p].global.currentPerSplit;
copyGlobalSettingsNoteLights(&t->preset[p].global, s->preset[p].global.mainNotes, s->preset[p].global.accentNotes);
t->preset[p].global.rowOffset = s->preset[p].global.rowOffset;
t->preset[p].global.customRowOffset = 12;
t->preset[p].global.velocitySensitivity = s->preset[p].global.velocitySensitivity;
t->preset[p].global.minForVelocity = 0;
t->preset[p].global.maxForVelocity = DEFAULT_MAX_VELOCITY;
Expand Down Expand Up @@ -735,6 +761,7 @@ void copyGlobalSettingsV3(void* target, void* source) {
t->currentPerSplit = s->currentPerSplit;
copyGlobalSettingsNoteLights(t, s->mainNotes, s->accentNotes);
t->rowOffset = s->rowOffset;
t->customRowOffset = 12;
t->velocitySensitivity = s->velocitySensitivity;
t->minForVelocity = 0;
t->maxForVelocity = DEFAULT_MAX_VELOCITY;
Expand Down Expand Up @@ -852,6 +879,7 @@ void copyGlobalSettingsV4(void* target, void* source) {
t->currentPerSplit = s->currentPerSplit;
copyGlobalSettingsNoteLights(t, s->mainNotes, s->accentNotes);
t->rowOffset = s->rowOffset;
t->customRowOffset = 12;
t->velocitySensitivity = s->velocitySensitivity;
t->minForVelocity = 0;
t->maxForVelocity = DEFAULT_MAX_VELOCITY;
Expand Down Expand Up @@ -945,6 +973,7 @@ void copyGlobalSettingsV5(void* target, void* source) {
memcpy(t->mainNotes, s->mainNotes, sizeof(int)*12);
memcpy(t->accentNotes, s->accentNotes, sizeof(int)*12);
t->rowOffset = s->rowOffset;
t->customRowOffset = 12;
t->velocitySensitivity = s->velocitySensitivity;
t->minForVelocity = 0;
t->maxForVelocity = DEFAULT_MAX_VELOCITY;
Expand All @@ -967,9 +996,9 @@ void copyConfigurationV7(void* target, void* source) {

copyDeviceSettingsV5(&t->device, &s->device);

t->settings = s->settings;
copyPresetSettingsV6(&t->settings, &s->settings);
for (byte p = 0; p < NUMPRESETS; ++p) {
t->preset[p] = s->preset[p];
copyPresetSettingsV6(&t->preset[p], &s->preset[p]);
}
}

Expand All @@ -991,3 +1020,39 @@ void copyDeviceSettingsV5(void* target, void* source) {
t->operatingLowPower = false;
t->leftHanded = false;
}

void copyPresetSettingsV6(void* target, void* source) {
PresetSettings* t = (PresetSettings*)target;
PresetSettingsV6* s = (PresetSettingsV6*)source;

copyGlobalSettingsV6(&t->global, &s->global);

t->split[LEFT] = s->split[LEFT];
t->split[RIGHT] = s->split[RIGHT];
}

void copyGlobalSettingsV6(void* target, void* source) {
GlobalSettings* t = (GlobalSettings*)target;
GlobalSettingsV6* s = (GlobalSettingsV6*)source;

t->splitPoint = s->splitPoint;
t->currentPerSplit = s->currentPerSplit;
memcpy(t->mainNotes, s->mainNotes, sizeof(int)*12);
memcpy(t->accentNotes, s->accentNotes, sizeof(int)*12);
t->rowOffset = s->rowOffset;
t->customRowOffset = 12;
t->velocitySensitivity = s->velocitySensitivity;
t->minForVelocity = s->minForVelocity;
t->maxForVelocity = s->maxForVelocity;
t->valueForFixedVelocity = s->valueForFixedVelocity;
t->pressureSensitivity = s->pressureSensitivity;
t->pressureAftertouch = s->pressureAftertouch;
memcpy(t->switchAssignment, s->switchAssignment, sizeof(byte)*4);
memcpy(t->switchBothSplits, s->switchBothSplits, sizeof(boolean)*4);
t->ccForSwitch = s->ccForSwitch;
t->midiIO = s->midiIO;
t->arpDirection = s->arpDirection;
t->arpTempo = s->arpTempo;
t->arpOctave = s->arpOctave;
t->sustainBehavior = s->sustainBehavior;
}
10 changes: 10 additions & 0 deletions ls_handleTouches.ino
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,9 @@ void handleNonPlayingTouch() {
case displaySleepConfig:
handleSleepConfigNewTouch();
break;
case displayRowOffset:
handleRowOffsetNewTouch();
break;
case displayMinUSBMIDIInterval:
handleMinUSBMIDIIntervalNewTouch();
break;
Expand Down Expand Up @@ -1276,6 +1279,9 @@ boolean handleNonPlayingRelease() {
case displaySleepConfig:
handleSleepConfigRelease();
break;
case displayRowOffset:
handleRowOffsetRelease();
break;
case displayMinUSBMIDIInterval:
handleMinUSBMIDIIntervalRelease();
break;
Expand Down Expand Up @@ -1547,6 +1553,10 @@ void determineNoteOffsetAndLowest(byte split, byte row, short& offset, short& lo
lowest = LOWEST_NOTE;

if (Global.rowOffset <= 12) { // if rowOffset is set to between 0 and 12..
if (Global.rowOffset == ROWOFFSET_OCTAVECUSTOM) {
offset = Global.customRowOffset;
}

if (Global.rowOffset == ROWOFFSET_NOOVERLAP) { // no overlap mode
byte lowCol, highCol;
getSplitBoundaries(split, lowCol, highCol);
Expand Down
8 changes: 7 additions & 1 deletion ls_midi.ino
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ void receivedNrpn(int parameter, int value) {
break;
// Global Row Offset
case 227:
if (value == ROWOFFSET_NOOVERLAP || value == 3 || value == 4 || value == 5 || value == 6 || value == 7 || value == 12 || value == 13 || ROWOFFSET_ZERO) {
if (value == ROWOFFSET_NOOVERLAP || value == 3 || value == 4 || value == 5 || value == 6 || value == 7 || value == ROWOFFSET_OCTAVECUSTOM || value == 13 || value == ROWOFFSET_ZERO) {
Global.rowOffset = value;
}
break;
Expand Down Expand Up @@ -935,6 +935,12 @@ void receivedNrpn(int parameter, int value) {
applyMidiInterval();
}
break;
// Global Custom Row Offset Instead Of Octave
case 253:
if (inRange(value, 0, 16)) {
Global.customRowOffset = value;
}
break;
}

updateDisplay();
Expand Down
45 changes: 38 additions & 7 deletions ls_settings.ino
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ void initializePresetSettings() {
g.currentPerSplit = LEFT;

g.rowOffset = 5;
g.customRowOffset = 12;
g.velocitySensitivity = velocityMedium;
g.minForVelocity = DEFAULT_MIN_VELOCITY;
g.maxForVelocity = DEFAULT_MAX_VELOCITY;
Expand Down Expand Up @@ -1746,6 +1747,14 @@ void handleSleepConfigRelease() {
handleNumericDataReleaseRow(false);
}

void handleRowOffsetNewTouch() {
handleNumericDataNewTouchCol(Global.customRowOffset, 0, 16, true);
}

void handleRowOffsetRelease() {
handleNumericDataReleaseCol(false);
}

void handleMinUSBMIDIIntervalNewTouch() {
handleNumericDataNewTouchCol(Device.minUSBMIDIInterval, 0, 512, false);
}
Expand Down Expand Up @@ -2203,12 +2212,7 @@ void handleGlobalSettingNewTouch() {
}
break;
case 2:
if (Global.rowOffset == 12) {
Global.rowOffset = ROWOFFSET_ZERO;
}
else {
Global.rowOffset = 12; // octave
}
// handled at release
break;
case 3:
if (Global.rowOffset == 13) {
Expand Down Expand Up @@ -2398,6 +2402,14 @@ void handleGlobalSettingNewTouch() {

// make the sensors that are waiting for hold pulse slowly to indicate that something is going on
switch (sensorCol) {
case 6:
switch (sensorRow) {
case 2:
setLed(sensorCol, sensorRow, getRowOffsetColor(), cellSlowPulse);
break;
}
break;

case 9:
switch (sensorRow) {
case 1:
Expand Down Expand Up @@ -2462,6 +2474,16 @@ void handleGlobalSettingHold() {
sensorCell->lastTouch = 0;

switch (sensorCol) {
case 6:
switch (sensorRow) {
case 2:
resetNumericDataChange();
setDisplayMode(displayRowOffset);
updateDisplay();
break;
}
break;

case 9:
switch (sensorRow) {
case 1:
Expand Down Expand Up @@ -2547,7 +2569,16 @@ void handleGlobalSettingHold() {
}

void handleGlobalSettingRelease() {
if (sensorRow == 7) {
if (sensorCol == 6 && sensorRow == 2 &&
ensureCellBeforeHoldWait(globalColor, Global.rowOffset == ROWOFFSET_OCTAVECUSTOM ? cellOn : cellOff)) {
if (Global.rowOffset == ROWOFFSET_OCTAVECUSTOM) {
Global.rowOffset = ROWOFFSET_ZERO;
}
else {
Global.rowOffset = ROWOFFSET_OCTAVECUSTOM;
}
}
else if (sensorRow == 7) {
// only show the messages if the tempo was changed more than 1s ago to prevent accidental touches
if (calcTimeDelta(micros(), tempoChangeTime) >= 1000000) {
if (sensorCol <= 16 && ensureCellBeforeHoldWait(COLOR_BLACK, cellOff)) {
Expand Down
1 change: 1 addition & 0 deletions midi.txt
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ NRPN Value Description
250 1-127 Global Maximum Value For Velocity
251 1-127 Global Value For Fixed Velocity
252 0-512 Global Minimum Interval Between MIDI Bytes Over USB
253 0-16 Global Custom Row Offset Instead Of Octave

Color Values
============
Expand Down

0 comments on commit 204722c

Please sign in to comment.