-
Notifications
You must be signed in to change notification settings - Fork 2
/
Dr55_Sync.ino
390 lines (344 loc) · 11.4 KB
/
Dr55_Sync.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
/*
RD-55 MIDI sync version 2.1
created 10 March 2017
updated 12 April 2017
updated 29 July 2017
by Takao Watase
This is free software released into the public domain.
*/
// select circuit board version
//#define PCB_VERSION_1_0 // version 1.0
#define PCB_VERSION_2_1 // version 2.1
// constants
#define TPQN24 6 // number of F8 clock when TPQN=24
#define TPQN48 12 // number of F8 clock when TPQN=48
#define LED_ON HIGH
#define LED_OFF LOW
// Length of control pulse (msec)
#define DUR_BD 20 // BD gate time
#define DUR_SD 20 // SD gate time
#define DUR_RS 20 // RS gate time
#define DUR_AC 30 // gate time of Accent
#define DUR_HH_CLOSE 5 // gate time for close HH
#define DUR_HH_PEDAL 35 // gate time for pedal HH
#define DUR_HH_OPEN 150 // gate time for open HH
#define WIDTH_CLOCK 20 // gate time of tempo clock
#define WIDTH_LED 50 // gate time for led
#define THRES_AC 90 // threshold velocity for accent
#ifdef PCB_VERSION_2_1 // PCB Version 2.1
// I/O pins I/0 pin# of Connector - DR-55 components
#define IO_HH 10 // D10 2 S4 Common
#define IO_RS 11 // D11 3 TC5501P pin 12
#define IO_SD 12 // D12 4 TC5501P pin 14
#define IO_BD 13 // D13 5 TC5501P pin 16
#define CLOCK 14 // A0 6 TC4011UB pin 13
#define ST 15 // A1 7 TC4011UB pin 3
#define IO_AC 16 // A2 8 TC5501P pin 10
#define SW_OMNI 9 // D9 Omni mode switch
// pin# of LEDs
#define LED_MIDI 4 // midi/clock indicator
#define LED_RUN 5 // light while running clock
#endif
#ifdef PCB_VERSION_1_0 // PCB Version 1.0
// I/O pins I/O pin# of Connector - DR-55 components
#define IO_HH 10 // D10 2 S4 Common
#define IO_RS 11 // D11 3 TC5501P pin 12
#define IO_SD 12 // D12 4 TC5501P pin 14
#define IO_BD 13 // D13 5 TC5501P pin 16
#define CLOCK 17 // A3 6 TC4011UB pin 13
#define ST 16 // A2 7 TC4011UB pin 3
#define IO_AC 15 // A1 8 TC5501P pin 10
#define SW_OMNI 9 // D9 Omni mode switch
// pin# of LEDs
#define LED_MIDI 4 // midi/clock indicator
#define LED_RUN 5 // lit while running
#endif
// midi status
#define MIDI_START 0xfa
#define MIDI_STOP 0xfc
#define MIDI_CLOCK 0xf8
#define MIDI_NOTE 0x90
#define MIDI_STATUS 0x80
#define MIDI_CH 10 // receive channel , 10 = rhythm ch.
#define isStatus(data) (data >= 0x80) // check status byte
#define getMidiCh(ch) (ch - 1) // midi channel start from 1, but actual value start from 0.
// variables
int cntClock = 0; // count F8
int cntClkLed = 0; // count clock led
bool isRun = false; // true while running clock
bool reqRun = false; // request to run
bool isMidiOmni = false; // true while omni sw on
int tpqn = TPQN24; // Ticks Per Quater Note means number of clock pulse for quarter note.
int fData; // waiting data type
const int flag_st = 0; // waiting 1st byte as status
const int flag_d1 = 1; // waiting 2nd byte as data 1
const int flag_d2 = 2; // waiting 3rd byte as data 2
byte key; // note number
byte vel; // velocity
// timers
// use Metro library
#include <Metro.h>
Metro tmLed = Metro(WIDTH_LED); // midi/clock led indicator
Metro tmClock = Metro(WIDTH_CLOCK); // clock pulse width
Metro tmBD = Metro(DUR_BD); // duration BD
Metro tmSD = Metro(DUR_SD); // duration SD
Metro tmRS = Metro(DUR_RS); // duration RS
Metro tmAC = Metro(DUR_AC); // duration AC
Metro tmHH = Metro(DUR_HH_CLOSE); // duration HH
// decralation of subroutines
void handleStart(); // event handler for midi start (FA)
void handleStop(); // event handler for midi stop (FC)
void handleNoteOn(byte key, byte vel); // event handler for midi note messages
void Sync(); // process F8 clock
void StartClockPulse(); // process to start clock pulse
void StartFirstClockPulse(); // process the first clock pulse
void EndClockPulse(); // process to end clock pulse
// programs
/*
* the setup routine runs once when you press reset:
*/
void setup() {
// initialize the digital pin as an output.
Serial.begin(31250); // rate for MIDI
pinMode(LED_MIDI, OUTPUT);
pinMode(LED_RUN, OUTPUT);
pinMode(SW_OMNI, INPUT_PULLUP); // use internal pull-up
/*
following pins should be set "INPUT", set signal line open, while not running.
*/
pinMode(CLOCK, INPUT);
pinMode(ST, INPUT);
pinMode(IO_BD, INPUT);
pinMode(IO_SD, INPUT);
pinMode(IO_RS, INPUT);
pinMode(IO_HH, INPUT);
pinMode(IO_AC, INPUT);
digitalWrite(IO_BD, LOW);
digitalWrite(IO_SD, LOW);
digitalWrite(IO_RS, LOW);
digitalWrite(IO_HH, LOW);
digitalWrite(IO_AC, LOW);
digitalWrite(LED_MIDI, LED_OFF);
digitalWrite(LED_RUN, LED_OFF);
fData = flag_st; // waiting status
key = vel = 0;
// sign for start up
for ( int i = 0; i < 4; i++ ) {
digitalWrite(LED_RUN, LED_ON);
delay(250);
digitalWrite(LED_RUN, LED_OFF);
delay(250);
}
}
/*
* the loop routine runs over and over again forever:
*/
void loop() {
// check serial rx data
if (Serial.available() <= 0) goto TIMER_PROC;
// processing rx data
byte data;
data = Serial.read();
if (isStatus(data)) { // check status byte
if (data == MIDI_START) {
handleStart(); // Start clock
}
else if(data == MIDI_STOP) {
handleStop(); // Stop clock
}
else if(data == MIDI_CLOCK) {
Sync(); // process F8 clock
}
else if((data & 0xf0) == MIDI_NOTE) {
// process note status message
if (isMidiOmni || ((data & 0x0f) == getMidiCh(MIDI_CH))) { // if not omni mode, check midi channel.
// if ((data & 0x0f) == MIDI_CH) { // if not omni mode, check midi channel.
fData = flag_d1; // if the channel is valid, next data is data 1
} else {
fData = flag_st; // if the channel is invalid, ignore rx till coming status byte
}
}
else if((data & 0xf0) != 0xf0) {
// channel message other than note
fData = flag_st; // waiting next status
}
}
else {
// process data byte
if (fData == flag_d1) {
// data 1 is note number
key = data;
fData = flag_d2; // next data shold be data 2.
}
else if (fData == flag_d2) {
// data 2 is velocity
vel = data;
fData = flag_d1; // waiting data 1 if running status was available
if (vel > 0) handleNoteOn(key, vel); // process note on
}
}
/*
* Timer process
*/
TIMER_PROC:
// Clock pulse end
if (tmClock.check() == 1) {
EndClockPulse();
}
// sound pulse end
if (tmBD.check() == 1) {
digitalWrite(IO_BD, LOW); // set pulse low
pinMode(IO_BD, INPUT); // set line open
}
if (tmRS.check() == 1) {
digitalWrite(IO_RS, LOW);
pinMode(IO_RS, INPUT);
}
if (tmSD.check() == 1) {
digitalWrite(IO_SD, LOW);
pinMode(IO_SD, INPUT);
}
if (tmHH.check() == 1) {
digitalWrite(IO_HH, LOW);
pinMode(IO_HH, INPUT);
}
if (tmAC.check() == 1) {
digitalWrite(IO_AC, LOW);
pinMode(IO_AC, INPUT);
}
// read omni mode sw
isMidiOmni = (digitalRead(SW_OMNI) == HIGH) ? false : true;
// midi/clock led off
if (tmLed.check() == 1) {
digitalWrite(LED_MIDI, LED_OFF);
}
}
/*
* Process F8 clock
*/
void Sync() {
if (reqRun) { // if the request flag was rised,
StartFirstClockPulse(); // process to start clock
cntClock = 0; // reset clock count
return;
}
// generating tempo clock pulse
if (++cntClock == tpqn) { // increment clock count and check it.
StartClockPulse(); // start clock pulse
cntClock = 0; // reset clock count
}
}
/*
* Process to start clock pulse
*/
void StartClockPulse() {
// start clock pulse (set low)
digitalWrite(CLOCK, LOW);
tmClock.reset();
// clock led on
if (isRun && // while running and
cntClkLed++ % 4 == 0) { // per 4 clocks.
digitalWrite(LED_MIDI, LED_ON);
tmLed.interval(WIDTH_LED); // start led timer
tmLed.reset();
}
}
/*
* Process the first clock pulse
*/
void StartFirstClockPulse()
{
isRun = true; // set status running
reqRun = false; // reset request flag
cntClkLed = 0; // reset count clock led
pinMode(ST, OUTPUT); // set pin as "OUTPUT" to control status line.
digitalWrite(ST, HIGH); // set running.
pinMode(CLOCK, OUTPUT); // set pin as "OUTPUT" to control clock line.
StartClockPulse(); // generate pulse on clock line.
}
/*
* process to stop clock pulse
*/
void EndClockPulse() {
// end clock pulse (set high)
digitalWrite(CLOCK, HIGH);
}
/*
* midi handler routine - Start
*/
void handleStart(void)
{
reqRun = true; // set request flag
digitalWrite(LED_RUN, LED_ON); // led on
}
/*
* midi handler routine - Stop
*/
void handleStop(void)
{
digitalWrite(ST, LOW); // Set status line low.
isRun = false; // set status stop
pinMode(CLOCK, INPUT); // open clock line
pinMode(ST, INPUT); // open status line
digitalWrite(LED_RUN, LED_OFF); // led off
}
/*
* midi handler routine - note message
*/
void handleNoteOn(byte key, byte vel)
{
int pin = 0; // pin#
int dur = 0; // duration (gate time)
switch (key) {
case 48: // note# of BD
pin = IO_BD;
dur = DUR_BD;
tmBD.reset();
break;
case 51: // note# of RS
pin = IO_RS;
dur = DUR_RS;
tmRS.reset();
break;
case 50: // note# of SD1
case 52: // note# of SD2
pin = IO_SD;
dur = DUR_SD;
tmSD.reset();
break;
case 54: // note# of Close HH
pin = IO_HH;
dur = DUR_HH_CLOSE;
tmHH.interval(dur);
tmHH.reset();
break;
case 56: // note# of Pedal HH
pin = IO_HH;
dur = DUR_HH_PEDAL;
tmHH.interval(dur);
tmHH.reset();
break;
case 58: // note# of Open HH
pin = IO_HH;
dur = DUR_HH_OPEN;
tmHH.interval(dur);
tmHH.reset();
break;
default:
return;
}
// start accent pulse
// process before start note pulse
if (vel > THRES_AC) {
pinMode(IO_AC, OUTPUT); // set accent line ready
digitalWrite(IO_AC, HIGH); // start pulse
tmAC.reset(); // start timer
}
// start note pulse
pinMode(pin, OUTPUT); // set note line ready
digitalWrite(pin, HIGH); // start pulse
digitalWrite(LED_MIDI, LED_ON); // set led on
tmLed.interval(dur); // start led off timer
tmLed.reset();
}
// End of file