diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/waveforms/Sawtooth.cpp b/app/src/main/cpp/waveforms/Sawtooth.cpp index 3bfe814..de3d955 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.cpp +++ b/app/src/main/cpp/waveforms/Sawtooth.cpp @@ -1,16 +1,12 @@ #include "Sawtooth.h" -void Sawtooth::initialize(AudioHost *host) { - this->host = host; -} - void Sawtooth::setFrequency(float frequency) { step = 2 * frequency / (double) host->sampleRate; } -void Sawtooth::render(float *data, uint32_t frameCount) { +void Sawtooth::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += value * amplitude; + buffer[i] = value; value += step; if (value > 1) { value = -1; diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/waveforms/Sawtooth.cpp b/app/src/main/cpp/waveforms/Sawtooth.cpp index 3bfe814..de3d955 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.cpp +++ b/app/src/main/cpp/waveforms/Sawtooth.cpp @@ -1,16 +1,12 @@ #include "Sawtooth.h" -void Sawtooth::initialize(AudioHost *host) { - this->host = host; -} - void Sawtooth::setFrequency(float frequency) { step = 2 * frequency / (double) host->sampleRate; } -void Sawtooth::render(float *data, uint32_t frameCount) { +void Sawtooth::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += value * amplitude; + buffer[i] = value; value += step; if (value > 1) { value = -1; diff --git a/app/src/main/cpp/waveforms/Sawtooth.h b/app/src/main/cpp/waveforms/Sawtooth.h index b307371..498c27d 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.h +++ b/app/src/main/cpp/waveforms/Sawtooth.h @@ -10,9 +10,7 @@ private: float value = 0, step = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/waveforms/Sawtooth.cpp b/app/src/main/cpp/waveforms/Sawtooth.cpp index 3bfe814..de3d955 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.cpp +++ b/app/src/main/cpp/waveforms/Sawtooth.cpp @@ -1,16 +1,12 @@ #include "Sawtooth.h" -void Sawtooth::initialize(AudioHost *host) { - this->host = host; -} - void Sawtooth::setFrequency(float frequency) { step = 2 * frequency / (double) host->sampleRate; } -void Sawtooth::render(float *data, uint32_t frameCount) { +void Sawtooth::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += value * amplitude; + buffer[i] = value; value += step; if (value > 1) { value = -1; diff --git a/app/src/main/cpp/waveforms/Sawtooth.h b/app/src/main/cpp/waveforms/Sawtooth.h index b307371..498c27d 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.h +++ b/app/src/main/cpp/waveforms/Sawtooth.h @@ -10,9 +10,7 @@ private: float value = 0, step = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Sine.cpp b/app/src/main/cpp/waveforms/Sine.cpp index f692542..98969a2 100644 --- a/app/src/main/cpp/waveforms/Sine.cpp +++ b/app/src/main/cpp/waveforms/Sine.cpp @@ -3,17 +3,13 @@ #include #include -void Sine::initialize(AudioHost *host) { - this->host = host; -} - void Sine::setFrequency(float frequency) { phaseStep = (2 * M_PI * frequency) / (double) host->sampleRate; } -void Sine::render(float *data, uint32_t frameCount) { +void Sine::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += (float) (sin(phase) * amplitude); + buffer[i] = sin(phase); phase += phaseStep; if (phase > 2 * M_PI) { phase -= 2 * M_PI; diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/waveforms/Sawtooth.cpp b/app/src/main/cpp/waveforms/Sawtooth.cpp index 3bfe814..de3d955 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.cpp +++ b/app/src/main/cpp/waveforms/Sawtooth.cpp @@ -1,16 +1,12 @@ #include "Sawtooth.h" -void Sawtooth::initialize(AudioHost *host) { - this->host = host; -} - void Sawtooth::setFrequency(float frequency) { step = 2 * frequency / (double) host->sampleRate; } -void Sawtooth::render(float *data, uint32_t frameCount) { +void Sawtooth::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += value * amplitude; + buffer[i] = value; value += step; if (value > 1) { value = -1; diff --git a/app/src/main/cpp/waveforms/Sawtooth.h b/app/src/main/cpp/waveforms/Sawtooth.h index b307371..498c27d 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.h +++ b/app/src/main/cpp/waveforms/Sawtooth.h @@ -10,9 +10,7 @@ private: float value = 0, step = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Sine.cpp b/app/src/main/cpp/waveforms/Sine.cpp index f692542..98969a2 100644 --- a/app/src/main/cpp/waveforms/Sine.cpp +++ b/app/src/main/cpp/waveforms/Sine.cpp @@ -3,17 +3,13 @@ #include #include -void Sine::initialize(AudioHost *host) { - this->host = host; -} - void Sine::setFrequency(float frequency) { phaseStep = (2 * M_PI * frequency) / (double) host->sampleRate; } -void Sine::render(float *data, uint32_t frameCount) { +void Sine::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += (float) (sin(phase) * amplitude); + buffer[i] = sin(phase); phase += phaseStep; if (phase > 2 * M_PI) { phase -= 2 * M_PI; diff --git a/app/src/main/cpp/waveforms/Sine.h b/app/src/main/cpp/waveforms/Sine.h index 93dc620..ba727f4 100644 --- a/app/src/main/cpp/waveforms/Sine.h +++ b/app/src/main/cpp/waveforms/Sine.h @@ -4,16 +4,13 @@ class Sine; #include -#include "../AudioHost.h" #include "Waveform.h" class Sine : public Waveform { private: float phaseStep, phase = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/waveforms/Sawtooth.cpp b/app/src/main/cpp/waveforms/Sawtooth.cpp index 3bfe814..de3d955 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.cpp +++ b/app/src/main/cpp/waveforms/Sawtooth.cpp @@ -1,16 +1,12 @@ #include "Sawtooth.h" -void Sawtooth::initialize(AudioHost *host) { - this->host = host; -} - void Sawtooth::setFrequency(float frequency) { step = 2 * frequency / (double) host->sampleRate; } -void Sawtooth::render(float *data, uint32_t frameCount) { +void Sawtooth::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += value * amplitude; + buffer[i] = value; value += step; if (value > 1) { value = -1; diff --git a/app/src/main/cpp/waveforms/Sawtooth.h b/app/src/main/cpp/waveforms/Sawtooth.h index b307371..498c27d 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.h +++ b/app/src/main/cpp/waveforms/Sawtooth.h @@ -10,9 +10,7 @@ private: float value = 0, step = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Sine.cpp b/app/src/main/cpp/waveforms/Sine.cpp index f692542..98969a2 100644 --- a/app/src/main/cpp/waveforms/Sine.cpp +++ b/app/src/main/cpp/waveforms/Sine.cpp @@ -3,17 +3,13 @@ #include #include -void Sine::initialize(AudioHost *host) { - this->host = host; -} - void Sine::setFrequency(float frequency) { phaseStep = (2 * M_PI * frequency) / (double) host->sampleRate; } -void Sine::render(float *data, uint32_t frameCount) { +void Sine::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += (float) (sin(phase) * amplitude); + buffer[i] = sin(phase); phase += phaseStep; if (phase > 2 * M_PI) { phase -= 2 * M_PI; diff --git a/app/src/main/cpp/waveforms/Sine.h b/app/src/main/cpp/waveforms/Sine.h index 93dc620..ba727f4 100644 --- a/app/src/main/cpp/waveforms/Sine.h +++ b/app/src/main/cpp/waveforms/Sine.h @@ -4,16 +4,13 @@ class Sine; #include -#include "../AudioHost.h" #include "Waveform.h" class Sine : public Waveform { private: float phaseStep, phase = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Waveform.cpp b/app/src/main/cpp/waveforms/Waveform.cpp new file mode 100644 index 0000000..64e0991 --- /dev/null +++ b/app/src/main/cpp/waveforms/Waveform.cpp @@ -0,0 +1,8 @@ +#include "Waveform.h" + +void Waveform::doRender(uint32_t sampleCount) { + renderWaveform(sampleCount); + for (uint32_t i = 0; i < sampleCount; i++) { + buffer[i] *= amplitude; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/waveforms/Sawtooth.cpp b/app/src/main/cpp/waveforms/Sawtooth.cpp index 3bfe814..de3d955 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.cpp +++ b/app/src/main/cpp/waveforms/Sawtooth.cpp @@ -1,16 +1,12 @@ #include "Sawtooth.h" -void Sawtooth::initialize(AudioHost *host) { - this->host = host; -} - void Sawtooth::setFrequency(float frequency) { step = 2 * frequency / (double) host->sampleRate; } -void Sawtooth::render(float *data, uint32_t frameCount) { +void Sawtooth::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += value * amplitude; + buffer[i] = value; value += step; if (value > 1) { value = -1; diff --git a/app/src/main/cpp/waveforms/Sawtooth.h b/app/src/main/cpp/waveforms/Sawtooth.h index b307371..498c27d 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.h +++ b/app/src/main/cpp/waveforms/Sawtooth.h @@ -10,9 +10,7 @@ private: float value = 0, step = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Sine.cpp b/app/src/main/cpp/waveforms/Sine.cpp index f692542..98969a2 100644 --- a/app/src/main/cpp/waveforms/Sine.cpp +++ b/app/src/main/cpp/waveforms/Sine.cpp @@ -3,17 +3,13 @@ #include #include -void Sine::initialize(AudioHost *host) { - this->host = host; -} - void Sine::setFrequency(float frequency) { phaseStep = (2 * M_PI * frequency) / (double) host->sampleRate; } -void Sine::render(float *data, uint32_t frameCount) { +void Sine::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += (float) (sin(phase) * amplitude); + buffer[i] = sin(phase); phase += phaseStep; if (phase > 2 * M_PI) { phase -= 2 * M_PI; diff --git a/app/src/main/cpp/waveforms/Sine.h b/app/src/main/cpp/waveforms/Sine.h index 93dc620..ba727f4 100644 --- a/app/src/main/cpp/waveforms/Sine.h +++ b/app/src/main/cpp/waveforms/Sine.h @@ -4,16 +4,13 @@ class Sine; #include -#include "../AudioHost.h" #include "Waveform.h" class Sine : public Waveform { private: float phaseStep, phase = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Waveform.cpp b/app/src/main/cpp/waveforms/Waveform.cpp new file mode 100644 index 0000000..64e0991 --- /dev/null +++ b/app/src/main/cpp/waveforms/Waveform.cpp @@ -0,0 +1,8 @@ +#include "Waveform.h" + +void Waveform::doRender(uint32_t sampleCount) { + renderWaveform(sampleCount); + for (uint32_t i = 0; i < sampleCount; i++) { + buffer[i] *= amplitude; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/waveforms/Waveform.h b/app/src/main/cpp/waveforms/Waveform.h index 4f94b8e..a70ed39 100644 --- a/app/src/main/cpp/waveforms/Waveform.h +++ b/app/src/main/cpp/waveforms/Waveform.h @@ -1,20 +1,24 @@ #ifndef MUSIC_WAVEFORM_H #define MUSIC_WAVEFORM_H +class Waveform; + enum WaveformType { SINE = 0, SAWTOOTH = 1, }; -class Waveform { -protected: - AudioHost *host; +#include "../effects/Processable.h" +#include "../AudioHost.h" + +class Waveform : public Processable { public: - float amplitude = 0.3f; + float amplitude = 0.0f; + AudioHost *host; - virtual void initialize(AudioHost *host) = 0; + void doRender(uint32_t sampleCount); - virtual void render(float *data, uint32_t frameCount) = 0; + virtual void renderWaveform(uint32_t sampleCount) = 0; virtual void setFrequency(float freq) = 0; }; diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/waveforms/Sawtooth.cpp b/app/src/main/cpp/waveforms/Sawtooth.cpp index 3bfe814..de3d955 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.cpp +++ b/app/src/main/cpp/waveforms/Sawtooth.cpp @@ -1,16 +1,12 @@ #include "Sawtooth.h" -void Sawtooth::initialize(AudioHost *host) { - this->host = host; -} - void Sawtooth::setFrequency(float frequency) { step = 2 * frequency / (double) host->sampleRate; } -void Sawtooth::render(float *data, uint32_t frameCount) { +void Sawtooth::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += value * amplitude; + buffer[i] = value; value += step; if (value > 1) { value = -1; diff --git a/app/src/main/cpp/waveforms/Sawtooth.h b/app/src/main/cpp/waveforms/Sawtooth.h index b307371..498c27d 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.h +++ b/app/src/main/cpp/waveforms/Sawtooth.h @@ -10,9 +10,7 @@ private: float value = 0, step = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Sine.cpp b/app/src/main/cpp/waveforms/Sine.cpp index f692542..98969a2 100644 --- a/app/src/main/cpp/waveforms/Sine.cpp +++ b/app/src/main/cpp/waveforms/Sine.cpp @@ -3,17 +3,13 @@ #include #include -void Sine::initialize(AudioHost *host) { - this->host = host; -} - void Sine::setFrequency(float frequency) { phaseStep = (2 * M_PI * frequency) / (double) host->sampleRate; } -void Sine::render(float *data, uint32_t frameCount) { +void Sine::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += (float) (sin(phase) * amplitude); + buffer[i] = sin(phase); phase += phaseStep; if (phase > 2 * M_PI) { phase -= 2 * M_PI; diff --git a/app/src/main/cpp/waveforms/Sine.h b/app/src/main/cpp/waveforms/Sine.h index 93dc620..ba727f4 100644 --- a/app/src/main/cpp/waveforms/Sine.h +++ b/app/src/main/cpp/waveforms/Sine.h @@ -4,16 +4,13 @@ class Sine; #include -#include "../AudioHost.h" #include "Waveform.h" class Sine : public Waveform { private: float phaseStep, phase = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Waveform.cpp b/app/src/main/cpp/waveforms/Waveform.cpp new file mode 100644 index 0000000..64e0991 --- /dev/null +++ b/app/src/main/cpp/waveforms/Waveform.cpp @@ -0,0 +1,8 @@ +#include "Waveform.h" + +void Waveform::doRender(uint32_t sampleCount) { + renderWaveform(sampleCount); + for (uint32_t i = 0; i < sampleCount; i++) { + buffer[i] *= amplitude; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/waveforms/Waveform.h b/app/src/main/cpp/waveforms/Waveform.h index 4f94b8e..a70ed39 100644 --- a/app/src/main/cpp/waveforms/Waveform.h +++ b/app/src/main/cpp/waveforms/Waveform.h @@ -1,20 +1,24 @@ #ifndef MUSIC_WAVEFORM_H #define MUSIC_WAVEFORM_H +class Waveform; + enum WaveformType { SINE = 0, SAWTOOTH = 1, }; -class Waveform { -protected: - AudioHost *host; +#include "../effects/Processable.h" +#include "../AudioHost.h" + +class Waveform : public Processable { public: - float amplitude = 0.3f; + float amplitude = 0.0f; + AudioHost *host; - virtual void initialize(AudioHost *host) = 0; + void doRender(uint32_t sampleCount); - virtual void render(float *data, uint32_t frameCount) = 0; + virtual void renderWaveform(uint32_t sampleCount) = 0; virtual void setFrequency(float freq) = 0; }; diff --git a/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt b/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt index d524f58..98888de 100644 --- a/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt @@ -12,7 +12,7 @@ set(value) { field = value setInstrumentWaveform(id, value.id) - println("set instrument to $value") + active = active } fun startNote(frequency: Double) { diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/waveforms/Sawtooth.cpp b/app/src/main/cpp/waveforms/Sawtooth.cpp index 3bfe814..de3d955 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.cpp +++ b/app/src/main/cpp/waveforms/Sawtooth.cpp @@ -1,16 +1,12 @@ #include "Sawtooth.h" -void Sawtooth::initialize(AudioHost *host) { - this->host = host; -} - void Sawtooth::setFrequency(float frequency) { step = 2 * frequency / (double) host->sampleRate; } -void Sawtooth::render(float *data, uint32_t frameCount) { +void Sawtooth::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += value * amplitude; + buffer[i] = value; value += step; if (value > 1) { value = -1; diff --git a/app/src/main/cpp/waveforms/Sawtooth.h b/app/src/main/cpp/waveforms/Sawtooth.h index b307371..498c27d 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.h +++ b/app/src/main/cpp/waveforms/Sawtooth.h @@ -10,9 +10,7 @@ private: float value = 0, step = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Sine.cpp b/app/src/main/cpp/waveforms/Sine.cpp index f692542..98969a2 100644 --- a/app/src/main/cpp/waveforms/Sine.cpp +++ b/app/src/main/cpp/waveforms/Sine.cpp @@ -3,17 +3,13 @@ #include #include -void Sine::initialize(AudioHost *host) { - this->host = host; -} - void Sine::setFrequency(float frequency) { phaseStep = (2 * M_PI * frequency) / (double) host->sampleRate; } -void Sine::render(float *data, uint32_t frameCount) { +void Sine::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += (float) (sin(phase) * amplitude); + buffer[i] = sin(phase); phase += phaseStep; if (phase > 2 * M_PI) { phase -= 2 * M_PI; diff --git a/app/src/main/cpp/waveforms/Sine.h b/app/src/main/cpp/waveforms/Sine.h index 93dc620..ba727f4 100644 --- a/app/src/main/cpp/waveforms/Sine.h +++ b/app/src/main/cpp/waveforms/Sine.h @@ -4,16 +4,13 @@ class Sine; #include -#include "../AudioHost.h" #include "Waveform.h" class Sine : public Waveform { private: float phaseStep, phase = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Waveform.cpp b/app/src/main/cpp/waveforms/Waveform.cpp new file mode 100644 index 0000000..64e0991 --- /dev/null +++ b/app/src/main/cpp/waveforms/Waveform.cpp @@ -0,0 +1,8 @@ +#include "Waveform.h" + +void Waveform::doRender(uint32_t sampleCount) { + renderWaveform(sampleCount); + for (uint32_t i = 0; i < sampleCount; i++) { + buffer[i] *= amplitude; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/waveforms/Waveform.h b/app/src/main/cpp/waveforms/Waveform.h index 4f94b8e..a70ed39 100644 --- a/app/src/main/cpp/waveforms/Waveform.h +++ b/app/src/main/cpp/waveforms/Waveform.h @@ -1,20 +1,24 @@ #ifndef MUSIC_WAVEFORM_H #define MUSIC_WAVEFORM_H +class Waveform; + enum WaveformType { SINE = 0, SAWTOOTH = 1, }; -class Waveform { -protected: - AudioHost *host; +#include "../effects/Processable.h" +#include "../AudioHost.h" + +class Waveform : public Processable { public: - float amplitude = 0.3f; + float amplitude = 0.0f; + AudioHost *host; - virtual void initialize(AudioHost *host) = 0; + void doRender(uint32_t sampleCount); - virtual void render(float *data, uint32_t frameCount) = 0; + virtual void renderWaveform(uint32_t sampleCount) = 0; virtual void setFrequency(float freq) = 0; }; diff --git a/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt b/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt index d524f58..98888de 100644 --- a/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt @@ -12,7 +12,7 @@ set(value) { field = value setInstrumentWaveform(id, value.id) - println("set instrument to $value") + active = active } fun startNote(frequency: Double) { diff --git a/app/src/main/res/layout/fragment_instrument.xml b/app/src/main/res/layout/fragment_instrument.xml index 13222a3..c08b868 100644 --- a/app/src/main/res/layout/fragment_instrument.xml +++ b/app/src/main/res/layout/fragment_instrument.xml @@ -59,7 +59,6 @@ android:layout_marginTop="16dp" android:layout_marginEnd="16dp" android:contentDescription="@string/instrument_type_description" - android:entries="@array/waveforms" android:minHeight="48dp" android:spinnerMode="dropdown" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/cpp/AudioHost.h b/app/src/main/cpp/AudioHost.h index d84ccda..f439fdc 100644 --- a/app/src/main/cpp/AudioHost.h +++ b/app/src/main/cpp/AudioHost.h @@ -3,7 +3,6 @@ class AudioHost; -#include "waveforms/Sine.h" #include "Instrument.h" #include #include @@ -19,4 +18,4 @@ }; -#endif //MUSIC_AUDIO_HOST_H +#endif \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 6d9f302..e7286cb 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -9,10 +9,12 @@ waveforms/Sine.cpp waveforms/Sawtooth.cpp + waveforms/Waveform.cpp JavaFunctions.cpp AudioHost.cpp Instrument.cpp - Envelope.cpp + effects/Envelope.cpp + effects/Processable.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp deleted file mode 100644 index be0ae8b..0000000 --- a/app/src/main/cpp/Envelope.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "Instrument.h" -#include "Envelope.h" - -void Envelope::initialize(AudioHost *host) { - attackIncrement = 1 / attack / host->sampleRate; - delayIncrement = 1 / delay / host->sampleRate; - releaseIncrement = 1 / release / host->sampleRate; -} - -void Envelope::startNote() { - phase = ATTACK; -} - -void Envelope::endNote() { - phase = RELEASE; -} - -float *Envelope::render(uint32_t sampleCount) { - if (sampleCount > bufferSize) { - bufferSize = sampleCount; - buffer = new float[sampleCount]; - } - for (int i = 0; i < sampleCount; ++i) { - switch (phase) { - case ATTACK: - value += attackIncrement; - if (value > 1) { - value = 1; - phase = DELAY; - } - break; - case DELAY: - value -= delayIncrement; - if (value < sustain) { - value = sustain; - phase = SUSTAIN; - } - break; - case RELEASE: - value -= releaseIncrement; - if (value < 0) { - value = 0; - phase = NONE; - } - break; - } - buffer[i] = value; - } - return buffer; -} \ No newline at end of file diff --git a/app/src/main/cpp/Envelope.h b/app/src/main/cpp/Envelope.h deleted file mode 100644 index 134dcc5..0000000 --- a/app/src/main/cpp/Envelope.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUSIC_ENVELOPE_H -#define MUSIC_ENVELOPE_H - -class Envelope; - -#include -#include "AudioHost.h" - -enum EnvelopePhase { - NONE, ATTACK, DELAY, SUSTAIN, RELEASE, -}; - -class Envelope { -private: - uint32_t bufferSize = 0; - float *buffer; - EnvelopePhase phase; - float attackIncrement, delayIncrement, releaseIncrement; - float value = 1; -public: - float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; - - void initialize(AudioHost *host); - void startNote(); - void endNote(); - float *render(uint32_t sampleCount); -}; - - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.cpp b/app/src/main/cpp/Instrument.cpp index 5be6f92..3d9396d 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,22 +1,31 @@ #include "Instrument.h" #include "waveforms/Sawtooth.h" +#include "waveforms/Sine.h" Instrument::Instrument(AudioHost *host) { this->host = host; - wave->initialize(host); + wave = new Sine(); + wave->host = host; envelope->initialize(host); } -float *multiply(float *target, float *modulation, uint32_t size) { +void multiply(float *target, float *modulation, uint32_t size) { for (uint32_t i = 0; i < size; i++) { target[i] *= modulation[i]; } - return target; +} + +void add(float *target, float *other, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] += other[i]; + } } void Instrument::render(float *buffer, uint32_t count) { float *modulation = envelope->render(count); - wave->render(buffer, count); + float *waveform = wave->render(count); + multiply(waveform, modulation, count); + add(buffer, waveform, count); } void Instrument::startNote(float frequency) { @@ -29,7 +38,7 @@ } void Instrument::setWaveform(WaveformType waveform) { - // delete &wave; + Waveform *old = wave; switch (waveform) { case SINE: wave = new Sine(); @@ -38,5 +47,6 @@ wave = new Sawtooth(); break; } - wave->initialize(host); + wave->host = host; + delete old; } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 191c084..f15d631 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,8 +3,9 @@ class Instrument; +#include "effects/Envelope.h" +#include "waveforms/Waveform.h" #include "AudioHost.h" -#include "Envelope.h" class Instrument { private: @@ -13,14 +14,11 @@ Instrument(AudioHost *host); Envelope *const envelope = new Envelope(); - Waveform *wave = new Sine(); + Waveform *wave; void render(float *buffer, uint32_t count); - void startNote(float frequency); - void endNote(); - void setWaveform(WaveformType waveform); }; diff --git a/app/src/main/cpp/effects/Envelope.cpp b/app/src/main/cpp/effects/Envelope.cpp new file mode 100644 index 0000000..f8dfd61 --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.cpp @@ -0,0 +1,46 @@ +#include +#include "../Instrument.h" +#include "Envelope.h" + +void Envelope::initialize(AudioHost *host) { + attackIncrement = 1 / attack / host->sampleRate; + delayIncrement = 1 / delay / host->sampleRate; + releaseIncrement = 1 / release / host->sampleRate; +} + +void Envelope::startNote() { + phase = ATTACK; +} + +void Envelope::endNote() { + phase = RELEASE; +} + +void Envelope::doRender(uint32_t sampleCount) { + for (int i = 0; i < sampleCount; ++i) { + switch (phase) { + case ATTACK: + value += attackIncrement; + if (value > 1) { + value = 1; + phase = DELAY; + } + break; + case DELAY: + value -= delayIncrement; + if (value < sustain) { + value = sustain; + phase = SUSTAIN; + } + break; + case RELEASE: + value -= releaseIncrement; + if (value < 0) { + value = 0; + phase = NONE; + } + break; + } + buffer[i] = value; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Envelope.h b/app/src/main/cpp/effects/Envelope.h new file mode 100644 index 0000000..7076f8f --- /dev/null +++ b/app/src/main/cpp/effects/Envelope.h @@ -0,0 +1,32 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +class Envelope; + +#include +#include "../AudioHost.h" +#include "Processable.h" + +enum EnvelopePhase { + NONE, ATTACK, DELAY, SUSTAIN, RELEASE, +}; + +class Envelope : public Processable { +private: + EnvelopePhase phase; + float attackIncrement, delayIncrement, releaseIncrement; + float value = 0; +public: + float attack = 0.05, delay = 0.2, sustain = 0.75, release = 1; + + void initialize(AudioHost *host); + + void startNote(); + + void endNote(); + + void doRender(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.cpp b/app/src/main/cpp/effects/Processable.cpp new file mode 100644 index 0000000..f6c565a --- /dev/null +++ b/app/src/main/cpp/effects/Processable.cpp @@ -0,0 +1,13 @@ +#include "Processable.h" + +float *Processable::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + if (buffer) { + delete buffer; + } + buffer = new float[sampleCount]; + } + doRender(sampleCount); + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/effects/Processable.h b/app/src/main/cpp/effects/Processable.h new file mode 100644 index 0000000..bc38784 --- /dev/null +++ b/app/src/main/cpp/effects/Processable.h @@ -0,0 +1,18 @@ +#ifndef MUSIC_PROCESSABLE_H +#define MUSIC_PROCESSABLE_H + + +#include + +class Processable { +protected: + float *buffer = nullptr; + uint32_t bufferSize = 0; +public: + float *render(uint32_t sampleCount); + + virtual void doRender(uint32_t sampleCount) = 0; +}; + + +#endif diff --git a/app/src/main/cpp/waveforms/Sawtooth.cpp b/app/src/main/cpp/waveforms/Sawtooth.cpp index 3bfe814..de3d955 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.cpp +++ b/app/src/main/cpp/waveforms/Sawtooth.cpp @@ -1,16 +1,12 @@ #include "Sawtooth.h" -void Sawtooth::initialize(AudioHost *host) { - this->host = host; -} - void Sawtooth::setFrequency(float frequency) { step = 2 * frequency / (double) host->sampleRate; } -void Sawtooth::render(float *data, uint32_t frameCount) { +void Sawtooth::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += value * amplitude; + buffer[i] = value; value += step; if (value > 1) { value = -1; diff --git a/app/src/main/cpp/waveforms/Sawtooth.h b/app/src/main/cpp/waveforms/Sawtooth.h index b307371..498c27d 100644 --- a/app/src/main/cpp/waveforms/Sawtooth.h +++ b/app/src/main/cpp/waveforms/Sawtooth.h @@ -10,9 +10,7 @@ private: float value = 0, step = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Sine.cpp b/app/src/main/cpp/waveforms/Sine.cpp index f692542..98969a2 100644 --- a/app/src/main/cpp/waveforms/Sine.cpp +++ b/app/src/main/cpp/waveforms/Sine.cpp @@ -3,17 +3,13 @@ #include #include -void Sine::initialize(AudioHost *host) { - this->host = host; -} - void Sine::setFrequency(float frequency) { phaseStep = (2 * M_PI * frequency) / (double) host->sampleRate; } -void Sine::render(float *data, uint32_t frameCount) { +void Sine::renderWaveform(uint32_t frameCount) { for (uint32_t i = 0; i < frameCount; i++) { - data[i] += (float) (sin(phase) * amplitude); + buffer[i] = sin(phase); phase += phaseStep; if (phase > 2 * M_PI) { phase -= 2 * M_PI; diff --git a/app/src/main/cpp/waveforms/Sine.h b/app/src/main/cpp/waveforms/Sine.h index 93dc620..ba727f4 100644 --- a/app/src/main/cpp/waveforms/Sine.h +++ b/app/src/main/cpp/waveforms/Sine.h @@ -4,16 +4,13 @@ class Sine; #include -#include "../AudioHost.h" #include "Waveform.h" class Sine : public Waveform { private: float phaseStep, phase = 0; public: - void initialize(AudioHost *host); - - void render(float *data, uint32_t frameCount); + void renderWaveform(uint32_t frameCount); void setFrequency(float freq); }; diff --git a/app/src/main/cpp/waveforms/Waveform.cpp b/app/src/main/cpp/waveforms/Waveform.cpp new file mode 100644 index 0000000..64e0991 --- /dev/null +++ b/app/src/main/cpp/waveforms/Waveform.cpp @@ -0,0 +1,8 @@ +#include "Waveform.h" + +void Waveform::doRender(uint32_t sampleCount) { + renderWaveform(sampleCount); + for (uint32_t i = 0; i < sampleCount; i++) { + buffer[i] *= amplitude; + } +} \ No newline at end of file diff --git a/app/src/main/cpp/waveforms/Waveform.h b/app/src/main/cpp/waveforms/Waveform.h index 4f94b8e..a70ed39 100644 --- a/app/src/main/cpp/waveforms/Waveform.h +++ b/app/src/main/cpp/waveforms/Waveform.h @@ -1,20 +1,24 @@ #ifndef MUSIC_WAVEFORM_H #define MUSIC_WAVEFORM_H +class Waveform; + enum WaveformType { SINE = 0, SAWTOOTH = 1, }; -class Waveform { -protected: - AudioHost *host; +#include "../effects/Processable.h" +#include "../AudioHost.h" + +class Waveform : public Processable { public: - float amplitude = 0.3f; + float amplitude = 0.0f; + AudioHost *host; - virtual void initialize(AudioHost *host) = 0; + void doRender(uint32_t sampleCount); - virtual void render(float *data, uint32_t frameCount) = 0; + virtual void renderWaveform(uint32_t sampleCount) = 0; virtual void setFrequency(float freq) = 0; }; diff --git a/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt b/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt index d524f58..98888de 100644 --- a/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/InternalInstrument.kt @@ -12,7 +12,7 @@ set(value) { field = value setInstrumentWaveform(id, value.id) - println("set instrument to $value") + active = active } fun startNote(frequency: Double) { diff --git a/app/src/main/res/layout/fragment_instrument.xml b/app/src/main/res/layout/fragment_instrument.xml index 13222a3..c08b868 100644 --- a/app/src/main/res/layout/fragment_instrument.xml +++ b/app/src/main/res/layout/fragment_instrument.xml @@ -59,7 +59,6 @@ android:layout_marginTop="16dp" android:layout_marginEnd="16dp" android:contentDescription="@string/instrument_type_description" - android:entries="@array/waveforms" android:minHeight="48dp" android:spinnerMode="dropdown" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f55f3ab..83f27ab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,8 +7,4 @@ active select the instrument waveform edit this instrument\'s properties - - Sine - Sawtooth - \ No newline at end of file