-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstomper.ino
358 lines (287 loc) · 7.72 KB
/
stomper.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
/***
* _____ _______ ____ __ __ _____ ______ _____
* / ____|__ __/ __ \| \/ | __ \| ____| __ \
* | (___ | | | | | | \ / | |__) | |__ | |__) |
* \___ \ | | | | | | |\/| | ___/| __| | _ /
* ____) | | | | |__| | | | | | | |____| | \ \
* |_____/ |_| \____/|_| |_|_| |______|_| \_\
*
* ***THX2112***
*
* http://syinsi.com
*
*
* 4/26/2016 - Cleaned up code for Clock Reset (was Trigger).
* - Clock/Trigger only on D7, Clock Reset only on D8.
*
*/
#include "digitalWriteFast.h"
// Pins:
int freqPot = A0;
int freqCurvePot = A1;
int freqEndPot = A2;
int durationPot = A3;
int tempoPot = A4;
int ledPin = 3;
int gatePin = 4;
int buttonPin = 5;
int resetPin = 8;
int clockPin = 7;
int out = 9;
// Variables:
int tempoValue;
int potMap;
int clockDivMult;
int bounceTimer = 0;
int lastBounceTime = 0;
int clockPulse = 7;
boolean done;
boolean period = false;
unsigned long timeoutTimer = 0; // microseconds
unsigned long previousPulse = 0; // microseconds
unsigned long currentPulse = 0; // microseconds
unsigned long periodStartTime = 0; // microseconds
unsigned long periodEndTime = 0; // microseconds
unsigned long periodPW; // pulsewidth size in microseconds
float startFreq = 0;
float endFreq = 1000000;
unsigned long previousEndTime;
bool buttonState = 0;
bool lastButtonState = 0;
bool resetState = 0;
bool lastResetState = 0;
bool clockState = 0;
bool lastClockState = 0;
bool outState;
unsigned long pulseWidth = 512; // used later
float duration; // microseconds
float frequency; // wavelength in microseconds
float freqCurve; // 0-1
unsigned long periodNow = 0;
bool isHit = false;
bool ledLit = false;
bool justHit = false;
float beginTime;
float now;
///////////////////////////////////////////////////////////////////////////////
//
// Setup pins.
//
void setup()
{
pinModeFast(ledPin, OUTPUT);
pinModeFast(out, OUTPUT);
pinModeFast(buttonPin, INPUT_PULLUP);
pinModeFast(resetPin, INPUT);
pinModeFast(clockPin, INPUT);
pinModeFast(gatePin, OUTPUT);
// Unused pins tied high
pinMode(2, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
pinMode(12, INPUT_PULLUP);
pinMode(13, INPUT_PULLUP);
// Flash LED
digitalWriteFast(ledPin, HIGH);
delay(20);
digitalWriteFast(ledPin, LOW);
}
///////////////////////////////////////////////////////////////////////////////
//
// This is it.
//
void loop()
{
checkTrigger();
if (isHit)
{
hitIt();
}
}
///////////////////////////////////////////////////////////////////////////////
//
// Time stuff. See if trigger is being hit...
//
void checkTrigger()
{
//
// First check if button is being pressed, and debounce. Could be done better.
//
buttonState = digitalReadFast(buttonPin);
if ((buttonState == HIGH) && (lastButtonState == LOW))
{
lastButtonState = HIGH;
bounceTimer = millis() - lastBounceTime;
}
if ((buttonState == LOW) && (lastButtonState == HIGH))
{
lastButtonState = LOW;
if (bounceTimer >= 50)
{
isHit = true;
lastBounceTime = millis();
}
else {
lastBounceTime = millis();
}
}
//
// Reset clock if resetPin pulled high.
//
resetState = digitalReadFast(resetPin);
if ((resetState == HIGH) && (lastResetState == LOW))
{
lastResetState = HIGH;
clockPulse = 0;
}
if ((resetState == LOW) && (lastResetState == HIGH))
{
lastResetState = LOW;
}
//
// Check clock/trigger.
//
clockState = digitalReadFast(clockPin);
if ((clockState == HIGH) && (lastClockState == LOW))
{
currentPulse = millis();
lastClockState = HIGH;
if ((currentPulse - previousPulse) > 5000) // Reset clock pulse if clock stops to start on the first clock
{
clockPulse = 0;
}
previousPulse = currentPulse;
if (clockPulse > 96) // Clocks start at one.
{
clockPulse = 1;
}
//
// Set division. Half of range for 24ppqn clock, other half for trigger division
//
tempoValue = analogRead(tempoPot);
potMap = map(tempoValue, 0, 1023, 11, 0); // Reverse response of pot and map to X values
if (potMap == 11) { clockDivMult = 96; } // 1 Every bar @24ppqn
if (potMap == 10) { clockDivMult = 48; } // 2 half @24ppqn
if (potMap == 9) { clockDivMult = 24; } // 4 quarter @24ppqn
if (potMap == 8) { clockDivMult = 16; } // 6 @24ppqn
if (potMap == 7) { clockDivMult = 12; } // 8th notes @24ppqn
if (potMap == 6) { clockDivMult = 8; } // /8
if (potMap == 5) { clockDivMult = 6; } // /6
if (potMap == 4) { clockDivMult = 5; } // /5
if (potMap == 3) { clockDivMult = 4; } // /4
if (potMap == 2) { clockDivMult = 3; } // /3
if (potMap == 1) { clockDivMult = 2; } // /2
if (potMap == 0) { clockDivMult = 1; } // No Division. Each input triggers a hit, so acts as a regular trigger.
//
// Check if it's time to send a hit
//
if ((clockPulse % clockDivMult == 0))
{
isHit = true;
justHit = true;
clockPulse = 0; // Restart clock if this is a new hit or timing changed.
}
clockPulse++;
}
if ((clockState == LOW) && (lastClockState == HIGH))
{
lastClockState = LOW;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// Audio stuff. Send the audio pulse.
//
void hitIt()
{
//
// Start of the sound.
//
digitalWriteFast(gatePin, HIGH);
digitalWriteFast(out, HIGH); // Start hit immediately -- catch up with calculations later.
outState = HIGH;
periodStartTime = micros();
beginTime = micros();
now = 0;
periodStartTime = micros();
period = LOW;
duration = (analogRead(durationPot) * 2000.0) + 100000.0; // Microseconds
isHit = false;
unsigned long halfFreq;
//
// Calculate the duration of each individual wavelength, taking into consideration curvature.
// Can be put inside the next loop for faster response, but increases audio artifacts.
//
duration = (analogRead(durationPot) * 1000.0) + 100000.0; // Microseconds
startFreq = (analogRead(freqPot) * 2) + 200.0; // 200 to 2246 Hz
freqCurve = ((analogRead(freqCurvePot) / 1023.0)) + .2; // make range between 0 and +1 and add a bit for movement. 0 stands still, minus moves backwards.
endFreq = (analogRead(freqEndPot) / 4.0) + 20.0; // 20 to 276 Hz
//
// Loop until the end of DURATION set by pot. This needs to loop really fast.
// Could be improved by replacing float math with fixed math.
//
while (now < duration)
{
// When I wrote this, only God and I understood what I was doing.
// Now, God only knows.
frequency = (((now / duration) * (freqCurve * 10.0)) * ((1.0 / endFreq) * 1000000.0)) + ((1.0 / startFreq) * 1000000.0); //period length in micros
periodNow = micros();
halfFreq = frequency / 2;
periodEndTime = periodStartTime + halfFreq;
//
// Toggle the output to create a square wave.
//
if ((periodNow >= periodEndTime))
{
if (outState == LOW)
{
if (now + halfFreq <= duration) // Prevent new period from starting if a new clock is going to be sent.
{
digitalWriteFast(out, HIGH);
outState = HIGH;
}
else
{
// do nothing
}
}
else if (outState == HIGH)
{
digitalWriteFast(out, LOW);
outState = LOW;
}
periodStartTime = micros(); // Register time waveform was made.
}
//
// Flash LED for 100ms at start of hit.
//
if (now <= 100000) //
{
digitalWriteFast(ledPin, HIGH);
}
else
{
digitalWriteFast(ledPin, LOW);
}
//
// Break out of loop if there's another hit.
//
checkTrigger();
if (isHit)
{
break;
}
//
// End of fast wavelength loop -- a good place for timing tests.
//
now = (micros() - beginTime); // Register time for next run through.
}
//
// Clean up at end of hit. Diagnostic code here.
//
digitalWriteFast(gatePin, LOW);
digitalWriteFast(ledPin, LOW);
digitalWriteFast(out, LOW);
period = LOW;
}