FMVoice is now a class

This commit is contained in:
Neale Pickett 2020-11-11 17:05:28 -07:00
parent 458b9eb891
commit e565fb35b6
3 changed files with 77 additions and 63 deletions

View File

@ -1,47 +1,47 @@
#include "synth.h" #include "synth.h"
#include "synth_waveform.h" #include "synth_waveform.h"
void FMVoiceLoadPatch(FMVoice *v, FMPatch *p) { void FMVoice::LoadPatch(FMPatch *p) {
for (int i=0; i<NUM_OPERATORS; i++) { for (int i=0; i<NUM_OPERATORS; i++) {
FMOperator op = p->operators[i]; FMOperator op = p->operators[i];
v->oscillators[i].frequencyModulation(1); this->oscillators[i].frequencyModulation(1);
v->oscillators[i].begin(op.waveform); this->oscillators[i].begin(op.waveform);
v->envelopes[i].delay(op.delayTime); this->envelopes[i].delay(op.delayTime);
v->envelopes[i].attack(op.attackTime); this->envelopes[i].attack(op.attackTime);
v->oscillators[i].amplitude(op.holdAmplitude); this->oscillators[i].amplitude(op.holdAmplitude);
v->envelopes[i].hold(op.holdTime); this->envelopes[i].hold(op.holdTime);
v->envelopes[i].decay(op.decayTime); this->envelopes[i].decay(op.decayTime);
v->envelopes[i].sustain(op.sustainAmplitude / op.holdAmplitude); this->envelopes[i].sustain(op.sustainAmplitude / op.holdAmplitude);
v->envelopes[i].release(op.releaseTime); this->envelopes[i].release(op.releaseTime);
// This feels wasteful 🙁 // This feels wasteful 🙁
for (int j=0; j<NUM_OPERATORS; j++) { for (int j=0; j<NUM_OPERATORS; j++) {
v->mixers[i].gain(j, p->gains[i][j]); this->mixers[i].gain(j, p->gains[i][j]);
} }
v->outputMixer.gain(i, p->gains[i][NUM_OPERATORS]); this->outputMixer.gain(i, p->gains[i][NUM_OPERATORS]);
} }
v->patch = p; this->patch = p;
} }
void FMVoiceSetPitch(FMVoice *v, float freq) { void FMVoice::SetPitch(float freq) {
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
FMOperator op = v->patch->operators[i]; FMOperator op = this->patch->operators[i];
v->oscillators[i].frequency(op.offset + (freq * op.multiplier)); this->oscillators[i].frequency(op.offset + (freq * op.multiplier));
} }
} }
void FMVoiceNoteOn(FMVoice *v, float freq) { void FMVoice::NoteOn(float freq) {
FMVoiceSetPitch(v, freq); SetPitch(freq);
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
v->envelopes[i].noteOn(); this->envelopes[i].noteOn();
} }
v->playing = true; this->playing = true;
} }
void FMVoiceNoteOff(FMVoice *v) { void FMVoice::NoteOff() {
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
v->envelopes[i].noteOff(); this->envelopes[i].noteOff();
} }
v->playing = false; this->playing = false;
} }

82
synth.h
View File

