aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-01-15 16:06:05 +0100
committerBad Diode <bd@badd10de.dev>2024-01-15 16:06:05 +0100
commitf6efcdd98b32f1cd0d5a4a52abb333437c04b44f (patch)
treef4542a21ceb080af21b684250650368de7fc9e3e
parent65089bc6ca9e31878afd583e133cb376ef03f268 (diff)
downloadstepper-f6efcdd98b32f1cd0d5a4a52abb333437c04b44f.tar.gz
stepper-f6efcdd98b32f1cd0d5a4a52abb333437c04b44f.zip
[WIP] Add decay control and attack/decay params on ch3
-rw-r--r--Makefile2
-rw-r--r--src/assets.c4
-rw-r--r--src/clipboard.c135
-rw-r--r--src/drawing.c225
-rw-r--r--src/main.c15
-rw-r--r--src/patterns.c105
-rw-r--r--src/sequencer.c42
7 files changed, 388 insertions, 140 deletions
diff --git a/Makefile b/Makefile
index 6a33d16..9894173 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ INC_FLAGS := $(addprefix -I,$(INC_DIRS))
27INC_FLAGS += -I$(LIBGBA_SRC) 27INC_FLAGS += -I$(LIBGBA_SRC)
28 28
29# Output library names and executables. 29# Output library names and executables.
30TARGET := STEPPER-v1.8-dev-11 30TARGET := STEPPER-v1.8-dev-14
31ELF := $(BUILD_DIR)/$(TARGET).elf 31ELF := $(BUILD_DIR)/$(TARGET).elf
32BIN := $(BUILD_DIR)/$(TARGET).gba 32BIN := $(BUILD_DIR)/$(TARGET).gba
33 33
diff --git a/src/assets.c b/src/assets.c
index c11364e..be4b87c 100644
--- a/src/assets.c
+++ b/src/assets.c
@@ -97,8 +97,10 @@ enum WAVES {
97 97
98typedef u32 Wave[WAVE_SIZE]; 98typedef u32 Wave[WAVE_SIZE];
99static Wave wave_active = {0}; 99static Wave wave_active = {0};
100static Wave wave_target = {0}; 100// static Wave wave_target = {0};
101// TODO: wave env status: OFF, ATTACK, DECAY
101static int wave_env_ticks = 0; 102static int wave_env_ticks = 0;
103static int wave_env_attack = 8;
102static int wave_env_decay = 8; 104static int wave_env_decay = 8;
103 105
104static const Wave waves[][WAVE_VARS] = { 106static const Wave waves[][WAVE_VARS] = {
diff --git a/src/clipboard.c b/src/clipboard.c
index d82f576..e92d4c5 100644
--- a/src/clipboard.c
+++ b/src/clipboard.c
@@ -37,20 +37,25 @@ clipboard_paste(void) {
37 case 0: { 37 case 0: {
38 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig]; 38 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
39 pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; 39 pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
40 send_notif("PASTED NOTE & PARAMS");
41 } break; 40 } break;
42 case 1: { 41 case 1: {
43 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig]; 42 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
44 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; 43 pat_dst->ch2.params[trig_selection_loc].env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
45 send_notif("PASTED NOTE & PARAMS"); 44 pat_dst->ch2.params[trig_selection_loc].env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
45 pat_dst->ch2.params[trig_selection_loc].env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
46 pat_dst->ch2.params[trig_selection_loc].duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
47 pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
48 pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
46 } break; 49 } break;
47 case 2: { 50 case 2: {
48 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig]; 51 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
49 send_notif("PASTED NOTE"); 52 pat_dst->ch3.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
53 pat_dst->ch3.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
50 } break; 54 } break;
51 case 3: { 55 case 3: {
52 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig]; 56 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
53 send_notif("PASTED NOTE"); 57 pat_dst->ch4.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
58 pat_dst->ch4.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
54 } break; 59 } break;
55 } 60 }
56 } break; 61 } break;
@@ -62,20 +67,22 @@ clipboard_paste(void) {
62 pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time; 67 pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
63 pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction; 68 pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
64 pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle; 69 pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
65 send_notif("PASTED NOTE & PARAMS"); 70 pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
71 pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
66 } break; 72 } break;
67 case 1: { 73 case 1: {
68 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig]; 74 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
69 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig]; 75 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig];
70 send_notif("PASTED NOTE & PARAMS");
71 } break; 76 } break;
72 case 2: { 77 case 2: {
73 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig]; 78 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
74 send_notif("PASTED NOTE"); 79 pat_dst->ch3.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
80 pat_dst->ch3.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
75 } break; 81 } break;
76 case 3: { 82 case 3: {
77 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig]; 83 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
78 send_notif("PASTED NOTE"); 84 pat_dst->ch4.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
85 pat_dst->ch4.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
79 } break; 86 } break;
80 } 87 }
81 } break; 88 } break;
@@ -83,20 +90,22 @@ clipboard_paste(void) {
83 switch (channel_selection_loc) { 90 switch (channel_selection_loc) {
84 case 0: { 91 case 0: {
85 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig]; 92 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
86 send_notif("PASTED NOTE"); 93 pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch3.params[clipboard.src_trig].prob;
94 pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch3.params[clipboard.src_trig].pan;
87 } break; 95 } break;
88 case 1: { 96 case 1: {
89 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig]; 97 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
90 send_notif("PASTED NOTE"); 98 pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch3.params[clipboard.src_trig].prob;
99 pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch3.params[clipboard.src_trig].pan;
91 } break; 100 } break;
92 case 2: { 101 case 2: {
93 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig]; 102 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
94 pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig]; 103 pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig];
95 send_notif("PASTED NOTE & PARAMS");
96 } break; 104 } break;
97 case 3: { 105 case 3: {
98 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig]; 106 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
99 send_notif("PASTED NOTE"); 107 pat_dst->ch4.params[trig_selection_loc].prob = pat_src->ch3.params[clipboard.src_trig].prob;
108 pat_dst->ch4.params[trig_selection_loc].pan = pat_src->ch3.params[clipboard.src_trig].pan;
100 } break; 109 } break;
101 } 110 }
102 } break; 111 } break;
@@ -104,37 +113,44 @@ clipboard_paste(void) {
104 switch (channel_selection_loc) { 113 switch (channel_selection_loc) {
105 case 0: { 114 case 0: {
106 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig]; 115 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
107 send_notif("PASTED NOTE"); 116 pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch4.params[clipboard.src_trig].prob;
117 pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch4.params[clipboard.src_trig].pan;
108 } break; 118 } break;
109 case 1: { 119 case 1: {
110 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig]; 120 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
111 send_notif("PASTED NOTE"); 121 pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch4.params[clipboard.src_trig].prob;
122 pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch4.params[clipboard.src_trig].pan;
112 } break; 123 } break;
113 case 2: { 124 case 2: {
114 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig]; 125 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
115 send_notif("PASTED NOTE"); 126 pat_dst->ch3.params[trig_selection_loc].prob = pat_src->ch4.params[clipboard.src_trig].prob;
127 pat_dst->ch3.params[trig_selection_loc].pan = pat_src->ch4.params[clipboard.src_trig].pan;
116 } break; 128 } break;
117 case 3: { 129 case 3: {
118 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig]; 130 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
119 pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig]; 131 pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig];
120 send_notif("PASTED NOTE & PARAMS");
121 } break; 132 } break;
122 } 133 }
123 } break; 134 } break;
124 } 135 }
136 send_notif("PASTED NOTE & PARAMS");
125 } 137 }
126 // Only paste the params for the respective trigger. 138 // Only paste the params for the respective trigger.
127 if (clipboard.type == CLIP_PARAM_CH1) { 139 if (clipboard.type == CLIP_PARAM_CH1) {
128 switch (channel_selection_loc) { 140 switch (channel_selection_loc) {
129 case 0: { 141 case 0: {
130 pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; 142 pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
131 send_notif("PASTED PARAMS");
132 } break; 143 } break;
133 case 1: { 144 case 1: {
134 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; 145 pat_dst->ch2.params[trig_selection_loc].env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
135 send_notif("PASTED PARAMS"); 146 pat_dst->ch2.params[trig_selection_loc].env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
147 pat_dst->ch2.params[trig_selection_loc].env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
148 pat_dst->ch2.params[trig_selection_loc].duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
149 pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
150 pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
136 } break; 151 } break;
137 } 152 }
153 send_notif("PASTED PARAMS");
138 } 154 }
139 if (clipboard.type == CLIP_PARAM_CH2) { 155 if (clipboard.type == CLIP_PARAM_CH2) {
140 switch (channel_selection_loc) { 156 switch (channel_selection_loc) {
@@ -143,13 +159,14 @@ clipboard_paste(void) {
143 pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time; 159 pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
144 pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction; 160 pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
145 pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle; 161 pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
146 send_notif("PASTED PARAMS"); 162 pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
163 pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
147 } break; 164 } break;
148 case 1: { 165 case 1: {
149 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig]; 166 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig];
150 send_notif("PASTED PARAMS");
151 } break; 167 } break;
152 } 168 }
169 send_notif("PASTED PARAMS");
153 } 170 }
154 if (clipboard.type == CLIP_PARAM_CH3 && channel_selection_loc == clipboard.src_chan) { 171 if (clipboard.type == CLIP_PARAM_CH3 && channel_selection_loc == clipboard.src_chan) {
155 pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig]; 172 pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig];
@@ -170,6 +187,8 @@ clipboard_paste(void) {
170 pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time; 187 pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
171 pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction; 188 pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
172 pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle; 189 pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
190 pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
191 pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
173 send_notif("PASTED PARAMS"); 192 send_notif("PASTED PARAMS");
174 draw_parameters(); 193 draw_parameters();
175 } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH2) { 194 } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH2) {
@@ -177,7 +196,12 @@ clipboard_paste(void) {
177 send_notif("PASTED PARAMS"); 196 send_notif("PASTED PARAMS");
178 draw_parameters(); 197 draw_parameters();
179 } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH1) { 198 } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH1) {
180 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig]; 199 pat_dst->ch2.params[trig_selection_loc].env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
200 pat_dst->ch2.params[trig_selection_loc].env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
201 pat_dst->ch2.params[trig_selection_loc].env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
202 pat_dst->ch2.params[trig_selection_loc].duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
203 pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
204 pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
181 send_notif("PASTED PARAMS"); 205 send_notif("PASTED PARAMS");
182 draw_parameters(); 206 draw_parameters();
183 } else if (input_handler == handle_param_selection_wave && clipboard.type == CLIP_PARAM_CH3) { 207 } else if (input_handler == handle_param_selection_wave && clipboard.type == CLIP_PARAM_CH3) {
@@ -198,7 +222,6 @@ clipboard_paste(void) {
198 case 2: { pat_dst->ch3 = pat_src->ch3; } break; 222 case 2: { pat_dst->ch3 = pat_src->ch3; } break;
199 case 3: { pat_dst->ch4 = pat_src->ch4; } break; 223 case 3: { pat_dst->ch4 = pat_src->ch4; } break;
200 } 224 }
201 send_notif("PASTED NOTES & PARAMS");
202 } else { 225 } else {
203 switch (clipboard.src_chan) { 226 switch (clipboard.src_chan) {
204 case 0: { 227 case 0: {
@@ -208,26 +231,31 @@ clipboard_paste(void) {
208 pat_dst->ch1.notes[i] = pat_src->ch1.notes[i]; 231 pat_dst->ch1.notes[i] = pat_src->ch1.notes[i];
209 pat_dst->ch1.params[i] = pat_src->ch1.params[i]; 232 pat_dst->ch1.params[i] = pat_src->ch1.params[i];
210 } 233 }
211 send_notif("PASTED NOTES & PARAMS");
212 } break; 234 } break;
213 case 1: { 235 case 1: {
214 for (size_t i = 0; i < 16; i++) { 236 for (size_t i = 0; i < 16; i++) {
215 pat_dst->ch2.notes[i] = pat_src->ch1.notes[i]; 237 pat_dst->ch2.notes[i] = pat_src->ch1.notes[i];
216 pat_dst->ch2.params[i] = pat_src->ch1.params[i]; 238 pat_dst->ch2.params[i].env_volume = pat_src->ch1.params[i].env_volume;
239 pat_dst->ch2.params[i].env_time = pat_src->ch1.params[i].env_time;
240 pat_dst->ch2.params[i].env_direction = pat_src->ch1.params[i].env_direction;
241 pat_dst->ch2.params[i].duty_cycle = pat_src->ch1.params[i].duty_cycle;
242 pat_dst->ch2.params[i].prob = pat_src->ch1.params[i].prob;
243 pat_dst->ch2.params[i].pan = pat_src->ch1.params[i].pan;
217 } 244 }
218 send_notif("PASTED NOTES & PARAMS");
219 } break; 245 } break;
220 case 2: { 246 case 2: {
221 for (size_t i = 0; i < 16; i++) { 247 for (size_t i = 0; i < 16; i++) {
222 pat_dst->ch3.notes[i] = pat_src->ch1.notes[i]; 248 pat_dst->ch3.notes[i] = pat_src->ch1.notes[i];
249 pat_dst->ch3.params[i].prob = pat_src->ch1.params[i].prob;
250 pat_dst->ch3.params[i].pan = pat_src->ch1.params[i].pan;
223 } 251 }
224 send_notif("PASTED NOTES");
225 } break; 252 } break;
226 case 3: { 253 case 3: {
227 for (size_t i = 0; i < 16; i++) { 254 for (size_t i = 0; i < 16; i++) {
228 pat_dst->ch4.notes[i] = pat_src->ch1.notes[i]; 255 pat_dst->ch4.notes[i] = pat_src->ch1.notes[i];
256 pat_dst->ch4.params[i].prob = pat_src->ch1.params[i].prob;
257 pat_dst->ch4.params[i].pan = pat_src->ch1.params[i].pan;
229 } 258 }
230 send_notif("PASTED NOTES");
231 } break; 259 } break;
232 } 260 }
233 } break; 261 } break;
@@ -240,27 +268,29 @@ clipboard_paste(void) {
240 pat_dst->ch1.params[i].env_time = pat_src->ch2.params[i].env_time; 268 pat_dst->ch1.params[i].env_time = pat_src->ch2.params[i].env_time;
241 pat_dst->ch1.params[i].env_direction = pat_src->ch2.params[i].env_direction; 269 pat_dst->ch1.params[i].env_direction = pat_src->ch2.params[i].env_direction;
242 pat_dst->ch1.params[i].duty_cycle = pat_src->ch2.params[i].duty_cycle; 270 pat_dst->ch1.params[i].duty_cycle = pat_src->ch2.params[i].duty_cycle;
271 pat_dst->ch1.params[i].prob = pat_src->ch2.params[i].prob;
272 pat_dst->ch1.params[i].pan = pat_src->ch2.params[i].pan;
243 } 273 }
244 send_notif("PASTED NOTES & PARAMS");
245 } break; 274 } break;
246 case 1: { 275 case 1: {
247 for (size_t i = 0; i < 16; i++) { 276 for (size_t i = 0; i < 16; i++) {
248 pat_dst->ch2.notes[i] = pat_src->ch2.notes[i]; 277 pat_dst->ch2.notes[i] = pat_src->ch2.notes[i];
249 pat_dst->ch2.params[i] = pat_src->ch2.params[i]; 278 pat_dst->ch2.params[i] = pat_src->ch2.params[i];
250 } 279 }
251 send_notif("PASTED NOTES & PARAMS");
252 } break; 280 } break;
253 case 2: { 281 case 2: {
254 for (size_t i = 0; i < 16; i++) { 282 for (size_t i = 0; i < 16; i++) {
255 pat_dst->ch3.notes[i] = pat_src->ch2.notes[i]; 283 pat_dst->ch3.notes[i] = pat_src->ch2.notes[i];
284 pat_dst->ch3.params[i].prob = pat_src->ch2.params[i].prob;
285 pat_dst->ch3.params[i].pan = pat_src->ch2.params[i].pan;
256 } 286 }
257 send_notif("PASTED NOTES");
258 } break; 287 } break;
259 case 3: { 288 case 3: {
260 for (size_t i = 0; i < 16; i++) { 289 for (size_t i = 0; i < 16; i++) {
261 pat_dst->ch4.notes[i] = pat_src->ch2.notes[i]; 290 pat_dst->ch4.notes[i] = pat_src->ch2.notes[i];
291 pat_dst->ch4.params[i].prob = pat_src->ch2.params[i].prob;
292 pat_dst->ch4.params[i].pan = pat_src->ch2.params[i].pan;
262 } 293 }
263 send_notif("PASTED NOTES");
264 } break; 294 } break;
265 } 295 }
266 } break; 296 } break;
@@ -269,27 +299,29 @@ clipboard_paste(void) {
269 case 0: { 299 case 0: {
270 for (size_t i = 0; i < 16; i++) { 300 for (size_t i = 0; i < 16; i++) {
271 pat_dst->ch1.notes[i] = pat_src->ch3.notes[i]; 301 pat_dst->ch1.notes[i] = pat_src->ch3.notes[i];
302 pat_dst->ch1.params[i].prob = pat_src->ch3.params[i].prob;
303 pat_dst->ch1.params[i].pan = pat_src->ch3.params[i].pan;
272 } 304 }
273 send_notif("PASTED NOTES");
274 } break; 305 } break;
275 case 1: { 306 case 1: {
276 for (size_t i = 0; i < 16; i++) { 307 for (size_t i = 0; i < 16; i++) {
277 pat_dst->ch2.notes[i] = pat_src->ch3.notes[i]; 308 pat_dst->ch2.notes[i] = pat_src->ch3.notes[i];
309 pat_dst->ch2.params[i].prob = pat_src->ch3.params[i].prob;
310 pat_dst->ch2.params[i].pan = pat_src->ch3.params[i].pan;
278 } 311 }
279 send_notif("PASTED NOTES");
280 } break; 312 } break;
281 case 2: { 313 case 2: {
282 for (size_t i = 0; i < 16; i++) { 314 for (size_t i = 0; i < 16; i++) {
283 pat_dst->ch3.notes[i] = pat_src->ch3.notes[i]; 315 pat_dst->ch3.notes[i] = pat_src->ch3.notes[i];
284 pat_dst->ch3.params[i] = pat_src->ch3.params[i]; 316 pat_dst->ch3.params[i] = pat_src->ch3.params[i];
285 } 317 }
286 send_notif("PASTED NOTES & PARAMS");
287 } break; 318 } break;
288 case 3: { 319 case 3: {
289 for (size_t i = 0; i < 16; i++) { 320 for (size_t i = 0; i < 16; i++) {
290 pat_dst->ch4.notes[i] = pat_src->ch3.notes[i]; 321 pat_dst->ch4.notes[i] = pat_src->ch3.notes[i];
322 pat_dst->ch4.params[i].prob = pat_src->ch3.params[i].prob;
323 pat_dst->ch4.params[i].pan = pat_src->ch3.params[i].pan;
291 } 324 }
292 send_notif("PASTED NOTES");
293 } break; 325 } break;
294 } 326 }
295 } break; 327 } break;
@@ -298,32 +330,35 @@ clipboard_paste(void) {
298 case 0: { 330 case 0: {
299 for (size_t i = 0; i < 16; i++) { 331 for (size_t i = 0; i < 16; i++) {
300 pat_dst->ch1.notes[i] = pat_src->ch4.notes[i]; 332 pat_dst->ch1.notes[i] = pat_src->ch4.notes[i];
333 pat_dst->ch1.params[i].prob = pat_src->ch4.params[i].prob;
334 pat_dst->ch1.params[i].pan = pat_src->ch4.params[i].pan;
301 } 335 }
302 send_notif("PASTED NOTES");
303 } break; 336 } break;
304 case 1: { 337 case 1: {
305 for (size_t i = 0; i < 16; i++) { 338 for (size_t i = 0; i < 16; i++) {
306 pat_dst->ch2.notes[i] = pat_src->ch4.notes[i]; 339 pat_dst->ch2.notes[i] = pat_src->ch4.notes[i];
340 pat_dst->ch2.params[i].prob = pat_src->ch4.params[i].prob;
341 pat_dst->ch2.params[i].pan = pat_src->ch4.params[i].pan;
307 } 342 }
308 send_notif("PASTED NOTES");
309 } break; 343 } break;
310 case 2: { 344 case 2: {
311 for (size_t i = 0; i < 16; i++) { 345 for (size_t i = 0; i < 16; i++) {
312 pat_dst->ch3.notes[i] = pat_src->ch4.notes[i]; 346 pat_dst->ch3.notes[i] = pat_src->ch4.notes[i];
347 pat_dst->ch3.params[i].prob = pat_src->ch4.params[i].prob;
348 pat_dst->ch3.params[i].pan = pat_src->ch4.params[i].pan;
313 } 349 }
314 send_notif("PASTED NOTES");
315 } break; 350 } break;
316 case 3: { 351 case 3: {
317 for (size_t i = 0; i < 16; i++) { 352 for (size_t i = 0; i < 16; i++) {
318 pat_dst->ch4.notes[i] = pat_src->ch4.notes[i]; 353 pat_dst->ch4.notes[i] = pat_src->ch4.notes[i];
319 pat_dst->ch4.params[i] = pat_src->ch4.params[i]; 354 pat_dst->ch4.params[i] = pat_src->ch4.params[i];
320 } 355 }
321 send_notif("PASTED NOTES & PARAMS");
322 } break; 356 } break;
323 } 357 }
324 } break; 358 } break;
325 } 359 }
326 } 360 }
361 send_notif("PASTED NOTES & PARAMS");
327 draw_channels(); 362 draw_channels();
328 draw_triggers(); 363 draw_triggers();
329 } else if (input_handler == handle_channel_selection) { 364 } else if (input_handler == handle_channel_selection) {
@@ -344,11 +379,15 @@ clipboard_paste(void) {
344 ch1_params.env_time = pat_src->ch2.params[clipboard.src_trig].env_time; 379 ch1_params.env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
345 ch1_params.env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction; 380 ch1_params.env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
346 ch1_params.duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle; 381 ch1_params.duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
382 ch1_params.prob = pat_src->ch2.params[clipboard.src_trig].prob;
383 ch1_params.pan = pat_src->ch2.params[clipboard.src_trig].pan;
347 for (size_t i = 0; i < 16; i++) { 384 for (size_t i = 0; i < 16; i++) {
348 pat_dst->ch1.params[i].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume; 385 pat_dst->ch1.params[i].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume;
349 pat_dst->ch1.params[i].env_time = pat_src->ch2.params[clipboard.src_trig].env_time; 386 pat_dst->ch1.params[i].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
350 pat_dst->ch1.params[i].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction; 387 pat_dst->ch1.params[i].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
351 pat_dst->ch1.params[i].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle; 388 pat_dst->ch1.params[i].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
389 pat_dst->ch1.params[i].prob = pat_src->ch2.params[clipboard.src_trig].prob;
390 pat_dst->ch1.params[i].pan = pat_src->ch2.params[clipboard.src_trig].pan;
352 } 391 }
353 send_notif("PASTED PARAMS"); 392 send_notif("PASTED PARAMS");
354 } 393 }
@@ -359,9 +398,19 @@ clipboard_paste(void) {
359 clipboard.type == CLIP_PARAM_CH1 || 398 clipboard.type == CLIP_PARAM_CH1 ||
360 clipboard.type == CLIP_PARAM_CH2) { 399 clipboard.type == CLIP_PARAM_CH2) {
361 if (clipboard.src_chan == 0) { 400 if (clipboard.src_chan == 0) {
362 ch2_params = pat_src->ch1.params[clipboard.src_trig]; 401 ch2_params.env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
402 ch2_params.env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
403 ch2_params.env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
404 ch2_params.duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
405 ch2_params.prob = pat_src->ch1.params[clipboard.src_trig].prob;
406 ch2_params.pan = pat_src->ch1.params[clipboard.src_trig].pan;
363 for (size_t i = 0; i < 16; i++) { 407 for (size_t i = 0; i < 16; i++) {
364 pat_dst->ch2.params[i] = pat_src->ch1.params[clipboard.src_trig]; 408 pat_dst->ch2.params[i].env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
409 pat_dst->ch2.params[i].env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
410 pat_dst->ch2.params[i].env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
411 pat_dst->ch2.params[i].duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
412 pat_dst->ch2.params[i].prob = pat_src->ch1.params[clipboard.src_trig].prob;
413 pat_dst->ch2.params[i].pan = pat_src->ch1.params[clipboard.src_trig].pan;
365 } 414 }
366 send_notif("PASTED PARAMS"); 415 send_notif("PASTED PARAMS");
367 } 416 }
diff --git a/src/drawing.c b/src/drawing.c
index 2368627..f18f094 100644
--- a/src/drawing.c
+++ b/src/drawing.c
@@ -681,6 +681,16 @@ draw_params_cursor_wave(size_t i, u8 clr) {
681 y += PARAMS_BOX_H - 7 + PARAMS_BOX_OFFSET_Y; 681 y += PARAMS_BOX_H - 7 + PARAMS_BOX_OFFSET_Y;
682 txt_drawf_small("vol", x, y, COL_BG); 682 txt_drawf_small("vol", x, y, COL_BG);
683 } break; 683 } break;
684 case 7: {
685 x += 2 + PARAMS_BOX_OFFSET_X * 2;
686 y += PARAMS_BOX_H - 7 + PARAMS_BOX_OFFSET_Y;
687 txt_drawf_small("attack", x, y, COL_BG);
688 } break;
689 case 8: {
690 x += 4 + PARAMS_BOX_OFFSET_X * 3;
691 y += PARAMS_BOX_H - 7 + PARAMS_BOX_OFFSET_Y;
692 txt_drawf_small("decay", x, y, COL_BG);
693 } break;
684 case 9: { 694 case 9: {
685 x += 8 + PARAMS_BOX_OFFSET_X * 4; 695 x += 8 + PARAMS_BOX_OFFSET_X * 4;
686 y += PARAMS_BOX_H - 7 + PARAMS_BOX_OFFSET_Y; 696 y += PARAMS_BOX_H - 7 + PARAMS_BOX_OFFSET_Y;
@@ -1012,6 +1022,32 @@ draw_parameters_wave(ChannelWaveParams *params, bool global) {
1012 } 1022 }
1013 } 1023 }
1014 1024
1025 // Attack.
1026 {
1027 size_t x = PARAMS_START_X + PARAMS_BOX_OFFSET_X * 2 + 3;
1028 size_t y = PARAMS_START_Y + PARAMS_BOX_OFFSET_Y + 5;
1029 if (params->wave_attack == 0) {
1030 txt_drawf("OFF", x + 3, y, cols[6]);
1031 } else if (params->wave_attack < 10) {
1032 txt_drawf("%d", x + 8, y, cols[6], params->wave_attack);
1033 } else {
1034 txt_drawf("%d", x + 6, y, cols[6], params->wave_attack);
1035 }
1036 }
1037
1038 // Decay.
1039 {
1040 size_t x = PARAMS_START_X + PARAMS_BOX_OFFSET_X * 3 + 3;
1041 size_t y = PARAMS_START_Y + PARAMS_BOX_OFFSET_Y + 5;
1042 if (params->wave_decay == 0) {
1043 txt_drawf("OFF", x + 3, y, cols[6]);
1044 } else if (params->wave_decay < 10) {
1045 txt_drawf("%d", x + 8, y, cols[6], params->wave_decay);
1046 } else {
1047 txt_drawf("%d", x + 6, y, cols[6], params->wave_decay);
1048 }
1049 }
1050
1015 // Labels. 1051 // Labels.
1016 { 1052 {
1017 size_t x = PARAMS_START_X; 1053 size_t x = PARAMS_START_X;
@@ -1024,18 +1060,14 @@ draw_parameters_wave(ChannelWaveParams *params, bool global) {
1024 y += PARAMS_BOX_OFFSET_Y; 1060 y += PARAMS_BOX_OFFSET_Y;
1025 txt_drawf_small("voice", x + 4 + PARAMS_BOX_OFFSET_X * 0, y + PARAMS_BOX_H - 7, cols[5]); 1061 txt_drawf_small("voice", x + 4 + PARAMS_BOX_OFFSET_X * 0, y + PARAMS_BOX_H - 7, cols[5]);
1026 txt_drawf_small("vol", x + 8 + PARAMS_BOX_OFFSET_X * 1, y + PARAMS_BOX_H - 7, cols[6]); 1062 txt_drawf_small("vol", x + 8 + PARAMS_BOX_OFFSET_X * 1, y + PARAMS_BOX_H - 7, cols[6]);
1063 txt_drawf_small("attack", x + 2 + PARAMS_BOX_OFFSET_X * 2, y + PARAMS_BOX_H - 7, cols[7]);
1064 txt_drawf_small("decay", x + 4 + PARAMS_BOX_OFFSET_X * 3, y + PARAMS_BOX_H - 7, cols[8]);
1027 txt_drawf_small("pan", x + 8 + PARAMS_BOX_OFFSET_X * 4, y + PARAMS_BOX_H - 7, cols[9]); 1065 txt_drawf_small("pan", x + 8 + PARAMS_BOX_OFFSET_X * 4, y + PARAMS_BOX_H - 7, cols[9]);
1028 } 1066 }
1029
1030 // Empty spacers.
1031 {
1032 draw_param_stub(7, COL_OFF);
1033 draw_param_stub(8, COL_OFF);
1034 }
1035} 1067}
1036 1068
1037void 1069void
1038draw_parameters_square(ChannelSquareParams *params, bool sweep, bool global) { 1070draw_parameters_square1(ChannelSquare1Params *params, bool global) {
1039 u8 cols[10] = { 1071 u8 cols[10] = {
1040 COL_FG, COL_FG, COL_FG, COL_FG, COL_FG, 1072 COL_FG, COL_FG, COL_FG, COL_FG, COL_FG,
1041 COL_FG, COL_FG, COL_FG, COL_FG, COL_FG, 1073 COL_FG, COL_FG, COL_FG, COL_FG, COL_FG,
@@ -1044,12 +1076,8 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep, bool global) {
1044 // Adjust colors for global trigger parameters. 1076 // Adjust colors for global trigger parameters.
1045 if (global && input_handler == handle_channel_selection) { 1077 if (global && input_handler == handle_channel_selection) {
1046 for (size_t i = 0; i < 16; i++) { 1078 for (size_t i = 0; i < 16; i++) {
1047 ChannelSquareParams *trig_params; 1079 ChannelSquare1Params *trig_params;
1048 if (sweep) { 1080 trig_params = &patterns[pattern_selection_loc].ch1.params[i];
1049 trig_params = &patterns[pattern_selection_loc].ch1.params[i];
1050 } else {
1051 trig_params = &patterns[pattern_selection_loc].ch2.params[i];
1052 }
1053 if (params->duty_cycle != trig_params->duty_cycle) { 1081 if (params->duty_cycle != trig_params->duty_cycle) {
1054 cols[0] = COL_OFF; 1082 cols[0] = COL_OFF;
1055 } 1083 }
@@ -1168,7 +1196,7 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep, bool global) {
1168 draw_panning(params->pan, cols[9]); 1196 draw_panning(params->pan, cols[9]);
1169 1197
1170 // Sweep. 1198 // Sweep.
1171 if (sweep) { 1199 {
1172 size_t x = PARAMS_START_X; 1200 size_t x = PARAMS_START_X;
1173 size_t y = PARAMS_START_Y + PARAMS_BOX_OFFSET_Y; 1201 size_t y = PARAMS_START_Y + PARAMS_BOX_OFFSET_Y;
1174 1202
@@ -1229,21 +1257,156 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep, bool global) {
1229 txt_drawf_small("dir", x + 8 + PARAMS_BOX_OFFSET_X * 3, y + PARAMS_BOX_H - 7, cols[3]); 1257 txt_drawf_small("dir", x + 8 + PARAMS_BOX_OFFSET_X * 3, y + PARAMS_BOX_H - 7, cols[3]);
1230 txt_drawf_small("prob", x + 6 + PARAMS_BOX_OFFSET_X * 4, y + PARAMS_BOX_H - 7, cols[4]); 1258 txt_drawf_small("prob", x + 6 + PARAMS_BOX_OFFSET_X * 4, y + PARAMS_BOX_H - 7, cols[4]);
1231 y += PARAMS_BOX_OFFSET_Y; 1259 y += PARAMS_BOX_OFFSET_Y;
1232 if (sweep) { 1260 txt_drawf_small("sweep", x + 4 + PARAMS_BOX_OFFSET_X * 0, y + PARAMS_BOX_H - 7, cols[5]);
1233 txt_drawf_small("sweep", x + 4 + PARAMS_BOX_OFFSET_X * 0, y + PARAMS_BOX_H - 7, cols[5]); 1261 txt_drawf_small("time", x + 6 + PARAMS_BOX_OFFSET_X * 1, y + PARAMS_BOX_H - 7, cols[6]);
1234 txt_drawf_small("time", x + 6 + PARAMS_BOX_OFFSET_X * 1, y + PARAMS_BOX_H - 7, cols[6]); 1262 txt_drawf_small("dir", x + 8 + PARAMS_BOX_OFFSET_X * 2, y + PARAMS_BOX_H - 7, cols[7]);
1235 txt_drawf_small("dir", x + 8 + PARAMS_BOX_OFFSET_X * 2, y + PARAMS_BOX_H - 7, cols[7]);
1236 }
1237 txt_drawf_small("pan", x + 8 + PARAMS_BOX_OFFSET_X * 4, y + PARAMS_BOX_H - 7, cols[9]); 1263 txt_drawf_small("pan", x + 8 + PARAMS_BOX_OFFSET_X * 4, y + PARAMS_BOX_H - 7, cols[9]);
1238 } 1264 }
1239 1265
1240 // Empty spacers. 1266 // Empty spacers.
1241 { 1267 {
1242 if (!sweep) { 1268 draw_param_stub(8, COL_OFF);
1243 draw_param_stub(5, COL_OFF); 1269 }
1244 draw_param_stub(6, COL_OFF); 1270}
1245 draw_param_stub(7, COL_OFF); 1271
1272void
1273draw_parameters_square2(ChannelSquare2Params *params, bool global) {
1274 u8 cols[10] = {
1275 COL_FG, COL_FG, COL_FG, COL_FG, COL_FG,
1276 COL_FG, COL_FG, COL_FG, COL_FG, COL_FG,
1277 };
1278
1279 // Adjust colors for global trigger parameters.
1280 if (global && input_handler == handle_channel_selection) {
1281 for (size_t i = 0; i < 16; i++) {
1282 ChannelSquare2Params *trig_params;
1283 trig_params = &patterns[pattern_selection_loc].ch2.params[i];
1284 if (params->duty_cycle != trig_params->duty_cycle) {
1285 cols[0] = COL_OFF;
1286 }
1287 if (params->env_volume != trig_params->env_volume) {
1288 cols[1] = COL_OFF;
1289 }
1290 if (params->env_time != trig_params->env_time) {
1291 cols[2] = COL_OFF;
1292 }
1293 if (params->env_direction != trig_params->env_direction) {
1294 cols[3] = COL_OFF;
1295 }
1296 if (params->env_direction != trig_params->env_direction) {
1297 cols[3] = COL_OFF;
1298 }
1299 if (params->prob != trig_params->prob) {
1300 cols[4] = COL_OFF;
1301 }
1302 if (params->pan != trig_params->pan) {
1303 cols[9] = COL_OFF;
1304 }
1246 } 1305 }
1306 }
1307
1308 // Duty cycle / shape.
1309 {
1310 size_t x = PARAMS_START_X + 3;
1311 size_t y = PARAMS_START_Y + 1;
1312
1313 size_t x0 = x + 2;
1314 size_t x1 = x0;
1315 size_t x2 = x0;
1316 size_t x3 = x0;
1317 size_t x4 = x0;
1318 size_t x5 = x0;
1319 size_t y0 = y + 14;
1320 size_t y1 = y + 2;
1321
1322 switch (params->duty_cycle) {
1323 case 0: {
1324 x1 += 4;
1325 x2 += 6;
1326 x3 += 13;
1327 x4 += 15;
1328 x5 += 20;
1329 } break;
1330 case 1: {
1331 x1 += 4;
1332 x2 += 7;
1333 x3 += 13;
1334 x4 += 16;
1335 x5 += 20;
1336 } break;
1337 case 2: {
1338 x1 += 3;
1339 x2 += 8;
1340 x3 += 12;
1341 x4 += 17;
1342 x5 += 20;
1343 } break;
1344 case 3: {
1345 x1 += 2;
1346 x2 += 9;
1347 x3 += 11;
1348 x4 += 18;
1349 x5 += 20;
1350 } break;
1351 }
1352 u8 col_shape = cols[0] != COL_OFF ? COL_ACC_1 : COL_OFF;
1353 draw_line(x0, y0, x1, y0, col_shape);
1354 draw_line(x1, y1, x1, y0, col_shape);
1355 draw_line(x1, y1, x2, y1, col_shape);
1356 draw_line(x2, y1, x2, y0, col_shape);
1357 draw_line(x2, y0, x3, y0, col_shape);
1358 draw_line(x3, y1, x3, y0, col_shape);
1359 draw_line(x3, y1, x4, y1, col_shape);
1360 draw_line(x4, y1, x4, y0, col_shape);
1361 draw_line(x4, y0, x5, y0, col_shape);
1362 }
1363
1364 // Envelope.
1365 {
1366 size_t x = PARAMS_START_X + PARAMS_BOX_OFFSET_X * 1 + 1;
1367 size_t y = PARAMS_START_Y + 1;
1368 size_t x0 = x;
1369 size_t y0 = y + 15 - params->env_volume;
1370 size_t x1 = x + (3 * PARAMS_BOX_OFFSET_X) * params->env_time / 8 + 7;
1371 size_t y1 = params->env_direction == 0 ? y + 15 : y;
1372 size_t x2 = x + PARAMS_BOX_OFFSET_X * 3 - 5;
1373 size_t y2 = y1;
1374
1375 // Env.
1376 u8 col_env = cols[1] != COL_OFF && cols[2] != COL_OFF && cols[3] != COL_OFF
1377 ? COL_ACC_2 : COL_OFF;
1378 if (params->env_time == 0) {
1379 draw_line(x0, y0, x2, y0, col_env);
1380 } else {
1381 draw_line(x0, y0, x1, y1, col_env);
1382 draw_line(x1, y1, x2, y2, col_env);
1383 }
1384 }
1385
1386 // Trig probability.
1387 draw_prob(params->prob, cols[4]);
1388
1389 // Trig pannning.
1390 draw_panning(params->pan, cols[9]);
1391
1392 // Labels.
1393 {
1394 size_t x = PARAMS_START_X;
1395 size_t y = PARAMS_START_Y;
1396 txt_drawf_small("shape", x + 4 + PARAMS_BOX_OFFSET_X * 0, y + PARAMS_BOX_H - 7, cols[0]);
1397 txt_drawf_small("vol", x + 8 + PARAMS_BOX_OFFSET_X * 1, y + PARAMS_BOX_H - 7, cols[1]);
1398 txt_drawf_small("time", x + 6 + PARAMS_BOX_OFFSET_X * 2, y + PARAMS_BOX_H - 7, cols[2]);
1399 txt_drawf_small("dir", x + 8 + PARAMS_BOX_OFFSET_X * 3, y + PARAMS_BOX_H - 7, cols[3]);
1400 txt_drawf_small("prob", x + 6 + PARAMS_BOX_OFFSET_X * 4, y + PARAMS_BOX_H - 7, cols[4]);
1401 y += PARAMS_BOX_OFFSET_Y;
1402 txt_drawf_small("pan", x + 8 + PARAMS_BOX_OFFSET_X * 4, y + PARAMS_BOX_H - 7, cols[9]);
1403 }
1404
1405 // Empty spacers.
1406 {
1407 draw_param_stub(5, COL_OFF);
1408 draw_param_stub(6, COL_OFF);
1409 draw_param_stub(7, COL_OFF);
1247 draw_param_stub(8, COL_OFF); 1410 draw_param_stub(8, COL_OFF);
1248 } 1411 }
1249} 1412}
@@ -1358,15 +1521,15 @@ draw_parameters(void) {
1358 input_handler == handle_param_selection_noise) { 1521 input_handler == handle_param_selection_noise) {
1359 if (!pat->empty) { 1522 if (!pat->empty) {
1360 switch (channel_selection_loc) { 1523 switch (channel_selection_loc) {
1361 case 0: { draw_parameters_square(&pat->ch1.params[trig_selection_loc], true, false); } break; 1524 case 0: { draw_parameters_square1(&pat->ch1.params[trig_selection_loc], false); } break;
1362 case 1: { draw_parameters_square(&pat->ch2.params[trig_selection_loc], false, false); } break; 1525 case 1: { draw_parameters_square2(&pat->ch2.params[trig_selection_loc], false); } break;
1363 case 2: { draw_parameters_wave(&pat->ch3.params[trig_selection_loc], false); } break; 1526 case 2: { draw_parameters_wave(&pat->ch3.params[trig_selection_loc], false); } break;
1364 case 3: { draw_parameters_noise(&pat->ch4.params[trig_selection_loc], false); } break; 1527 case 3: { draw_parameters_noise(&pat->ch4.params[trig_selection_loc], false); } break;
1365 } 1528 }
1366 } else { 1529 } else {
1367 switch (channel_selection_loc) { 1530 switch (channel_selection_loc) {
1368 case 0: { draw_parameters_square(&default_ch1.params, true, false); } break; 1531 case 0: { draw_parameters_square1(&default_ch1.params, false); } break;
1369 case 1: { draw_parameters_square(&default_ch2.params, false, false); } break; 1532 case 1: { draw_parameters_square2(&default_ch2.params, false); } break;
1370 case 2: { draw_parameters_wave(&default_ch3.params, true); } break; 1533 case 2: { draw_parameters_wave(&default_ch3.params, true); } break;
1371 case 3: { draw_parameters_noise(&default_ch4.params, true); } break; 1534 case 3: { draw_parameters_noise(&default_ch4.params, true); } break;
1372 } 1535 }
@@ -1379,8 +1542,8 @@ draw_parameters(void) {
1379 input_handler == handle_param_selection_ch3 || 1542 input_handler == handle_param_selection_ch3 ||
1380 input_handler == handle_param_selection_ch4) { 1543 input_handler == handle_param_selection_ch4) {
1381 switch (channel_selection_loc) { 1544 switch (channel_selection_loc) {
1382 case 0: { draw_parameters_square(&ch1_params, true, true); } break; 1545 case 0: { draw_parameters_square1(&ch1_params, true); } break;
1383 case 1: { draw_parameters_square(&ch2_params, false, true); } break; 1546 case 1: { draw_parameters_square2(&ch2_params, true); } break;
1384 case 2: { draw_parameters_wave(&ch3_params, true); } break; 1547 case 2: { draw_parameters_wave(&ch3_params, true); } break;
1385 case 3: { draw_parameters_noise(&ch4_params, true); } break; 1548 case 3: { draw_parameters_noise(&ch4_params, true); } break;
1386 } 1549 }
@@ -1640,7 +1803,7 @@ draw_notif_bar() {
1640 Pattern *pat = &patterns[pattern_selection_loc]; 1803 Pattern *pat = &patterns[pattern_selection_loc];
1641 if (input_handler == handle_param_selection_sq1 1804 if (input_handler == handle_param_selection_sq1
1642 || input_handler == handle_param_selection_ch1) { 1805 || input_handler == handle_param_selection_ch1) {
1643 ChannelSquareParams *params; 1806 ChannelSquare1Params *params;
1644 if (input_handler == handle_param_selection_sq1) { 1807 if (input_handler == handle_param_selection_sq1) {
1645 params = &pat->ch1.params[trig_selection_loc]; 1808 params = &pat->ch1.params[trig_selection_loc];
1646 } else { 1809 } else {
@@ -1704,7 +1867,7 @@ draw_notif_bar() {
1704 1867
1705 if (input_handler == handle_param_selection_sq2 1868 if (input_handler == handle_param_selection_sq2
1706 || input_handler == handle_param_selection_ch2) { 1869 || input_handler == handle_param_selection_ch2) {
1707 ChannelSquareParams *params; 1870 ChannelSquare2Params *params;
1708 if (input_handler == handle_param_selection_sq2) { 1871 if (input_handler == handle_param_selection_sq2) {
1709 params = &pat->ch2.params[trig_selection_loc]; 1872 params = &pat->ch2.params[trig_selection_loc];
1710 } else { 1873 } else {
diff --git a/src/main.c b/src/main.c
index a8c93bf..a72e5e5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -16,6 +16,7 @@ WITH REGARD TO THIS SOFTWARE.
16// + Look back again at the emulator issues... (I give up) 16// + Look back again at the emulator issues... (I give up)
17// + Sync via MIDI with the Analogue cables. 17// + Sync via MIDI with the Analogue cables.
18// + Fix bank switching behaviour (bug) 18// + Fix bank switching behaviour (bug)
19// + Fix bug: Clipboard doesn't copy probability/pan? maybe others?
19// + Add more sync options 20// + Add more sync options
20// + When switching sync, play status acts wonky (bug) 21// + When switching sync, play status acts wonky (bug)
21// + Channel params should show if there are some already on all triggers and 22// + Channel params should show if there are some already on all triggers and
@@ -165,6 +166,20 @@ render_settings(void) {
165 166
166void 167void
167render(void) { 168render(void) {
169 // NOTE: Debug key input
170 // PROF(screen_fill(COL_BG), clear_cycles);
171 // txt_printf("UP: %d\n", ctrl.key_up);
172 // txt_printf("DOWN: %d\n", ctrl.key_down);
173 // txt_printf("LEFT: %d\n", ctrl.key_left);
174 // txt_printf("RIGHT: %d\n", ctrl.key_right);
175 // txt_printf("A: %d\n", ctrl.key_a);
176 // txt_printf("B: %d\n", ctrl.key_b);
177 // txt_printf("L: %d\n", ctrl.key_l);
178 // txt_printf("R: %d\n", ctrl.key_r);
179 // txt_printf("SEL: %d\n", ctrl.key_select);
180 // txt_printf("START: %d\n", ctrl.key_start);
181 // txt_render();
182 // txt_clear();
168 if (clear_screen) { 183 if (clear_screen) {
169 PROF(screen_fill(COL_BG), clear_cycles); 184 PROF(screen_fill(COL_BG), clear_cycles);
170 clear_screen = false; 185 clear_screen = false;
diff --git a/src/patterns.c b/src/patterns.c
index a1f8f24..8dd0f5c 100644
--- a/src/patterns.c
+++ b/src/patterns.c
@@ -7,7 +7,7 @@ typedef struct TriggerNote {
7 Note note; 7 Note note;
8} TriggerNote; 8} TriggerNote;
9 9
10typedef struct ChannelSquareParams { 10typedef struct ChannelSquare1Params {
11 u8 env_volume; 11 u8 env_volume;
12 u8 env_time; 12 u8 env_time;
13 u8 env_direction; 13 u8 env_direction;
@@ -17,7 +17,16 @@ typedef struct ChannelSquareParams {
17 u8 sweep_direction; 17 u8 sweep_direction;
18 u8 prob; 18 u8 prob;
19 s8 pan; 19 s8 pan;
20} ChannelSquareParams; 20} ChannelSquare1Params;
21
22typedef struct ChannelSquare2Params {
23 u8 env_volume;
24 u8 env_time;
25 u8 env_direction;
26 u8 duty_cycle;
27 u8 prob;
28 s8 pan;
29} ChannelSquare2Params;
21 30
22typedef struct ChannelWaveParams { 31typedef struct ChannelWaveParams {
23 u8 wave_volume; 32 u8 wave_volume;
@@ -26,6 +35,8 @@ typedef struct ChannelWaveParams {
26 u8 type_a; 35 u8 type_a;
27 u8 shape_b; 36 u8 shape_b;
28 u8 type_b; 37 u8 type_b;
38 u8 wave_attack;
39 u8 wave_decay;
29 u8 prob; 40 u8 prob;
30 s8 pan; 41 s8 pan;
31} ChannelWaveParams; 42} ChannelWaveParams;
@@ -39,11 +50,17 @@ typedef struct ChannelNoiseParams {
39 s8 pan; 50 s8 pan;
40} ChannelNoiseParams; 51} ChannelNoiseParams;
41 52
42typedef struct ChannelSquare { 53typedef struct ChannelSquare1 {
43 bool active; 54 bool active;
44 TriggerNote notes[16]; 55 TriggerNote notes[16];
45 ChannelSquareParams params[16]; 56 ChannelSquare1Params params[16];
46} ChannelSquare; 57} ChannelSquare1;
58
59typedef struct ChannelSquare2 {
60 bool active;
61 TriggerNote notes[16];
62 ChannelSquare2Params params[16];
63} ChannelSquare2;
47 64
48typedef struct ChannelWave { 65typedef struct ChannelWave {
49 bool active; 66 bool active;
@@ -58,8 +75,8 @@ typedef struct ChannelNoise {
58} ChannelNoise; 75} ChannelNoise;
59 76
60typedef struct Pattern { 77typedef struct Pattern {
61 ChannelSquare ch1; 78 ChannelSquare1 ch1;
62 ChannelSquare ch2; 79 ChannelSquare2 ch2;
63 ChannelWave ch3; 80 ChannelWave ch3;
64 ChannelNoise ch4; 81 ChannelNoise ch4;
65 int bpm; 82 int bpm;
@@ -71,7 +88,7 @@ typedef struct Pattern {
71// Defaults. 88// Defaults.
72// 89//
73 90
74const ChannelSquare default_ch1 = { 91const ChannelSquare1 default_ch1 = {
75 .notes = { 92 .notes = {
76 {true, NOTE_C_4}, 93 {true, NOTE_C_4},
77 {true, NOTE_D_SHARP_4}, 94 {true, NOTE_D_SHARP_4},
@@ -111,7 +128,7 @@ const ChannelSquare default_ch1 = {
111 .active = true, 128 .active = true,
112}; 129};
113 130
114const ChannelSquare default_ch2 = { 131const ChannelSquare2 default_ch2 = {
115 .notes = { 132 .notes = {
116 {true, NOTE_C_3}, 133 {true, NOTE_C_3},
117 {true, NOTE_C_3}, 134 {true, NOTE_C_3},
@@ -131,22 +148,22 @@ const ChannelSquare default_ch2 = {
131 {true, NOTE_C_3}, 148 {true, NOTE_C_3},
132 }, 149 },
133 .params = { 150 .params = {
134 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 151 {8, 4, 0, 2, PROB_100, 0},
135 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 152 {8, 4, 0, 2, PROB_100, 0},
136 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 153 {8, 4, 0, 2, PROB_100, 0},
137 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 154 {8, 4, 0, 2, PROB_100, 0},
138 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 155 {8, 4, 0, 2, PROB_100, 0},
139 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 156 {8, 4, 0, 2, PROB_100, 0},
140 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 157 {8, 4, 0, 2, PROB_100, 0},
141 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 158 {8, 4, 0, 2, PROB_100, 0},
142 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 159 {8, 4, 0, 2, PROB_100, 0},
143 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 160 {8, 4, 0, 2, PROB_100, 0},
144 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 161 {8, 4, 0, 2, PROB_100, 0},
145 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 162 {8, 4, 0, 2, PROB_100, 0},
146 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 163 {8, 4, 0, 2, PROB_100, 0},
147 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 164 {8, 4, 0, 2, PROB_100, 0},
148 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 165 {8, 4, 0, 2, PROB_100, 0},
149 {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}, 166 {8, 4, 0, 2, PROB_100, 0},
150 }, 167 },
151 .active = true, 168 .active = true,
152}; 169};
@@ -171,22 +188,22 @@ const ChannelWave default_ch3 = {
171 {true, NOTE_G_5}, 188 {true, NOTE_G_5},
172 }, 189 },
173 .params = { 190 .params = {
174 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 191 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
175 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 192 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
176 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 193 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
177 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 194 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
178 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 195 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
179 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 196 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
180 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 197 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
181 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 198 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
182 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 199 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
183 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 200 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
184 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 201 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
185 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 202 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
186 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 203 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
187 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 204 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
188 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 205 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
189 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}, 206 {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0},
190 }, 207 },
191 .active = true, 208 .active = true,
192}; 209};
@@ -244,7 +261,7 @@ static Pattern patterns[8] = {
244 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0, true}, 261 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0, true},
245}; 262};
246 263
247static ChannelSquareParams ch1_params = {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}; 264static ChannelSquare1Params ch1_params = {8, 4, 0, 2, 0, 0, 0, PROB_100, 0};
248static ChannelSquareParams ch2_params = {8, 4, 0, 2, 0, 0, 0, PROB_100, 0}; 265static ChannelSquare2Params ch2_params = {8, 4, 0, 2, PROB_100, 0};
249static ChannelWaveParams ch3_params = {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, PROB_100, 0}; 266static ChannelWaveParams ch3_params = {3, 0, WAVE_SIN, 0, WAVE_SAW, 0, 0, 0, PROB_100, 0};
250static ChannelNoiseParams ch4_params = {0xF, 0x2, 0, 0, PROB_100, 0}; 267static ChannelNoiseParams ch4_params = {0xF, 0x2, 0, 0, PROB_100, 0};
diff --git a/src/sequencer.c b/src/sequencer.c
index 01b8e95..8863d14 100644
--- a/src/sequencer.c
+++ b/src/sequencer.c
@@ -160,7 +160,7 @@ play_step(void) {
160 bool ch1_active = settings.global_mute ? !settings.mutes[0] : pat->ch1.active; 160 bool ch1_active = settings.global_mute ? !settings.mutes[0] : pat->ch1.active;
161 if (ch1_active && !pat->empty) { 161 if (ch1_active && !pat->empty) {
162 TriggerNote *trig = &pat->ch1.notes[step_counter]; 162 TriggerNote *trig = &pat->ch1.notes[step_counter];
163 ChannelSquareParams *params = &pat->ch1.params[step_counter]; 163 ChannelSquare1Params *params = &pat->ch1.params[step_counter];
164 if (trig->active && should_play(params->prob)) { 164 if (trig->active && should_play(params->prob)) {
165 if (params->sweep_time == 0) { 165 if (params->sweep_time == 0) {
166 SOUND_SQUARE1_SWEEP = SOUND_SWEEP_DIR(1); 166 SOUND_SQUARE1_SWEEP = SOUND_SWEEP_DIR(1);
@@ -204,7 +204,7 @@ play_step(void) {
204 bool ch2_active = settings.global_mute ? !settings.mutes[1] : pat->ch2.active; 204 bool ch2_active = settings.global_mute ? !settings.mutes[1] : pat->ch2.active;
205 if (ch2_active && !pat->empty) { 205 if (ch2_active && !pat->empty) {
206 TriggerNote *trig = &pat->ch2.notes[step_counter]; 206 TriggerNote *trig = &pat->ch2.notes[step_counter];
207 ChannelSquareParams *params = &pat->ch2.params[step_counter]; 207 ChannelSquare2Params *params = &pat->ch2.params[step_counter];
208 if (trig->active && should_play(params->prob)) { 208 if (trig->active && should_play(params->prob)) {
209 SOUND_SQUARE2_CTRL = SOUND_SQUARE_ENV_VOL(params->env_volume) 209 SOUND_SQUARE2_CTRL = SOUND_SQUARE_ENV_VOL(params->env_volume)
210 | SOUND_SQUARE_ENV_TIME(params->env_time) 210 | SOUND_SQUARE_ENV_TIME(params->env_time)
@@ -252,6 +252,8 @@ play_step(void) {
252 } break; 252 } break;
253 } 253 }
254 wave_env_ticks = 0; 254 wave_env_ticks = 0;
255 wave_env_attack = params->wave_attack;
256 wave_env_decay = params->wave_decay;
255 SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE; 257 SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE;
256 258
257 SOUND_WAVE_FREQ = SOUND_FREQ_RESET 259 SOUND_WAVE_FREQ = SOUND_FREQ_RESET
@@ -1075,7 +1077,7 @@ handle_pattern_selection(void) {
1075} 1077}
1076 1078
1077bool 1079bool
1078set_param_selection_sq1(ChannelSquareParams *params, InputHandler return_handler) { 1080set_param_selection_sq1(ChannelSquare1Params *params, InputHandler return_handler) {
1079 // Go back to trigger selection. 1081 // Go back to trigger selection.
1080 if (key_released(KEY_A)) { 1082 if (key_released(KEY_A)) {
1081 input_handler = return_handler; 1083 input_handler = return_handler;
@@ -1159,7 +1161,7 @@ set_param_selection_sq1(ChannelSquareParams *params, InputHandler return_handler
1159} 1161}
1160 1162
1161bool 1163bool
1162set_param_selection_sq2(ChannelSquareParams *params, InputHandler return_handler) { 1164set_param_selection_sq2(ChannelSquare2Params *params, InputHandler return_handler) {
1163 // Go back to trigger selection. 1165 // Go back to trigger selection.
1164 if (key_released(KEY_A)) { 1166 if (key_released(KEY_A)) {
1165 input_handler = return_handler; 1167 input_handler = return_handler;
@@ -1245,11 +1247,9 @@ set_param_selection_wave(ChannelWaveParams *params, InputHandler return_handler)
1245 if (key_retrig(KEY_RIGHT)) { 1247 if (key_retrig(KEY_RIGHT)) {
1246 if (param_selection_loc == 4) { 1248 if (param_selection_loc == 4) {
1247 param_selection_loc = 0; 1249 param_selection_loc = 0;
1248 } else if (param_selection_loc == 6) {
1249 param_selection_loc = 9;
1250 } else if (param_selection_loc == 9) { 1250 } else if (param_selection_loc == 9) {
1251 param_selection_loc = 5; 1251 param_selection_loc = 5;
1252 } else if (param_selection_loc < 6) { 1252 } else {
1253 param_selection_loc++; 1253 param_selection_loc++;
1254 } 1254 }
1255 } else { 1255 } else {
@@ -1257,9 +1257,7 @@ set_param_selection_wave(ChannelWaveParams *params, InputHandler return_handler)
1257 param_selection_loc = 4; 1257 param_selection_loc = 4;
1258 } else if (param_selection_loc == 5) { 1258 } else if (param_selection_loc == 5) {
1259 param_selection_loc = 9; 1259 param_selection_loc = 9;
1260 } else if (param_selection_loc == 9) { 1260 } else {
1261 param_selection_loc = 6;
1262 } else if (param_selection_loc > 0) {
1263 param_selection_loc--; 1261 param_selection_loc--;
1264 } 1262 }
1265 } 1263 }
@@ -1268,13 +1266,9 @@ set_param_selection_wave(ChannelWaveParams *params, InputHandler return_handler)
1268 } 1266 }
1269 1267
1270 if (key_tap(KEY_UP) || key_tap(KEY_DOWN)) { 1268 if (key_tap(KEY_UP) || key_tap(KEY_DOWN)) {
1271 if (param_selection_loc == 4) { 1269 if (param_selection_loc < 5) {
1272 param_selection_loc = 9;
1273 } else if (param_selection_loc == 9) {
1274 param_selection_loc = 4;
1275 } else if (param_selection_loc < 2) {
1276 param_selection_loc += 5; 1270 param_selection_loc += 5;
1277 } else if (param_selection_loc > 4) { 1271 } else if (param_selection_loc >= 5) {
1278 param_selection_loc -= 5; 1272 param_selection_loc -= 5;
1279 } 1273 }
1280 redraw_params = true; 1274 redraw_params = true;
@@ -1297,6 +1291,8 @@ set_param_selection_wave(ChannelWaveParams *params, InputHandler return_handler)
1297 case 4: { params->prob = CLAMP(params->prob + inc * -1, 0, PROB_NUM - 1); } break; 1291 case 4: { params->prob = CLAMP(params->prob + inc * -1, 0, PROB_NUM - 1); } break;
1298 case 5: { params->wave_mode = CLAMP(params->wave_mode + inc, 0, 2); } break; 1292 case 5: { params->wave_mode = CLAMP(params->wave_mode + inc, 0, 2); } break;
1299 case 6: { params->wave_volume = CLAMP(params->wave_volume + inc, 0, 4); } break; 1293 case 6: { params->wave_volume = CLAMP(params->wave_volume + inc, 0, 4); } break;
1294 case 7: { params->wave_attack = CLAMP(params->wave_attack + inc, 0, 24); } break;
1295 case 8: { params->wave_decay = CLAMP(params->wave_decay + inc, 0, 24); } break;
1300 case 9: { params->pan = CLAMP(params->pan + inc, -1, 1); } break; 1296 case 9: { params->pan = CLAMP(params->pan + inc, -1, 1); } break;
1301 } 1297 }
1302 redraw_params = true; 1298 redraw_params = true;
@@ -1475,6 +1471,12 @@ handle_param_selection_ch3() {
1475 case 6: { 1471 case 6: {
1476 pat->ch3.params[i].wave_volume = ch3_params.wave_volume; 1472 pat->ch3.params[i].wave_volume = ch3_params.wave_volume;
1477 } break; 1473 } break;
1474 case 7: {
1475 pat->ch3.params[i].wave_attack = ch3_params.wave_attack;
1476 } break;
1477 case 8: {
1478 pat->ch3.params[i].wave_decay = ch3_params.wave_decay;
1479 } break;
1478 case 9: { 1480 case 9: {
1479 pat->ch3.params[i].pan = ch3_params.pan; 1481 pat->ch3.params[i].pan = ch3_params.pan;
1480 } break; 1482 } break;
@@ -1516,13 +1518,13 @@ handle_param_selection_ch4() {
1516 1518
1517void 1519void
1518handle_param_selection_sq1() { 1520handle_param_selection_sq1() {
1519 ChannelSquareParams *params = &patterns[pattern_selection_loc].ch1.params[trig_selection_loc]; 1521 ChannelSquare1Params *params = &patterns[pattern_selection_loc].ch1.params[trig_selection_loc];
1520 set_param_selection_sq1(params, handle_trigger_selection); 1522 set_param_selection_sq1(params, handle_trigger_selection);
1521} 1523}
1522 1524
1523void 1525void
1524handle_param_selection_sq2() { 1526handle_param_selection_sq2() {
1525 ChannelSquareParams *params = &patterns[pattern_selection_loc].ch2.params[trig_selection_loc]; 1527 ChannelSquare2Params *params = &patterns[pattern_selection_loc].ch2.params[trig_selection_loc];
1526 set_param_selection_sq2(params, handle_trigger_selection); 1528 set_param_selection_sq2(params, handle_trigger_selection);
1527} 1529}
1528 1530
@@ -1543,7 +1545,7 @@ nudge_trigs(int cur_loc, int next_loc) {
1543 Pattern *pat = &patterns[pattern_selection_loc]; 1545 Pattern *pat = &patterns[pattern_selection_loc];
1544 switch (channel_selection_loc) { 1546 switch (channel_selection_loc) {
1545 case 0: { 1547 case 0: {
1546 ChannelSquareParams cur_params = pat->ch1.params[cur_loc]; 1548 ChannelSquare1Params cur_params = pat->ch1.params[cur_loc];
1547 TriggerNote cur_trig = pat->ch1.notes[cur_loc]; 1549 TriggerNote cur_trig = pat->ch1.notes[cur_loc];
1548 pat->ch1.params[cur_loc] = pat->ch1.params[next_loc]; 1550 pat->ch1.params[cur_loc] = pat->ch1.params[next_loc];
1549 pat->ch1.notes[cur_loc] = pat->ch1.notes[next_loc]; 1551 pat->ch1.notes[cur_loc] = pat->ch1.notes[next_loc];
@@ -1551,7 +1553,7 @@ nudge_trigs(int cur_loc, int next_loc) {
1551 pat->ch1.notes[next_loc] = cur_trig; 1553 pat->ch1.notes[next_loc] = cur_trig;
1552 } break; 1554 } break;
1553 case 1: { 1555 case 1: {
1554 ChannelSquareParams cur_params = pat->ch2.params[cur_loc]; 1556 ChannelSquare2Params cur_params = pat->ch2.params[cur_loc];
1555 TriggerNote cur_trig = pat->ch2.notes[cur_loc]; 1557 TriggerNote cur_trig = pat->ch2.notes[cur_loc];
1556 pat->ch2.params[cur_loc] = pat->ch2.params[next_loc]; 1558 pat->ch2.params[cur_loc] = pat->ch2.params[next_loc];
1557 pat->ch2.notes[cur_loc] = pat->ch2.notes[next_loc]; 1559 pat->ch2.notes[cur_loc] = pat->ch2.notes[next_loc];