Skip to content

Commit 625ac33

Browse files
committed
added mute pattern component for live page
1 parent 08a516b commit 625ac33

File tree

8 files changed

+263
-101
lines changed

8 files changed

+263
-101
lines changed

v2/AciduinoV2/acid_ui_components.ino

Lines changed: 239 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,6 @@
33
// all UI components are programmed as PageComponent to be reused on different pages
44
//
55

6-
// used by page module for themed function button display
7-
void functionDrawCallback(const char * f1, const char * f2, uint8_t f1_state, uint8_t f2_state)
8-
{
9-
// menu action
10-
uCtrl.oled->print(f1, 8, 1+((14-strlen(f1))/2));
11-
uCtrl.oled->print(f2, 8, 14+((14-strlen(f2))/2));
12-
// state variation
13-
if (f1_state == 1) {
14-
uCtrl.oled->display->drawBox(0, 57, 63, 7);
15-
}
16-
if (f2_state == 1) {
17-
uCtrl.oled->display->drawBox(64, 57, 64, 7);
18-
}
19-
// horizontal line
20-
uCtrl.oled->display->drawBox(0, 56, 128, 1);
21-
// vertical separator
22-
//uCtrl.oled->display->drawBox(64, 59, 1, 5);
23-
}
24-
256
// for a 1x grid 1x line size
267
// large == true ? 2x grid size
278
// used by a lot of simple components
@@ -238,6 +219,183 @@ struct TopBar : PageComponent {
238219
}
239220
} topBarComponent;
240221

