-
Notifications
You must be signed in to change notification settings - Fork 0
/
DrummerBoy.ino
3084 lines (2939 loc) · 108 KB
/
DrummerBoy.ino
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
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <Metro.h>
#include <AltSoftSerial.h> // Arduino build environment requires this
#include <wavTrigger.h>
#include "Adafruit_LiquidCrystal.h"
#include <Wire.h> //EEPROM 24LC256 pin 5 to SDA(20), 24LC256 pin 5 to SCL(21)
#include <EEPROMAnythingEXTERNAL.h> // for extrnal memory ( 24LC256 ) saving/loading
Metro seqMetro(1000); // Sequencer state machine interval timer
Metro tripletMetro(1000);
Metro readAnalogInputs(100); // Read potentiometer values
Metro readDigitalInputsHP(50); //
Metro readDigitalInputsLP(150);
Adafruit_LiquidCrystal lcd(51, 50, 49, 48, 47, 46); // define the pins used to connect to the LCD display
//WAV Trigger will only play WAV files formatted as 16-bit, stereo, 44.1kHz, and there can be no meta-data (non-audio data) in the file before the audio data.
//Make sure the file name starts with a 3 digit number.
wavTrigger wTrig; // Our WAV Trigger object
// ------------------------------------------------------------------ DECLARE PINS AND CONSTANTS ------------------------------------------------------------//
// const avoids the pitfalls of the define operator (essentially search and replace)
#define deviceaddress 0x50 //Address of 24LC256 eeprom chip
#define NUM_TRACKS 128
#define REDLITE 4
#define GREENLITE 5
#define BLUELITE 6
const int brightness = 100; // you can change the overall brightness by range 0 -> 255
const int sampleRatePin = A0; // Analog input pins
const int swingPin = A1;
const int trckVolPn = A2;
const int tempoPin = A3;
const int volumePin = A4;
const int groupPin = A5;
const int stutterSwitchPin = 19;
const int trackVolBtnPin = 18;
const int swingSwitchPin = 17;
const int pitchSwitchPin = 16;
const int pauseSwitchPin = 43;
const int gSwitchPin[] = {A8, A9, A10, A11, A12, A13, A14, A15}; // define group switch pins
const int sampleTogglePin = 13;
const int functionBtnPin = 40;
const int tapBtnPin = 41;
const int polyBtnPin = 42;
const int eraseBtnPin = 44;
const int accentSelectPin = 45;
const int clockOutPin = 8;
// the 16 beat buttons are connected to digital pins 22 - 37
const int buttonPin[] = {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37}; // define button pins
//--------- serial control for the 24 leds through 3 74HC595 chips
const int dataPin = 10; ////Pin connected to DS of 74HC595 (Purple)
const int latchPin = 11; //Pin connected to ST_CP of 74HC595 (GREEN)
const int clockPin = 12; //Pin connected to SH_CP of 74HC595 (Yellow)
//--------------------------------------------------------------VARIABLE DECLARATION & INITIALIZATION------------------------------------------------------//
// arrays containing sample wav numbers
// since we use byte for storage the sample numbers are limited to 0-255 range, this is easily changed but uses more dynamic memory (sram)
const byte hat[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
const byte snare[] = {17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
const byte kick[] = {33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48};
const byte perc1[] = {49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64};
const byte perc2[] = {65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80};
const byte sample1[] = {81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96};
const byte sample2[] = {97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112};
const byte hit[] = {113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128};
const byte livePlaySamples[16] = {250, 251, 11, 15, 21, 27, 31, 33, 35, 37, 38, 43, 44, 77, 78, 79};
// variables for selecting sample group
boolean hatGroupSelect = true;
boolean snareGroupSelect = false;
boolean kickGroupSelect = false;
boolean perc1GroupSelect = false;
boolean perc2GroupSelect = false;
boolean sample1GroupSelect = false;
boolean sample2GroupSelect = false;
boolean hitGroupSelect = false;
byte groupLedData;
// for displaying selection
boolean buttonsActive[16];
boolean accentBtnsActive[16];
boolean rollBtnsActive[16];
//more array variables
byte chain[4] = {1, 0, 0, 0};
byte playSamplesBuffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
byte playSamplesDelayBuffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
byte playSamplesTripletDelayBuffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
byte selectionMem[8] = {0, 0, 0, 0, 0, 0, 0, 0}; //holds the selected sample for each group
boolean lastAccented[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // 1 element per group - flag is set when accent is activated on the next beat and deactivated when the next beat is not accented
char trackVol[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // char is signed 8 bit (2's compliment so -128 to 127)
byte lastSmpl_Accntd[8] = {0, 0, 0, 0, 0, 0, 0, 0};
boolean groupSwitchState[8] = {0, 0, 0, 0, 0, 0, 0, 0};
boolean delayGroup[8] = {0, 0, 0, 0, 0, 0, 0, 0};
char savedPatternNames[16][16];
//bool & ints
boolean clockOutLogicHigh = false;
boolean beatBtnPshdRN = 0;
boolean accentBtnPshdRN = 0;
boolean polyBtnPshdRN = 0;
boolean rollBtnPshdRN = 0;
boolean groupSelectPushedRN = 0;
boolean tapBtnPushedRN = 0;
boolean sampleSelectPushedRN = 0;
boolean erasePushedRN = 0;
boolean accentPushedRN = 0;
boolean functionBtnPushedRN = 0;
boolean trackVolBtnPushedRN = 0;
boolean polyBtnPushedRN = 0;
boolean accent = 0;
boolean poly = 0;
word currentGroup = 0;
word lastGroup = 1;
word currentSlotPtr = 0;
word tempStorage = 0;
word lastBtnPushed;
word lastAccentBtnPushed;
word lastRollBtnPushed;
word lastPolyBtnPushed;
//boolean patternA = true; // first pattern active - if low pattern B is active (chorus/verse)
boolean polyFlag = false;
boolean tripletFlag = false;
boolean allTripletFlag = false;
boolean copyPatternFlag = false;
boolean fillFlag = false;
boolean restoreChainFlag = false;
boolean liveMash = false; //when active live mode plays samples rapidly while btn is pushed, when off live mode behaves normally
boolean lockedSamples = true;
boolean pitchOn = false;
word numPatternsSelected = 0;
word copyPtr = 0;
word copyFrom = 0;
word copyTo = 0;
byte selectedSampleNumber = 0;
boolean newSampleSelected = false; //indicates that a beat button has been played while pressing down the sample button (sample preview)
boolean erasePerformed = false;
static int tempoMS;
static int tripletMS;
static int volume;
word beatMaster = 0;
byte beatMasterTriplet = 0;
word beatHat = 0; // set initial beat locations
word beatSnare = 0;
word beatKick = 0;
word beatPerc1 = 0;
word beatPerc2 = 0;
word beatSmp1 = 0;
word beatHit = 0;
word beatSmp2 = 0;
word prevBeatHat = 15;
word prevBeatSnare = 15;
word prevBeatKick = 15;
word prevBeatPerc1 = 15;
word prevBeatPerc2 = 15;
word prevBeatSmp1 = 15;
word prevBeatHit = 15;
word prevBeatSmp2 = 15;
word lastHatBeat = 16;
word lastSnareBeat = 16;
word lastKickBeat = 16;
word lastBassBeat = 16;
word lastPerc1Beat = 16;
word lastPerc2Beat = 16;
word lastSmp1Beat = 16;
word lastHitBeat = 16;
word lastSmp2Beat = 16;
word selectedLastBeat = 0;
word accentDBOffset = 20; // default 20
int startTime; // for "tap" entry timing
int startTimeTriplet;
long lastNormalRollMs = 0;
long lastTripletRollMs = 0;
long lastClockMs = 0;
word rollCounterNormal = 0;
word rollCounterTriplet = 0;
int reading;
int halfMS;
int halfTripletMS;
//led display variables
byte data;
byte data2;
byte segmentData[10];
boolean groupLeds[8];
boolean displayingLiveMash = false;
int tempoBPM;
char saveName[16];
int accentVolLastIntermediate;
boolean swingOn = false;
boolean stutterOn = false;
boolean pauseOn = false;
int swingMS = 0;
boolean synced = false;
boolean fastSynced = false;
char trackVolumes[NUM_TRACKS] = {0}; // char data type range is -128 to 127 which is perfect for out volume range of -70 to 10
int delayTime = 40;
boolean delayFlag = 0;
boolean delayTripletFlag = 0;
long startMS_d = 0;
long startMS_tripD = 0;
word lastObj = 0;
word lastPatt = 0; // holds last pattern that was printed to lcd
boolean erasingHats = false;
boolean erasingSnares = false;
boolean erasingKicks = false;
boolean erasingPerc1 = false;
boolean erasingPerc2 = false;
boolean erasingSmp1 = false;
boolean erasingSmp2 = false;
boolean erasingHits = false;
boolean erasingAll = false;
//----------------------------------------------------------------------------------SAMPLE NAMES----------------------------------------------------------------------------------------------//
// save sample names in flash memory in order to preserve precious precious sram
const char sampleName0[] PROGMEM = "808 closed hat"; // Hats
const char sampleName1[] PROGMEM = "elec hat";
const char sampleName2[] PROGMEM = "mouse click";
const char sampleName3[] PROGMEM = "ice hat";
const char sampleName4[] PROGMEM = "jungle hat";
const char sampleName5[] PROGMEM = "open hat 1";
const char sampleName6[] PROGMEM = "open hat 2";
const char sampleName7[] PROGMEM = "open hat 3";
const char sampleName8[] PROGMEM = "click";
const char sampleName9[] PROGMEM = "closed hat";
const char sampleName10[] PROGMEM = "open hat 4";
const char sampleName11[] PROGMEM = "big crash";
const char sampleName12[] PROGMEM = "tiny hat";
const char sampleName13[] PROGMEM = "splash f";
const char sampleName14[] PROGMEM = "chiptune o hat";
const char sampleName15[] PROGMEM = "chiptune c hat";
const char sampleName16[] PROGMEM = "808 Snare"; // Snares
const char sampleName17[] PROGMEM = "collider snare";
const char sampleName18[] PROGMEM = "echo snap";
const char sampleName19[] PROGMEM = "hip snap";
const char sampleName20[] PROGMEM = "clap";
const char sampleName21[] PROGMEM = "echo snare";
const char sampleName22[] PROGMEM = "elec snare";
const char sampleName23[] PROGMEM = "Empty";
const char sampleName24[] PROGMEM = "FPC Rim";
const char sampleName25[] PROGMEM = "cassette Snr";
const char sampleName26[] PROGMEM = "snare hi 1";
const char sampleName27[] PROGMEM = "snare hi 2";
const char sampleName28[] PROGMEM = "chiptune snare 1";
const char sampleName29[] PROGMEM = "chiptune snare 2";
const char sampleName30[] PROGMEM = "chiptune snare 3";
const char sampleName31[] PROGMEM = "empty";
const char sampleName32[] PROGMEM = "808 kick"; // Kicks
const char sampleName33[] PROGMEM = "DNC kick";
const char sampleName34[] PROGMEM = "MAL kick";
const char sampleName35[] PROGMEM = "WhoDat kick";
const char sampleName36[] PROGMEM = "Linn Kick";
const char sampleName37[] PROGMEM = "House kick";
const char sampleName38[] PROGMEM = "frame drum";
const char sampleName39[] PROGMEM = "house gen";
const char sampleName40[] PROGMEM = "brick 808";
const char sampleName41[] PROGMEM = "ms20";
const char sampleName42[] PROGMEM = "808 Drop";
const char sampleName43[] PROGMEM = "chiptune kick";
const char sampleName44[] PROGMEM = "empty";
const char sampleName45[] PROGMEM = "empty";
const char sampleName46[] PROGMEM = "empty";
const char sampleName47[] PROGMEM = "empty";
const char sampleName48[] PROGMEM = "Guiro"; // Perc 1
const char sampleName49[] PROGMEM = "bell shake";
const char sampleName50[] PROGMEM = "808 cowbell";
const char sampleName51[] PROGMEM = "Chika Crunch";
const char sampleName52[] PROGMEM = "Crunch 1";
const char sampleName53[] PROGMEM = "Bubble 1";
const char sampleName54[] PROGMEM = "Bubble 2";
const char sampleName55[] PROGMEM = "Bubble 3";
const char sampleName56[] PROGMEM = "Bloop";
const char sampleName57[] PROGMEM = "salt rim";
const char sampleName58[] PROGMEM = "glassbell";
const char sampleName59[] PROGMEM = "Chika Perc";
const char sampleName60[] PROGMEM = "Drip";
const char sampleName61[] PROGMEM = "soda";
const char sampleName62[] PROGMEM = "clav reverb";
const char sampleName63[] PROGMEM = "909 clav";
const char sampleName64[] PROGMEM = "pop"; // Perc 2
const char sampleName65[] PROGMEM = "stapler";
const char sampleName66[] PROGMEM = "phone 1";
const char sampleName67[] PROGMEM = "phone 2";
const char sampleName68[] PROGMEM = "phone 3";
const char sampleName69[] PROGMEM = "egg shaker";
const char sampleName70[] PROGMEM = "seed shaker";
const char sampleName71[] PROGMEM = "shutter 1";
const char sampleName72[] PROGMEM = "shutter 2";
const char sampleName73[] PROGMEM = "chiptune tom 1";
const char sampleName74[] PROGMEM = "chiptune tom 2";
const char sampleName75[] PROGMEM = "chiptune tom 3";
const char sampleName76[] PROGMEM = "empty";
const char sampleName77[] PROGMEM = "empty";
const char sampleName78[] PROGMEM = "empty";
const char sampleName79[] PROGMEM = "empty";
const char sampleName80[] PROGMEM = "cha!"; //Samples 1
const char sampleName81[] PROGMEM = "game points";
const char sampleName82[] PROGMEM = "Nova beep";
const char sampleName83[] PROGMEM = "droplet";
const char sampleName84[] PROGMEM = "pong";
const char sampleName85[] PROGMEM = "echo harp";
const char sampleName86[] PROGMEM = "punch";
const char sampleName87[] PROGMEM = "chika A";
const char sampleName88[] PROGMEM = "chika B";
const char sampleName89[] PROGMEM = "chika C";
const char sampleName90[] PROGMEM = "chicka D";
const char sampleName91[] PROGMEM = "chika E";
const char sampleName92[] PROGMEM = "wow";
const char sampleName93[] PROGMEM = "Laser";
const char sampleName94[] PROGMEM = "noisefall";
const char sampleName95[] PROGMEM = "letmehearUsay";
const char sampleName96[] PROGMEM = "crowd chant"; // Samples 2
const char sampleName97[] PROGMEM = "im a gun man";
const char sampleName98[] PROGMEM = "sound of wealth";
const char sampleName99[] PROGMEM = "i understand now";
const char sampleName100[] PROGMEM = "going up";
const char sampleName101[] PROGMEM = "empty";
const char sampleName102[] PROGMEM = "empty";
const char sampleName103[] PROGMEM = "empty";
const char sampleName104[] PROGMEM = "empty";
const char sampleName105[] PROGMEM = "empty";
const char sampleName106[] PROGMEM = "empty";
const char sampleName107[] PROGMEM = "empty";
const char sampleName108[] PROGMEM = "empty";
const char sampleName109[] PROGMEM = "c bell";
const char sampleName110[] PROGMEM = "e bell";
const char sampleName111[] PROGMEM = "g bell";
const char sampleName112[] PROGMEM = "orchestral hit 1"; // HITS
const char sampleName113[] PROGMEM = "nitrodeluxe G";
const char sampleName114[] PROGMEM = "nitrodeluxe C";
const char sampleName115[] PROGMEM = "dancemachine C";
const char sampleName116[] PROGMEM = "dancemachine C#";
const char sampleName117[] PROGMEM = "yeah!";
const char sampleName118[] PROGMEM = "sword";
const char sampleName119[] PROGMEM = "getready";
const char sampleName120[] PROGMEM = "churh bell";
const char sampleName121[] PROGMEM = "orchestral hit 2";
const char sampleName122[] PROGMEM = "empty";
const char sampleName123[] PROGMEM = "empty";
const char sampleName124[] PROGMEM = "empty";
const char sampleName125[] PROGMEM = "empty";
const char sampleName126[] PROGMEM = "empty";
const char sampleName127[] PROGMEM = "emptylast";
const char * const string_table[] PROGMEM = // change "string_table" name to suit
{
sampleName0,
sampleName1,
sampleName2,
sampleName3,
sampleName4,
sampleName5,
sampleName6,
sampleName7,
sampleName8,
sampleName9,
sampleName10,
sampleName11,
sampleName12,
sampleName13,
sampleName14,
sampleName15,
sampleName16,
sampleName17,
sampleName18,
sampleName19,
sampleName20,
sampleName21,
sampleName22,
sampleName23,
sampleName24,
sampleName25,
sampleName26,
sampleName27,
sampleName28,
sampleName29,
sampleName30,
sampleName31,
sampleName32,
sampleName33,
sampleName34,
sampleName35,
sampleName36,
sampleName37,
sampleName38,
sampleName39,
sampleName40,
sampleName41,
sampleName42,
sampleName43,
sampleName44,
sampleName45,
sampleName46,
sampleName47,
sampleName48,
sampleName49,
sampleName50,
sampleName51,
sampleName52,
sampleName53,
sampleName54,
sampleName55,
sampleName56,
sampleName57,
sampleName58,
sampleName59,
sampleName60,
sampleName61,
sampleName62,
sampleName63,
sampleName64,
sampleName65,
sampleName66,
sampleName67,
sampleName68,
sampleName69,
sampleName70,
sampleName71,
sampleName72,
sampleName73,
sampleName74,
sampleName75,
sampleName76,
sampleName77,
sampleName78,
sampleName79,
sampleName80,
sampleName81,
sampleName82,
sampleName83,
sampleName84,
sampleName85,
sampleName86,
sampleName87,
sampleName88,
sampleName89,
sampleName90,
sampleName91,
sampleName92,
sampleName93,
sampleName94,
sampleName95,
sampleName96,
sampleName97,
sampleName98,
sampleName99,
sampleName100,
sampleName101,
sampleName102,
sampleName103,
sampleName104,
sampleName105,
sampleName106,
sampleName107,
sampleName108,
sampleName109,
sampleName110,
sampleName111,
sampleName112,
sampleName113,
sampleName114,
sampleName115,
sampleName116,
sampleName117,
sampleName118,
sampleName119,
sampleName120,
sampleName121,
sampleName122,
sampleName123,
sampleName124,
sampleName125,
sampleName126,
sampleName127
};
char buffer[16]; // make sure this is large enough for the largest string it must hold
//----------------------------------------------------------------------------------OBJECT CREATION-----------------------------------------------------------------------------//
// this class contains all the information contained in 1 Drummer Boy bar of music excluding sample volumes which are only stored/restored when saving/loading
class Bar
{
public:
byte hatActiveSamples[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte snareActiveSamples[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte kickActiveSamples[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte perc1ActiveSamples[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte perc2ActiveSamples[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte smp1ActiveSamples[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte smp2ActiveSamples[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte hitActiveSamples[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte rollSamples[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
boolean tripletGroup[8] = {false, false, false, false, false, false, false, false };
boolean shuffleGroup[8] = {false, false, false, false, false, false, false, false };
word hatAccents;
word snareAccents;
word kickAccents;
word perc1Accents;
word perc2Accents;
word smpAccents;
word smp2Accents;
word hitAccents;
word buttonsHat;
word buttonsSnare;
word buttonsKick;
word buttonsPerc1;
word buttonsPerc2;
word buttonsSmp1;
word buttonsSmp2;
word buttonsHit;
};
// 192 bytes each
Bar a;
Bar b;
Bar c;
Bar f;
struct saveLoad // declare a structure for saving/loading
{
Bar a_ROM;
Bar b_ROM;
Bar c_ROM;
Bar f_ROM;
char trackVolumes_ROM[NUM_TRACKS] = {0};
byte chain_ROM[4] = {0}; //modifymem
} memory;
//------------------------------------------------------------------- FUNCTION PROTOTYPES--------------------------------------------------------------------------------------------------//
// FUNCTION PROTOTYPES // - The Arduino IDE creates function prototypes for you. Normally, this works quite well. There are some situations, like functions with reference arguments, where it doesn't.
void setAccents(Bar &obj, boolean triplet);
void setAccent(int i, int nextBeat, word accentArray, Bar &obj);
void checkAnalogIO(Bar &obj);
void loadNextBeat(Bar &obj, boolean triplet);
void checkAccentButtons(Bar &obj);
void checkDigitalIO(Bar &obj);
void checkMedPriorityButtons(Bar &obj);
void save(Bar &obj);
void load(Bar &obj);
void checkLowPriorityButtons(Bar &obj);
void changeActiveSamples(int last, int current, Bar &obj);
void copyToActiveGroup(Bar &obj);
void copyTFromActiveGroup(Bar &obj);
void addSample(int beat, Bar &obj);
void checkBeatButtons(Bar &obj);
void checkHighPriorityButtons(Bar &obj);
void switchGroup(Bar &obj);
void removeSample(int beat, Bar &obj);
void readTrackVolume(boolean firstCall, Bar &obj);
void readGroup(boolean firstCall, Bar &obj);
void setTrackVolumes();
void readBtn_Sample(Bar &obj);
void readBtn_Erase(Bar &obj);
void readBtn_Accent(Bar &obj);
void readBtn_TrackVol(Bar &obj);
void readBtn_Poly(Bar &obj);
void readBtn_Tap(Bar &obj);
void readBtn_Function(Bar &obj);
int getSelection(Bar & obj, boolean saving);
void playRoll(Bar &obj);
void addRollSample(int beat, Bar &obj);
void removeRollSample(int beat, Bar &obj);
void incrementBeatCounters(boolean triplet, Bar &obj);
void setTriplet(Bar &obj);
boolean tripletActiveforCrntGrp(Bar &obj);
void waitForDelay(Bar &obj);
void resetBeat(Bar &obj);
void checkPattern(Bar &obj);
Bar getObjectByRef(int ptr);
void mainLoop(Bar &object);
Bar getOb();
void randomize(Bar &obj);
void randomizeContinuously(Bar &obj);
void shuffle(Bar &obj);
void stutter(Bar &obj);
void playNormalRoll(Bar &obj, byte beat);
void playTripletRoll(Bar &obj, byte beat);
//void updateLCD(boolean updateSampleName, int updateBpm, int);
// ***************************************SETUP*******************************************************
void setup() {
// set default track volumes to prevent anvil/stirrup combustion
trackVolumes[4] = -4; //ice hat
trackVolumes[9] = -4; //click
trackVolumes[11] = -4; //open hat
trackVolumes[12] = -20; //grav crash
trackVolumes[15] = -10; //chiptune hh open
trackVolumes[16] = -5; //chiptune hh closed
trackVolumes[29] = -5; //chiptune snare 1
trackVolumes[30] = -5; //chiptune snare 2
trackVolumes[31] = -5; //chiptune snare 3
trackVolumes[33] = -5; //808 kick
trackVolumes[35] = -8; //MAL kick
trackVolumes[37] = -8; //LINN kick
trackVolumes[38] = -10; //House kick
trackVolumes[40] = -10; //House gen
trackVolumes[57] = -5; //bloop
trackVolumes[58] = -15; //triangle
trackVolumes[59] = -15; //glassbell
trackVolumes[64] = -15; //909 clav
trackVolumes[67] = -15; //phone 1
trackVolumes[67] = -5; //phone 3
trackVolumes[81] = -10; //cha1
trackVolumes[86] = -15; //echo harp
trackVolumes[87] = -10; //punch
trackVolumes[88] = -10; //chicka 1
trackVolumes[94] = -15; //laser
trackVolumes[95] = -10; //noisefall
trackVolumes[96] = -15; //let me hear you say
trackVolumes[98] = -5; //gun
trackVolumes[99] = -20; //sound of wealth
trackVolumes[100] = -5; //oh
trackVolumes[101] = -10; //going up
trackVolumes[113] = -12; //orchestral hit
trackVolumes[116] = -12; //dancemachine
trackVolumes[117] = -12; //dancemachine
trackVolumes[118] = -5; //yea
trackVolumes[119] = -12; //sword
trackVolumes[120] = -12; //get ready
trackVolumes[121] = -12; //church bell
// create objects, each is 1 bar (16 beats)
a = Bar();
b = Bar();
c = Bar();
f = Bar();
//for eeprom SDA SCL (I2C communication)
Wire.begin();
// Serial monitor for debugging
Serial.begin(9600);
pinMode(latchPin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(clockOutPin, OUTPUT);
segmentData[0] = 0b10000001; //0
segmentData[1] = 0b11110011; //1
segmentData[2] = 0b01001001; //2
segmentData[3] = 0b01100001; //3
segmentData[4] = 0b00110011; //4
segmentData[5] = 0b00100101; //5
segmentData[6] = 0b00000101; //6
segmentData[7] = 0b11110001; //7
segmentData[8] = 0b00000001; //8
segmentData[9] = 0b00100001; //9
pinMode(buttonPin[0], INPUT_PULLUP);
pinMode(buttonPin[1], INPUT_PULLUP);
pinMode(buttonPin[2], INPUT_PULLUP);
pinMode(buttonPin[3], INPUT_PULLUP);
pinMode(buttonPin[4], INPUT_PULLUP);
pinMode(buttonPin[5], INPUT_PULLUP);
pinMode(buttonPin[6], INPUT_PULLUP);
pinMode(buttonPin[7], INPUT_PULLUP);
pinMode(buttonPin[8], INPUT_PULLUP);
pinMode(buttonPin[9], INPUT_PULLUP);
pinMode(buttonPin[10], INPUT_PULLUP);
pinMode(buttonPin[11], INPUT_PULLUP);
pinMode(buttonPin[12], INPUT_PULLUP);
pinMode(buttonPin[13], INPUT_PULLUP);
pinMode(buttonPin[14], INPUT_PULLUP);
pinMode(buttonPin[15], INPUT_PULLUP);
pinMode(eraseBtnPin, INPUT_PULLUP);
pinMode(functionBtnPin, INPUT_PULLUP);
pinMode(accentSelectPin, INPUT_PULLUP);
pinMode(polyBtnPin, INPUT_PULLUP);
pinMode(tapBtnPin, INPUT_PULLUP);
pinMode(trackVolBtnPin, INPUT_PULLUP);
pinMode(sampleTogglePin, INPUT_PULLUP);
pinMode(pitchSwitchPin, INPUT_PULLUP);
pinMode(swingSwitchPin, INPUT_PULLUP);
pinMode(stutterSwitchPin, INPUT_PULLUP);
pinMode(pauseSwitchPin, INPUT_PULLUP);
pinMode(gSwitchPin[0], INPUT_PULLUP);
pinMode(gSwitchPin[1], INPUT_PULLUP);
pinMode(gSwitchPin[2], INPUT_PULLUP);
pinMode(gSwitchPin[3], INPUT_PULLUP);
pinMode(gSwitchPin[4], INPUT_PULLUP);
pinMode(gSwitchPin[5], INPUT_PULLUP);
pinMode(gSwitchPin[6], INPUT_PULLUP);
pinMode(gSwitchPin[7], INPUT_PULLUP);
delay(500); // wait for the WAV Trigger to finish reset before trying to send commands.
wTrig.start(); // WAV Trigger startup at 57600
delay(10);
wTrig.stopAllTracks();// Send a stop-all command and reset the sample-rate offset, in case we have reset while the WAV Trigger was already playing.
wTrig.samplerateOffset(0); // make sure the pitch is unmodified
// enable track reporting (recieve data from the WAV Trigger)
wTrig.setReporting(true);
delay(100);
// get version/track info from the wav trigger
char gWTrigVersion[VERSION_STRING_LEN]; // WAV Trigger version string
if (wTrig.getVersion(gWTrigVersion, VERSION_STRING_LEN)) {
Serial.print(gWTrigVersion);
Serial.print("\n");
int gNumTracks = wTrig.getNumTracks();
Serial.print("Number of tracks = ");
Serial.println(gNumTracks);
}
else
Serial.print("WAV Trigger response not available");
updateGroupData();
formatTrackVolumes(); // reset all track volumes to 0
setTrackVolumes();
tripletMetro.previous_millis = seqMetro.previous_millis; //sync timers
// setup lcd
lcd.begin(16, 2);
lcd.print("Drummer Boy!");
lcd.setCursor(0, 1);
lcd.write(byte(0));
//setBacklight(100, 0, 255 - 100); //set backlight color
delay(1000);
updateLCD(true, 0, true); // update all info on the lcd
readTempo(1); // read vol and tempo values
readVolume(1);
wTrig.trackPlayPoly(200); // play startup sound
EEPROM_readAnything(900 * 16, savedPatternNames);
// for (int i = 0 ; i < 16; i++) { // format save names
// savedPatternNames[i][0] = 'e';
// savedPatternNames[i][1] = 'm';
// savedPatternNames[i][2] = 'p';
// savedPatternNames[i][3] = 't';
// savedPatternNames[i][4] = 'y';
// savedPatternNames[i][5] = ' ';
// savedPatternNames[i][6] = ' ';
// savedPatternNames[i][7] = ' ';
// savedPatternNames[i][8] = ' ';
// savedPatternNames[i][9] = ' ';
// savedPatternNames[i][10] = ' ';
// savedPatternNames[i][11] = ' ';
// savedPatternNames[i][12] = ' ';
// savedPatternNames[i][13] = ' ';
// savedPatternNames[i][14] = ' ';
// savedPatternNames[i][15] = ' ';
// }
}
//------------------------------------------------------------------------------------MAIN LOOP------------------------------------------------------------------------//
void loop() {
if (chain[currentSlotPtr] == 1) mainLoop(a);
if (chain[currentSlotPtr] == 2) mainLoop(b);
if (chain[currentSlotPtr] == 3) mainLoop(c);
if (chain[currentSlotPtr] == 4) mainLoop(f);
}
void mainLoop(Bar &object) {
if (lastObj != chain[currentSlotPtr]) {
copyToActiveGroup(object);
lastObj = chain[currentSlotPtr];
}
if (!pauseOn) {
if (seqMetro.check() == 1) {
//Serial.println("quarter");
setSwing();
setAccents(object, false); //set accents before to prevent change in volume while track is playing
lastNormalRollMs = millis(); // for roll
rollCounterNormal = 0; // for roll
for (int i = 0; i < 8 ; i++) {
if ( playSamplesBuffer[i] != 0) {
if (groupSwitchState[i] == 1 && !object.tripletGroup[i]) {
if (!delayGroup[i]) {
wTrig.trackPlayPoly( playSamplesBuffer[i] );
//Serial.print("Playing sample:"); Serial.println(playSamplesBuffer[i]);
}
else {
playSamplesDelayBuffer[i] = playSamplesBuffer[i];
startMS_d = millis();
delayFlag = true;
Serial.print("liveMash:"); Serial.println(liveMash);
}
}
}
}
if (delayFlag == false) {
incrementBeatCounters(false, object);
if (beatMaster == 14)shuffle(object);
if (beatMaster == 15) checkPattern(object);
loadNextBeat(object, false);
}
startTime = millis();
}
if (tripletMetro.check() == 1) {
//Serial.println("triplet");
setAccents(object, true); //set accents before to prevent change in volume while track is playing
lastTripletRollMs = millis(); // for roll
rollCounterTriplet = 0; // for roll
for (int i = 0; i < 8 ; i++) {
if ( playSamplesBuffer[i] != 0) {
if (groupSwitchState[i] == 1 && object.tripletGroup[i]) {
if (!delayGroup[i]) {
wTrig.trackPlayPoly( playSamplesBuffer[i] );
Serial.println("Normal Triplet");
}
else {
playSamplesTripletDelayBuffer[i] = playSamplesBuffer[i];
startMS_tripD = millis();
delayTripletFlag = true;
Serial.print("1T:"); Serial.println(millis());
}
}
}
}
if (delayTripletFlag == false) {
incrementBeatCounters(true, object);
loadNextBeat(object, true);
}
startTime = millis();
}
waitForDelay(object);
playRoll(object);
checkDigitalIO(object);
checkAnalogIO(object);
clockOut();
if (stutterOn) stutter(object);
updateLCD(false, 0, false);
} else {
if (digitalRead(pauseSwitchPin) == HIGH && pauseOn) {
pauseOn = false;
seqMetro.reset();
tripletMetro.reset();
startAtBeat0();
}
checkDigitalIO(object);
checkAnalogIO(object);
}
}
////////////////////////////////////////////////////////////////////////////////////// OOP Methods /////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void clockOut() {
if (millis() - lastClockMs > tempoMS / 32) {
if (clockOutLogicHigh) {
digitalWrite(clockOutPin, LOW);
clockOutLogicHigh = false;
}
else {
digitalWrite(clockOutPin, HIGH);
clockOutLogicHigh = true;
}
lastClockMs = millis();
}
}
void stutter(Bar &obj) {
if ( !obj.tripletGroup[0]) beatHat = 15;
else beatHat = 14;
if ( !obj.tripletGroup[1]) beatSnare = 15;
else beatSnare = 14;
if ( !obj.tripletGroup[2]) beatKick = 15;
else beatKick = 14;
if ( !obj.tripletGroup[3]) beatPerc1 = 15;
else beatPerc1 = 14;
if ( !obj.tripletGroup[4]) beatPerc2 = 15;
else beatPerc2 = 14;
if ( !obj.tripletGroup[5]) beatSmp1 = 15;
else beatSmp1 = 14;
if ( !obj.tripletGroup[6]) beatSmp2 = 15;
else beatSmp2 = 14;
if ( !obj.tripletGroup[7]) beatHit = 15;
else beatHit = 14;
}
void updateLCD(boolean updateSampleName, int updateBpm, boolean updatePattern) {
if(accent){
lcd.home();
lcd.print("accent decibel ");
lcd.setCursor(0, 1);
lcd.print("difference: ");
lcd.print(accentDBOffset);
lcd.print(" ");
return;
}else if (erasePushedRN) {
lcd.home();
lcd.print("select btn below");
lcd.setCursor(0, 1);
lcd.print("group to erase!");
return;
} else if (liveMash && !displayingLiveMash) {
displayingLiveMash = true;
Serial.println("PRINTING LIVE");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print("LIVE");
return;
}
if (updateSampleName) {
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
int currSamp = getCrrntSlctdSmpl();
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[currSamp - 1]))); // Necessary casts and dereferencing, just copy.
lcd.print(buffer); //untested!!!
}
if (updateBpm > 0) {
lcd.setCursor(10, 0);
lcd.print(updateBpm);
lcd.print("BPM ");
}
if (chain[currentSlotPtr] != lastPatt || updatePattern) {
lcd.home();
lcd.print("Pattern:");
if (chain[currentSlotPtr] == 1) lcd.print("A");
if (chain[currentSlotPtr] == 2) lcd.print("B");
if (chain[currentSlotPtr] == 3) lcd.print("C");
if (chain[currentSlotPtr] == 4) lcd.print("D");
lastPatt = chain[currentSlotPtr];
lcd.print(" ");
}
}
void addPattern(int pattern) { //set the pattern order
if (numPatternsSelected < 4) {
Serial.print("Add pattern:"); Serial.print(pattern); Serial.print(" to slot:"); Serial.println(numPatternsSelected);
chain[numPatternsSelected] = pattern;
numPatternsSelected++;
}
}
void checkPattern(Bar &obj) { //checked at the end of every bar, plays the next patten in the 'chain'
copyFromActiveGroup(obj);
if (restoreChainFlag) { //restores old chain after the fill has played before incrementing the ptr
chain[currentSlotPtr] = tempStorage;
restoreChainFlag = false;
}
if (chain[1] == 0) currentSlotPtr = 0; //reset pointer if the next element is zero, otherwise increment it
else if (chain[2] == 0 && currentSlotPtr == 1) currentSlotPtr = 0;
else if (chain[3] == 0 && currentSlotPtr == 2) currentSlotPtr = 0;
else currentSlotPtr++;
if (currentSlotPtr == 4) currentSlotPtr = 0; //reset pointer
if (fillFlag) { // set fill
tempStorage = chain[currentSlotPtr];
chain[currentSlotPtr] = 4;
fillFlag = false; restoreChainFlag = true;
}
}
void copy(int pat) {
Serial.print("Copy...");
if (copyPtr < 2) { // no need to do anything if a third button is pressed
if (copyPtr == 0) { // store selection from first push
copyFrom = pat;
}
if (copyPtr == 1) { //second push we copy the selected pattern over
copyTo = pat;
if (copyFrom == 1 && copyTo == 2) memcpy(&b, &a, sizeof(a));
else if (copyFrom == 1 && copyTo == 3) memcpy(&c, &a, sizeof(a));
else if (copyFrom == 1 && copyTo == 4) memcpy(&f, &a, sizeof(a));
else if (copyFrom == 2 && copyTo == 1) memcpy(&a, &b, sizeof(a));
else if (copyFrom == 2 && copyTo == 3) memcpy(&c, &b, sizeof(a));
else if (copyFrom == 2 && copyTo == 4) memcpy(&f, &b, sizeof(a));
else if (copyFrom == 3 && copyTo == 1) memcpy(&a, &c, sizeof(a));
else if (copyFrom == 3 && copyTo == 2) memcpy(&b, &c, sizeof(a));
else if (copyFrom == 3 && copyTo == 4) memcpy(&f, &c, sizeof(a));
else if (copyFrom == 4 && copyTo == 1) memcpy(&a, &f, sizeof(a));
else if (copyFrom == 4 && copyTo == 2) memcpy(&b, &f, sizeof(a));
else if (copyFrom == 4 && copyTo == 3) memcpy(&c, &f, sizeof(a));
Serial.print("Copy pattern"); Serial.print(copyFrom); Serial.print(" to "); Serial.println(copyTo);
}
copyPtr++;
}
}