Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed USBDevice PinDetect
Revision 9:1e012f67470c, committed 2016-04-13
- Comitter:
- asuszek
- Date:
- Wed Apr 13 19:46:28 2016 +0000
- Parent:
- 7:8f270e2071e2
- Child:
- 10:b9e14412cc23
- Commit message:
- Moved Audio into it's own folder
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Audio/AudioEngine.cpp Wed Apr 13 19:46:28 2016 +0000
@@ -0,0 +1,91 @@
+/*
+ * The interface for all audio input and output.
+ * This class acts as a container for individual voices.
+ * It takes in MIDI events and handles processing and output.
+ *
+ * @author Austin Suszek
+ */
+
+#include "AudioEngine.h"
+
+#if USE_PWM
+PwmOut audioOut(p21);
+#else
+AnalogOut audioOut(p18);
+#endif
+
+AudioEngine::AudioEngine() {
+ // Initialize the synthesizers.
+ for (int i = 0; i < C::MAX_POLYPHONY; i++) {
+ synthesizers[i] = Synthesizer();
+ }
+
+ #if USE_PWM
+ audioOut.period(1.0/200000.0);
+ #endif
+
+ // Set up the sampler.
+ samplePeriod.attach(this, &AudioEngine::outputAudio, 1.0 / float(C::SAMPLE_RATE));
+}
+
+void AudioEngine::midiNoteOn(const int key, const int velocity) {
+ // Find the firt disabled voice or the one that has been playing longest.
+ int64_t min = synthesizers[0].getVoiceIndex();
+ int minIndex = 0;
+ for (int i = 1; i < C::MAX_POLYPHONY; i++) {
+ int64_t voiceIndex = synthesizers[i].getVoiceIndex();
+ if (voiceIndex < min) {
+ min = voiceIndex;
+ minIndex = i;
+ }
+ }
+
+ // Send the note to the minimum voice.
+ synthesizers[minIndex].midiNoteOn(key, velocity);
+}
+
+void AudioEngine::midiNoteOff(const int key) {
+ for (int i = 0; i < C::MAX_POLYPHONY; i++) {
+ if (synthesizers[i].isPlaying() && synthesizers[i].getCurrentKey() == key) {
+ synthesizers[i].midiNoteOff();
+ break;
+ }
+ }
+}
+
+void AudioEngine::nextSynth(int direction) {
+ // Hand the command down to the synthesizers.
+ for (int i = 0; i < C::MAX_POLYPHONY; i++) {
+ synthesizers[i].nextSynth(direction);
+ }
+}
+
+void AudioEngine::outputAudio() {
+ float output = 0.0;
+
+ // Poll all of the synthesizers.
+ for (int i = 0; i < C::MAX_POLYPHONY; i++) {
+ if (synthesizers[i].isPlaying()) {
+ output += synthesizers[i].getSample();
+ }
+ }
+
+ // Scale the output by the number of voices.
+ output /= float(C::MAX_POLYPHONY);
+ // Check that we do not clip.
+ if (output > 1.0) {
+ output = 1.0;
+ }
+ if (output < -1.0) {
+ output = -1.0;
+ }
+ // Map [-1, 1] range to [0, 1] range.
+ audioOut = (output + 1.0) / 2.0;
+
+ // Go back and process the next sample on all voices.
+ for (int i = 0; i < C::MAX_POLYPHONY; i++) {
+ if (synthesizers[i].isPlaying()) {
+ synthesizers[i].processBuffer();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Audio/AudioEngine.h Wed Apr 13 19:46:28 2016 +0000
@@ -0,0 +1,55 @@
+/**
+ * The interface for all audio input and output.
+ * This class acts as a container for individual voices.
+ * It takes in MIDI events and handles processing and output.
+ *
+ * @author Austin Suszek
+ */
+
+#ifndef AS_AUDIO_ENGINE_H
+#define AS_AUDIO_ENGINE_H
+
+#include "../Constants.h"
+#include "../mbed.h"
+#include "Synthesizer.h"
+
+class AudioEngine {
+public:
+
+ /**
+ * Constructor
+ */
+ AudioEngine();
+
+ /**
+ * Signal the beginning of a note being pressed.
+ *
+ * @param key The integer representation of the note
+ * @param velocity (optional) The note velocity in the range of 0-127
+ */
+ void midiNoteOn(const int key, const int velocity = 0x7F);
+
+ /**
+ * Signal the end of a note being pressed.
+ *
+ * @param key The integer representation of the note
+ */
+ void midiNoteOff(const int key);
+
+ /**
+ * Switch to a new synth instrument.
+ *
+ * @param direction 1 for next, -1 for previous.
+ */
+ void nextSynth(int direction);
+
+private:
+
+ Ticker samplePeriod;
+ void outputAudio();
+
+ Synthesizer synthesizers[C::MAX_POLYPHONY];
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Audio/Synthesizer.cpp Wed Apr 13 19:46:28 2016 +0000
@@ -0,0 +1,250 @@
+
+#include "Synthesizer.h"
+
+const float TWO_PI = 6.28318530717959;
+
+/**
+ * A function that acts as an individual synthesizer.
+ * It's job is to process the next sample at the current index
+ * based on the current state of the overall synthesizer.
+ * Output should be in the range of [-1.0, 1.0] and saved back into the buffer.
+ */
+typedef void (Synthesizer::*processorFunction)();
+const int numSynths = 4;
+
+// Array of pointers to all synthesizer functions.
+processorFunction processors[] = {
+ &Synthesizer::processSine,
+ &Synthesizer::processTriangle,
+ &Synthesizer::processSquare,
+ &Synthesizer::processSaw,
+};
+
+int64_t Synthesizer::nextVoiceIndex = 0;
+
+Synthesizer::Synthesizer() {
+ bufferIndex = 0;
+ currentState = OFF;
+ nextBufferSize = -1;
+ voiceIndex = -1;
+ processorIndex = 0;
+}
+
+void Synthesizer::midiNoteOn(int key, int velocity) {
+ float freq = 440.0 * std::pow(2.0, float(key - 69) / 12.0);
+
+ // Make sure we are in bounds.
+ if (freq < C::MIN_FREQUENCY) {
+ #ifdef DEBUG
+ printf("Error: Note is below minimum frequency");
+ #endif
+ return;
+ }
+
+ currentKey = key;
+ int size = int((float(C::SAMPLE_RATE) / freq) + 0.5);
+
+ if (currentState == OFF) {
+ // We can immediately play the new note.
+ bufferSize = size;
+ this->velocity = float(velocity) / 127.0;
+
+ voiceIndex = Synthesizer::nextVoiceIndex;
+ ++Synthesizer::nextVoiceIndex;
+ fromDisabled = true;
+ currentState = FILL;
+ } else {
+ // Put the values in the queue for later.
+ nextBufferSize = size;
+ nextVelocity = float(velocity) / 127.0;
+ }
+}
+
+void Synthesizer::midiNoteOff() {
+ // Begin release of current note.
+ currentState = RELEASE;
+
+ // Clear the queue.
+ nextBufferSize = -1;
+}
+
+float Synthesizer::getSample() {
+ if (currentState == FILL && fromDisabled) {
+ // The buffer may contain the release of the previous note so just return 0.0
+ return 0.0;
+ }
+
+ // Simply return the next sample. Do not increment.
+ return buffer[bufferIndex];
+}
+
+void Synthesizer::processBuffer() {
+ // Assert that we are playing.
+ if (currentState == OFF) {
+ #ifdef DEBUG
+ printf("Error: Attempting to process a disabled synthesizer.");
+ #endif
+ return;
+ }
+
+ // Use the current processor to process the buffer.
+ (this->*processors[processorIndex])();
+}
+
+bool Synthesizer::isPlaying() {
+ return currentState != OFF;
+}
+
+int64_t Synthesizer::getVoiceIndex() {
+ return voiceIndex;
+}
+
+void Synthesizer::nextSynth(int direction) {
+ // Rotate to the next synth.
+ processorIndex += direction;
+ if (processorIndex >= numSynths) {
+ processorIndex -= numSynths;
+ } else if (processorIndex < 0) {
+ processorIndex += numSynths;
+ }
+
+ // If we are playing, restart the buffer.
+ if (isPlaying()) {
+ fromDisabled = true;
+ bufferIndex = 0;
+ currentState = FILL;
+ }
+}
+
+int Synthesizer::getCurrentKey() {
+ return currentKey;
+}
+
+// Processor Functions.
+
+void Synthesizer::processSine() {
+ if (currentState == FILL) {
+ // Create the sine wave.
+ buffer[bufferIndex] = velocity * sin(TWO_PI * float(bufferIndex) / float(bufferSize));
+ ++bufferIndex;
+
+ // Check if we have reached the end of the buffer.
+ if (bufferIndex == bufferSize) {
+ bufferIndex = 0;
+
+ // Check if there are new notes waiting in the queue.
+ if (nextBufferSize != -1) {
+ currentState = RELEASE;
+ } else {
+ currentState = SUSTAIN;
+ }
+ }
+ } else {
+ identityProcess();
+ }
+}
+
+void Synthesizer::processTriangle() {
+ if (currentState == FILL) {
+ // Create the triangle wave.
+ // Rotate pi/2 to remove phase offset.
+ int index = (bufferIndex + (bufferSize >> 2)) % bufferSize;
+ // Calculate linear function from -1 to 3
+ int sample = -1.0 + (4.0 * float(index) / float(bufferSize));
+ // Redirect second half of the line.
+ if (sample > 1.0) {
+ sample = -sample + 2.0;
+ }
+ buffer[bufferIndex] = velocity * sample;
+ ++bufferIndex;
+
+ // Check if we have reached the end of the buffer.
+ if (bufferIndex == bufferSize) {
+ bufferIndex = 0;
+
+ // Check if there are new notes waiting in the queue.
+ if (nextBufferSize != -1) {
+ currentState = RELEASE;
+ } else {
+ currentState = SUSTAIN;
+ }
+ }
+ } else {
+ identityProcess();
+ }
+}
+
+void Synthesizer::processSquare() {
+ if (currentState == FILL) {
+ // Create the square wave.
+ buffer[bufferIndex] = bufferIndex < (bufferSize >> 1) ? -velocity : velocity;
+ ++bufferIndex;
+
+ // Check if we have reached the end of the buffer.
+ if (bufferIndex == bufferSize) {
+ bufferIndex = 0;
+
+ // Check if there are new notes waiting in the queue.
+ if (nextBufferSize != -1) {
+ currentState = RELEASE;
+ } else {
+ currentState = SUSTAIN;
+ }
+ }
+ } else {
+ identityProcess();
+ }
+}
+
+void Synthesizer::processSaw() {
+ if (currentState == FILL) {
+ // Create the saw wave.
+ buffer[bufferIndex] = velocity * (1.0 - 2.0 * float(bufferIndex) / float(bufferSize));
+ ++bufferIndex;
+
+ // Check if we have reached the end of the buffer.
+ if (bufferIndex == bufferSize) {
+ bufferIndex = 0;
+
+ // Check if there are new notes waiting in the queue.
+ if (nextBufferSize != -1) {
+ currentState = RELEASE;
+ } else {
+ currentState = SUSTAIN;
+ }
+ }
+ } else {
+ identityProcess();
+ }
+}
+
+void Synthesizer::identityProcess() {
+ if (currentState == RELEASE) {
+ // Attenuate the current buffer.
+ buffer[bufferIndex] *= -(float(bufferIndex) / float(bufferSize)) + 1.0;
+ }
+
+ ++bufferIndex;
+
+ // Check if we have reached the end of the buffer.
+ if (bufferIndex == bufferSize) {
+ bufferIndex = 0;
+
+ // Check the queue to see if we have a new note waiting.
+ if (nextBufferSize != -1) {
+ if (currentState == SUSTAIN) {
+ currentState = RELEASE;
+ } else {
+ bufferSize = nextBufferSize;
+ velocity = nextVelocity;
+ nextBufferSize = -1;
+ fromDisabled = false;
+ currentState = FILL;
+ }
+ } else if (currentState == RELEASE) {
+ // Disable the synthesizer.
+ currentState = OFF;
+ voiceIndex = -1;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Audio/Synthesizer.h Wed Apr 13 19:46:28 2016 +0000
@@ -0,0 +1,116 @@
+/**
+ * The class representing a single monophonic voice.
+ * This class holds and processes its own buffer and play state.
+ *
+ * Note: This class also holds implementations for each of the different instruments.
+ * In a perfect OOP world this would be extracted out into an interface with a
+ * concrete class for each instrument, but in order to keep overhead low, I
+ * went for an array of member function pointers instead.
+ *
+ * @author Austin Suszek
+ */
+
+#ifndef AS_SYNTHESIZER_H
+#define AS_SYNTHESIZER_H
+
+#include "../Constants.h"
+#include "../mbed.h"
+
+/**
+ * An enum representing the possible states of the synthesizer.
+ */
+enum SynthState {
+ OFF,
+ FILL,
+ SUSTAIN,
+ RELEASE
+};
+
+class Synthesizer {
+public:
+
+ /**
+ * Constructor
+ */
+ Synthesizer();
+
+ /**
+ * Signal the beginning of a note being pressed.
+ *
+ * @param key The integer representation of the note
+ * @param velocity (optional) The note velocity in the range of 0-127
+ */
+ void midiNoteOn(int key, int velocity);
+
+ /**
+ * Signal the end of a note being pressed.
+ */
+ void midiNoteOff();
+
+ /**
+ * Get the next sample to output.
+ */
+ float getSample();
+
+ /**
+ * Process the current buffer.
+ */
+ void processBuffer();
+
+ /**
+ * Returns false for SynthState OFF and true for all other states.
+ */
+ bool isPlaying();
+
+ /**
+ * Getter for the voiceIndex variable.
+ */
+ int64_t getVoiceIndex();
+
+ /**
+ * Switch to a new synth instrument.
+ *
+ * @param direction 1 for next, -1 for previous.
+ */
+ void nextSynth(int direction);
+
+ /**
+ * A getter for the current key.
+ * It is always overwritten to the most recent key.
+ */
+ int getCurrentKey();
+
+ /**
+ * Processor functions. These are responsible for all procesing of the buffer based on their instrument.
+ */
+ void processSine();
+ void processTriangle();
+ void processSquare();
+ void processSaw();
+
+private:
+
+ float buffer[(C::SAMPLE_RATE / C::MIN_FREQUENCY) + 1];
+ int bufferIndex;
+
+ SynthState currentState;
+
+ int currentKey;
+ int bufferSize;
+ float velocity;
+
+ int nextBufferSize;
+ float nextVelocity;
+
+ int64_t voiceIndex;
+ static int64_t nextVoiceIndex;
+ bool fromDisabled;
+
+ // A process that just outputs input.
+ void identityProcess();
+
+ volatile int processorIndex;
+
+};
+
+#endif
\ No newline at end of file
--- a/AudioEngine.cpp Tue Apr 12 20:39:18 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * The interface for all audio input and output.
- * This class acts as a container for individual voices.
- * It takes in MIDI events and handles processing and output.
- *
- * @author Austin Suszek
- */
-
-#include "AudioEngine.h"
-
-#if USE_PWM
-PwmOut audioOut(p21);
-#else
-AnalogOut audioOut(p18);
-#endif
-
-AudioEngine::AudioEngine() {
- // Initialize the synthesizers.
- for (int i = 0; i < C::MAX_POLYPHONY; i++) {
- synthesizers[i] = Synthesizer();
- }
-
- #if USE_PWM
- audioOut.period(1.0/200000.0);
- #endif
-
- // Set up the sampler.
- samplePeriod.attach(this, &AudioEngine::outputAudio, 1.0 / float(C::SAMPLE_RATE));
-}
-
-void AudioEngine::midiNoteOn(const int key, const int velocity) {
- // Find the firt disabled voice or the one that has been playing longest.
- int64_t min = synthesizers[0].getVoiceIndex();
- int minIndex = 0;
- for (int i = 1; i < C::MAX_POLYPHONY; i++) {
- int64_t voiceIndex = synthesizers[i].getVoiceIndex();
- if (voiceIndex < min) {
- min = voiceIndex;
- minIndex = i;
- }
- }
-
- // Send the note to the minimum voice.
- synthesizers[minIndex].midiNoteOn(key, velocity);
-}
-
-void AudioEngine::midiNoteOff(const int key) {
- for (int i = 0; i < C::MAX_POLYPHONY; i++) {
- if (synthesizers[i].isPlaying() && synthesizers[i].getCurrentKey() == key) {
- synthesizers[i].midiNoteOff();
- break;
- }
- }
-}
-
-void AudioEngine::nextSynth(int direction) {
- // Hand the command down to the synthesizers.
- for (int i = 0; i < C::MAX_POLYPHONY; i++) {
- synthesizers[i].nextSynth(direction);
- }
-}
-
-void AudioEngine::outputAudio() {
- float output = 0.0;
-
- // Poll all of the synthesizers.
- for (int i = 0; i < C::MAX_POLYPHONY; i++) {
- if (synthesizers[i].isPlaying()) {
- output += synthesizers[i].getSample();
- }
- }
-
- // Scale the output by the number of voices.
- output /= float(C::MAX_POLYPHONY);
- // Check that we do not clip.
- if (output > 1.0) {
- output = 1.0;
- }
- if (output < -1.0) {
- output = -1.0;
- }
- // Map [-1, 1] range to [0, 1] range.
- audioOut = (output + 1.0) / 2.0;
-
- // Go back and process the next sample on all voices.
- for (int i = 0; i < C::MAX_POLYPHONY; i++) {
- if (synthesizers[i].isPlaying()) {
- synthesizers[i].processBuffer();
- }
- }
-}
\ No newline at end of file
--- a/AudioEngine.h Tue Apr 12 20:39:18 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/**
- * The interface for all audio input and output.
- * This class acts as a container for individual voices.
- * It takes in MIDI events and handles processing and output.
- *
- * @author Austin Suszek
- */
-
-#ifndef AS_AUDIO_ENGINE_H
-#define AS_AUDIO_ENGINE_H
-
-#include "Constants.h"
-#include "mbed.h"
-#include "Synthesizer.h"
-
-class AudioEngine {
-public:
-
- /**
- * Constructor
- */
- AudioEngine();
-
- /**
- * Signal the beginning of a note being pressed.
- *
- * @param key The integer representation of the note
- * @param velocity (optional) The note velocity in the range of 0-127
- */
- void midiNoteOn(const int key, const int velocity = 0x7F);
-
- /**
- * Signal the end of a note being pressed.
- *
- * @param key The integer representation of the note
- */
- void midiNoteOff(const int key);
-
- /**
- * Switch to a new synth instrument.
- *
- * @param direction 1 for next, -1 for previous.
- */
- void nextSynth(int direction);
-
-private:
-
- Ticker samplePeriod;
- void outputAudio();
-
- Synthesizer synthesizers[C::MAX_POLYPHONY];
-
-};
-
-#endif
\ No newline at end of file
--- a/Synthesizer.cpp Tue Apr 12 20:39:18 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,250 +0,0 @@
-
-#include "Synthesizer.h"
-
-const float TWO_PI = 6.28318530717959;
-const int numSynths = 4;
-
-/**
- * A function that acts as an individual synthesizer.
- * It's job is to process the next sample at the current index
- * based on the current state of the overall synthesizer.
- * Output should be in the range of [-1.0, 1.0] and saved back into the buffer.
- */
-typedef void (Synthesizer::*processorFunction)();
-
-// Array of pointers to all synthesizer functions.
-processorFunction processors[] = {
- &Synthesizer::processSine,
- &Synthesizer::processTriangle,
- &Synthesizer::processSquare,
- &Synthesizer::processSaw,
-};
-
-int64_t Synthesizer::nextVoiceIndex = 0;
-
-Synthesizer::Synthesizer() {
- bufferIndex = 0;
- currentState = OFF;
- nextBufferSize = -1;
- voiceIndex = -1;
- processorIndex = 0;
-}
-
-void Synthesizer::midiNoteOn(int key, int velocity) {
- float freq = 440.0 * std::pow(2.0, float(key - 69) / 12.0);
-
- // Make sure we are in bounds.
- if (freq < C::MIN_FREQUENCY) {
- #ifdef DEBUG
- printf("Error: Note is below minimum frequency");
- #endif
- return;
- }
-
- currentKey = key;
- int size = int((float(C::SAMPLE_RATE) / freq) + 0.5);
-
- if (currentState == OFF) {
- // We can immediately play the new note.
- bufferSize = size;
- this->velocity = float(velocity) / 127.0;
-
- voiceIndex = Synthesizer::nextVoiceIndex;
- ++Synthesizer::nextVoiceIndex;
- fromDisabled = true;
- currentState = FILL;
- } else {
- // Put the values in the queue for later.
- nextBufferSize = size;
- nextVelocity = float(velocity) / 127.0;
- }
-}
-
-void Synthesizer::midiNoteOff() {
- // Begin release of current note.
- currentState = RELEASE;
-
- // Clear the queue.
- nextBufferSize = -1;
-}
-
-float Synthesizer::getSample() {
- if (currentState == FILL && fromDisabled) {
- // The buffer may contain the release of the previous note so just return 0.0
- return 0.0;
- }
-
- // Simply return the next sample. Do not increment.
- return buffer[bufferIndex];
-}
-
-void Synthesizer::processBuffer() {
- // Assert that we are playing.
- if (currentState == OFF) {
- #ifdef DEBUG
- printf("Error: Attempting to process a disabled synthesizer.");
- #endif
- return;
- }
-
- // Use the current processor to process the buffer.
- (this->*processors[processorIndex])();
-}
-
-bool Synthesizer::isPlaying() {
- return currentState != OFF;
-}
-
-int64_t Synthesizer::getVoiceIndex() {
- return voiceIndex;
-}
-
-void Synthesizer::nextSynth(int direction) {
- // Rotate to the next synth.
- processorIndex += direction;
- if (processorIndex >= numSynths) {
- processorIndex -= numSynths;
- } else if (processorIndex < 0) {
- processorIndex += numSynths;
- }
-
- // If we are playing, restart the buffer.
- if (isPlaying()) {
- fromDisabled = true;
- bufferIndex = 0;
- currentState = FILL;
- }
-}
-
-int Synthesizer::getCurrentKey() {
- return currentKey;
-}
-
-// Processor Functions.
-
-void Synthesizer::processSine() {
- if (currentState == FILL) {
- // Create the sine wave.
- buffer[bufferIndex] = velocity * sin(TWO_PI * float(bufferIndex) / float(bufferSize));
- ++bufferIndex;
-
- // Check if we have reached the end of the buffer.
- if (bufferIndex == bufferSize) {
- bufferIndex = 0;
-
- // Check if there are new notes waiting in the queue.
- if (nextBufferSize != -1) {
- currentState = RELEASE;
- } else {
- currentState = SUSTAIN;
- }
- }
- } else {
- identityProcess();
- }
-}
-
-void Synthesizer::processTriangle() {
- if (currentState == FILL) {
- // Create the triangle wave.
- // Rotate pi/2 to remove phase offset.
- int index = (bufferIndex + (bufferSize >> 2)) % bufferSize;
- // Calculate linear function from -1 to 3
- int sample = -1.0 + (4.0 * float(index) / float(bufferSize));
- // Redirect second half of the line.
- if (sample > 1.0) {
- sample = -sample + 2.0;
- }
- buffer[bufferIndex] = velocity * sample;
- ++bufferIndex;
-
- // Check if we have reached the end of the buffer.
- if (bufferIndex == bufferSize) {
- bufferIndex = 0;
-
- // Check if there are new notes waiting in the queue.
- if (nextBufferSize != -1) {
- currentState = RELEASE;
- } else {
- currentState = SUSTAIN;
- }
- }
- } else {
- identityProcess();
- }
-}
-
-void Synthesizer::processSquare() {
- if (currentState == FILL) {
- // Create the square wave.
- buffer[bufferIndex] = bufferIndex < (bufferSize >> 1) ? -velocity : velocity;
- ++bufferIndex;
-
- // Check if we have reached the end of the buffer.
- if (bufferIndex == bufferSize) {
- bufferIndex = 0;
-
- // Check if there are new notes waiting in the queue.
- if (nextBufferSize != -1) {
- currentState = RELEASE;
- } else {
- currentState = SUSTAIN;
- }
- }
- } else {
- identityProcess();
- }
-}
-
-void Synthesizer::processSaw() {
- if (currentState == FILL) {
- // Create the saw wave.
- buffer[bufferIndex] = velocity * (1.0 - 2.0 * float(bufferIndex) / float(bufferSize));
- ++bufferIndex;
-
- // Check if we have reached the end of the buffer.
- if (bufferIndex == bufferSize) {
- bufferIndex = 0;
-
- // Check if there are new notes waiting in the queue.
- if (nextBufferSize != -1) {
- currentState = RELEASE;
- } else {
- currentState = SUSTAIN;
- }
- }
- } else {
- identityProcess();
- }
-}
-
-void Synthesizer::identityProcess() {
- if (currentState == RELEASE) {
- // Attenuate the current buffer.
- buffer[bufferIndex] *= -(float(bufferIndex) / float(bufferSize)) + 1.0;
- }
-
- ++bufferIndex;
-
- // Check if we have reached the end of the buffer.
- if (bufferIndex == bufferSize) {
- bufferIndex = 0;
-
- // Check the queue to see if we have a new note waiting.
- if (nextBufferSize != -1) {
- if (currentState == SUSTAIN) {
- currentState = RELEASE;
- } else {
- bufferSize = nextBufferSize;
- velocity = nextVelocity;
- nextBufferSize = -1;
- fromDisabled = false;
- currentState = FILL;
- }
- } else if (currentState == RELEASE) {
- // Disable the synthesizer.
- currentState = OFF;
- voiceIndex = -1;
- }
- }
-}
\ No newline at end of file
--- a/Synthesizer.h Tue Apr 12 20:39:18 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/**
- * The class representing a single monophonic voice.
- * This class holds and processes its own buffer and play state.
- *
- * Note: This class also holds implementations for each of the different instruments.
- * In a perfect OOP world this would be extracted out into an interface with a
- * concrete class for each instrument, but in order to keep overhead low, I
- * went for an array of member function pointers instead.
- *
- * @author Austin Suszek
- */
-
-#ifndef AS_SYNTHESIZER_H
-#define AS_SYNTHESIZER_H
-
-#include "Constants.h"
-#include "mbed.h"
-
-/**
- * An enum representing the possible states of the synthesizer.
- */
-enum SynthState {
- OFF,
- FILL,
- SUSTAIN,
- RELEASE
-};
-
-class Synthesizer {
-public:
-
- /**
- * Constructor
- */
- Synthesizer();
-
- /**
- * Signal the beginning of a note being pressed.
- *
- * @param key The integer representation of the note
- * @param velocity (optional) The note velocity in the range of 0-127
- */
- void midiNoteOn(int key, int velocity);
-
- /**
- * Signal the end of a note being pressed.
- */
- void midiNoteOff();
-
- /**
- * Get the next sample to output.
- */
- float getSample();
-
- /**
- * Process the current buffer.
- */
- void processBuffer();
-
- /**
- * Returns false for SynthState OFF and true for all other states.
- */
- bool isPlaying();
-
- /**
- * Getter for the voiceIndex variable.
- */
- int64_t getVoiceIndex();
-
- /**
- * Switch to a new synth instrument.
- *
- * @param direction 1 for next, -1 for previous.
- */
- void nextSynth(int direction);
-
- /**
- * A getter for the current key.
- * It is always overwritten to the most recent key.
- */
- int getCurrentKey();
-
- /**
- * Processor functions. These are responsible for all procesing of the buffer based on their instrument.
- */
- void processSine();
- void processTriangle();
- void processSquare();
- void processSaw();
-
-private:
-
- float buffer[(C::SAMPLE_RATE / C::MIN_FREQUENCY) + 1];
- int bufferIndex;
-
- SynthState currentState;
-
- int currentKey;
- int bufferSize;
- float velocity;
-
- int nextBufferSize;
- float nextVelocity;
-
- int64_t voiceIndex;
- static int64_t nextVoiceIndex;
- bool fromDisabled;
-
- // A process that just outputs input.
- void identityProcess();
-
- volatile int processorIndex;
-
-};
-
-#endif
\ No newline at end of file
--- a/main.cpp Tue Apr 12 20:39:18 2016 +0000 +++ b/main.cpp Wed Apr 13 19:46:28 2016 +0000 @@ -4,7 +4,7 @@ * @author Nick Delfino */ -#include "AudioEngine.h" +#include "Audio/AudioEngine.h" #include "Constants.h" #include "mbed.h" #include "PinDetect.h"
