Skip to content

Commit

Permalink
feature: session macro sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
bfredl committed Jul 28, 2024
1 parent ab4f0f4 commit b676a02
Show file tree
Hide file tree
Showing 19 changed files with 628 additions and 23 deletions.
23 changes: 23 additions & 0 deletions docs/community_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,10 @@ Here is a list of features that have been added to the firmware as a list, group
- Normal clips are dull grey.
- Active clips are green, or whatever colour is set for active pads.
- The colours can be changed in `SETTINGS > PADS > COLOURS > FILL/ONCE`
- `Purple mode`
- [Song macros](#419-song-macros) can be set up. First select a macro slot in the left sidebar and then press a clip to
put it in the slot. press the same clip multiple times to switch between macro kinds (i e affect the entire
output or section for the clip)
- ([#970]) Streamline recording new clips while Deluge is playing
- This assumes the Deluge is in Grid mode, you are in Green mode, the Deluge is Playing, and Recording is enabled.
- To use this feature you will need to enable it in the menu:
Expand Down Expand Up @@ -468,6 +472,23 @@ Here is a list of features that have been added to the firmware as a list, group
- y1 = -26.4 to -22.1
- y0 = -30.8 to -26.5

### 4.1.9 - Song macros

Macros are a way to quickly switch playing clips without needing to go into song view.
Within grid view, purple mode is used to edit macros. There are 8 macro slots
shown in the left sidebar. To assign a macro,
first select a macro slot and then press a clip in the grid. Pressing the same clip multiple
time cycles though different modes:

- clip macro: Launch or mute the clip
- output macro: cycle though all clips for this particular output
- section macro: Launch all clips for this section

Inside a clip timeline view, hold SONG button and press the left sidebar to launch a macro.
In keyboard view, macros are available as a sidebar control.
SHIFT makes the launch immediate just like in song view. AFFECT ENTIRE + clip macro can be
used to jump to edit the clip.

### 4.2 - Clip View - General Features (Instrument and Audio Clips)

#### 4.2.1 - Filters
Expand Down Expand Up @@ -938,6 +959,8 @@ to each individual note onset. ([#1978])
pads will default to the first 7 scale modes, but you can change any pad to any scale by
holding it down and turning the vertical encoder. If the scale that is going to be set
can't fit/transpose the existing notes from your clips, screen will show `Can't`.
- **`Song Macro Mode (SONG - various):`** Activate [Song macros](#419-song-macros).

- ([#2174]) With the addition of the new Keyboard Sidebar Controls, the default behaviour of being able to immediately exit the menu by pressing a sidebar pad while in Keyboard View was removed. To accomodate users that still wish to be able to exit the menus immediately by pressing a sidebar pad, a new community feature toggle has been added (`Enable KB View Sidebar Menu Exit (EXIT)`) which will enable you to immediately exit the menu using the top left sidebar pad if you are in the `SETTINGS` or `SOUND` menu for `KEYBOARD VIEW`.

#### 4.4.2 - New scales
Expand Down
2 changes: 1 addition & 1 deletion src/definitions_cxx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,7 @@ enum GridMode : uint8_t {
Unassigned1,
Unassigned2,
Unassigned3,
Unassigned4,
MAGENTA,
YELLOW,
BLUE,
GREEN,
Expand Down
85 changes: 85 additions & 0 deletions src/deluge/gui/ui/keyboard/column_controls/session.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright © 2016-2024 Synthstrom Audible Limited
*
* This file is part of The Synthstrom Audible Deluge Firmware.
*
* The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/

#include "session.h"
#include "gui/ui/keyboard/layout/column_controls.h"
#include "gui/views/session_view.h"
#include "gui/views/view.h"
#include "hid/buttons.h"
#include "playback/mode/session.h"

using namespace deluge::gui::ui::keyboard::layout;

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

void SessionColumn::renderColumn(RGB image[][kDisplayWidth + kSideBarWidth], int32_t column) {
bool armed = false;
for (int32_t y = 0; y < kDisplayHeight; ++y) {
armed |= view.renderMacros(column, y, -1, image, nullptr);
}
if (armed) {
view.flashPlayEnable();
}
}

bool SessionColumn::handleVerticalEncoder(int8_t pad, int32_t offset) {
SessionMacro& m = currentSong->sessionMacros[pad];
int kindIndex = (int32_t)m.kind + offset;
if (kindIndex >= SessionMacroKind::NUM_KINDS) {
kindIndex = 0;
}
else if (kindIndex < 0) {
kindIndex = SessionMacroKind::NUM_KINDS - 1;
}

m.kind = (SessionMacroKind)kindIndex;

switch (m.kind) {
case CLIP_LAUNCH:
m.clip = getCurrentClip();
break;

case OUTPUT_CYCLE:
m.clip = nullptr;
m.output = getCurrentOutput();
break;

case SECTION:
m.section = getCurrentClip()->section;

default:
break;
}

return true;
};

void SessionColumn::handleLeavingColumn(ModelStackWithTimelineCounter* modelStackWithTimelineCounter,
KeyboardLayout* layout){};

void SessionColumn::handlePad(ModelStackWithTimelineCounter* modelStackWithTimelineCounter, PressedPad pad,
KeyboardLayout* layout) {

SessionMacro& m = currentSong->sessionMacros[pad.y];
if (pad.active) {}
else {
view.activateMacro(pad.y, pad.padPressHeld);
}
view.flashPlayEnable();
};

} // namespace deluge::gui::ui::keyboard::controls
42 changes: 42 additions & 0 deletions src/deluge/gui/ui/keyboard/column_controls/session.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright © 2016-2024 Synthstrom Audible Limited
*
* This file is part of The Synthstrom Audible Deluge Firmware.
*
* The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once

#include "gui/ui/keyboard/column_controls/control_column.h"
#include "model/song/song.h"

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

class SessionColumn : public ControlColumn {
public:
SessionColumn() = default;

void renderColumn(RGB image[][kDisplayWidth + kSideBarWidth], int32_t column) override;
bool handleVerticalEncoder(int8_t pad, int32_t offset) override;
void handleLeavingColumn(ModelStackWithTimelineCounter* modelStackWithTimelineCounter,
KeyboardLayout* layout) override;
void handlePad(ModelStackWithTimelineCounter* modelStackWithTimelineCounter, PressedPad pad,
KeyboardLayout* layout) override;

void handleOutput(SessionMacro& m, PressedPad pad);
Clip* findNextClipForOutput(SessionMacro& m, PressedPad pad);

private:
};

} // namespace deluge::gui::ui::keyboard::controls
3 changes: 3 additions & 0 deletions src/deluge/gui/ui/keyboard/layout/column_control_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "gui/ui/keyboard/column_controls/dx.h"
#include "gui/ui/keyboard/column_controls/mod.h"
#include "gui/ui/keyboard/column_controls/scale_mode.h"
#include "gui/ui/keyboard/column_controls/session.h"
#include "gui/ui/keyboard/column_controls/song_chord_mem.h"
#include "gui/ui/keyboard/column_controls/velocity.h"

Expand All @@ -35,6 +36,7 @@ enum ColumnControlFunction : int8_t {
CHORD_MEM,
SCALE_MODE,
DX,
SESSION,
// BEAT_REPEAT,
COL_CTRL_FUNC_MAX,
};
Expand All @@ -50,6 +52,7 @@ struct ColumnControlState {
ChordMemColumn chordMemColumn{};
ScaleModeColumn scaleModeColumn{};
DXColumn dxColumn{};
SessionColumn sessionColumn{};

ColumnControlFunction leftColFunc = VELOCITY;
ColumnControlFunction rightColFunc = MOD;
Expand Down
8 changes: 8 additions & 0 deletions src/deluge/gui/ui/keyboard/layout/column_controls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const char* functionNames[][2] = {
/* CHORD_MEM */ {"CCME", "Clip Chord Memory"},
/* SCALE_MODE */ {"SMOD", "Scales"},
/* DX */ {"DX", "DX operators"},
/* SESSION */ {"SONG", "song macros"},
/* BEAT_REPEAT */ {"BEAT", "Beat Repeat"},
};

Expand Down Expand Up @@ -204,6 +205,8 @@ ControlColumn* ColumnControlState::getColumnForFunc(ColumnControlFunction func)
return &scaleModeColumn;
case DX:
return &dxColumn;
case SESSION:
return &sessionColumn;
}
return nullptr;
}
Expand All @@ -224,6 +227,8 @@ const char* columnFunctionToString(ColumnControlFunction func) {
return "scale_mode";
case DX:
return "dx";
case SESSION:
return "session";
}
return "";
}
Expand All @@ -250,6 +255,9 @@ ColumnControlFunction stringToColumnFunction(char const* string) {
else if (!strcmp(string, "dx")) {
return DX;
}
else if (!strcmp(string, "session")) {
return SESSION;
}
else {
return VELOCITY; // unknown column, just pick the default
}
Expand Down
1 change: 1 addition & 0 deletions src/deluge/gui/ui/ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ extern bool pendingUIRenderingLock;
#define UI_MODE_HOLDING_STATUS_PAD 62
#define UI_MODE_IMPLODE_ANIMATION 63
#define UI_MODE_STEM_EXPORT 64
#define UI_MODE_HOLDING_SONG_BUTTON 65

#define EXCLUSIVE_UI_MODES_MASK ((uint32_t)255)

Expand Down
5 changes: 1 addition & 4 deletions src/deluge/gui/ui_timer_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,7 @@ void UITimerManager::routine() {
break;

case TimerName::PLAY_ENABLE_FLASH: {
RootUI* rootUI = getRootUI();
if ((rootUI == &sessionView) || (rootUI == &performanceSessionView)) {
sessionView.flashPlayRoutine();
}
view.flashPlayRoutine();
break;
}
case TimerName::DISPLAY:
Expand Down
39 changes: 38 additions & 1 deletion src/deluge/gui/views/audio_clip_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,18 @@ bool AudioClipView::renderSidebar(uint32_t whichRows, RGB image[][kDisplayWidth
return true;
}

int32_t macroColumn = kDisplayWidth;
bool armed = false;
for (int32_t y = 0; y < kDisplayHeight; y++) {
RGB* const start = &image[y][kDisplayWidth];
std::fill(start, start + kSideBarWidth, colours::black);

if (isUIModeActive(UI_MODE_HOLDING_SONG_BUTTON)) {
armed |= view.renderMacros(macroColumn, y, -1, image, occupancyMask);
}
}
if (armed) {
view.flashPlayEnable();
}

return true;
Expand Down Expand Up @@ -282,10 +291,27 @@ ActionResult AudioClipView::buttonAction(deluge::hid::Button b, bool on, bool in

// Song view button
if (b == SESSION_VIEW) {
if (on && currentUIMode == UI_MODE_NONE) {
if (on) {
if (currentUIMode == UI_MODE_NONE) {
currentUIMode = UI_MODE_HOLDING_SONG_BUTTON;
timeSongButtonPressed = AudioEngine::audioSampleTimer;
indicator_leds::setLedState(IndicatorLED::SESSION_VIEW, true);
uiNeedsRendering(this, 0, 0xFFFFFFFF);
}
}
else {
if (!isUIModeActive(UI_MODE_HOLDING_SONG_BUTTON)) {
return ActionResult::DEALT_WITH;
}
if (inCardRoutine) {
return ActionResult::REMIND_ME_OUTSIDE_CARD_ROUTINE;
}
exitUIMode(UI_MODE_HOLDING_SONG_BUTTON);
if ((int32_t)(AudioEngine::audioSampleTimer - timeSongButtonPressed) > kShortPressTime) {
uiNeedsRendering(this, 0, 0xFFFFFFFF);
indicator_leds::setLedState(IndicatorLED::SESSION_VIEW, false);
return ActionResult::DEALT_WITH;
}

uiTimerManager.unsetTimer(TimerName::UI_SPECIFIC);

Expand Down Expand Up @@ -502,6 +528,17 @@ ActionResult AudioClipView::padAction(int32_t x, int32_t y, int32_t on) {
}
}
}
else if (x == kDisplayWidth) {
if (isUIModeActive(UI_MODE_HOLDING_SONG_BUTTON)) {
if (sdRoutineLock) {
return ActionResult::REMIND_ME_OUTSIDE_CARD_ROUTINE;
}
if (!on) {
view.activateMacro(y, false);
}
return ActionResult::DEALT_WITH;
}
}

return ActionResult::DEALT_WITH;
}
Expand Down
1 change: 1 addition & 0 deletions src/deluge/gui/views/audio_clip_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class AudioClipView final : public ClipView, public ClipMinder {
const char* getName() { return "audio_clip_view"; }

private:
uint32_t timeSongButtonPressed;
void needsRenderingDependingOnSubMode();
int32_t lastTickSquare;
bool mustRedrawTickSquares;
Expand Down
Loading

0 comments on commit b676a02

Please sign in to comment.