aboutsummaryrefslogtreecommitdiffstats
path: root/src/clipboard.c
blob: e92d4c5bf5ca225d6e8cec496d728a65974d49b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
void clipboard_paste(void);
void clipboard_copy(void);

typedef enum ClipboardType {
    CLIP_EMPTY,
    CLIP_TRIG,
    CLIP_PARAM_CH1,
    CLIP_PARAM_CH2,
    CLIP_PARAM_CH3,
    CLIP_PARAM_CH4,
    CLIP_PATTERN,
    CLIP_CHANNEL,
} ClipboardType;

typedef struct Clipboard {
    ClipboardType type;
    u8 src_pat;
    u8 src_chan;
    u8 src_trig;
} Clipboard;

static Clipboard clipboard = {CLIP_EMPTY, 0, 0, 0};

void send_notif(char *msg);

void
clipboard_paste(void) {
    Pattern *pat_dst = &patterns[pattern_selection_loc];
    Pattern *pat_src = &patterns[clipboard.src_pat];

    if (input_handler == handle_trigger_selection) {
        if (clipboard.type == CLIP_TRIG) {
            // Copy notes or parameters when applicable.
            switch (clipboard.src_chan) {
                case 0: {
                    switch (channel_selection_loc) {
                        case 0: {
                            pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
                            pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
                        } break;
                        case 1: {
                            pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
                            pat_dst->ch2.params[trig_selection_loc].env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
                            pat_dst->ch2.params[trig_selection_loc].env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
                            pat_dst->ch2.params[trig_selection_loc].env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
                            pat_dst->ch2.params[trig_selection_loc].duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
                            pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
                            pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
                        } break;
                        case 2: {
                            pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
                            pat_dst->ch3.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
                            pat_dst->ch3.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
                        } break;
                        case 3: {
                            pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
                            pat_dst->ch4.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
                            pat_dst->ch4.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
                        } break;
                    }
                } break;
                case 1: {
                    switch (channel_selection_loc) {
                        case 0: {
                            pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
                            pat_dst->ch1.params[trig_selection_loc].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume;
                            pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
                            pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
                            pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
                            pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
                            pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
                        } break;
                        case 1: {
                            pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
                            pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig];
                        } break;
                        case 2: {
                            pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
                            pat_dst->ch3.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
                            pat_dst->ch3.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
                        } break;
                        case 3: {
                            pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
                            pat_dst->ch4.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
                            pat_dst->ch4.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
                        } break;
                    }
                } break;
                case 2: {
                    switch (channel_selection_loc) {
                        case 0: {
                            pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
                            pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch3.params[clipboard.src_trig].prob;
                            pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch3.params[clipboard.src_trig].pan;
                        } break;
                        case 1: {
                            pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
                            pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch3.params[clipboard.src_trig].prob;
                            pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch3.params[clipboard.src_trig].pan;
                        } break;
                        case 2: {
                            pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
                            pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig];
                        } break;
                        case 3: {
                            pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
                            pat_dst->ch4.params[trig_selection_loc].prob = pat_src->ch3.params[clipboard.src_trig].prob;
                            pat_dst->ch4.params[trig_selection_loc].pan = pat_src->ch3.params[clipboard.src_trig].pan;
                        } break;
                    }
                } break;
                case 3: {
                    switch (channel_selection_loc) {
                        case 0: {
                            pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
                            pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch4.params[clipboard.src_trig].prob;
                            pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch4.params[clipboard.src_trig].pan;
                        } break;
                        case 1: {
                            pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
                            pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch4.params[clipboard.src_trig].prob;
                            pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch4.params[clipboard.src_trig].pan;
                        } break;
                        case 2: {
                            pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
                            pat_dst->ch3.params[trig_selection_loc].prob = pat_src->ch4.params[clipboard.src_trig].prob;
                            pat_dst->ch3.params[trig_selection_loc].pan = pat_src->ch4.params[clipboard.src_trig].pan;
                        } break;
                        case 3: {
                            pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
                            pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig];
                        } break;
                    }
                } break;
            }
            send_notif("PASTED NOTE & PARAMS");
        }
        // Only paste the params for the respective trigger.
        if (clipboard.type == CLIP_PARAM_CH1) {
            switch (channel_selection_loc) {
                case 0: {
                    pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
                } break;
                case 1: {
                    pat_dst->ch2.params[trig_selection_loc].env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
                    pat_dst->ch2.params[trig_selection_loc].env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
                    pat_dst->ch2.params[trig_selection_loc].env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
                    pat_dst->ch2.params[trig_selection_loc].duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
                    pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
                    pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
                } break;
            }
            send_notif("PASTED PARAMS");
        }
        if (clipboard.type == CLIP_PARAM_CH2) {
            switch (channel_selection_loc) {
                case 0: {
                    pat_dst->ch1.params[trig_selection_loc].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume;
                    pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
                    pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
                    pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
                    pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
                    pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
                } break;
                case 1: {
                    pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig];
                } break;
            }
            send_notif("PASTED PARAMS");
        }
        if (clipboard.type == CLIP_PARAM_CH3 && channel_selection_loc == clipboard.src_chan) {
            pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig];
            send_notif("PASTED PARAMS");
        }
        if (clipboard.type == CLIP_PARAM_CH4 && channel_selection_loc == clipboard.src_chan) {
            pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig];
            send_notif("PASTED PARAMS");
        }
        draw_triggers();
        draw_parameters();
    } else if (input_handler == handle_param_selection_sq1 && clipboard.type == CLIP_PARAM_CH1) {
        pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
        send_notif("PASTED PARAMS");
        draw_parameters();
    } else if (input_handler == handle_param_selection_sq1 && clipboard.type == CLIP_PARAM_CH2) {
        pat_dst->ch1.params[trig_selection_loc].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume;
        pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
        pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
        pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
        pat_dst->ch1.params[trig_selection_loc].prob = pat_src->ch2.params[clipboard.src_trig].prob;
        pat_dst->ch1.params[trig_selection_loc].pan = pat_src->ch2.params[clipboard.src_trig].pan;
        send_notif("PASTED PARAMS");
        draw_parameters();
    } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH2) {
        pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig];
        send_notif("PASTED PARAMS");
        draw_parameters();
    } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH1) {
        pat_dst->ch2.params[trig_selection_loc].env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
        pat_dst->ch2.params[trig_selection_loc].env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
        pat_dst->ch2.params[trig_selection_loc].env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
        pat_dst->ch2.params[trig_selection_loc].duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
        pat_dst->ch2.params[trig_selection_loc].prob = pat_src->ch1.params[clipboard.src_trig].prob;
        pat_dst->ch2.params[trig_selection_loc].pan = pat_src->ch1.params[clipboard.src_trig].pan;
        send_notif("PASTED PARAMS");
        draw_parameters();
    } else if (input_handler == handle_param_selection_wave && clipboard.type == CLIP_PARAM_CH3) {
        pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig];
        send_notif("PASTED PARAMS");
        draw_parameters();
    } else if (input_handler == handle_param_selection_noise && clipboard.type == CLIP_PARAM_CH4) {
        pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig];
        send_notif("PASTED PARAMS");
        draw_parameters();
    } else if (input_handler == handle_channel_selection && clipboard.type == CLIP_CHANNEL) {
        // Copy notes from a different channel OR notes and parameters
        // from a different pattern.
        if (clipboard.src_chan == channel_selection_loc) {
            switch (clipboard.src_chan) {
                case 0: { pat_dst->ch1 = pat_src->ch1; } break;
                case 1: { pat_dst->ch2 = pat_src->ch2; } break;
                case 2: { pat_dst->ch3 = pat_src->ch3; } break;
                case 3: { pat_dst->ch4 = pat_src->ch4; } break;
            }
        } else {
            switch (clipboard.src_chan) {
                case 0: {
                    switch (channel_selection_loc) {
                        case 0: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch1.notes[i] = pat_src->ch1.notes[i];
                                pat_dst->ch1.params[i] = pat_src->ch1.params[i];
                            }
                        } break;
                        case 1: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch2.notes[i] = pat_src->ch1.notes[i];
                                pat_dst->ch2.params[i].env_volume = pat_src->ch1.params[i].env_volume;
                                pat_dst->ch2.params[i].env_time = pat_src->ch1.params[i].env_time;
                                pat_dst->ch2.params[i].env_direction = pat_src->ch1.params[i].env_direction;
                                pat_dst->ch2.params[i].duty_cycle = pat_src->ch1.params[i].duty_cycle;
                                pat_dst->ch2.params[i].prob = pat_src->ch1.params[i].prob;
                                pat_dst->ch2.params[i].pan = pat_src->ch1.params[i].pan;
                            }
                        } break;
                        case 2: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch3.notes[i] = pat_src->ch1.notes[i];
                                pat_dst->ch3.params[i].prob = pat_src->ch1.params[i].prob;
                                pat_dst->ch3.params[i].pan = pat_src->ch1.params[i].pan;
                            }
                        } break;
                        case 3: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch4.notes[i] = pat_src->ch1.notes[i];
                                pat_dst->ch4.params[i].prob = pat_src->ch1.params[i].prob;
                                pat_dst->ch4.params[i].pan = pat_src->ch1.params[i].pan;
                            }
                        } break;
                    }
                } break;
                case 1: {
                    switch (channel_selection_loc) {
                        case 0: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch1.notes[i] = pat_src->ch2.notes[i];
                                pat_dst->ch1.params[i].env_volume = pat_src->ch2.params[i].env_volume;
                                pat_dst->ch1.params[i].env_time = pat_src->ch2.params[i].env_time;
                                pat_dst->ch1.params[i].env_direction = pat_src->ch2.params[i].env_direction;
                                pat_dst->ch1.params[i].duty_cycle = pat_src->ch2.params[i].duty_cycle;
                                pat_dst->ch1.params[i].prob = pat_src->ch2.params[i].prob;
                                pat_dst->ch1.params[i].pan = pat_src->ch2.params[i].pan;
                            }
                        } break;
                        case 1: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch2.notes[i] = pat_src->ch2.notes[i];
                                pat_dst->ch2.params[i] = pat_src->ch2.params[i];
                            }
                        } break;
                        case 2: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch3.notes[i] = pat_src->ch2.notes[i];
                                pat_dst->ch3.params[i].prob = pat_src->ch2.params[i].prob;
                                pat_dst->ch3.params[i].pan = pat_src->ch2.params[i].pan;
                            }
                        } break;
                        case 3: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch4.notes[i] = pat_src->ch2.notes[i];
                                pat_dst->ch4.params[i].prob = pat_src->ch2.params[i].prob;
                                pat_dst->ch4.params[i].pan = pat_src->ch2.params[i].pan;
                            }
                        } break;
                    }
                } break;
                case 2: {
                    switch (channel_selection_loc) {
                        case 0: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch1.notes[i] = pat_src->ch3.notes[i];
                                pat_dst->ch1.params[i].prob = pat_src->ch3.params[i].prob;
                                pat_dst->ch1.params[i].pan = pat_src->ch3.params[i].pan;
                            }
                        } break;
                        case 1: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch2.notes[i] = pat_src->ch3.notes[i];
                                pat_dst->ch2.params[i].prob = pat_src->ch3.params[i].prob;
                                pat_dst->ch2.params[i].pan = pat_src->ch3.params[i].pan;
                            }
                        } break;
                        case 2: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch3.notes[i] = pat_src->ch3.notes[i];
                                pat_dst->ch3.params[i] = pat_src->ch3.params[i];
                            }
                        } break;
                        case 3: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch4.notes[i] = pat_src->ch3.notes[i];
                                pat_dst->ch4.params[i].prob = pat_src->ch3.params[i].prob;
                                pat_dst->ch4.params[i].pan = pat_src->ch3.params[i].pan;
                            }
                        } break;
                    }
                } break;
                case 3: {
                    switch (channel_selection_loc) {
                        case 0: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch1.notes[i] = pat_src->ch4.notes[i];
                                pat_dst->ch1.params[i].prob = pat_src->ch4.params[i].prob;
                                pat_dst->ch1.params[i].pan = pat_src->ch4.params[i].pan;
                            }
                        } break;
                        case 1: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch2.notes[i] = pat_src->ch4.notes[i];
                                pat_dst->ch2.params[i].prob = pat_src->ch4.params[i].prob;
                                pat_dst->ch2.params[i].pan = pat_src->ch4.params[i].pan;
                            }
                        } break;
                        case 2: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch3.notes[i] = pat_src->ch4.notes[i];
                                pat_dst->ch3.params[i].prob = pat_src->ch4.params[i].prob;
                                pat_dst->ch3.params[i].pan = pat_src->ch4.params[i].pan;
                            }
                        } break;
                        case 3: {
                            for (size_t i = 0; i < 16; i++) {
                                pat_dst->ch4.notes[i] = pat_src->ch4.notes[i];
                                pat_dst->ch4.params[i] = pat_src->ch4.params[i];
                            }
                        } break;
                    }
                } break;
            }
        }
        send_notif("PASTED NOTES & PARAMS");
        draw_channels();
        draw_triggers();
    } else if (input_handler == handle_channel_selection) {
        switch (channel_selection_loc) {
            case 0: {
                if (clipboard.type == CLIP_TRIG ||
                        clipboard.type == CLIP_PARAM_CH1 ||
                        clipboard.type == CLIP_PARAM_CH2) {
                    if (clipboard.src_chan == 0) {
                        ch1_params = pat_src->ch1.params[clipboard.src_trig];
                        for (size_t i = 0; i < 16; i++) {
                            pat_dst->ch1.params[i] = pat_src->ch1.params[clipboard.src_trig];
                        }
                        send_notif("PASTED PARAMS");
                    }
                    if (clipboard.src_chan == 1) {
                        ch1_params.env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume;
                        ch1_params.env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
                        ch1_params.env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
                        ch1_params.duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
                        ch1_params.prob = pat_src->ch2.params[clipboard.src_trig].prob;
                        ch1_params.pan = pat_src->ch2.params[clipboard.src_trig].pan;
                        for (size_t i = 0; i < 16; i++) {
                            pat_dst->ch1.params[i].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume;
                            pat_dst->ch1.params[i].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
                            pat_dst->ch1.params[i].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
                            pat_dst->ch1.params[i].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
                            pat_dst->ch1.params[i].prob = pat_src->ch2.params[clipboard.src_trig].prob;
                            pat_dst->ch1.params[i].pan = pat_src->ch2.params[clipboard.src_trig].pan;
                        }
                        send_notif("PASTED PARAMS");
                    }
                }
            } break;
            case 1: {
                if (clipboard.type == CLIP_TRIG ||
                        clipboard.type == CLIP_PARAM_CH1 ||
                        clipboard.type == CLIP_PARAM_CH2) {
                    if (clipboard.src_chan == 0) {
                        ch2_params.env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
                        ch2_params.env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
                        ch2_params.env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
                        ch2_params.duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
                        ch2_params.prob = pat_src->ch1.params[clipboard.src_trig].prob;
                        ch2_params.pan = pat_src->ch1.params[clipboard.src_trig].pan;
                        for (size_t i = 0; i < 16; i++) {
                            pat_dst->ch2.params[i].env_volume = pat_src->ch1.params[clipboard.src_trig].env_volume;
                            pat_dst->ch2.params[i].env_time = pat_src->ch1.params[clipboard.src_trig].env_time;
                            pat_dst->ch2.params[i].env_direction = pat_src->ch1.params[clipboard.src_trig].env_direction;
                            pat_dst->ch2.params[i].duty_cycle = pat_src->ch1.params[clipboard.src_trig].duty_cycle;
                            pat_dst->ch2.params[i].prob = pat_src->ch1.params[clipboard.src_trig].prob;
                            pat_dst->ch2.params[i].pan = pat_src->ch1.params[clipboard.src_trig].pan;
                        }
                        send_notif("PASTED PARAMS");
                    }
                    if (clipboard.src_chan == 1) {
                        ch2_params = pat_src->ch2.params[clipboard.src_trig];
                        for (size_t i = 0; i < 16; i++) {
                            pat_dst->ch2.params[i] = pat_src->ch2.params[clipboard.src_trig];
                        }
                        send_notif("PASTED PARAMS");
                    }
                }
            } break;
            case 2: {
                if (clipboard.src_chan != channel_selection_loc) {
                    return;
                }
                if (clipboard.type == CLIP_TRIG || clipboard.type == CLIP_PARAM_CH3) {
                    ch3_params = pat_src->ch3.params[clipboard.src_trig];
                    for (size_t i = 0; i < 16; i++) {
                        pat_dst->ch3.params[i] = pat_src->ch3.params[clipboard.src_trig];
                    }
                    send_notif("PASTED PARAMS");
                }
            } break;
            case 3: {
                if (clipboard.src_chan != channel_selection_loc) {
                    return;
                }
                if (clipboard.type == CLIP_TRIG || clipboard.type == CLIP_PARAM_CH4) {
                    ch4_params = pat_src->ch4.params[clipboard.src_trig];
                    for (size_t i = 0; i < 16; i++) {
                        pat_dst->ch4.params[i] = pat_src->ch4.params[clipboard.src_trig];
                    }
                    send_notif("PASTED PARAMS");
                }
            } break;
        }
    } else if (input_handler == handle_pattern_selection && clipboard.type == CLIP_PATTERN) {
        // Copy an entire pattern.
        if (pattern_selection_loc != clipboard.src_pat) {
            *pat_dst = *pat_src;
            draw_channels();
            draw_triggers();
            send_notif("PASTED PATTERN");
        }
    }
}

