diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + buffer[i] = value; + } + return buffer; +} \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + void startNote(); + + void endNote(); + + float *render(uint32_t sampleCount); +}; + + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + 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 f17846b..9e200d8 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,9 +1,27 @@ #include "Instrument.h" Instrument::Instrument(AudioHost *host) { - this->wave = new SineWave(host); + wave->initialize(host); +} + +float *multiply(float *target, float *modulation, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] *= modulation[i]; + } + return target; } void Instrument::render(float *buffer, uint32_t count) { - this->wave->render(buffer, count); + float *modulation = envelope->render(count); + wave->render(buffer, count); + multiply(buffer, modulation, count); +} + +void Instrument::startNote(float frequency) { + wave->setFrequency(frequency); + envelope->startNote(); +} + +void Instrument::endNote(float frequency) { + envelope->endNote(); } \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + 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 f17846b..9e200d8 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,9 +1,27 @@ #include "Instrument.h" Instrument::Instrument(AudioHost *host) { - this->wave = new SineWave(host); + wave->initialize(host); +} + +float *multiply(float *target, float *modulation, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] *= modulation[i]; + } + return target; } void Instrument::render(float *buffer, uint32_t count) { - this->wave->render(buffer, count); + float *modulation = envelope->render(count); + wave->render(buffer, count); + multiply(buffer, modulation, count); +} + +void Instrument::startNote(float frequency) { + wave->setFrequency(frequency); + envelope->startNote(); +} + +void Instrument::endNote(float frequency) { + envelope->endNote(); } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 9f9f901..8fecbd1 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,13 +3,22 @@ class Instrument; +#include "SineWave.h" #include "AudioHost.h" +#include "Envelope.h" class Instrument { public: Instrument(AudioHost *host); - SineWave *wave; + + Envelope *const envelope = new Envelope(); + SineWave *const wave = new SineWave(); + void render(float *buffer, uint32_t count); + + void startNote(float frequency); + + void endNote(float frequency); }; -#endif //MUSIC_INSTRUMENT_H +#endif diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + 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 f17846b..9e200d8 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,9 +1,27 @@ #include "Instrument.h" Instrument::Instrument(AudioHost *host) { - this->wave = new SineWave(host); + wave->initialize(host); +} + +float *multiply(float *target, float *modulation, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] *= modulation[i]; + } + return target; } void Instrument::render(float *buffer, uint32_t count) { - this->wave->render(buffer, count); + float *modulation = envelope->render(count); + wave->render(buffer, count); + multiply(buffer, modulation, count); +} + +void Instrument::startNote(float frequency) { + wave->setFrequency(frequency); + envelope->startNote(); +} + +void Instrument::endNote(float frequency) { + envelope->endNote(); } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 9f9f901..8fecbd1 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,13 +3,22 @@ class Instrument; +#include "SineWave.h" #include "AudioHost.h" +#include "Envelope.h" class Instrument { public: Instrument(AudioHost *host); - SineWave *wave; + + Envelope *const envelope = new Envelope(); + SineWave *const wave = new SineWave(); + void render(float *buffer, uint32_t count); + + void startNote(float frequency); + + void endNote(float frequency); }; -#endif //MUSIC_INSTRUMENT_H +#endif diff --git a/app/src/main/cpp/JavaFunctions.cpp b/app/src/main/cpp/JavaFunctions.cpp index af3f819..4e70c26 100644 --- a/app/src/main/cpp/JavaFunctions.cpp +++ b/app/src/main/cpp/JavaFunctions.cpp @@ -45,7 +45,25 @@ JNIEXPORT void JNICALL Java_com_lukas_music_instruments_Instrument_setInstrumentActive(JNIEnv *env, jobject thiz, jint id, jboolean active) { - Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), id)); + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); instrument->wave->amplitude = active ? 0.3 : 0.0; } +} +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_startNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->startNote(frequency); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_endNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->endNote(frequency); } \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + 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 f17846b..9e200d8 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,9 +1,27 @@ #include "Instrument.h" Instrument::Instrument(AudioHost *host) { - this->wave = new SineWave(host); + wave->initialize(host); +} + +float *multiply(float *target, float *modulation, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] *= modulation[i]; + } + return target; } void Instrument::render(float *buffer, uint32_t count) { - this->wave->render(buffer, count); + float *modulation = envelope->render(count); + wave->render(buffer, count); + multiply(buffer, modulation, count); +} + +void Instrument::startNote(float frequency) { + wave->setFrequency(frequency); + envelope->startNote(); +} + +void Instrument::endNote(float frequency) { + envelope->endNote(); } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 9f9f901..8fecbd1 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,13 +3,22 @@ class Instrument; +#include "SineWave.h" #include "AudioHost.h" +#include "Envelope.h" class Instrument { public: Instrument(AudioHost *host); - SineWave *wave; + + Envelope *const envelope = new Envelope(); + SineWave *const wave = new SineWave(); + void render(float *buffer, uint32_t count); + + void startNote(float frequency); + + void endNote(float frequency); }; -#endif //MUSIC_INSTRUMENT_H +#endif diff --git a/app/src/main/cpp/JavaFunctions.cpp b/app/src/main/cpp/JavaFunctions.cpp index af3f819..4e70c26 100644 --- a/app/src/main/cpp/JavaFunctions.cpp +++ b/app/src/main/cpp/JavaFunctions.cpp @@ -45,7 +45,25 @@ JNIEXPORT void JNICALL Java_com_lukas_music_instruments_Instrument_setInstrumentActive(JNIEnv *env, jobject thiz, jint id, jboolean active) { - Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), id)); + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); instrument->wave->amplitude = active ? 0.3 : 0.0; } +} +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_startNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->startNote(frequency); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_endNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->endNote(frequency); } \ No newline at end of file diff --git a/app/src/main/cpp/SineWave.cpp b/app/src/main/cpp/SineWave.cpp index 8b572b7..ac14843 100644 --- a/app/src/main/cpp/SineWave.cpp +++ b/app/src/main/cpp/SineWave.cpp @@ -1,8 +1,9 @@ +#include "AudioHost.h" #include "SineWave.h" #include #include -SineWave::SineWave(AudioHost *host) { +void SineWave::initialize(AudioHost *host) { this->host = host; } diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + 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 f17846b..9e200d8 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,9 +1,27 @@ #include "Instrument.h" Instrument::Instrument(AudioHost *host) { - this->wave = new SineWave(host); + wave->initialize(host); +} + +float *multiply(float *target, float *modulation, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] *= modulation[i]; + } + return target; } void Instrument::render(float *buffer, uint32_t count) { - this->wave->render(buffer, count); + float *modulation = envelope->render(count); + wave->render(buffer, count); + multiply(buffer, modulation, count); +} + +void Instrument::startNote(float frequency) { + wave->setFrequency(frequency); + envelope->startNote(); +} + +void Instrument::endNote(float frequency) { + envelope->endNote(); } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 9f9f901..8fecbd1 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,13 +3,22 @@ class Instrument; +#include "SineWave.h" #include "AudioHost.h" +#include "Envelope.h" class Instrument { public: Instrument(AudioHost *host); - SineWave *wave; + + Envelope *const envelope = new Envelope(); + SineWave *const wave = new SineWave(); + void render(float *buffer, uint32_t count); + + void startNote(float frequency); + + void endNote(float frequency); }; -#endif //MUSIC_INSTRUMENT_H +#endif diff --git a/app/src/main/cpp/JavaFunctions.cpp b/app/src/main/cpp/JavaFunctions.cpp index af3f819..4e70c26 100644 --- a/app/src/main/cpp/JavaFunctions.cpp +++ b/app/src/main/cpp/JavaFunctions.cpp @@ -45,7 +45,25 @@ JNIEXPORT void JNICALL Java_com_lukas_music_instruments_Instrument_setInstrumentActive(JNIEnv *env, jobject thiz, jint id, jboolean active) { - Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), id)); + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); instrument->wave->amplitude = active ? 0.3 : 0.0; } +} +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_startNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->startNote(frequency); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_endNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->endNote(frequency); } \ No newline at end of file diff --git a/app/src/main/cpp/SineWave.cpp b/app/src/main/cpp/SineWave.cpp index 8b572b7..ac14843 100644 --- a/app/src/main/cpp/SineWave.cpp +++ b/app/src/main/cpp/SineWave.cpp @@ -1,8 +1,9 @@ +#include "AudioHost.h" #include "SineWave.h" #include #include -SineWave::SineWave(AudioHost *host) { +void SineWave::initialize(AudioHost *host) { this->host = host; } diff --git a/app/src/main/cpp/SineWave.h b/app/src/main/cpp/SineWave.h index b13aab4..3d8df12 100644 --- a/app/src/main/cpp/SineWave.h +++ b/app/src/main/cpp/SineWave.h @@ -12,10 +12,10 @@ float frequency; AudioHost *host; public: - SineWave(AudioHost *host); + void initialize(AudioHost *host); float amplitude = 0.0f; void render(float *data, uint32_t frameCount); void setFrequency(float freq); }; -#endif //MUSIC_SINEWAVE_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + 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 f17846b..9e200d8 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,9 +1,27 @@ #include "Instrument.h" Instrument::Instrument(AudioHost *host) { - this->wave = new SineWave(host); + wave->initialize(host); +} + +float *multiply(float *target, float *modulation, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] *= modulation[i]; + } + return target; } void Instrument::render(float *buffer, uint32_t count) { - this->wave->render(buffer, count); + float *modulation = envelope->render(count); + wave->render(buffer, count); + multiply(buffer, modulation, count); +} + +void Instrument::startNote(float frequency) { + wave->setFrequency(frequency); + envelope->startNote(); +} + +void Instrument::endNote(float frequency) { + envelope->endNote(); } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 9f9f901..8fecbd1 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,13 +3,22 @@ class Instrument; +#include "SineWave.h" #include "AudioHost.h" +#include "Envelope.h" class Instrument { public: Instrument(AudioHost *host); - SineWave *wave; + + Envelope *const envelope = new Envelope(); + SineWave *const wave = new SineWave(); + void render(float *buffer, uint32_t count); + + void startNote(float frequency); + + void endNote(float frequency); }; -#endif //MUSIC_INSTRUMENT_H +#endif diff --git a/app/src/main/cpp/JavaFunctions.cpp b/app/src/main/cpp/JavaFunctions.cpp index af3f819..4e70c26 100644 --- a/app/src/main/cpp/JavaFunctions.cpp +++ b/app/src/main/cpp/JavaFunctions.cpp @@ -45,7 +45,25 @@ JNIEXPORT void JNICALL Java_com_lukas_music_instruments_Instrument_setInstrumentActive(JNIEnv *env, jobject thiz, jint id, jboolean active) { - Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), id)); + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); instrument->wave->amplitude = active ? 0.3 : 0.0; } +} +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_startNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->startNote(frequency); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_endNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->endNote(frequency); } \ No newline at end of file diff --git a/app/src/main/cpp/SineWave.cpp b/app/src/main/cpp/SineWave.cpp index 8b572b7..ac14843 100644 --- a/app/src/main/cpp/SineWave.cpp +++ b/app/src/main/cpp/SineWave.cpp @@ -1,8 +1,9 @@ +#include "AudioHost.h" #include "SineWave.h" #include #include -SineWave::SineWave(AudioHost *host) { +void SineWave::initialize(AudioHost *host) { this->host = host; } diff --git a/app/src/main/cpp/SineWave.h b/app/src/main/cpp/SineWave.h index b13aab4..3d8df12 100644 --- a/app/src/main/cpp/SineWave.h +++ b/app/src/main/cpp/SineWave.h @@ -12,10 +12,10 @@ float frequency; AudioHost *host; public: - SineWave(AudioHost *host); + void initialize(AudioHost *host); float amplitude = 0.0f; void render(float *data, uint32_t frameCount); void setFrequency(float freq); }; -#endif //MUSIC_SINEWAVE_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/MainActivity.kt b/app/src/main/java/com/lukas/music/MainActivity.kt index 1a534dd..89a97e6 100644 --- a/app/src/main/java/com/lukas/music/MainActivity.kt +++ b/app/src/main/java/com/lukas/music/MainActivity.kt @@ -1,15 +1,14 @@ package com.lukas.music -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle -import android.widget.Switch -import androidx.fragment.app.Fragment +import androidx.appcompat.app.AppCompatActivity import com.lukas.music.databinding.ActivityMainBinding -import com.lukas.music.ui.tab.TabAdapter +import com.lukas.music.instruments.Rhythm import com.lukas.music.ui.fragments.CreditsFragment import com.lukas.music.ui.fragments.InstrumentListFragment import com.lukas.music.ui.fragments.PlayFragment import com.lukas.music.ui.tab.PageListener +import com.lukas.music.ui.tab.TabAdapter import com.lukas.music.ui.tab.TabListener class MainActivity : AppCompatActivity() { @@ -25,6 +24,7 @@ binding.tabPager.registerOnPageChangeCallback(PageListener(binding.tabLayout)) binding.tabLayout.addOnTabSelectedListener(TabListener(binding.tabPager)) startAudio() + Rhythm.start() } companion object { diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + 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 f17846b..9e200d8 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,9 +1,27 @@ #include "Instrument.h" Instrument::Instrument(AudioHost *host) { - this->wave = new SineWave(host); + wave->initialize(host); +} + +float *multiply(float *target, float *modulation, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] *= modulation[i]; + } + return target; } void Instrument::render(float *buffer, uint32_t count) { - this->wave->render(buffer, count); + float *modulation = envelope->render(count); + wave->render(buffer, count); + multiply(buffer, modulation, count); +} + +void Instrument::startNote(float frequency) { + wave->setFrequency(frequency); + envelope->startNote(); +} + +void Instrument::endNote(float frequency) { + envelope->endNote(); } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 9f9f901..8fecbd1 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,13 +3,22 @@ class Instrument; +#include "SineWave.h" #include "AudioHost.h" +#include "Envelope.h" class Instrument { public: Instrument(AudioHost *host); - SineWave *wave; + + Envelope *const envelope = new Envelope(); + SineWave *const wave = new SineWave(); + void render(float *buffer, uint32_t count); + + void startNote(float frequency); + + void endNote(float frequency); }; -#endif //MUSIC_INSTRUMENT_H +#endif diff --git a/app/src/main/cpp/JavaFunctions.cpp b/app/src/main/cpp/JavaFunctions.cpp index af3f819..4e70c26 100644 --- a/app/src/main/cpp/JavaFunctions.cpp +++ b/app/src/main/cpp/JavaFunctions.cpp @@ -45,7 +45,25 @@ JNIEXPORT void JNICALL Java_com_lukas_music_instruments_Instrument_setInstrumentActive(JNIEnv *env, jobject thiz, jint id, jboolean active) { - Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), id)); + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); instrument->wave->amplitude = active ? 0.3 : 0.0; } +} +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_startNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->startNote(frequency); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_endNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->endNote(frequency); } \ No newline at end of file diff --git a/app/src/main/cpp/SineWave.cpp b/app/src/main/cpp/SineWave.cpp index 8b572b7..ac14843 100644 --- a/app/src/main/cpp/SineWave.cpp +++ b/app/src/main/cpp/SineWave.cpp @@ -1,8 +1,9 @@ +#include "AudioHost.h" #include "SineWave.h" #include #include -SineWave::SineWave(AudioHost *host) { +void SineWave::initialize(AudioHost *host) { this->host = host; } diff --git a/app/src/main/cpp/SineWave.h b/app/src/main/cpp/SineWave.h index b13aab4..3d8df12 100644 --- a/app/src/main/cpp/SineWave.h +++ b/app/src/main/cpp/SineWave.h @@ -12,10 +12,10 @@ float frequency; AudioHost *host; public: - SineWave(AudioHost *host); + void initialize(AudioHost *host); float amplitude = 0.0f; void render(float *data, uint32_t frameCount); void setFrequency(float freq); }; -#endif //MUSIC_SINEWAVE_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/MainActivity.kt b/app/src/main/java/com/lukas/music/MainActivity.kt index 1a534dd..89a97e6 100644 --- a/app/src/main/java/com/lukas/music/MainActivity.kt +++ b/app/src/main/java/com/lukas/music/MainActivity.kt @@ -1,15 +1,14 @@ package com.lukas.music -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle -import android.widget.Switch -import androidx.fragment.app.Fragment +import androidx.appcompat.app.AppCompatActivity import com.lukas.music.databinding.ActivityMainBinding -import com.lukas.music.ui.tab.TabAdapter +import com.lukas.music.instruments.Rhythm import com.lukas.music.ui.fragments.CreditsFragment import com.lukas.music.ui.fragments.InstrumentListFragment import com.lukas.music.ui.fragments.PlayFragment import com.lukas.music.ui.tab.PageListener +import com.lukas.music.ui.tab.TabAdapter import com.lukas.music.ui.tab.TabListener class MainActivity : AppCompatActivity() { @@ -25,6 +24,7 @@ binding.tabPager.registerOnPageChangeCallback(PageListener(binding.tabLayout)) binding.tabLayout.addOnTabSelectedListener(TabListener(binding.tabPager)) startAudio() + Rhythm.start() } companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index a3000b7..a73439d 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,7 +2,7 @@ import com.lukas.music.databinding.FragmentInstrumentBinding -class Instrument(val name: String, frequency: Double) { +class Instrument(val name: String, var frequency: Double) { private val id = createInstrument() private var active = false @@ -16,14 +16,33 @@ binding.floatingActionButton2.setOnClickListener { println("click instrument $name") } - binding.activeSwitch.setOnCheckedChangeListener {_, newActive -> + binding.activeSwitch.setOnCheckedChangeListener { _, newActive -> active = newActive setInstrumentActive(id, newActive) } binding.activeSwitch.isChecked = active } + fun startNote(frequency: Double) { + startNote(id, frequency) + } + + fun endNote(frequency: Double) { + endNote(id, frequency) + } + private external fun createInstrument(): Int private external fun setInstrumentFrequency(id: Int, frequency: Double) private external fun setInstrumentActive(id: Int, isActive: Boolean) + private external fun startNote(id: Int, frequency: Double) + private external fun endNote(id: Int, frequency: Double) + + companion object { + val instruments = + mutableListOf( + Instrument("A", 440.0), + Instrument("C#", 440 * 1.25), + Instrument("E", 440 * 1.5), + ) + } } \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + 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 f17846b..9e200d8 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,9 +1,27 @@ #include "Instrument.h" Instrument::Instrument(AudioHost *host) { - this->wave = new SineWave(host); + wave->initialize(host); +} + +float *multiply(float *target, float *modulation, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] *= modulation[i]; + } + return target; } void Instrument::render(float *buffer, uint32_t count) { - this->wave->render(buffer, count); + float *modulation = envelope->render(count); + wave->render(buffer, count); + multiply(buffer, modulation, count); +} + +void Instrument::startNote(float frequency) { + wave->setFrequency(frequency); + envelope->startNote(); +} + +void Instrument::endNote(float frequency) { + envelope->endNote(); } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 9f9f901..8fecbd1 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,13 +3,22 @@ class Instrument; +#include "SineWave.h" #include "AudioHost.h" +#include "Envelope.h" class Instrument { public: Instrument(AudioHost *host); - SineWave *wave; + + Envelope *const envelope = new Envelope(); + SineWave *const wave = new SineWave(); + void render(float *buffer, uint32_t count); + + void startNote(float frequency); + + void endNote(float frequency); }; -#endif //MUSIC_INSTRUMENT_H +#endif diff --git a/app/src/main/cpp/JavaFunctions.cpp b/app/src/main/cpp/JavaFunctions.cpp index af3f819..4e70c26 100644 --- a/app/src/main/cpp/JavaFunctions.cpp +++ b/app/src/main/cpp/JavaFunctions.cpp @@ -45,7 +45,25 @@ JNIEXPORT void JNICALL Java_com_lukas_music_instruments_Instrument_setInstrumentActive(JNIEnv *env, jobject thiz, jint id, jboolean active) { - Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), id)); + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); instrument->wave->amplitude = active ? 0.3 : 0.0; } +} +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_startNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->startNote(frequency); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_endNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->endNote(frequency); } \ No newline at end of file diff --git a/app/src/main/cpp/SineWave.cpp b/app/src/main/cpp/SineWave.cpp index 8b572b7..ac14843 100644 --- a/app/src/main/cpp/SineWave.cpp +++ b/app/src/main/cpp/SineWave.cpp @@ -1,8 +1,9 @@ +#include "AudioHost.h" #include "SineWave.h" #include #include -SineWave::SineWave(AudioHost *host) { +void SineWave::initialize(AudioHost *host) { this->host = host; } diff --git a/app/src/main/cpp/SineWave.h b/app/src/main/cpp/SineWave.h index b13aab4..3d8df12 100644 --- a/app/src/main/cpp/SineWave.h +++ b/app/src/main/cpp/SineWave.h @@ -12,10 +12,10 @@ float frequency; AudioHost *host; public: - SineWave(AudioHost *host); + void initialize(AudioHost *host); float amplitude = 0.0f; void render(float *data, uint32_t frameCount); void setFrequency(float freq); }; -#endif //MUSIC_SINEWAVE_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/MainActivity.kt b/app/src/main/java/com/lukas/music/MainActivity.kt index 1a534dd..89a97e6 100644 --- a/app/src/main/java/com/lukas/music/MainActivity.kt +++ b/app/src/main/java/com/lukas/music/MainActivity.kt @@ -1,15 +1,14 @@ package com.lukas.music -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle -import android.widget.Switch -import androidx.fragment.app.Fragment +import androidx.appcompat.app.AppCompatActivity import com.lukas.music.databinding.ActivityMainBinding -import com.lukas.music.ui.tab.TabAdapter +import com.lukas.music.instruments.Rhythm import com.lukas.music.ui.fragments.CreditsFragment import com.lukas.music.ui.fragments.InstrumentListFragment import com.lukas.music.ui.fragments.PlayFragment import com.lukas.music.ui.tab.PageListener +import com.lukas.music.ui.tab.TabAdapter import com.lukas.music.ui.tab.TabListener class MainActivity : AppCompatActivity() { @@ -25,6 +24,7 @@ binding.tabPager.registerOnPageChangeCallback(PageListener(binding.tabLayout)) binding.tabLayout.addOnTabSelectedListener(TabListener(binding.tabPager)) startAudio() + Rhythm.start() } companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index a3000b7..a73439d 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,7 +2,7 @@ import com.lukas.music.databinding.FragmentInstrumentBinding -class Instrument(val name: String, frequency: Double) { +class Instrument(val name: String, var frequency: Double) { private val id = createInstrument() private var active = false @@ -16,14 +16,33 @@ binding.floatingActionButton2.setOnClickListener { println("click instrument $name") } - binding.activeSwitch.setOnCheckedChangeListener {_, newActive -> + binding.activeSwitch.setOnCheckedChangeListener { _, newActive -> active = newActive setInstrumentActive(id, newActive) } binding.activeSwitch.isChecked = active } + fun startNote(frequency: Double) { + startNote(id, frequency) + } + + fun endNote(frequency: Double) { + endNote(id, frequency) + } + private external fun createInstrument(): Int private external fun setInstrumentFrequency(id: Int, frequency: Double) private external fun setInstrumentActive(id: Int, isActive: Boolean) + private external fun startNote(id: Int, frequency: Double) + private external fun endNote(id: Int, frequency: Double) + + companion object { + val instruments = + mutableListOf( + Instrument("A", 440.0), + Instrument("C#", 440 * 1.25), + Instrument("E", 440 * 1.5), + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt new file mode 100644 index 0000000..181ad4a --- /dev/null +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -0,0 +1,20 @@ +package com.lukas.music.instruments + +import java.util.* +import kotlin.concurrent.schedule + +object Rhythm { + var on = false + fun start() { + Timer().schedule(0, 500) { + on = !on + Instrument.instruments.forEach { + if (on) { + it.startNote(it.frequency) + } else { + it.endNote(it.frequency) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/cpp/AudioHost.cpp b/app/src/main/cpp/AudioHost.cpp index cf182be..359bb2d 100644 --- a/app/src/main/cpp/AudioHost.cpp +++ b/app/src/main/cpp/AudioHost.cpp @@ -4,25 +4,19 @@ #include const uint32_t bufferSize = 2; -static uint32_t sampleCount; -static float *buffer; - -void renderInstrument(Instrument * instrument) { - instrument->render(buffer, sampleCount); -} - aaudio_data_callback_result_t dataCallback( AAudioStream *stream, void *userData, void *audioData, - int32_t _sampleCount) { - sampleCount = _sampleCount; - buffer = static_cast(audioData); - for (uint32_t i = 0; i < _sampleCount; i++) { + int32_t sampleCount) { + float *buffer = static_cast(audioData); + for (uint32_t i = 0; i < sampleCount; i++) { buffer[i] = 0; } AudioHost *thiz = static_cast(userData); - std::for_each(thiz->instruments->begin(), thiz->instruments->end(), renderInstrument); + for (auto const &instrument: *thiz->instruments) { + instrument->render(buffer, sampleCount); + } return AAUDIO_CALLBACK_RESULT_CONTINUE; } diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 9d6721f..d1e0f76 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -11,6 +11,7 @@ JavaFunctions.cpp AudioHost.cpp Instrument.cpp + Envelope.cpp ) find_library( diff --git a/app/src/main/cpp/Envelope.cpp b/app/src/main/cpp/Envelope.cpp new file mode 100644 index 0000000..56e9316 --- /dev/null +++ b/app/src/main/cpp/Envelope.cpp @@ -0,0 +1,20 @@ +#include "Envelope.h" + +void Envelope::startNote() { + value = 1; +} + +void Envelope::endNote() { + value = 0; +} + +float *Envelope::render(uint32_t sampleCount) { + if (sampleCount > bufferSize) { + bufferSize = sampleCount; + buffer = new float[sampleCount]; + } + for (int i = 0; i < sampleCount; ++i) { + 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 new file mode 100644 index 0000000..57bdfeb --- /dev/null +++ b/app/src/main/cpp/Envelope.h @@ -0,0 +1,24 @@ +#ifndef MUSIC_ENVELOPE_H +#define MUSIC_ENVELOPE_H + +#include + +class Envelope; + +class Envelope { +private: + uint32_t bufferSize = 0; + float *buffer; +public: + float attack, delay, sustain, release; + float value = 1; + + 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 f17846b..9e200d8 100644 --- a/app/src/main/cpp/Instrument.cpp +++ b/app/src/main/cpp/Instrument.cpp @@ -1,9 +1,27 @@ #include "Instrument.h" Instrument::Instrument(AudioHost *host) { - this->wave = new SineWave(host); + wave->initialize(host); +} + +float *multiply(float *target, float *modulation, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + target[i] *= modulation[i]; + } + return target; } void Instrument::render(float *buffer, uint32_t count) { - this->wave->render(buffer, count); + float *modulation = envelope->render(count); + wave->render(buffer, count); + multiply(buffer, modulation, count); +} + +void Instrument::startNote(float frequency) { + wave->setFrequency(frequency); + envelope->startNote(); +} + +void Instrument::endNote(float frequency) { + envelope->endNote(); } \ No newline at end of file diff --git a/app/src/main/cpp/Instrument.h b/app/src/main/cpp/Instrument.h index 9f9f901..8fecbd1 100644 --- a/app/src/main/cpp/Instrument.h +++ b/app/src/main/cpp/Instrument.h @@ -3,13 +3,22 @@ class Instrument; +#include "SineWave.h" #include "AudioHost.h" +#include "Envelope.h" class Instrument { public: Instrument(AudioHost *host); - SineWave *wave; + + Envelope *const envelope = new Envelope(); + SineWave *const wave = new SineWave(); + void render(float *buffer, uint32_t count); + + void startNote(float frequency); + + void endNote(float frequency); }; -#endif //MUSIC_INSTRUMENT_H +#endif diff --git a/app/src/main/cpp/JavaFunctions.cpp b/app/src/main/cpp/JavaFunctions.cpp index af3f819..4e70c26 100644 --- a/app/src/main/cpp/JavaFunctions.cpp +++ b/app/src/main/cpp/JavaFunctions.cpp @@ -45,7 +45,25 @@ JNIEXPORT void JNICALL Java_com_lukas_music_instruments_Instrument_setInstrumentActive(JNIEnv *env, jobject thiz, jint id, jboolean active) { - Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), id)); + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); instrument->wave->amplitude = active ? 0.3 : 0.0; } +} +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_startNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->startNote(frequency); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_lukas_music_instruments_Instrument_endNote(JNIEnv *env, jobject thiz, + jint id, jdouble frequency) { + Instrument *instrument = static_cast(listGet(audioHost->instruments->begin(), + id)); + instrument->endNote(frequency); } \ No newline at end of file diff --git a/app/src/main/cpp/SineWave.cpp b/app/src/main/cpp/SineWave.cpp index 8b572b7..ac14843 100644 --- a/app/src/main/cpp/SineWave.cpp +++ b/app/src/main/cpp/SineWave.cpp @@ -1,8 +1,9 @@ +#include "AudioHost.h" #include "SineWave.h" #include #include -SineWave::SineWave(AudioHost *host) { +void SineWave::initialize(AudioHost *host) { this->host = host; } diff --git a/app/src/main/cpp/SineWave.h b/app/src/main/cpp/SineWave.h index b13aab4..3d8df12 100644 --- a/app/src/main/cpp/SineWave.h +++ b/app/src/main/cpp/SineWave.h @@ -12,10 +12,10 @@ float frequency; AudioHost *host; public: - SineWave(AudioHost *host); + void initialize(AudioHost *host); float amplitude = 0.0f; void render(float *data, uint32_t frameCount); void setFrequency(float freq); }; -#endif //MUSIC_SINEWAVE_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/MainActivity.kt b/app/src/main/java/com/lukas/music/MainActivity.kt index 1a534dd..89a97e6 100644 --- a/app/src/main/java/com/lukas/music/MainActivity.kt +++ b/app/src/main/java/com/lukas/music/MainActivity.kt @@ -1,15 +1,14 @@ package com.lukas.music -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle -import android.widget.Switch -import androidx.fragment.app.Fragment +import androidx.appcompat.app.AppCompatActivity import com.lukas.music.databinding.ActivityMainBinding -import com.lukas.music.ui.tab.TabAdapter +import com.lukas.music.instruments.Rhythm import com.lukas.music.ui.fragments.CreditsFragment import com.lukas.music.ui.fragments.InstrumentListFragment import com.lukas.music.ui.fragments.PlayFragment import com.lukas.music.ui.tab.PageListener +import com.lukas.music.ui.tab.TabAdapter import com.lukas.music.ui.tab.TabListener class MainActivity : AppCompatActivity() { @@ -25,6 +24,7 @@ binding.tabPager.registerOnPageChangeCallback(PageListener(binding.tabLayout)) binding.tabLayout.addOnTabSelectedListener(TabListener(binding.tabPager)) startAudio() + Rhythm.start() } companion object { diff --git a/app/src/main/java/com/lukas/music/instruments/Instrument.kt b/app/src/main/java/com/lukas/music/instruments/Instrument.kt index a3000b7..a73439d 100644 --- a/app/src/main/java/com/lukas/music/instruments/Instrument.kt +++ b/app/src/main/java/com/lukas/music/instruments/Instrument.kt @@ -2,7 +2,7 @@ import com.lukas.music.databinding.FragmentInstrumentBinding -class Instrument(val name: String, frequency: Double) { +class Instrument(val name: String, var frequency: Double) { private val id = createInstrument() private var active = false @@ -16,14 +16,33 @@ binding.floatingActionButton2.setOnClickListener { println("click instrument $name") } - binding.activeSwitch.setOnCheckedChangeListener {_, newActive -> + binding.activeSwitch.setOnCheckedChangeListener { _, newActive -> active = newActive setInstrumentActive(id, newActive) } binding.activeSwitch.isChecked = active } + fun startNote(frequency: Double) { + startNote(id, frequency) + } + + fun endNote(frequency: Double) { + endNote(id, frequency) + } + private external fun createInstrument(): Int private external fun setInstrumentFrequency(id: Int, frequency: Double) private external fun setInstrumentActive(id: Int, isActive: Boolean) + private external fun startNote(id: Int, frequency: Double) + private external fun endNote(id: Int, frequency: Double) + + companion object { + val instruments = + mutableListOf( + Instrument("A", 440.0), + Instrument("C#", 440 * 1.25), + Instrument("E", 440 * 1.5), + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/instruments/Rhythm.kt b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt new file mode 100644 index 0000000..181ad4a --- /dev/null +++ b/app/src/main/java/com/lukas/music/instruments/Rhythm.kt @@ -0,0 +1,20 @@ +package com.lukas.music.instruments + +import java.util.* +import kotlin.concurrent.schedule + +object Rhythm { + var on = false + fun start() { + Timer().schedule(0, 500) { + on = !on + Instrument.instruments.forEach { + if (on) { + it.startNote(it.frequency) + } else { + it.endNote(it.frequency) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lukas/music/ui/InstrumentAdapter.kt b/app/src/main/java/com/lukas/music/ui/InstrumentAdapter.kt index 1125b74..f772787 100644 --- a/app/src/main/java/com/lukas/music/ui/InstrumentAdapter.kt +++ b/app/src/main/java/com/lukas/music/ui/InstrumentAdapter.kt @@ -11,13 +11,6 @@ class InstrumentViewHolder(val binding: FragmentInstrumentBinding) : RecyclerView.ViewHolder(binding.root) - private val instruments = - mutableListOf( - Instrument("A", 440.0), - Instrument("C#", 440 * 1.25), - Instrument("E", 440 * 1.5), - ) - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): InstrumentViewHolder { val context = parent.context val inflater = LayoutInflater.from(context) @@ -26,11 +19,11 @@ } override fun onBindViewHolder(holder: InstrumentViewHolder, position: Int) { - val instrument = instruments[position] + val instrument = Instrument.instruments[position] instrument.applyToView(holder.binding) } override fun getItemCount(): Int { - return instruments.size + return Instrument.instruments.size } } \ No newline at end of file