-
Notifications
You must be signed in to change notification settings - Fork 0
/
midiVelocity.ino
287 lines (236 loc) · 8.1 KB
/
midiVelocity.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
/******************************************************************************
Use SparkFun MIDI Shield as a on the fly MIDI velocity modifier.
Arnaud Fenioux - afenioux.fr
October 2016
This programe will change note velocity on channel 1
depending on the value of the pots,
all others messages are transmitied as is (Through).
Press Buton 0 to enable the Min/Max velocity reduction (green led on):
pot0 will set min velocity
pot1 will set max velocity
velocity received under pot0 value is set to pot0 value
velocity received above pot1 value is set to pot1 value
Press Buton 2 to enable the Range/Offset velocity reduction (red led on):
pot0 will set velocity range (default is 127, can be reducte down to 1)
pot1 will set the offset (if pot0 is set to 1 and port1 to 64, velocity returned will be 65)
velocity is now reduced as a linear function :
velocity received with a value of 1 is set to pot1 value
velocity received with a value of 127 is set to pot1 + pot0 value
This code is dependent on the FortySevenEffects MIDI library for Arduino.
https://github.com/FortySevenEffects/arduino_midi_library
You'll need to install that library into the Arduino IDE before compiling.
This code is more than inspired of repo :
https://github.com/sparkfun/MIDI_Shield/
Development environment specifics:
It was developed for the Arduino Uno compatible SparkFun RedBoard, with a SparkFun
MIDI Shield.
Distributed as-is; no warranty is given.
******************************************************************************/
#include <MIDI.h>
//MIDI_CREATE_INSTANCE(SoftwareSerial, SoftSerial, MIDI);
//MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI);
MIDI_CREATE_DEFAULT_INSTANCE();
#define LED_ARD 13 // LED pin on Arduino Uno
#define BTN0 2
#define BTN1 3
#define BTN2 4
#define POT0 0
#define POT1 1
#define LED_GRN 6
#define LED_RED 7
#define DBG 0
int pot0;
int pot1;
int ticks = 0;
//TODO : using a struct would be a plus
boolean button_state[3];
boolean led_state[14];
void BlinkLed(byte led, byte num) // Basic blink function
{
// I'm only using this function when debug is enable
// because delay() imply latency and non real time execution
for (byte i=0;i<num;i++)
{
digitalWrite(led, LOW);
delay(60);
digitalWrite(led, HIGH);
delay(60);
}
}
void CheckButtonPushed() // Return true if button is pressed
{
// A bit of a funny statement below.
// digitalRead return HIGH or LOW.
// We want boolean (true/false) indicators of whether the button are
// pushed.
// And button inputs are active low - when a button is pushed, it'll read "LOW"
for(int i=0; i<3; i++) {
button_state[i] = (digitalRead(i+2) == LOW);
}
}
void SetLight(int led, bool state) //Light on/off led
{
led_state[led] = state;
//if state is true, set light up
if (state) digitalWrite(led, LOW);
else digitalWrite(led, HIGH);
}
void ToggleLight(int led) //Light on/off led
{
//TODO This function needs to be tested
if (led_state[led]) digitalWrite(led, LOW);
else digitalWrite(led, HIGH);
led_state[led] = !led_state[led];
}
void ButtonAction() //Light led if button was pressed
{
// Light on the green led if BTN0 is pressed
if (button_state[0]) {
SetLight(LED_GRN, true);
//And light off red led
SetLight(LED_RED, false);
}
// Light on the red led if BTN2 is pressed
if (button_state[2]) {
SetLight(LED_RED, true);
//And light off green led
SetLight(LED_GRN, false);
}
// Middle button BTN1 clears the selection
if (button_state[1]) {
SetLight(LED_GRN, false);
SetLight(LED_RED, false);
}
}
void MidiSendAsIs() //Send MIDI to out and blink once if debug is enabled
{
if (DBG) BlinkLed(LED_RED, 1);
MIDI.send(MIDI.getType(),
MIDI.getData1(),
MIDI.getData2(),
MIDI.getChannel());
}
byte SetVelocityMinMax(byte velocity) //Adjust Velocity Min on POT0 and Velocity Max on POT1
{
if (DBG) BlinkLed(LED_GRN, 2);
// velocity need to be between 0 and 127 -> /2
int velocityMin = pot0/2;
int velocityMax = pot1/2;
int velocityModified = velocity;
//set velocityMin to velocityMax when velocityMin > velocityMax
if ( velocityMin > velocityMax ) velocityMin = velocityMax;
if ( velocity < velocityMin ) velocityModified = velocityMin;
if ( velocity > velocityMax ) velocityModified = velocityMax;
if ( velocityModified > 127 ) velocityModified = 127;
if ( velocityModified < 1 ) velocityModified = 1;
return (byte)velocityModified;
}
byte SetVelocityRangeOff(byte velocity) //Adjust Velocity Range on POT0 and Velocity Offset on POT1
{
if (DBG) BlinkLed(LED_RED, 1);
if (DBG) BlinkLed(LED_GRN, 1);
// velocity need to be between 0 and 127 -> /2
int range = pot0/2;
int offset = pot1/2;
// we avoid a "saturation"
//the priority is to keep the velocity's range
if (offset > 127-range)
offset = 127-range;
// Mathematical functin is a*x+b
// Where : a is range/127.0
// x is velocity
// b is offset
float velocityModified = (range/127.0) * velocity + offset;
if ( velocityModified > 127) velocityModified = 127;
if ( velocityModified < 1) velocityModified = 1;
return (byte)velocityModified;
}
void handleNoteOn(byte channel, byte pitch, byte velocity)
{
// Do whatever you want when a note is pressed.
// Try to keep your callbacks short (no delays etc)
// otherwise it would slow down the loop() and have a bad impact
// on real-time performance.
if (MIDI.getChannel() == 1)
{
// Analog inputs have an LSB (out of 10 bits) or so noise,
// leading to "chatter" in the change detector logic.
// Shifting off the 2 LSBs to remove it
// value is now between 0 and 255
pot0 = analogRead(POT0) >> 2;
pot1 = analogRead(POT1) >> 2;
byte velocityModified = velocity;
//if green led is lighted use Min/Max mode
if (!led_state[LED_RED] && led_state[LED_GRN])
velocityModified = SetVelocityMinMax(velocity);
//if red led is lighted use Range/Offset mode
else if (led_state[LED_RED] && !led_state[LED_GRN])
velocityModified = SetVelocityRangeOff(velocity);
MIDI.sendNoteOn(pitch,velocityModified,channel);
if (DBG) BlinkLed(LED_GRN, 1);
}
else
MIDI.sendNoteOn(pitch,velocity,channel);
}
void setup() {
// put your setup code here, to run once:
pinMode(LED_ARD, OUTPUT);
pinMode(BTN0, INPUT_PULLUP);
pinMode(BTN1, INPUT_PULLUP);
pinMode(BTN2, INPUT_PULLUP);
pinMode(LED_GRN, OUTPUT);
pinMode(LED_RED, OUTPUT);
digitalWrite(LED_GRN, HIGH);
digitalWrite(LED_RED, HIGH);
for (byte i=0;i<3;i++)
{
BlinkLed(LED_GRN, 1);
BlinkLed(LED_RED, 1);
}
// Connect the handleNoteOn function to the library,
// so it is called upon reception of a NoteOn.
MIDI.setHandleNoteOn(handleNoteOn); // Put only the name of the function
// We want to receive messages on all channels
MIDI.begin(MIDI_CHANNEL_OMNI);
//MIDI.begin(1); // Launch MIDI and listen to channel 1
MIDI.turnThruOff();
//MIDI.turnThruOn();
}
void loop() {
// put your main code here, to run repeatedly:
CheckButtonPushed();
ButtonAction();
if (MIDI.read()) // Is there a MIDI message incoming ?
{
switch (MIDI.getType())
{
case midi::NoteOn :
{
// Do nothing (handler is set)
}
break;
case midi::Clock :
{
ticks++;
if (ticks == 3)
SetLight(LED_ARD, true);
else if (ticks == 24) {
ticks = 0;
SetLight(LED_ARD, false);
}
}
break;
case midi::Start :
{
ticks = 0;
}
break;
default:
{
//send stuff
MidiSendAsIs();
}
break;
}
}
}