void
clipboard_copy(void) {
    if (input_handler == handle_trigger_selection) {
        clipboard.type = CLIP_TRIG;
        clipboard.src_pat = pattern_selection_loc;
        clipboard.src_chan = channel_selection_loc;
        clipboard.src_trig = trig_selection_loc;
        send_notif("COPIED TRIGGER");
    } else if (input_handler == handle_param_selection_sq1) {
        clipboard.type = CLIP_PARAM_CH1;
        clipboard.src_pat = pattern_selection_loc;
        clipboard.src_chan = channel_selection_loc;
        clipboard.src_trig = trig_selection_loc;
        send_notif("COPIED CH1 PARAMS");
    } else if (input_handler == handle_param_selection_sq2) {
        clipboard.type = CLIP_PARAM_CH2;
        clipboard.src_pat = pattern_selection_loc;
        clipboard.src_chan = channel_selection_loc;
        clipboard.src_trig = trig_selection_loc;
        send_notif("COPIED CH2 PARAMS");
    } else if (input_handler == handle_param_selection_wave) {
        clipboard.type = CLIP_PARAM_CH3;
        clipboard.src_pat = pattern_selection_loc;
        clipboard.src_chan = channel_selection_loc;
        clipboard.src_trig = trig_selection_loc;
        send_notif("COPIED CH3 PARAMS");
    } else if (input_handler == handle_param_selection_noise) {
        clipboard.type = CLIP_PARAM_CH4;
        clipboard.src_pat = pattern_selection_loc;
        clipboard.src_chan = channel_selection_loc;
        clipboard.src_trig = trig_selection_loc;
        send_notif("COPIED CH4 PARAMS");
    } else if (input_handler == handle_channel_selection) {
        clipboard.type = CLIP_CHANNEL;
        clipboard.src_pat = pattern_selection_loc;
        clipboard.src_chan = channel_selection_loc;
        send_notif("COPIED CHANNEL");
    } else if (input_handler == handle_pattern_selection) {
        clipboard.type = CLIP_PATTERN;
        clipboard.src_pat = pattern_selection_loc;
        send_notif("COPIED PATTERN");
    }
}