@ -80,14 +80,54 @@ typedef struct FMPatch {
/** FMVoice sets up all the Audio objects for a voice. /** FMVoice sets up all the Audio objects for a voice.
*/ */
typedef struct FMVoice { class FMVoice {
AudioMixer4 mixers[NUM_OPERATORS]; public:
AudioSynthWaveformModulated oscillators[NUM_OPERATORS]; /** LoadPatch loads a patch into a voice.
AudioEffectEnvelope envelopes[NUM_OPERATORS]; */
AudioMixer4 outputMixer; void LoadPatch(FMPatch *p);
FMPatch *patch;
bool playing; /** SetPitch sets the pitch (Hz) of a voice.
} FMVoice; *
* This does not signal the envelope in any way.
* You would use this for a glissando, portamento, or pitch bend.
* In my bagpipe, this prevents "reed noise" when changing notes.
*/
void SetPitch(float pitch);
/** SetModulation sets the modulation amount of a voice.
*
* What this means depends on the loaded patch.
* For a "normal" bagpipe patch, this would adjust the intensity of
* of a filter, or set the level of an oscillator.
* In an old-school keyboard patch, this would set the
* intensity of a Low Frequency Oscillator to set a vibrato.
*/
void setModulation(float level);
/** NoteOn sets the pitch (Hz) of a voice, and starts in playing.
*
* This tells the envelope generators to begin.
* On a piano, this is what you would use when a key is pressed.
* In my bagpipe, this triggers "reed noise".
*/
void NoteOn(float pitch);
/** NoteOff stops a note from playing.
*
* This turns the voice "off" by shutting down all the envelope generators.
* On a piano, this is what you would use when a key is released.
* In my bagpipe, this corresponds to all holes being closed.
*/
void NoteOff();
AudioMixer4 mixers[NUM_OPERATORS];
AudioSynthWaveformModulated oscillators[NUM_OPERATORS];
AudioEffectEnvelope envelopes[NUM_OPERATORS];
AudioMixer4 outputMixer;
FMPatch *patch;
bool playing;
};
/** FMOperatorWiring outputs AudioConnection initializers to wire one FM Operator /** FMOperatorWiring outputs AudioConnection initializers to wire one FM Operator
*/ */
@ -108,30 +148,4 @@ typedef struct FMVoice {
FMOperatorWiring(name, 2), \ FMOperatorWiring(name, 2), \
FMOperatorWiring(name, 3) FMOperatorWiring(name, 3)
/** FMVoiceLoadPatch loads a patch into a voice.
*/
void FMVoiceLoadPatch(FMVoice *v, FMPatch *p);
/** FMVoiceSetPitch sets the pitch (Hz) of a voice.
*
* This does not signal the envelope in any way.
* You would use this for a glissando, portamento, or pitch bend.
* In my bagpipe, this prevents "reed noise" when changing notes.
*/
void FMVoiceSetPitch(FMVoice *v, float pitch);
/** FMVoiceNoteOn sets the pitch (Hz) of a voice, and starts in playing.
*
* This tells the envelope generators to begin.
* On a piano, this is what you would use when a key is pressed.
* In my bagpipe, this triggers "reed noise".
*/
void FMVoiceNoteOn(FMVoice *v, float pitch);
/** FMVoiceNoteOff stops a note from playing.
*
* This turns the voice "off" by shutting down all the envelope generators.
* On a piano, this is what you would use when a key is released.
* In my bagpipe, this corresponds to all holes being closed.
*/
void FMVoiceNoteOff(FMVoice *v);

View File

@ -128,8 +128,8 @@ void setup() {
// Turn on drones // Turn on drones
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
FMVoiceLoadPatch(&Drones[i], &Bank[0]); Drones[i].LoadPatch(&Bank[0]);
FMVoiceNoteOn(&Drones[i], JustPitches[NOTE_D4 - 12*i] + i); Drones[i].NoteOn(JustPitches[NOTE_D4 - 12*i] + i);
} }
// Turn on all mixer channels // Turn on all mixer channels
@ -201,7 +201,7 @@ void updateTunables(uint8_t buttons, int note) {
patch = (patch + bankSize) % bankSize; patch = (patch + bankSize) % bankSize;
FMPatch *p = &Bank[patch]; FMPatch *p = &Bank[patch];
FMVoiceLoadPatch(&Chanter, p); Chanter.LoadPatch(p);
display.clearDisplay(); display.clearDisplay();
display.setCursor(0, 0); display.setCursor(0, 0);
@ -302,7 +302,7 @@ void loop() {
if (silent) { if (silent) {
FMVoiceNoteOff(&Chanter); Chanter.NoteOff();
} else { } else {
// Calculate pitch, and glissando pitch // Calculate pitch, and glissando pitch
uint16_t pitch = JustPitches[note]; uint16_t pitch = JustPitches[note];
@ -321,9 +321,9 @@ void loop() {
} }
if (Chanter.playing) { if (Chanter.playing) {
FMVoiceSetPitch(&Chanter, pitch); Chanter.SetPitch(pitch);
} else { } else {
FMVoiceNoteOn(&Chanter, pitch); Chanter.NoteOn(pitch);
} }
} }