You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/midi-instrument.md
+127-1Lines changed: 127 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -119,4 +119,130 @@ void loop() {
119
119
}
120
120
````
121
121
122
-
Start up your MIDI synth application, and press the button. You should hear middle A playing whenever you press the button. Here is [the complete sketch](https://github.com/tigoe/SoundExamples/blob/master/MIDI_examples/MIDIUSB_oneKeyPiano/MIDIUSB_oneKeyPiano.ino).
122
+
Start up your MIDI synth application, and press the button. You should hear middle A playing whenever you press the button. Here is [the complete sketch](https://github.com/tigoe/SoundExamples/blob/master/MIDI_examples/MIDIUSB_oneKeyPiano/MIDIUSB_oneKeyPiano.ino).
123
+
124
+
## Improvise in a Particular Scale
125
+
126
+
Playing the same note is not so exciting, but even with one button, you can make an instrument that can improvise, by randomizing the note value. Try adding a global variable called noteValue before the setup:
127
+
128
+
````
129
+
int noteValue = 0;
130
+
````
131
+
132
+
Then in the loop, add in the following line right before you send the note on message, and change the value of the note in the note on and note off `midiCommand()` calls:
133
+
134
+
````
135
+
void loop() {
136
+
int buttonState = digitalRead(5);
137
+
if (buttonState != lastButtonState) {
138
+
if (buttonState == HIGH) {
139
+
noteValue = random(88) + 14;
140
+
midiCommand(0x90, noteValue, 0x7F);
141
+
} else {
142
+
if (buttonState == HIGH) {
143
+
// turn off the note:
144
+
midiCommand(0x80, noteValue, 0);
145
+
}
146
+
// save the current state as the previous state
147
+
// for the next comparison:
148
+
lastButtonState = buttonState;
149
+
}
150
+
````
151
+
152
+
Upload the sketch and press the button a few times. It sounds atonal, but you are playing random notes when you press, and turning then off.
153
+
154
+
If you want to constrain the improv to a given scale, you need to generate a scale. How about a major scale? [The pattern of notes in any major scale](https://www.musictheory.net/lessons/21) is:
155
+
156
+
whole whole half whole whole whole half
157
+
158
+
Armed with that, you can write a scale randomizer. Start a whole new sketch, as follows:
159
+
160
+
````
161
+
#include <MIDIUSB.h>
162
+
#include <pitchToNote.h>
163
+
164
+
// the intervals in a major and natural minor scale:
165
+
int major[] = {2, 2, 1, 2, 2, 2, 1};
166
+
167
+
// an array to hold the final notes of the scale:
168
+
int scale[8];
169
+
170
+
// start with middle C:
171
+
int tonic = pitchC4;
172
+
// note to play:
173
+
int noteValue = tonic;
174
+
175
+
// previous state of the button:
176
+
int lastButtonState = LOW;
177
+
178
+
````
179
+
180
+
Then in the setup(), you need to take the formula for a major scale and the tonic note you want, and generate a scale by adding the whole or half steps in sequence:
181
+
182
+
````
183
+
void setup() {
184
+
pinMode(5, INPUT);
185
+
// fill the scale array with the scale you want:
186
+
// start with the initial note:
187
+
scale[0] = tonic;
188
+
int note = scale[0];
189
+
// iterate over the intervals, adding each to the next note
190
+
// in the scale:
191
+
for (int n = 0; n < 7; n++) {
192
+
note = note + major[n];
193
+
scale[n+1] = note;
194
+
}
195
+
}
196
+
````
197
+
198
+
Now you've got a major scale. If you want to change from C major to another major scale, just change the tonic to another value, Try `pitchE4b` for E-flat. If you want a [natural minor scale](https://www.musictheory.net/lessons/22), try the following instead of the `major[]` array:
199
+
200
+
````
201
+
int naturalMinor[] = {2, 1, 2, 2, 1, 2, 2};
202
+
````
203
+
204
+
Now copy the state change detector on the pushbutton, but add in the randomizer to pick from the `scale[]` array like so:
205
+
206
+
````
207
+
208
+
void loop() {
209
+
// read the pushbutton:
210
+
int buttonState = digitalRead(5);
211
+
// compare its state to the previous state:
212
+
if (buttonState != lastButtonState) {
213
+
// debounce delay:
214
+
delay(5);
215
+
// if the button's changed and it's pressed:
216
+
if (buttonState == HIGH) {
217
+
// pick a random note in the scale:
218
+
noteValue = scale[random(8)];
219
+
// play it:
220
+
midiCommand(0x90, noteValue, 0x7F);
221
+
} else {
222
+
// turn the note off:
223
+
midiCommand(0x80, noteValue, 0);
224
+
}
225
+
// save the button state for comparison next time through:
226
+
lastButtonState = buttonState;
227
+
}
228
+
}
229
+
````
230
+
231
+
Finally, add the `midiCommand()` function from above. Then upload the sketch and press the button. You should hear random notes, all in the same scale. You're improvising a solo now! [ Here's the complete sketch](https://github.com/tigoe/SoundExamples/blob/master/MIDI_examples/MIDIUSB_oneKey_improviser/MIDIUSB_oneKey_improviser.ino).
232
+
233
+
## Other Instruments
234
+
235
+
You can build many other instruments by combining analog and digital inputs and changes in programming like this.
236
+
237
+
Here's an example that uses [eight pushbuttons to generate a piano](https://github.com/tigoe/SoundExamples/blob/master/MIDI_examples/MIDIUSBJoystick/MIDIUSBJoystick.ino). The eight pushbuttons are attached to pins 0 though 7 just as the one shown above. The pushbutton is connected to +Vcc on one side, and to the pin on the other, with a 10-kilohm pulldown resistor from the pin to ground on each one.
238
+
239
+

240
+
241
+
*Figure 2. Eight pushbuttons attached to pins 0-7 of a MKR Zero. This uses the same digital input configuration as Figure 1 above.*
242
+
243
+
Here's another example that uses a joystick to generate a note. A joystick has a built-in pushbutton and two potentiometers. This example uses the pushbutton to start or stop a note, and the joystick to generate a pitch bend on the note. Pitch bend is a controller type in MIDI that lets you bend a note up or down from its original pitch. The joystick's X axis pin is attached to pin A0 and the pushbutton pin, marked SEL, is attached to pin 5. Note that the pushbutton does not have a pulldown resistor because it is using the Arduino's internal pullup resistor. In this case, the pinMode is `INPUT_PULLUP`, and pressed is LOW and unpressed is HIGH.
244
+
245
+
246
+

247
+
248
+
*Figure 3. Joystick attached to pins 5 and A0 of a MKR Zero. The pushbutton does not have a pulldown resistor because it is using the Arduino's internal pullup resistor.*
0 commit comments