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_waveform.h"
void FMVoiceLoadPatch(FMVoice *v, FMPatch *p) {
void FMVoice::LoadPatch(FMPatch *p) {
for (int i=0; i<NUM_OPERATORS; i++) {
FMOperator op = p->operators[i];
v->oscillators[i].frequencyModulation(1);
v->oscillators[i].begin(op.waveform);
v->envelopes[i].delay(op.delayTime);
v->envelopes[i].attack(op.attackTime);
v->oscillators[i].amplitude(op.holdAmplitude);
v->envelopes[i].hold(op.holdTime);
v->envelopes[i].decay(op.decayTime);
v->envelopes[i].sustain(op.sustainAmplitude / op.holdAmplitude);
v->envelopes[i].release(op.releaseTime);
this->oscillators[i].frequencyModulation(1);
this->oscillators[i].begin(op.waveform);
this->envelopes[i].delay(op.delayTime);
this->envelopes[i].attack(op.attackTime);
this->oscillators[i].amplitude(op.holdAmplitude);
this->envelopes[i].hold(op.holdTime);
this->envelopes[i].decay(op.decayTime);
this->envelopes[i].sustain(op.sustainAmplitude / op.holdAmplitude);
this->envelopes[i].release(op.releaseTime);
// This feels wasteful 🙁
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++) {
FMOperator op = v->patch->operators[i];
v->oscillators[i].frequency(op.offset + (freq * op.multiplier));
FMOperator op = this->patch->operators[i];
this->oscillators[i].frequency(op.offset + (freq * op.multiplier));
}
}
void FMVoiceNoteOn(FMVoice *v, float freq) {
FMVoiceSetPitch(v, freq);
void FMVoice::NoteOn(float freq) {
SetPitch(freq);
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++) {
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.
*/
typedef struct FMVoice {
AudioMixer4 mixers[NUM_OPERATORS];
AudioSynthWaveformModulated oscillators[NUM_OPERATORS];
AudioEffectEnvelope envelopes[NUM_OPERATORS];
AudioMixer4 outputMixer;
FMPatch *patch;
bool playing;
} FMVoice;
class FMVoice {
public:
/** LoadPatch loads a patch into a voice.
*/
void LoadPatch(FMPatch *p);
/** SetPitch 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 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
*/
@ -108,30 +148,4 @@ typedef struct FMVoice {
FMOperatorWiring(name, 2), \
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
for (int i=0; i<3; i++) {
FMVoiceLoadPatch(&Drones[i], &Bank[0]);
FMVoiceNoteOn(&Drones[i], JustPitches[NOTE_D4 - 12*i] + i);
Drones[i].LoadPatch(&Bank[0]);
Drones[i].NoteOn(JustPitches[NOTE_D4 - 12*i] + i);
}
// Turn on all mixer channels
@ -201,7 +201,7 @@ void updateTunables(uint8_t buttons, int note) {
patch = (patch + bankSize) % bankSize;
FMPatch *p = &Bank[patch];
FMVoiceLoadPatch(&Chanter, p);
Chanter.LoadPatch(p);
display.clearDisplay();
display.setCursor(0, 0);
@ -302,7 +302,7 @@ void loop() {
if (silent) {
FMVoiceNoteOff(&Chanter);
Chanter.NoteOff();
} else {
// Calculate pitch, and glissando pitch
uint16_t pitch = JustPitches[note];
@ -321,9 +321,9 @@ void loop() {
}
if (Chanter.playing) {
FMVoiceSetPitch(&Chanter, pitch);
Chanter.SetPitch(pitch);
} else {
FMVoiceNoteOn(&Chanter, pitch);
Chanter.NoteOn(pitch);
}
}