222+
// pattern data for mute automation grid
223+
typedef struct
224+
{
225+
uint16_t map_303 = 0xFFFF;
226+
uint16_t map_808[TRACK_NUMBER_808] = {0xFFFF};
227+
} MUTE_PATTERN;
228+
229+
// the control knob will handle midi cc for the last selected midi cc of selected track inside this component
230+
struct MutePatternControl : PageComponent {
231+
232+
// layout:
233+
// mute automation pattern style driven
234+
// 4x16 grid style:
235+
// last 4 grids are mute automation clip change/status
236+
// 12 grids are for mute elements(on 808 max 12, for 303 1 big mute slot)
237+
// f1 = << (...)
238+
// f2 = >> (...)
239+
// this will be extended in the future to allow more patterns to be used, 4 for now!
240+
MUTE_PATTERN mute_pattern[4];
241+
uint8_t current_pattern = 0;
242+
uint8_t selected_pattern = 0;
243+
uint8_t selected_mute_chn = 0;
244+
245+
MutePatternControl()
246+
{
247+
// we want this component to be 4 lines max and 16 grids navigable object
248+
line_size = 4;
249+
grid_size = 2;
250+
// enable more complex nav by updating selector pointer of page component
251+
update_selector = true;
252+
}
253+
254+
void view() {
255+
256+
// update voice info for 808
257+
//...
258+
259+
// mute pattern
260+
for (uint8_t i=0; i < 4; i++) {
261+
// mute grid
262+
// 303
263+
if (AcidSequencer.is303(_selected_track)) {
264+
// print as not muted
265+
uCtrl.oled->drawBox(y+(i*8), x, 6, 86, i+1 == selected_line ? true : false);
266+
// if muted then just empty the box for ui feedback
267+
if (!GET_BIT(mute_pattern[i].map_303, _selected_track)) {
268+
uCtrl.oled->drawBox(y+(i*8)+1, x+1, 4, 84, i+1 == selected_line ? true : false);
269+
}
270+
// 808
271+
} else {
272+
uint8_t block_size = ceil(86.00 / VOICE_MAX_SIZE_808);
273+
for (uint8_t j=0; j < VOICE_MAX_SIZE_808; j++) {
274+
uCtrl.oled->drawBox(y+(i*8), x+(j*block_size), 6, block_size-2, i+1 == selected_line && j == selected_mute_chn ? true : false);
275+
if (!GET_BIT(mute_pattern[i].map_808[_selected_track-TRACK_NUMBER_303], j)) {
276+
uCtrl.oled->drawBox(y+(i*8)+1, x+(j*block_size)+1, 4, block_size-4, i+1 == selected_line && j == selected_mute_chn ? true : false);
277+
}
278+
}
279+
}
280+
281+
// pattern selector status
282+
uCtrl.oled->print(i+1, line+i, 22, i+1 == selected_line ? true : false);
283+
if (current_pattern == i)
284+
uCtrl.oled->print("<", line+i, 25);
285+
}
286+
287+
// track info
288+
if (AcidSequencer.is303(_selected_track)) {
289+
//if (AcidSequencer.stepOn(_selected_track, AcidSequencer.getCurrentStep(_selected_track)) && _playing) {
290+
// uCtrl.oled->print(AcidSequencer.getNoteString(AcidSequencer.getStepData(_selected_track, AcidSequencer.getCurrentStep(_selected_track))), line+4, 1);
291+
//}
292+
// 808
293+
} else {
294+
uCtrl.oled->print(AcidSequencer.getTrackVoiceName(_selected_track, AcidSequencer.getTrackVoice(_selected_track)), line+4, 1);
295+
}
296+
297+
setF1("<<");
298+
setF2(">>");
299+
}
300+
301+
void nav(uint8_t dir) {
302+
303+
switch (dir) {
304+
case LEFT:
305+
if (selected_mute_chn == 0) {
306+
selected_mute_chn = AcidSequencer.is303(_selected_track) ? 0 : VOICE_MAX_SIZE_808-1;
307+
} else {
308+
--selected_mute_chn;
309+
}
310+
if (!AcidSequencer.is303(_selected_track)) {
311+
AcidSequencer.setTrackVoice(_selected_track, selected_mute_chn);
312+
}
313+
break;
314+
case RIGHT:
315+
if (selected_mute_chn == VOICE_MAX_SIZE_808-1) {
316+
selected_mute_chn = 0;
317+
} else {
318+
++selected_mute_chn;
319+
}
320+
if (!AcidSequencer.is303(_selected_track)) {
321+
AcidSequencer.setTrackVoice(_selected_track, selected_mute_chn);
322+
}
323+
break;
324+
}
325+
326+
}
327+
328+
void change(int16_t data) {
329+
// INCREMENT -1
330+
// DECREMENT -2
331+
// INCREMENT_SECONDARY -3
332+
// DECREMENT_SECONDARY -4
333+
uint8_t pattern = selected_line-1;
334+
if (data == INCREMENT) {
335+
if (AcidSequencer.is303(_selected_track)) {
336+
SET_BIT(mute_pattern[pattern].map_303, _selected_track);
337+
} else {
338+
SET_BIT(mute_pattern[pattern].map_808[_selected_track-TRACK_NUMBER_303], selected_mute_chn);
339+
}
340+
// selected is same as current? update tracks mute state
341+
if (pattern == current_pattern)
342+
changePattern(current_pattern);
343+
} else if (data == DECREMENT) {
344+
if (AcidSequencer.is303(_selected_track)) {
345+
CLR_BIT(mute_pattern[pattern].map_303, _selected_track);
346+
} else {
347+
CLR_BIT(mute_pattern[pattern].map_808[_selected_track-TRACK_NUMBER_303], selected_mute_chn);
348+
}
349+
if (pattern == current_pattern)
350+
changePattern(current_pattern);
351+
}
352+
}
353+
354+
void function1() {
355+
current_pattern = --current_pattern % 4;
356+
changePattern(current_pattern);
357+
}
358+
359+
void function2() {
360+
current_pattern = ++current_pattern % 4;
361+
changePattern(current_pattern);
362+
}
363+
364+
void changePattern(uint8_t pattern) {
365+
// apply mute schema to 303s
366+
for (uint8_t i=0; i < TRACK_NUMBER_303; i++) {
367+
AcidSequencer.setMute(i, !GET_BIT(mute_pattern[pattern].map_303, i));
368+
}
369+
370+
// apply mute schema to 808s
371+
for (uint8_t i=0; i < TRACK_NUMBER_808; i++) {
372+
for (uint8_t j=0; j < VOICE_MAX_SIZE_808; j++) {
373+
AcidSequencer.setMute(i+TRACK_NUMBER_303, j, !GET_BIT(mute_pattern[pattern].map_808[i], j));
374+
}
375+
}
376+
}
377+
378+
void updateCurrentMuteState(uint8_t track, uint8_t voice = 0)
379+
{
380+
if (AcidSequencer.is303(track)) {
381+
if (AcidSequencer.getMute(track)) {
382+
CLR_BIT(mute_pattern[current_pattern].map_303, track);
383+
} else {
384+
SET_BIT(mute_pattern[current_pattern].map_303, track);
385+
}
386+
} else {
387+
if (AcidSequencer.getMute(track, AcidSequencer.getTrackVoice(track))) {
388+
CLR_BIT(mute_pattern[current_pattern].map_808[track-TRACK_NUMBER_303], voice);
389+
} else {
390+
SET_BIT(mute_pattern[current_pattern].map_808[track-TRACK_NUMBER_303], voice);
391+
}
392+
// update to selected voice too
393+
selected_mute_chn = voice;
394+
}
395+
}
396+
397+
} mutePatternComponent;
398+
241399
struct StepSequencer : PageComponent {
242400

243401
// step sequencer theme editor
@@ -383,7 +541,7 @@ struct StepSequencer : PageComponent {
383541
// f1 and f2
384542
// Selectors
385543
if (selected_line == 1) {
386-
setF1("mute", AcidSequencer.getMute(_selected_track));
544+
setF1("mute", AcidSequencer.is303(_selected_track) ? AcidSequencer.getMute(_selected_track) : AcidSequencer.getMute(_selected_track, AcidSequencer.getTrackVoice(_selected_track)));
387545
// you can only paste if the selected selector is cleared otherwise it will shows copy
388546
setF2("clear");
389547
// Steps
@@ -600,8 +758,15 @@ struct StepSequencer : PageComponent {
600758

601759
void function1() {
602760
if (selected_line == 1) {
603-
// mute track(subtrack for 808)
604-
AcidSequencer.setMute(_selected_track, !AcidSequencer.getMute(_selected_track));
761+
// mute track(voice for 808)
762+
if (AcidSequencer.is303(_selected_track)) {
763+
AcidSequencer.setMute(_selected_track, !AcidSequencer.getMute(_selected_track));
764+
// keep mutePatternComponent updated for current mute state
765+
mutePatternComponent.updateCurrentMuteState(_selected_track);
766+
} else {
767+
AcidSequencer.setMute(_selected_track, AcidSequencer.getTrackVoice(_selected_track), !AcidSequencer.getMute(_selected_track, AcidSequencer.getTrackVoice(_selected_track)));
768+
mutePatternComponent.updateCurrentMuteState(_selected_track, AcidSequencer.getTrackVoice(_selected_track));
769+
}
605770
} else if (selected_line >= 2) {
606771
// 303 and 808 uses the same accent button f1
607772
AcidSequencer.setAccent(_selected_track, selected_step, !AcidSequencer.accentOn(_selected_track, selected_step));
@@ -638,41 +803,6 @@ struct StepSequencer : PageComponent {
638803

639804
} stepSequencerComponent;
640805

641-
struct MutePatternControl : PageComponent {
642-
643-
// layout:
644-
// mute automation pattern style driven
645-
// 4x16 grid style:
646-
// last 4 grids are mute automation clip change/status
647-
// 12 grids are for mute elements(on 808 max 12, for 303 1 big mute slot)
648-
649-
MutePatternControl()
650-
{
651-
// we want this component to be 4 lines max and 16 grids navigable object
652-
line_size = 4;
653-
grid_size = 16;
654-
// enable more complex nav by updating selector pointer of page component
655-
update_selector = true;
656-
}
657-
658-
void view() {
659-
660-
}
661-
662-
void change(int16_t data) {
663-
664-
}
665-
666-
void function1() {
667-
668-
}
669-
670-
void function2() {
671-
672-
}
673-
674-
} mutePatternComponent;
675-
676806
struct TrackLength : PageComponent {
677807

678808
void view() {
@@ -914,3 +1044,55 @@ struct TrackFill : PageComponent {
9141044
}
9151045

9161046
} fillComponent;
1047+
1048+
// general functions
1049+
1050+
// used by page module for themed function button display
1051+
void functionDrawCallback(const char * f1, const char * f2, uint8_t f1_state, uint8_t f2_state)
1052+
{
1053+
// menu action
1054+
uCtrl.oled->print(f1, 8, 1+((14-strlen(f1))/2));
1055+
uCtrl.oled->print(f2, 8, 14+((14-strlen(f2))/2));
1056+
// state variation
1057+
if (f1_state == 1) {
1058+
uCtrl.oled->display->drawBox(0, 57, 63, 7);
1059+
}
1060+
if (f2_state == 1) {
1061+
uCtrl.oled->display->drawBox(64, 57, 64, 7);
1062+
}
1063+
// horizontal line
1064+
uCtrl.oled->display->drawBox(0, 56, 128, 1);
1065+
// vertical separator
1066+
//uCtrl.oled->display->drawBox(64, 59, 1, 5);
1067+
}
1068+
1069+
void playStop()
1070+
{
1071+
if (_playing)
1072+
uClock.stop();
1073+
else
1074+
uClock.start();
1075+
}
1076+
1077+
void tempoSetup()
1078+
{
1079+
uCtrl.page->selectComponent(topBarComponent);
1080+
}
1081+
1082+
void previousTrack()
1083+
{
1084+
if (_selected_track == 0) {
1085+
_selected_track = AcidSequencer.getTrackNumber() - 1;
1086+
} else {
1087+
--_selected_track;
1088+
}
1089+
}
1090+
1091+
void nextTrack()
1092+
{
1093+
if (_selected_track == AcidSequencer.getTrackNumber() - 1) {
1094+
_selected_track = 0;
1095+
} else {
1096+
++_selected_track;
1097+
}
1098+
}

v2/AciduinoV2/src/sequencer/acid_sequencer.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,19 +279,27 @@ void AcidSequencerClass::setMute(uint8_t track, uint8_t mute)
279279
// 303 request
280280
if(track < TRACK_NUMBER_303)
281281
_engine303.setMute(track, mute);
282-
// 808 request?
283-
else
284-
_engine808.setMute(track-TRACK_NUMBER_303, mute);
282+
}
283+
284+
void AcidSequencerClass::setMute(uint8_t track, uint8_t voice, uint8_t mute)
285+
{
286+
// 808 request
287+
if(track >= TRACK_NUMBER_303)
288+
_engine808.setMute(track-TRACK_NUMBER_303, voice, mute);
285289
}
286290

287291
uint8_t AcidSequencerClass::getMute(uint8_t track)
288292
{
289293
// 303 request
290294
if(track < TRACK_NUMBER_303)
291295
return _engine303.getMute(track);
296+
}
292297

298+
uint8_t AcidSequencerClass::getMute(uint8_t track, uint8_t voice)
299+
{
293300
// 808 request
294-
return _engine808.getMute(track-TRACK_NUMBER_303);
301+
if(track >= TRACK_NUMBER_303)
302+
return _engine808.getMute(track-TRACK_NUMBER_303, voice);
295303
}
296304

297305
void AcidSequencerClass::clearTrack(uint8_t track)

v2/AciduinoV2/src/sequencer/acid_sequencer.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ class AcidSequencerClass
8888
uint8_t getTrackMaxLength(uint8_t track);
8989
uint8_t getTrackLength(uint8_t track);
9090
void setTrackLength(uint8_t track, uint16_t length);
91-
void setMute(uint8_t track, uint8_t mute);
92-
uint8_t getMute(uint8_t track);
9391
void clearTrack(uint8_t track);
9492
void acidRandomize(uint8_t track, uint8_t fill, uint8_t param_1 = 0, uint8_t param_2 = 0, uint8_t param_3 = 0, uint8_t param_4 = 0, uint8_t param_5 = 0, uint8_t param_6 = 0);
9593
bool is303(uint8_t track);
@@ -103,6 +101,8 @@ class AcidSequencerClass
103101
void setTie(uint8_t track, uint8_t step, bool state);
104102
bool slideOn(uint8_t track, uint8_t step);
105103
bool tieOn(uint8_t track, uint8_t step);
104+
void setMute(uint8_t track, uint8_t mute);
105+
uint8_t getMute(uint8_t track);
106106
const char * getTemperamentName(uint8_t temperament_id);
107107
void setTemperament(uint8_t temperament_id);
108108
uint8_t getTemperamentId();
@@ -117,6 +117,8 @@ class AcidSequencerClass
117117
uint8_t getTrackVoice(uint8_t track);
118118
void setTrackVoiceConfig(uint8_t track, uint8_t note);
119119
uint8_t getTrackVoiceConfig(uint8_t track);
120+
void setMute(uint8_t track, uint8_t voice, uint8_t mute);
121+
uint8_t getMute(uint8_t track, uint8_t voice);
120122
const char * getTrackVoiceName(uint8_t track = 0, uint8_t voice = 0);
121123

122124
// main callback outputs... CV ouput for next release please!

0 commit comments

Comments
 (0)