Deluge Firmware 1.3.0
Build date: 2026.03.11
Loading...
Searching...
No Matches
session_view.h
1/*
2 * Copyright © 2014-2023 Synthstrom Audible Limited
3 *
4 * This file is part of The Synthstrom Audible Deluge Firmware.
5 *
6 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software Foundation,
8 * either version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with this program.
15 * If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#pragma once
19
20#include "definitions_cxx.hpp"
21#include "gui/views/clip_navigation_timeline_view.h"
22#include "hid/button.h"
23#include "model/song/song.h"
24#include "storage/flash_storage.h"
25
26class Editor;
27class InstrumentClip;
28class AudioClip;
29class Clip;
30class ModelStack;
32
33enum SessionGridMode : uint8_t {
34 SessionGridModeEdit,
35 SessionGridModeLaunch,
36 SessionGridModeMacros,
37 SessionGridModeMaxElement // Keep as boundary
38};
39
40extern float getTransitionProgress();
41
42constexpr uint32_t kGridHeight = kDisplayHeight;
43
44class SessionView final : public ClipNavigationTimelineView {
45public:
46 SessionView();
47 bool getGreyoutColsAndRows(uint32_t* cols, uint32_t* rows) override;
48 bool opened() override;
49 void focusRegained() override;
50
51 ActionResult buttonAction(deluge::hid::Button b, bool on, bool inCardRoutine) override;
52 ActionResult clipCreationButtonPressed(hid::Button i, bool on, bool routine);
53 ActionResult padAction(int32_t x, int32_t y, int32_t velocity) override;
54 ActionResult horizontalEncoderAction(int32_t offset) override;
55 ActionResult verticalEncoderAction(int32_t offset, bool inCardRoutine) override;
56 bool renderSidebar(uint32_t whichRows, RGB image[][kDisplayWidth + kSideBarWidth],
57 uint8_t occupancyMask[][kDisplayWidth + kSideBarWidth]) override;
58 void removeClip(Clip* clip);
59 void redrawClipsOnScreen(bool doRender = true);
60 uint32_t getMaxZoom() override;
61 void cloneClip(uint8_t yDisplayFrom, uint8_t yDisplayTo);
62 bool renderRow(ModelStack* modelStack, uint8_t yDisplay, RGB thisImage[kDisplayWidth + kSideBarWidth],
63 uint8_t thisOccupancyMask[kDisplayWidth + kSideBarWidth], bool drawUndefinedArea = true);
64 void graphicsRoutine() override;
65 void potentiallyUpdateCompressorLEDs();
66 int32_t displayLoopsRemainingPopup(bool ephemeral = false);
67 void potentiallyRenderClipLaunchPlayhead(bool reallyNoTickSquare, int32_t sixteenthNotesRemaining);
68 void requestRendering(UI* ui, uint32_t whichMainRows = 0xFFFFFFFF, uint32_t whichSideRows = 0xFFFFFFFF);
69
70 int32_t getClipPlaceOnScreen(Clip* clip);
71 void drawStatusSquare(uint8_t yDisplay, RGB thisImage[]);
72 void drawSectionSquare(uint8_t yDisplay, RGB thisImage[]);
73 bool calculateZoomPinSquares(uint32_t oldScroll, uint32_t newScroll, uint32_t newZoom, uint32_t oldZoom) override;
74 uint32_t getMaxLength() override;
75 bool setupScroll(uint32_t oldScroll) override;
76 uint32_t getClipLocalScroll(Clip* loopable, uint32_t overviewScroll, uint32_t xZoom);
77 void flashPlayRoutine();
78
79 void modEncoderButtonAction(uint8_t whichModEncoder, bool on) override;
80 void modButtonAction(uint8_t whichButton, bool on) override;
81 void selectEncoderAction(int8_t offset) override;
82 ActionResult timerCallback() override;
83 void noteRowChanged(InstrumentClip* clip, NoteRow* noteRow) override;
84 void setLedStates();
85 void editNumRepeatsTilLaunch(int32_t offset);
86 uint32_t getGreyedOutRowsNotRepresentingOutput(Output* output) override;
87 bool renderMainPads(uint32_t whichRows, RGB image[][kDisplayWidth + kSideBarWidth],
88 uint8_t occupancyMask[][kDisplayWidth + kSideBarWidth], bool drawUndefinedArea = true) override;
89 void midiLearnFlash() override;
90
91 void transitionToViewForClip(Clip* clip = nullptr);
92 void transitionToSessionView();
93 void finishedTransitioningHere();
94 void playbackEnded() override;
95 void clipNeedsReRendering(Clip* clip) override;
96 void sampleNeedsReRendering(Sample* sample) override;
97 Clip* getClipOnScreen(int32_t yDisplay);
98 Output* getOutputFromPad(int32_t x, int32_t y);
99 void modEncoderAction(int32_t whichModEncoder, int32_t offset) override;
100 ActionResult verticalScrollOneSquare(int32_t direction);
101
102 void renderOLED(deluge::hid::display::oled_canvas::Canvas& canvas) override;
103
104 // 7SEG only
105 void redrawNumericDisplay();
106 void clearNumericDisplay();
107 void displayRepeatsTilLaunch();
108
109 uint32_t selectedClipTimePressed;
110 uint8_t selectedClipYDisplay; // Where the clip is on screen
111 uint8_t selectedClipPressYDisplay; // Where the user's finger actually is on screen
112 uint8_t selectedClipPressXDisplay;
113 bool clipWasSelectedWithShift; // Whether shift was held when clip pad started to be held
114 bool performActionOnPadRelease;
115 bool performActionOnSectionPadRelease; // Keep this separate from the above one because we don't want a mod encoder
116 // action to set this to false
117 uint8_t sectionPressed;
118 uint8_t masterCompEditMode;
119 int8_t selectedMacro = -1;
120
121 Clip* getClipForLayout();
122 int32_t getClipIndexForLayout();
123
124 void copyClipName(Clip* source, Clip* target, Output* targetOutput);
125
126 // Members for grid layout
127 inline bool gridFirstPadActive() { return (gridFirstPressedX != -1 && gridFirstPressedY != -1); }
128 ActionResult gridHandlePads(int32_t x, int32_t y, int32_t on);
129 ActionResult gridHandleScroll(int32_t offsetX, int32_t offsetY);
130
131 // ui
132 UIType getUIType() override { return UIType::SESSION; }
133 UIModControllableContext getUIModControllableContext() override { return UIModControllableContext::SONG; }
134
135 Clip* createNewClip(OutputType outputType, int32_t yDisplay);
136 bool createClip{false};
137 OutputType lastTypeCreated{OutputType::NONE};
138
139 // Grid macros config mode
140 void enterMacrosConfigMode();
141 void exitMacrosConfigMode();
142 char const* getMacroKindString(SessionMacroKind kind);
143
144 // Midi learn mode
145 void enterMidiLearnMode();
146 void exitMidiLearnMode();
147
148 // display tempo
149 void displayPotentialTempoChange(UI* ui);
150 void displayTempoBPM(deluge::hid::display::oled_canvas::Canvas& canvas, StringBuf& tempoBPM, bool clearArea);
151 float lastDisplayedTempo = 0;
152
153 // display root note and scale name
154 void displayCurrentRootNoteAndScaleName(deluge::hid::display::oled_canvas::Canvas& canvas,
155 StringBuf& rootNoteAndScaleName, bool clearArea);
156 int16_t lastDisplayedRootNote = 0;
157
158 // convert instrument clip to audio clip
159 void replaceInstrumentClipWithAudioClip(Clip* clip);
160
161 // pulse selected clip in grid view
162 void gridPulseSelectedClip();
163
164private:
165 // These and other (future) commandXXX methods perform actions triggered by HID, but contain
166 // no dispatch logic.
167 //
168 // selectEncoderAction() triggered commands
169 void commandChangeSectionRepeats(int8_t offset);
170 void commandChangeClipPreset(int8_t offset);
171 void commandChangeCurrentSectionRepeats(int8_t offset);
172 void commandChangeLayout(int8_t offset);
173
174private:
175 void renderViewDisplay();
176 void sectionPadAction(uint8_t y, bool on);
177 void clipPressEnded();
178 void drawSectionRepeatNumber();
179 void beginEditingSectionRepeatsNum();
180 void goToArrangementEditor();
181 void rowNeedsRenderingDependingOnSubMode(int32_t yDisplay);
182 void setCentralLEDStates();
183
184 Clip* createNewAudioClip(int32_t yDisplay);
185 Clip* createNewInstrumentClip(OutputType outputType, int32_t yDisplay);
186
187 bool createNewTrackForAudioClip(AudioClip* newClip);
188 bool createNewTrackForInstrumentClip(OutputType type, InstrumentClip* clip, bool copyDrumsFromClip);
189
190 bool insertAndResyncNewClip(Clip* newClip, int32_t yDisplay);
191 void resyncNewClip(Clip* newClip, ModelStackWithTimelineCounter* modelStackWithTimelineCounter);
192
193 // Members regarding rendering different layouts
194private:
195 void selectLayout(int8_t offset);
196 void renderLayoutChange(bool displayPopup = true);
197 void selectSpecificLayout(SessionLayoutType layout);
198 SessionLayoutType previousLayout;
199 SessionGridMode previousGridModeActive;
200
201 bool sessionButtonActive = false;
202 bool sessionButtonUsed = false;
203 bool horizontalEncoderPressed = false;
204 bool viewingRecordArmingActive = false;
205 // Members for grid layout
206private:
207 bool gridRenderSidebar(uint32_t whichRows, RGB image[][kDisplayWidth + kSideBarWidth],
208 uint8_t occupancyMask[][kDisplayWidth + kSideBarWidth]);
209 void gridRenderActionModes(int32_t y, RGB image[][kDisplayWidth + kSideBarWidth],
210 uint8_t occupancyMask[][kDisplayWidth + kSideBarWidth]);
211 bool gridRenderMainPads(uint32_t whichRows, RGB image[][kDisplayWidth + kSideBarWidth],
212 uint8_t occupancyMask[][kDisplayWidth + kSideBarWidth], bool drawUndefinedArea = true);
213
214 RGB gridRenderClipColor(Clip* clip, int32_t x, int32_t y, bool renderPulse = true);
215
216 ActionResult gridHandlePadsEdit(int32_t x, int32_t y, int32_t on, Clip* clip);
217 ActionResult gridHandlePadsLaunch(int32_t x, int32_t y, int32_t on, Clip* clip);
218 ActionResult gridHandlePadsLaunchImmediate(int32_t x, int32_t y, int32_t on, Clip* clip);
219 ActionResult gridHandlePadsLaunchWithSelection(int32_t x, int32_t y, int32_t on, Clip* clip);
220 void gridHandlePadsWithMidiLearnPressed(int32_t x, int32_t on, Clip* clip);
221 ActionResult gridHandlePadsMacros(int32_t x, int32_t y, int32_t on, Clip* clip);
222 void gridHandlePadsLaunchToggleArming(Clip* clip, bool immediate);
223
224 void gridTransitionToSessionView();
225 void gridTransitionToViewForClip(Clip* clip);
226
227 SessionGridMode gridModeSelected = SessionGridModeEdit;
228 SessionGridMode gridModeActive = SessionGridModeEdit;
229 bool gridActiveModeUsed = false;
230
231 int32_t gridFirstPressedX = -1;
232 int32_t gridFirstPressedY = -1;
233 int32_t gridSecondPressedX = -1;
234 int32_t gridSecondPressedY = -1;
235 inline bool gridSecondPadInactive() { return (gridSecondPressedX == -1 && gridSecondPressedY == -1); }
236
237 inline void gridResetPresses(bool first = true, bool second = true) {
238 if (first) {
239 gridFirstPressedX = -1;
240 gridFirstPressedY = -1;
241 }
242 if (second) {
243 gridSecondPressedX = -1;
244 gridSecondPressedY = -1;
245 }
246 }
247
248 Clip* gridCloneClip(Clip* sourceClip);
249 Clip* gridCreateClipInTrack(Output* targetOutput);
250 AudioClip* gridCreateAudioClipWithNewTrack();
251 InstrumentClip* gridCreateInstrumentClipWithNewTrack(OutputType type);
252 Clip* gridCreateClip(uint32_t targetSection, Output* targetOutput = nullptr, Clip* sourceClip = nullptr);
253 void gridClonePad(uint32_t sourceX, uint32_t sourceY, uint32_t targetX, uint32_t targetY);
254 void setupNewClip(Clip* newClip);
255
256 void gridStartSection(uint32_t section, bool instant);
257 void gridToggleClipPlay(Clip* clip, bool instant);
258
259 [[nodiscard]] const size_t gridTrackCount() const;
260 uint32_t gridClipCountForTrack(Output* track);
261 uint32_t gridTrackIndexFromTrack(Output* track, uint32_t maxTrack);
262 Output* gridTrackFromIndex(uint32_t trackIndex, uint32_t maxTrack);
263 int32_t gridYFromSection(uint32_t section);
264 int32_t gridSectionFromY(uint32_t y);
265 int32_t gridXFromTrack(uint32_t trackIndex);
266 int32_t gridTrackIndexFromX(uint32_t x, uint32_t maxTrack);
267 Output* gridTrackFromX(uint32_t x, uint32_t maxTrack);
268 Clip* gridClipFromCoords(uint32_t x, uint32_t y);
269 int32_t gridClipIndexFromCoords(uint32_t x, uint32_t y);
270 Cartesian gridXYFromClip(Clip& clip);
271
272 void gridSetDefaultMode() {
273 switch (FlashStorage::defaultGridActiveMode) {
274 case GridDefaultActiveModeGreen: {
275 gridModeSelected = SessionGridModeLaunch;
276 break;
277 }
278 case GridDefaultActiveModeBlue: {
279 gridModeSelected = SessionGridModeEdit;
280 break;
281 }
282 // explicit fallthrough cases
283 case GridDefaultActiveModeSelection: // handled outside
284 case GridDefaultActiveModeMaxElement:;
285 }
286 }
287
288 void setupTrackCreation() const;
289 void exitTrackCreation();
290
291 // selected clip pulsing in grid view
292
295
298
300 void gridSelectClipForPulsing(Clip& clip);
301
304
305 bool gridSelectedClipPulsing = false; // are we doing any pulsing
306 Clip* selectedClipForPulsing = nullptr; // selected clip we are pulsing
307 RGB gridSelectedClipRenderedColour; // last pulse colour we rendered
308 bool blendDirection = false; // direction we're blending towards
309 int32_t progress = 0; // pulse blend slider position
310
311 static constexpr int32_t kMinProgress = 1; // min position to reach in blend slider
312 static constexpr int32_t kMaxProgressFull = (65535 / 100) * 60; // max position to reach for unmuted clip
313 static constexpr int32_t kMaxProgressDim = 1000; // max position to reach for muted clip
314 static constexpr int32_t kPulseRate = 50; // speed of timer in ms
315 static constexpr int32_t kBlendRate = 60; // speed of blending colours
316 static constexpr int32_t kBlendOffsetFull = kPulseRate * kBlendRate; // amount to move slider for unmuted clip
317 static constexpr int32_t kBlendOffsetDim = kPulseRate; // amount to move slider for muted clip
318};
319
320extern SessionView sessionView;
Definition audio_clip.h:35
Definition clip.h:46
Definition instrument_clip.h:48
Definition model_stack.h:129
Definition model_stack.h:123
Definition note_row.h:99
Definition output.h:81
This class represents the colour format most used by the Deluge globally.
Definition rgb.h:14
Definition sample.h:50
Definition session_view.h:44
UIType getUIType() override
What type of UI is this? e.g. UIType::ARRANGER.
Definition session_view.h:132
void renderViewDisplay()
render session view display on opening
Definition session_view.cpp:2029
UIModControllableContext getUIModControllableContext() override
What mod controllable context is this UI using? E.g. Automation View can use the Song ModControllable...
Definition session_view.h:133
int32_t displayLoopsRemainingPopup(bool ephemeral=false)
display number of bars or quarter notes remaining until a launch event
Definition session_view.cpp:2376
bool gridCheckForPulseStop()
check if we should stop pulsing
Definition session_view.cpp:4770
void gridResetSelectedClipPulseProgress()
reset blend position for pulse
Definition session_view.cpp:4756
void gridSelectClipForPulsing(Clip &clip)
render pulse for selected clip
Definition session_view.cpp:4763
void gridStopSelectedClipPulsing()
disable selected clip pulsing
Definition session_view.cpp:4748
Definition ui.h:92