Skip to content

Commit

Permalink
Persist chord memory to song file (community) (SynthstromAudible#2120)
Browse files Browse the repository at this point in the history
* Update docs

* Read and write chord memory bank from/to song file

# Conflicts:
#	src/deluge/model/song/song.cpp

* Change tags written in XML to be same as bfredl’s PR
  • Loading branch information
soymonitus committed Jun 14, 2024
1 parent 548f470 commit 3219c70
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 15 deletions.
3 changes: 2 additions & 1 deletion docs/community_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,8 @@ to each individual note onset. ([#1978])
Minor, Major, Sus4, Minor7, Dom7, Major7. All are in closed root position.
- **`Chord Memory (CMEM - Cyan):`** Hold a chord down and press a pad to remember the chord. Press
that pad again to play it. You can play over the top of your saved chords. To clear a chord,
press shift and the pad you want to clear.
press shift and the pad you want to clear. Chord memory is shared across all song clips and it
is saved in the song file.
- **`Scale Mode (SMOD - Yellow):`** Press and hold a pad to temporarily change the scale of the
keyboard to the selected scale mode. Tap a scale mode to make it the new default. The scale
pads will default to the first 7 scale modes, but you can change any pad to any scale by
Expand Down
21 changes: 11 additions & 10 deletions src/deluge/gui/ui/keyboard/column_controls/chord_mem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@

#include "chord_mem.h"
#include "hid/buttons.h"
#include "model/song/song.h"

namespace deluge::gui::ui::keyboard::controls {

void ChordMemColumn::renderColumn(RGB image[][kDisplayWidth + kSideBarWidth], int32_t column) {
uint8_t otherChannels = 0;
for (int32_t y = 0; y < kDisplayHeight; ++y) {
bool chord_selected = y == activeChordMem;
uint8_t chord_slot_filled = chordMemNoteCount[y] > 0 ? 0x7f : 0;
uint8_t chord_slot_filled = currentSong->chordMemNoteCount[y] > 0 ? 0x7f : 0;
otherChannels = chord_selected ? 0xf0 : 0;
uint8_t base = chord_selected ? 0xff : chord_slot_filled;
image[y][column] = {otherChannels, base, base};
Expand All @@ -44,23 +45,23 @@ void ChordMemColumn::handlePad(ModelStackWithTimelineCounter* modelStackWithTime

if (pad.active) {
activeChordMem = pad.y;
auto noteCount = chordMemNoteCount[pad.y];
for (int i = 0; i < noteCount && i < kMaxNotesChordMem; i++) {
currentNotesState.enableNote(chordMem[pad.y][i], layout->velocity);
auto noteCount = currentSong->chordMemNoteCount[pad.y];
for (int i = 0; i < noteCount && i < MAX_NOTES_CHORD_MEM; i++) {
currentNotesState.enableNote(currentSong->chordMem[pad.y][i], layout->velocity);
}
chordMemNoteCount[pad.y] = noteCount;
currentSong->chordMemNoteCount[pad.y] = noteCount;
}
else {
activeChordMem = 0xFF;
if ((!chordMemNoteCount[pad.y] || Buttons::isShiftButtonPressed()) && currentNotesState.count) {
if ((!currentSong->chordMemNoteCount[pad.y] || Buttons::isShiftButtonPressed()) && currentNotesState.count) {
auto noteCount = currentNotesState.count;
for (int i = 0; i < noteCount && i < kMaxNotesChordMem; i++) {
chordMem[pad.y][i] = currentNotesState.notes[i].note;
for (int i = 0; i < noteCount && i < MAX_NOTES_CHORD_MEM; i++) {
currentSong->chordMem[pad.y][i] = currentNotesState.notes[i].note;
}
chordMemNoteCount[pad.y] = noteCount;
currentSong->chordMemNoteCount[pad.y] = noteCount;
}
else if (Buttons::isShiftButtonPressed()) {
chordMemNoteCount[pad.y] = 0;
currentSong->chordMemNoteCount[pad.y] = 0;
}
}
};
Expand Down
4 changes: 0 additions & 4 deletions src/deluge/gui/ui/keyboard/column_controls/chord_mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@

namespace deluge::gui::ui::keyboard::controls {

constexpr int32_t kMaxNotesChordMem = 10;

class ChordMemColumn : public ControlColumn {
public:
ChordMemColumn() = default;
Expand All @@ -35,8 +33,6 @@ class ChordMemColumn : public ControlColumn {
KeyboardLayout* layout) override;

private:
uint8_t chordMemNoteCount[8] = {0};
uint8_t chordMem[8][kMaxNotesChordMem] = {0};
uint8_t activeChordMem = 0xFF;
};

Expand Down
60 changes: 60 additions & 0 deletions src/deluge/model/song/song.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1457,6 +1457,29 @@ void Song::writeToFile(StorageManager& bdsm) {
writer.writeClosingTag("arrangementOnlyTracks");
}

// Chord mem

int maxChordPosToSave = 0;
for (int32_t y = 0; y < kDisplayHeight; y++) {
if (chordMemNoteCount[y] > 0) {
maxChordPosToSave = y + 1;
}
}
if (maxChordPosToSave > 0) {
// some chords to save
writer.writeOpeningTag("chordMem");
for (int32_t y = 0; y < maxChordPosToSave; y++) {
writer.writeOpeningTag("chord");
for (int i = 0; i < chordMemNoteCount[y]; i++) {
writer.writeOpeningTagBeginning("note");
writer.writeAttribute("code", chordMem[y][i]);
writer.closeTag();
}
writer.writeClosingTag("chord");
}
writer.writeClosingTag("chordMem");
}

writer.writeClosingTag("song");
}

Expand Down Expand Up @@ -1843,6 +1866,43 @@ Error Song::readFromFile(Deserializer& reader) {
reader.exitTag("modeNotes");
}

else if (!strcmp(tagName, "chordMem")) {
int slot_index = 0;
while (*(tagName = reader.readNextTagOrAttributeName())) {
if (!strcmp(tagName, "chord")) {
int y = slot_index++;
if (y >= 8) {
reader.exitTag("chord");
continue;
}
int i = 0;
while (*(tagName = reader.readNextTagOrAttributeName())) {
if (!strcmp(tagName, "note")) {
while (*(tagName = reader.readNextTagOrAttributeName())) {
if (!strcmp(tagName, "code")) {
if (i < MAX_NOTES_CHORD_MEM) {
chordMem[y][i] = reader.readTagOrAttributeValueInt();
}
}
else {
reader.exitTag();
}
}
i++;
}
else {
reader.exitTag();
}
}
chordMemNoteCount[y] = std::min(8, i);
}
else {
reader.exitTag();
}
}
reader.exitTag("chordMem");
}

else if (!strcmp(tagName, "sections")) {
// Read in all the sections
while (*(tagName = reader.readNextTagOrAttributeName())) {
Expand Down
6 changes: 6 additions & 0 deletions src/deluge/model/song/song.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ struct BackedUpParamManager {
ParamManager paramManager;
};

#define MAX_NOTES_CHORD_MEM 10

class Song final : public TimelineCounter {
public:
Song();
Expand Down Expand Up @@ -392,6 +394,10 @@ class Song final : public TimelineCounter {

int32_t countAudioClips() const;

// Chord memory
uint8_t chordMemNoteCount[kDisplayHeight] = {0};
uint8_t chordMem[kDisplayHeight][MAX_NOTES_CHORD_MEM] = {0};

private:
uint8_t indexLastUnusedScaleDegreeFrom7To6 = 0;
uint8_t indexLastUnusedScaleDegreeFrom6To5 = 0;
Expand Down

0 comments on commit 3219c70

Please sign in to comment.