-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathemprenda_R4a_35.ino
1843 lines (1519 loc) · 61.5 KB
/
emprenda_R4a_35.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
/*
Effigy Labs
for the Emprenda MIDI pitch bend pedal interface
(C)2012-2017, Effigy Labs
PUBLISHED AS FREE OPEN SOURCE SOFTWARE (FOSS) - see LICENSE.TXT
Author: Jody Roberts
Disclaimers to those brave enough to try to use this software:
This program is primitive. Do not expect all the correct techniques to be used.
I have certainly re-invented much needlessly.
Please share changes and improvements with the Community.
I am happy to discuss anything, for now, at Jody@effigylabs.com.
We'll have a web site and community forum soon.
Thanks
JR
updates:
Dec 13 2015 - for #32
Aug 26 2016 - for #33 using R4a pcb
Nov 28 2016 - for #34 concept
Dec 14 2016 - for #34 working
Feb 08 2017 - for #34b working
Feb 26 2017 - for #35-29 ROF / FOSS / USB VID/PID
02/08/17 - updates:
- remove OMNI broadcast
- ensure sustain threahold to natural
12/14/16 - updates:
fixed superfluous sensitivity traffic - so not re-sending sustain on or off after it is already on or off
OTAs are .75" so maybe different performance curve -
08-26-16 updates:
Now on ATMEGA32u4 mpu
no separate usb chip
separate serial (serial1) port from USB
can now send actual MIDI out all the time regardless of debug mode
pin mappings are different for most of the input and output circuits
new quieter circuit? mo betta caps keep it quieter
12-13-15 updates:
fadespeed changed and moved up front
sensitivity knob max var moved up front
midi preset section moved up front
all up-front moves can be generated in one block of code (one file / include /etc)
This program must be compiled as a TeeOnArdu for the pin mappings to work. On the Teensy 2.0:
a0 = Sensitivty knob
a1 = OTA3
a2 = OTA2
a3 = OTA1
but on the Leonardo,
A3 = Sensitivity knob,
A2 = OTA3
A1 = OTA2
A0 = OTA1
so the pin mappings will not work interchangeably.
dummy pin - to avoid cross-talk influence between the last OTA read and the sensitivity knob.
TO-DO:
- program rewrite
- use bounce objcts for de-jittering
- MIDI command input
x redo of debugging
x change pin mappings
x fix bug on sensitivity knob range so knob has full range of function in entire range of motion
- fix phasing/LED
- EEPROM - what to remember and where
remembering of states, modes, and presets
- MIDI channel
- mode 1, mode 2, mode 3 settings
- presets settings
- whatever else is storable and retrievable in 1K
- sensitivity knob setting
- sensitivity knob and other settings override on manual touch
- calibration results from previous calibrations
- mappings of pins early and late
- fuller implementation of keeping the columns in the OTA updated, active, etc. for later use
operation mode presets
preset modes: L - R - C
mode 1: pitchbend(0+1) + mod
mode 2: pitchbend(0+1) + breath
mode 3: mod, expression, and breath
sensor input operating range - 50-950 for phototransistors - #20+
50-600 for photoresistors #19 and earlier
20-1023 for photoresisters in straight OTAs #30+
updated max phase speeed to something that will flash reliably
max sensitivity knob pot = 512
main flow:
setup:
- initialize variables
- calibrate OTAs and initialize OTA array
- initialize sensitivity
- select mode and enter main loop
main loop:
- if mode3, go directly to mode 3 processing
- otherwise, process mode 1 or 2 which is pitch bend + a third middle function
- in mode 1 or 2:
- if either sensor is active, retrieve its value and process
- otherwise, enter inner loop and wait until a sensor becomes active
- while waiting, sensitivity knob and process the middle OTA
- when processing an OTA:
- check for jitter
- check for centering
- check for maxing
- if none of these:
- determine if a message should be sent:
- if the OTAs mode is switched (on/off only):
- if the sensor isn't already "on", process the message
- otherwise, if the OTA mode is not switched, process the message
spec:
restore factory defaults
change midi channel but do not save
save midi channel to memory
restore midi channel from memory
define 3 modes
define each mode
define what each OTA does in a mode
1-16 - change MIDI channel
17 - save current midi channel to boot
18 - restore saved midi channel from memory
19 - save current sensitivity knob to boot
20 - restore saved sensitivity knob from memory
21 - save current mode to boot incl sensitivity knob settings and all function-specific values: threshold, .....
22 -
1 - go to mode 1
2 - go to mode 2
3 - go to mode 3
4 - set preboot to mode 1
5 - set preboot to mode 2
6 - set preboot to mode 3
7 -
- ledFadeBrightness max brightness ****** 090816
defining presets
set mode 1 to be: OTA1+OTA2+OTA3 settings, OTA setting = function, threshold, lower range, upper range = 6 bytes x 3 = 18 bytes per ota, 54 per mode
set mode 2 to be:
set mode 3 to be:
*/
//#include <EEPROM.h>
#include <EEPROMex.h>
#include <EEPROMVar.h>
//#include <BOUNCE.h>
//////////////////////////DEBUG SECTION/////////////////////////////////////////////////////////
//comment out this for real operation when switching to MIDI device type enumeration on USB //
//#define DEBUG //
////////////////////////////////////////////////////////////////////////////////////////////////
// ****** commonly changed variables ****** - preset code section begin
// use this structure to include code that compiles only in non-debug mode i.e. midiSerial.* where the USB_MIDI must be defined in the environment
#ifdef DEBUG
int EffigyLabsDebuggerVersion = 3;
// enable debug output with dp and dpl functions - NOTE this code will not work here because you are not in setup() or loop()!
//dpl("Effigy Labs Debugger v3"); // include debugger printing etc. here
#endif
#ifndef DEBUG
// include midiSerial.*, etc. statements here // enable debug output with dp and dpl functions
#endif
//boolean debug = false; // disable debug output and send real MIDI
///////////////////////////////////////////////////////////////
int nop; // for no op logic when debug include makes nothing and you must do something in between an if and else.
int mode = 0; // 0 = mode is initially unset, or if mode = a supported mode, pedal enters that mode after calibration without interaction
// MIDI
int const MIDI_OMNI_MODE_ON = 0x7D;
int const MIDI_OMNI_MODE_OFF = 0x7C;
int CURRENT_MIDI_CHANNEL = 1;
int address = 0;
// channel 1 codes
int const MIDI_CHG = 0xB0; // midi change command channel 1 dec 176
int const MIDI_SUSTAIN = 0x40; // midi sustain channel 1, dec 64
int const MIDI_MOD_CMD = 0x01; // midi MOD wheel control - CC1
int const MIDI_BREATH_CMD = 0x02; // midi BREATH control - CC2
int const MIDI_XPRS_CMD = 0x0B; // midi EXPRESSION control - CC7
int const MIDI_SUSTAINON_CMD = 0x7F; // midi value for sustain on (>64)
int const MIDI_SUSTAINOFF_CMD = 0x00; // midi value for sustain off (<64)
/*
future
int const MIDI_CC3_CMD = 0x03; // CC3
int const MIDI_PAN_CMD = // CC
int const MIDI_REVERB_CMD = // CC91
int const MIDI_PORTAMENTO_CMD = 0x05; // CC5
int const MIDI_CHORUS_CMD = // CC93
int const MIDI_HARMONIC_CMD = // CC
int const MIDI_RELEASE_CMD = // CC72
int const MIDI_VOLUME_CMD = 0x07; // CC7
int const MIDI_ATTACK_CMD = // CC73
int const MIDI_BRIGHT_CMD = // CC74
int const MIDI_PHASER_CMD = // CC95
int const MIDI_CELESTE_CMD = // CC94
int const MIDI_EFFECTS_CMD = // CC91
int const MIDI_FOOTPEDAL_CMD = 0x04; // CC4 (MSB)
*/
int const PITCH_DOWN = 0x111; // Effigy reference code
int const PITCH_UP = 0x112; // Effigy reference code
// user-configurable section
// supply configurations for a preset here.
// prototypical - not implemented 3/30/2014 - JR
// this gets implemented in the eeprom - 12/14/16 - JR
// default preset 1
int mode_1_1 = PITCH_DOWN; // mode 1, OTA 1
int mode_1_1_min = 0x0000; // mode 1 OTA 1 min - NOTE: must agree with mode or pedal will not function!
int mode_1_1_max = 0x2000; // mode 1 OTA 1 min - NOTE: must agree with mode or pedal will not function!
int mode_1_2 = PITCH_UP; // mode 1, OTA 2
int mode_1_2_min = 0x2000; // mode 1 OTA 2 min - NOTE: must agree with mode or pedal will not function!
int mode_1_2_max = 0x3FFF; // mode 1 OTA 2 min - NOTE: must agree with mode or pedal will not function!
int mode_1_3 = MIDI_SUSTAIN; // mode 1, OTA 3
int mode_1_3_min = 0; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function! for an on-off function like sustain, use 0-127 for min-max
int mode_1_3_max = 127; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function!
int mode_2_1 = PITCH_DOWN; // mode 2, OTA 1
int mode_2_1_min = 0x0000; // mode 2 OTA 1 min - NOTE: must agree with mode or pedal will not function!
int mode_2_1_max = 0x2000; // mode 2 OTA 1 min - NOTE: must agree with mode or pedal will not function!
int mode_2_2 = PITCH_UP; // mode 2, OTA 2
int mode_2_2_min = 0x2000; // mode 2 OTA 2 min - NOTE: must agree with mode or pedal will not function!
int mode_2_2_max = 0x3FFF; // mode 2 OTA 2 min - NOTE: must agree with mode or pedal will not function!
int mode_2_3 = MIDI_MOD_CMD; // mode 2, OTA 3
int mode_2_3_min = 0; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function! for an on-off function like sustain, use 0-127 for min-max
int mode_2_3_max = 127; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function!
int mode_3_1 = MIDI_MOD_CMD; // mode 3, OTA 1
int mode_3_1_min = 0; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function! for an on-off function like sustain, use 0-127 for min-max
int mode_3_1_max = 127; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function!
int mode_3_2 = MIDI_BREATH_CMD; // mode 3. OTA 2
int mode_3_2_min = 0; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function! for an on-off function like sustain, use 0-127 for min-max
int mode_3_2_max = 127; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function!
int mode_3_3 = MIDI_XPRS_CMD; // mode 3, OTA 3
int mode_3_3_min = 0; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function! for an on-off function like sustain, use 0-127 for min-max
int mode_3_3_max = 127; // mode 1 OTA 3 min - NOTE: must agree with mode or pedal will not function!
// ****** commonly changed variables ****** - preset code section end
// global variables
int j = 0; // counter
int working_range = 0; //established at calibration time as the upper limit minus the maximum lower limit of all OTAs
// OTA Array
const int numberofOTAs = 3; // set the number of OTAs on the device
int OTAs[numberofOTAs][12]; // second number is the number of columns or global variables we have at this point in time
float OTAscaleratios[numberofOTAs];
int maxLowerLimit = 0;
// saved last values to prevent resends of same MIDI commands
int lastCmdType = 9999;
int lastCmdSubType = 9999;
int lastValue = 9999;
int lastPitchValue = 0x2000;
// named values for the columns in our table
const static int OTA_COL = 0; // Pin mapping to atmega328 analog pins
const static int LOWERLIMIT_COL = 1; // lower limit
const static int UPPERLIMIT_COL = 2; // upper limit
const static int open_gate_COL = 3; // currently open_gate?
const static int full_gate_COL = 4; // currently full_gate?
const static int VALUE_COL = 5; // current value measured
const static int LASTSENSORVALUE_COL = 6; // last value measured
const static int WORKINGRANGE_COL = 7; // set of messageable values
const static int SWITCH_COL = 8; // if true, OTA operates on on-off only
const static int MIDI_CMD_COL = 9; // the function assigned to this ota
const static int SENSITIVITY_COL = 10; // current sensitivity of this ota
const static int ACTIVE_COL = 11; // current sensitivity of this ota
//const static int WHATEVER_COL = 12; // another column of OTA values
/* left-right locking:
if the left or right OTA needs to lock out the other,
it sets this and the other OTA will not proces in processOTA().
if the OTA needs to exclude both other OTAs no matter what, it sets ALLOCK. LRLOCK still allows the middle OTA (2) to process. this is useful with pitch bend.
*/
int LRLOCK = 0; // 0=not locked, 1 = left locked, 2 = right locked
boolean ALLOCK = false;
// generic for different modes
// pin mapping
// array reference to the OTA array
int left_ota = 0;
int right_ota = 1;
int middle_ota = 2;
// pin maps. the An statics map to the pin numbers on the teensy 2.0
int OTA1 = A0; //left/down
int OTA2 = A1; //right/up
int OTA3 = A2; //middle/effect
int sensorPin = OTA1; // set to either the left or right sensor by the locker in LR mode - default = left or OTA1
const int numberOfSamples = 2000; // number of calibration samples to average,
// currently at 2000 samples, approximately 1 second of clock time. this is bypassed during mode switch, currently calibration only happens at setup.
int sensorPinActive = 0; // which pedal is active; 1 = down, 2 = up, 0 = neither
// LED outputs
int pedalLedPin = 2; // emitters
int commLedPin = 3; // comm LED
int fadeLedPin = 6; // fade LED, adds base current at variable brightness via pwm to let the comm led phase in an adjustable range off of black at the bottom
// allow analogwrite
//int faceboostPin = 9; // controllable phase to allow mid-level phase blinking - not too dim or too bright
// LED blink parameters
int delayInterval = 0; // time to wait between samples
long modeselectblinkinterval = 100; // indicator of mode cycle
int modeconfirmblinkspeed = 500; // first time is 1/2 second, after mode switch is very fast like 40
long setupblinkinterval = 250;
unsigned long timer2 = 0; // long-term timer for mode switch 2-second depress
long timer2_threshold=2000; //ms
// this provides a heartbeat phased blink effect for the ledon pin 9, so you can tell the software is running.
uint8_t hbval = 128;
int8_t hbdelta = 8;
int fadeSpeedMax = 40;
int fadeSpeedMin = 8;
int fadespeed = 40; // vary from 10 to 100 - when centered, cycle according to sensitivity. when pedal is operating, vary according to OTA position.
// 40 turns out to be the max not 80 as was before
unsigned long cyclestart; // led fader timer
/*
no-delay delay - bump every this many milliseconds
- this equates to almost 18 frames per second,
the min we can get away with: 1000ms / 18 (fps) = 55... so 60 is very slightly slower
*/
int delayint = 60;
//int fademax = 242; // maximum brightness to output
//int fademin = 32; // minimum brightness to output
int fademax = 200; // maximum brightness to output
int fademin = 0; // minimum brightness to output
int ledFadeBrightness = 200; // default value: start "on" ******** fix this and other parts of this for proper phasing
// sensitivity knob input
int sensitivityKnobPin = A3; // sensitivity knob input pin # for #33+ on atmega32u4 compiling as a teeonardu
int dummypin = A4; // unused pin. read before reading the knob value. this is necessary to discharge the hold/sample capacitor in the chip to get an
// accurate reading. If this is not done, the knob value will be influenced by the last value read from the last OTA. In this case,
// OTA3. Prior to this, the knob will return a wrong reading proportional to the OTA3
// value (data and graph shown in spreadsheet test_log_#34_121416_5.xlsx
int sensitivityKnobMinValue = 0; // knob's minimum reading
int sensitivityKnobValue = 255; // default value = half-way
int sensitivityKnobMaxValue = 510; // #34's maximum knob reading
int knobjitter = 4; // variance of sensitivity knob - to 4 for #34 12/24/16
//int knobjitter = 3; // variance of sensitivity knob - pped from 3 to 10 for #32
//int knobjitter = 3; // variance of sensitivity knob - pped from 3 to 10 for #32
// set to 6 for #33 - sep 1 2016 - 3 expressed jitter in the middle of the range
// set back to 3 for #34 after fixing the knob cross-talk issue between ota3 and the knob reading - idles nice and tight now
int lastSensitivityKnobValue = 9999; // sensitivity change detection
int tripp = 0; // keeps track of min sens knob raw value
int trigger = 3; // keeps track of min sens knob raw value
int sensmintune = 999; // keeps track of min sens knob raw value
int sensmaxtune = 0; // tracks max sens knob raw value
// mode switch button
int modeSwitchPin = 6; // for atmega32u4 R4a+ boards
int modeswitchstate = 9999;
float temp_midivalue = 0; // translated 0-127 MIDI message value
int midivalue = 0; // translated 0-127 MIDI message value
int ota_lowerlimit; // used in pitch latching module
int ota_upperlimit; // used in pitch latching module
// bounds and locking
boolean open_gate = true; // centered
boolean full_gate = false; // maxed
// pedal working range and scale
unsigned long timecounter = 0; // general purpose loop counter
int counter = 0; // general purpose loop counter
int max_working_range = 900; // new for #33 - defines largest range including everything - the lower limit + upper limit must fit in this
int upperlimit = 900; // #33 OTAs max between 900-1000, about 100 lower. also observed some type of recharge time on the OTAs? Anyway this works fine
// maximum working range size out of 1023 minus the highest upper limit of all the otas, adjusted by the sensitivity knob
// changed from 600 to 900 for #20 phototransistors
// kept for #21 - 30 Mar 2014 - JR
// 1023 - upper limit - highest lower limit of all otas
// this number now equates to the highest range of the sensitivity knob
// map sensitivity knob max to 0 on this working range.
// sensitivity knob changes decrease under but never increase over this number
//int knobsensitivity = 2; // sensitivity knob sensitivity dejitter factor
int sensitivity = 4; // pedal sensitivity dejitter factor - nice and low for better/later pedals
// this changes dynamically, the initial value is not used
// setting to 4 just coz for #34
// changed from 3 to 2 for #33+ - 08/31/16 - JR
float mode_select_threshold = .25; // single press on/off threshold
// porch size
// bigger value to lower_limit_pad_minimum sets the size of the smallest difference between the average (idle) of an OTA and it's lower limit trigger.
int lower_limit_pad_minimum = 10; // program will pick idle+this value as lower limit, or, min lower limit value, higher of the two (12/19/16 - verify???)
// changed from 6 to 10 for #33 - 08/31/16 - JR on apparent floor noise from OTA1....
int minporchsize = 2; // 12/25/16 for #34 - changed to variable for minimum distance from idle value of an OTA to the beginning of the working range
// minimum invariable increase to set off a mode select switch - prevents very quiet pedals from being oversensitized by the threshold percentrage.
int minthreshold = 40; // trying this for now for #33+
// lowered from 50 to 40 for #34
// MIDI pitch variables
int targetlower = 0x0000; // target (midi pitch) lowest value
int targetupper = 0x3FFF; // target (midi pitch) maximum value - 16384 values
int diff = 0;
float scaleratio = 0.0000; // used to scale ratio if upper or lower imits change
byte byte1 = 0;
byte byte2 = 0;
int pitchcmd = 0xE0;
int center = 0x2000;
int zerohex = 0x00;
int pitchvalue = 0;
// sensor tracking
int sensorValue = 0; // variable to store the value coming from the sensor
//int transformedvalue = 0; // working range adjusted value
int lastsensorValue = 0;
//////////////////////
// Beginning of code//
// Initialization //
//////////////////////
void setup() {
// check eeprom restore flag to go into a mode immediately or mode select
// int tch = EEPROM.read(address);
// Set MIDI baud rate:
#ifdef DEBUG
delay(5000); // wait for connection, maybe serial console connection, etc.
Serial.begin(9600); // for nice texty output
//delay(5000); // wait for connection, maybe serial console connection, etc.
dpl("Effigy Labs debugger v3");
dp(numberofOTAs);
dpl(" OTAs:");
#endif
Serial1.begin(31250); // always output real MIDI out the DIN5 MIDI port, separate from USB port now.
// set up the OTAs array
// OTA_Col maps the pins for teeonardu, not Leonardo
OTAs[left_ota][OTA_COL] = OTA1;
OTAs[right_ota][OTA_COL] = OTA2;
OTAs[middle_ota][OTA_COL] = OTA3;
// OTA_Col maps the pins
// default values for all OTAs
for (counter = 0; counter < numberofOTAs; counter++) {
OTAs[counter][open_gate_COL] = true;
OTAs[counter][full_gate_COL] = false;
OTAs[counter][SWITCH_COL] = false;
OTAs[counter][ACTIVE_COL] = false;
}
// declare the ledPin as an OUTPUT:
pinMode(commLedPin, OUTPUT);
pinMode(pedalLedPin, OUTPUT);
pinMode(fadeLedPin, OUTPUT);
//digitalWrite(fadeLedPin, HIGH); // turn on comm LED
digitalWrite(commLedPin, HIGH); // turn on comm LED
digitalWrite(pedalLedPin, HIGH); // turn on emitters
// maybe don't need ********
blinkCommLED(setupblinkinterval, 2); // indicate to user and give pedal sensors time to stabilize under illumination
// establish the lower limits for the OTAs
#ifdef DEBUG
// delay(2000); // to switch to console if desired
dpl("calibrating");
#endif
calibrateOTAs();
// read sensitivity knob and establish common upper limit
#ifdef DEBUG
dpl("setting initial sensitivity");
#endif
handleSensitivity();
timer2 = millis(); // initialize timer2 (longer timer)
#ifndef DEBUG
//if (usbMIDI.read() == true) handleMidiCmd(); // check for MIDI input
#endif
#ifdef DEBUG
report();
#endif
// select mode
#ifdef DEBUG
dpl("selecting mode");
#endif
selectMode();
//analogWrite(commLedPin, 700); // turn off bright led blink to the fader
// turn OMNI mode on
//#ifdef DEBUG
// dpl("sending OMNI mode ON.");
//#endif
// not sure what this should do, omni is listening, not sending, so there should be a channel picked, yeah
// removed 02/08/17
//sendMidiCmd(MIDI_CHG, MIDI_OMNI_MODE_ON, 0);
#ifdef DEBUG
dpl("entering main loop");
#endif
cyclestart = millis(); // prime fade led timer
}
//////////////////////////////////
// main loop - mode is selected //
//////////////////////////////////
void loop() {
// just go into mode 3 forever if mode3
if (mode == 3) enterMode3(); // enter mode 3
//
// we're in mode 1 or 2 so go through pitch bend + middle process
//
handleModeSwitch();
heartbeat();
handleSensitivity(); // check the sensitivity knob and make adjustments if that is happenin if(usbMIDI.read() == TRUE) handleMidiCmd(); // check for MIDI input
#ifndef DEBUG
////if (usbMIDI.read() == true) handleMidiCmd(); // check for MIDI input
#endif
//fadeOnSensitivity(); // set fade cycle speed to reflect the sensitivity knob's value
processOTA(middle_ota); // turn sustain on or off etc.
// else we are in mode 1 or 2 which is the original pitch bend emprenda program,
// with the third OTA added as an additional function which is checked inside the original pitch bend loop
// not open_gate, one of the sensors is active
if (sensorPinActive > 0) { // there is a lock already
sensorValue = analogRead(sensorPin); // read the value from the active pin
}
else { // all are open_gate so wait until one uncenters
//dp("sensorPinActive=");
//dpl(sensorPinActive);
do {
handleSensitivity(); // handle sensitivity knob inside the inner loop
handleModeSwitch(); // check for mode switch
#ifndef DEBUG
//if (usbMIDI.read() == true) handleMidiCmd(); // check for MIDI input
#endif
processOTA(middle_ota); // turn sustain on or off etc.
heartbeat();
sensorValue = analogRead(OTA1);
//dp("ota1 raw=");
//dpl(sensorValue);
if (sensorValue > (OTAs[left_ota][LOWERLIMIT_COL] + OTAs[left_ota][SENSITIVITY_COL])) {
sensorPin = OTAs[left_ota][OTA_COL];
ota_lowerlimit = OTAs[left_ota][LOWERLIMIT_COL];
ota_upperlimit = OTAs[left_ota][UPPERLIMIT_COL];
sensitivity = OTAs[left_ota][SENSITIVITY_COL];
scaleratio = OTAscaleratios[left_ota];
open_gate = false;
#ifdef DEBUG
dpl("L OTA on");
#endif
sensorPinActive = 1; // "left" - breaks when this value changes
break;
} // end check if L OTA is on
sensorValue = analogRead(OTA2);
if (sensorValue > (OTAs[right_ota][LOWERLIMIT_COL] + OTAs[right_ota][SENSITIVITY_COL])) {
sensorPin = OTAs[right_ota][OTA_COL];
ota_lowerlimit = OTAs[right_ota][LOWERLIMIT_COL];
ota_upperlimit = OTAs[right_ota][UPPERLIMIT_COL];
sensitivity = OTAs[right_ota][SENSITIVITY_COL];
scaleratio = OTAscaleratios[right_ota];
open_gate = false;
#ifdef DEBUG
dpl("R OTA on");
#endif
sensorPinActive = 2; // "right" - breaks on this value changing
//break; don't break here or it never maxes out
} // end check of if R OTA is on
}
while (sensorPinActive == 0);
}
// we now have a sensor value
if (sensorValue < ota_lowerlimit) {
#ifdef DEBUG
if (sensorPinActive == 1) dpl("L OTA now open gate");
if (sensorPinActive == 2) dpl("R OTA now open gate");
#endif
sensorPinActive = 0;
if (!open_gate) {
// the value is from the actively bending sensor - else it's a coming-off-center signal
open_gate = true;
// set last value to the center
//lastsensorValue = lowerlimit;
//sensorValue = lowerlimit;
lastsensorValue = sensorValue;
sendPitch(0x2000);
fadeOnSensitivity();
return;
} // if we are open_gate and were already open_gate, do nothing
} // centering
// handle maxing out
if (sensorValue > ota_upperlimit) {
if (!full_gate) {
full_gate = true;
//sensorValue = upperlimit;
lastsensorValue = sensorValue;
#ifdef DEBUG
if (sensorPinActive == 1) dpl ("L OTA now full gate");
if (sensorPinActive == 2) dpl ("R OTA now full gate");
#endif
if (sensorPinActive == 1) sendPitch(0x0000); // all the way down
if (sensorPinActive == 2) sendPitch(0x3FFF); // all the way up
fadeOnPosition(1, 0, 1); // fade at max speed
}
return; // we were full_gate so either way exit
} // maxing
// do nothing if not changed - filter out noise. do here before overhead of pitch conversion and also
// to incrase sensitivity granularity.
// if not jitter
if ((sensorValue < (lastsensorValue - sensitivity)) ||
(sensorValue > (lastsensorValue + sensitivity))) {
if (open_gate) {
#ifdef DEBUG
if (sensorPinActive == 1) dpl ("L OTA leaving open gate");
if (sensorPinActive == 2) dpl ("R OTA leaving open gate");
#endif
open_gate = false;
}
if (full_gate) {
#ifdef DEBUG
if (sensorPinActive == 1) dpl ("L OTA leaving full gate");
if (sensorPinActive == 2) dpl ("R OTA leaving full gate");
#endif
full_gate = false;
}
// if sensorValue is in the working range now, and it's not jitter, send pitch messages
if (sensorPinActive == 1) sendPitch(0x2000 - ((sensorValue - ota_lowerlimit) * scaleratio));
if (sensorPinActive == 2) sendPitch(0x2000 + ((sensorValue - ota_lowerlimit) * scaleratio));
fadeOnPosition(sensorValue, ota_lowerlimit, ota_upperlimit);
lastsensorValue = sensorValue;
}
} // loop
void enterMode3() {
// ensure initialize
// loop through each OTA
//Serial.println("in mode 3");
do {
// process the OTAs
for (counter = 0; counter < numberofOTAs; counter++) {
processOTA(counter);
heartbeat();
}
// check the sensitivity knob
handleSensitivity();
#ifndef DEBUG
//if (usbMIDI.read() == true) handleMidiCmd(); // check for MIDI input
#endif
handleModeSwitch();
}
while (mode == 3);
}
/*
Effigy Labs
Function library v1.1 January 29 2013, August 26, 2016
OTA handling
void calibrateOTAs() { - calculate nominal values and lower limits for OTAs
void processOTA(int OTA) { - get OTA value and output a MIDI message
void selectMode() { - accept input from pedal and set mode based on first OTA pressed
void handleSensitivity() {
void report() { - state of all OTAs and sensitivity knob
MIDI Output
void sendMidiCmd(int cmdType, int cmdSubType, int value)
void sendPitch(int pitchvalue)
LED Blinking functions
void blinkCommLED(int time, int repetitions) {
void blinkLED(int LED, int time, int repetitions) {
void blinkPedalLED(int time, int repetitions) {
Debugging for types, sensitive to global debug flag
void dp(String value) {
void dp(float value) {
void dp(int value) {
void dp(long value) {
void dpl(String value) {
void dpl(float value) {
void dpl(int value) {
void dpl(long value) {
State Checks, both active and passive
boolean isActive(int OTA) {
boolean isActive(int OTA, int value) {
boolean isopen_gate(int OTA) {
boolean isopen_gate(int OTA, int value) {
boolean isJitter(int OTA) {
boolean isJitter(int OTA, int val) {
boolean isfull_gate(int OTA) {
boolean isfull_gate(int OTA, int value) {
*/
// read a sensor and take action based on the mode.
// ignore jitter
// center or max sending the appropriate on or off midi messages
// if not jitter or center or max then send some midi message
void processOTA(int OTA) {
int OtaValue = analogRead( OTAs[OTA][OTA_COL]);
// noise?
if (isJitter(OTA, OtaValue)) {
//Serial.print("jitter");
return;
}
else {
// it's not jitter so save this value for the next one
//Serial.println("not jitter");
OTAs[OTA][LASTSENSORVALUE_COL] = OtaValue;
// and don't return
}
// not noise so check for stuff
// check for centering / open gate
if (isopen_gate(OTA, OtaValue)) {
if (OTAs[OTA][open_gate_COL] == false) {
#ifdef DEBUG
dp("ota ");
dp(OTA);
dpl(" now open gate");
#endif
OTAs[OTA][open_gate_COL] = true;
OTAs[OTA][full_gate_COL] = false;
// deactivate depending on the preset
fadeOnSensitivity();
switch (OTAs[OTA][MIDI_CMD_COL]) {
case MIDI_SUSTAIN:
#ifdef DEBUG
dpl("midi: sustain off");
#endif
if(OTAs[OTA][ACTIVE_COL] == true) {
sendMidiCmd(MIDI_CHG, MIDI_SUSTAIN, MIDI_SUSTAINOFF_CMD );
fadeOnPosition(1, 0, 1); // turn on
}
break;
case MIDI_MOD_CMD:
#ifdef DEBUG
dpl("midi: mod off");
#endif
if(OTAs[OTA][ACTIVE_COL] == true) {
sendMidiCmd(MIDI_CHG, MIDI_MOD_CMD, 0);
fadeOnPosition(1, 0, 1); // turn on
}
break;
case MIDI_BREATH_CMD:
#ifdef DEBUG
dpl("midi: breath off");
#endif
if(OTAs[OTA][ACTIVE_COL] == true) {
sendMidiCmd(MIDI_CHG, MIDI_BREATH_CMD, 0);
fadeOnPosition(1, 0, 1); // turn on
}
break;
case MIDI_XPRS_CMD:
#ifdef DEBUG
dpl("midi: expression off");
#endif
if(OTAs[OTA][ACTIVE_COL] == true) {
sendMidiCmd(MIDI_CHG, MIDI_XPRS_CMD, 0);
fadeOnPosition(1, 0, 1); // turn on
}
break;
default:
nop = 0;
#ifdef DEBUG
dpl("the MIDI command was not in the list!");
#endif
OTAs[OTA][ACTIVE_COL] = false; // this is done at the end so things can check to not turn off what's already off
}
return; // we open_gate so we're done for this pass
}
else {
//Serial.println(" and were open_gate before");
return; // return and finish if we were open_gate and were already open_gate
}
} // end of check for centering
// check for full gate
if (isfull_gate(OTA, OtaValue)) {
if (OTAs[OTA][full_gate_COL] == false) {
#ifdef DEBUG
dp("ota ");
dp(OTA);
dpl(" now full gate");
#endif
OTAs[OTA][full_gate_COL] = true;
OTAs[OTA][open_gate_COL] = false;
OTAs[OTA][ACTIVE_COL] = false;
// activate depending on the preset
switch (OTAs[OTA][MIDI_CMD_COL]) {
case MIDI_SUSTAIN:
#ifdef DEBUG
dpl("midi: sustain on");
#endif
// send sustain only if sustain not already on
sendMidiCmd(MIDI_CHG, MIDI_SUSTAIN, MIDI_SUSTAINON_CMD );
fadeOnPosition(1, 0, 1); // turn on full gate
break;
case MIDI_MOD_CMD:
#ifdef DEBUG
dpl("midi: mod 127");
#endif
sendMidiCmd(MIDI_CHG, MIDI_MOD_CMD, 127);
fadeOnPosition(1, 0, 1);
break;
case MIDI_BREATH_CMD:
#ifdef DEBUG
dpl("midi: breath 127");
#endif
sendMidiCmd(MIDI_CHG, MIDI_BREATH_CMD, 127);
fadeOnPosition(1, 0, 1); // turn on full gate
break;
case MIDI_XPRS_CMD:
#ifdef DEBUG
dpl("midi: expression 127");
#endif
sendMidiCmd(MIDI_CHG, MIDI_XPRS_CMD, 127);
fadeOnPosition(1, 0, 1); // turn on max
break;
default:
nop = 0;
#ifdef DEBUG
dpl("the MIDI command was not in the list!");
#endif
}
//Serial.println("and were full_gate already");
return; // we full_gate so that's it for this pass
}
else {
//Serial.print("and were full_gate before");
return; // return and finish if we were open_gate and were already open_gate
}
} // end of handle full gate
// we're not full_gate and not open_gate and not jitter so we should send a message
OTAs[OTA][full_gate_COL] = false;
OTAs[OTA][open_gate_COL] = false;
if (!(OTAs[OTA][MIDI_CMD_COL] == MIDI_SUSTAIN)) {
// calculate the output midi value for the non-binary (all except sustain) funcs for now
temp_midivalue = (OtaValue - OTAs[OTA][LOWERLIMIT_COL]) / (float) OTAs[OTA][WORKINGRANGE_COL] * 127;
midivalue = (int) temp_midivalue; // truncate or maybe round
}
// change fade speed
fadeOnPosition(midivalue, 0, 127); // fade speed based on
//dp("midi:fade on position (0-127): ");
//dpl(midivalue);
switch (OTAs[OTA][MIDI_CMD_COL]) {
case MIDI_SUSTAIN:
if (!OTAs[OTA][ACTIVE_COL] == true) { // if sustain is already on don't turn it on again with the *LOCK variables
OTAs[OTA][ACTIVE_COL] = true;
#ifdef DEBUG
dpl("midi: sustain leaving open gate");
#endif
sendMidiCmd(MIDI_CHG, MIDI_SUSTAIN, MIDI_SUSTAINON_CMD);
}
break;
case MIDI_MOD_CMD:
#ifdef DEBUG
dp("midi: mod ");
dpl(midivalue);
#endif
sendMidiCmd(MIDI_CHG, MIDI_MOD_CMD, midivalue);
break;
case MIDI_BREATH_CMD:
#ifdef DEBUG
dp("midi: breath ");
dpl(midivalue);
#endif
sendMidiCmd(MIDI_CHG, MIDI_BREATH_CMD, midivalue);
break;
case MIDI_XPRS_CMD:
#ifdef DEBUG
dp("midi: expression ");
dpl(midivalue);
#endif
sendMidiCmd(MIDI_CHG, MIDI_XPRS_CMD, midivalue);
break;
default:
nop = 0;
#ifdef DEBUG
dpl("the MIDI command was not in the list!");
#endif
}
}
///////////////////////
// end of main loop //
///////////////////////
////////////////////////////
////// methods follow //////
////////////////////////////
// set or change the mode explicitly
void selectMode(int newmode) {
mode = newmode;
}
// blink LEDs until one OTA is pressed and set the mode
void selectMode() {
#ifdef DEBUG
dpl("selectMode");
#endif
//int modeselectblinkinterval = 100; // turn on and off every this many ms
// if mode = 99 then make the blinker very fast
if(mode == 99) {
modeconfirmblinkspeed = 30;