-
Notifications
You must be signed in to change notification settings - Fork 254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add pitch bend support to the SimpleSynth example #205
Comments
Hey @franky47 #include <MIDI.h>
#include "noteList.h"
#include "pitches.h"
MIDI_CREATE_DEFAULT_INSTANCE();
#ifdef ARDUINO_SAM_DUE // Due has no tone function (yet), overriden to prevent build errors.
#define tone(...)
#define noTone(...)
#endif
// This example shows how to make a simple synth out of an Arduino, using the
// tone() function. It also outputs a gate signal for controlling external
// analog synth components (like envelopes).
static const unsigned sGatePin = 13;
static const unsigned sAudioOutPin = 10;
static const unsigned sMaxNumNotes = 16;
MidiNoteList<sMaxNumNotes> midiNotes;
// Pitch Bend Variables
const int pitchBendRange = 2; // pitch bend range in semitones
int currentPitchBend = 0;
// -----------------------------------------------------------------------------
inline void handleGateChanged(bool inGateActive) {
digitalWrite(sGatePin, inGateActive ? HIGH : LOW);
}
inline void pulseGate() {
handleGateChanged(false);
delay(1);
handleGateChanged(true);
}
// -----------------------------------------------------------------------------
void handleNotesChanged(bool isFirstNote = false) {
if (midiNotes.empty()) {
handleGateChanged(false);
noTone(sAudioOutPin); // Remove to keep oscillator running during envelope release.
} else {
// Possible playing modes:
// Mono Low: use midiNotes.getLow
// Mono High: use midiNotes.getHigh
// Mono Last: use midiNotes.getLast
byte currentNote = 0;
if (midiNotes.getLast(currentNote)) {
// apply pitch bend
float pitchBendFactor = pow(2.0, (float)currentPitchBend / 12.0);
int pitchBendFreq = (int)(sNotePitches[currentNote] * pitchBendFactor);
tone(sAudioOutPin, pitchBendFreq);
if (isFirstNote) {
handleGateChanged(true);
} else {
pulseGate(); // Retrigger envelopes. Remove for legato effect.
}
}
}
}
// -----------------------------------------------------------------------------
void handleNoteOn(byte inChannel, byte inNote, byte inVelocity) {
const bool firstNote = midiNotes.empty();
midiNotes.add(MidiNote(inNote, inVelocity));
handleNotesChanged(firstNote);
}
void handleNoteOff(byte inChannel, byte inNote, byte inVelocity) {
midiNotes.remove(inNote);
handleNotesChanged();
}
void handlePitchBend(byte channel, int bendValue) {
// convert the pitch bend value to semitones
float pitchBendSemitones = bendValue / (float)(8192 / pitchBendRange);
currentPitchBend = pitchBendSemitones;
handleNotesChanged();
}
// -----------------------------------------------------------------------------
void setup() {
pinMode(sGatePin, OUTPUT);
pinMode(sAudioOutPin, OUTPUT);
MIDI.setHandleNoteOn(handleNoteOn);
MIDI.setHandleNoteOff(handleNoteOff);
MIDI.setHandlePitchBend(handlePitchBend); // set pitch bend handler
MIDI.begin();
}
void loop() {
MIDI.read();
}
|
Original discussion and maths breakdown:
#203 (reply in thread)
Breakdown of the steps:
handlePitchBend
callbacktone
Caveats / things to look out for:
handleNoteOn
andhandleNoteOff
.handlePitchBend
is an int between 0 (max downwards bend), 0x2000 (neutral position) and 0x3fff (max upwards bend). The maximum bend in semitones should be astatic const int
constant (for an additional challenge, it could follow a ControlChange).The text was updated successfully, but these errors were encountered: