From 782ab237acb53b71bae1525a71709826168089fe Mon Sep 17 00:00:00 2001 From: Georgi Gerganov Date: Mon, 30 May 2022 22:01:38 +0300 Subject: [PATCH] ggwave : remove header dependency --- examples/CMakeLists.txt | 1 + examples/arduino-rx-web/arduino-rx-web.cpp | 43 +++--- examples/arduino-tx/arduino-tx.ino | 108 +++++++------- examples/ggwave-cli/main.cpp | 8 +- examples/ggwave-common-sdl2.cpp | 25 ++-- examples/ggwave-to-file/main.cpp | 12 +- examples/r2t2/main.cpp | 6 +- examples/r2t2/r2t2-rx.cpp | 28 ++-- examples/spectrogram/main.cpp | 10 +- include/ggwave/ggwave.h | 19 ++- src/ggwave.cpp | 161 ++++++++++---------- tests/test-ggwave.c | 10 +- tests/test-ggwave.cpp | 166 +++++++++------------ 13 files changed, 283 insertions(+), 314 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c2e2efa..f7e7bf3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -88,6 +88,7 @@ else() add_subdirectory(ggwave-to-file) add_subdirectory(arduino-rx) + add_subdirectory(arduino-tx) endif() if (GGWAVE_SUPPORT_SDL2) diff --git a/examples/arduino-rx-web/arduino-rx-web.cpp b/examples/arduino-rx-web/arduino-rx-web.cpp index 5672c7a..907a0e8 100644 --- a/examples/arduino-rx-web/arduino-rx-web.cpp +++ b/examples/arduino-rx-web/arduino-rx-web.cpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace { @@ -257,14 +258,6 @@ bool GGWave_mainLoop() { return false; } - static GGWave::CBWaveformOut cbWaveformOut = [&](const void * data, uint32_t nBytes) { - SDL_QueueAudio(g_devIdOut, data, nBytes); - }; - - static GGWave::CBWaveformInp cbWaveformInp = [&](void * data, uint32_t nMaxBytes) { - return SDL_DequeueAudio(g_devIdInp, data, nMaxBytes); - }; - if (g_ggWave->hasTxData() == false) { SDL_PauseAudioDevice(g_devIdOut, SDL_FALSE); @@ -273,22 +266,29 @@ bool GGWave_mainLoop() { if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesOut()) { SDL_PauseAudioDevice(g_devIdInp, SDL_FALSE); - if (::getTime_ms(tLastNoData, tNow) > 500.0f) { - g_ggWave->decode(cbWaveformInp); + const int nHave = (int) SDL_GetQueuedAudioSize(g_devIdInp); + const int nNeed = g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp(); + if (::getTime_ms(tLastNoData, tNow) > 500.0f && nHave >= nNeed) { + static std::vector dataInp(nNeed); + SDL_DequeueAudio(g_devIdInp, dataInp.data(), nNeed); - GGWave::TxRxData rxData; - int n = g_ggWave->takeRxData(rxData); - if (n > 0) { - for (int i = 0; i < n; i++) { - rxData[i] ^= kDSSMagic[i%kDSSMagic.size()]; + if (g_ggWave->decode(dataInp.data(), dataInp.size()) == false) { + fprintf(stderr, "Warning: failed to decode input data!\n"); + } else { + GGWave::TxRxData rxData; + int n = g_ggWave->takeRxData(rxData); + if (n > 0) { + for (int i = 0; i < n; i++) { + rxData[i] ^= kDSSMagic[i%kDSSMagic.size()]; + } + std::time_t timestamp = std::time(nullptr); + std::string tstr = std::asctime(std::localtime(×tamp)); + tstr.back() = 0; + printf("[%s] Received: '%s'\n", tstr.c_str(), rxData.data()); } - std::time_t timestamp = std::time(nullptr); - std::string tstr = std::asctime(std::localtime(×tamp)); - tstr.back() = 0; - printf("[%s] Received: '%s'\n", tstr.c_str(), rxData.data()); } - if ((int) SDL_GetQueuedAudioSize(g_devIdInp) > 32*g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp()) { + if (nHave > 32*nNeed) { fprintf(stderr, "Warning: slow processing, clearing queued audio buffer of %d bytes ...", SDL_GetQueuedAudioSize(g_devIdInp)); SDL_ClearQueuedAudio(g_devIdInp); } @@ -302,7 +302,8 @@ bool GGWave_mainLoop() { SDL_PauseAudioDevice(g_devIdOut, SDL_TRUE); SDL_PauseAudioDevice(g_devIdInp, SDL_TRUE); - g_ggWave->encode(cbWaveformOut); + const auto nBytes = g_ggWave->encode(); + SDL_QueueAudio(g_devIdOut, g_ggWave->txData(), nBytes); } return true; diff --git a/examples/arduino-tx/arduino-tx.ino b/examples/arduino-tx/arduino-tx.ino index 080631e..7673097 100644 --- a/examples/arduino-tx/arduino-tx.ino +++ b/examples/arduino-tx/arduino-tx.ino @@ -1,4 +1,6 @@ -#include "ggwave.h" +#include + +#include "ggwave/ggwave.h" const int kPinLed0 = 13; const int kPinSpeaker = 10; @@ -6,53 +8,53 @@ const int kPinButton0 = 2; const int kPinButton1 = 4; void setup() { - Serial.begin(57600); + //Serial.begin(57600); - pinMode(kPinLed0, OUTPUT); - pinMode(kPinSpeaker, OUTPUT); - pinMode(kPinButton0, INPUT); - pinMode(kPinButton1, INPUT); + //pinMode(kPinLed0, OUTPUT); + //pinMode(kPinSpeaker, OUTPUT); + //pinMode(kPinButton0, INPUT); + //pinMode(kPinButton1, INPUT); - delay(3000); + //delay(3000); - digitalWrite(kPinLed0, HIGH); - GGWave::send_text(kPinSpeaker, "Hello!", GGWave::TX_ARDUINO_512_FASTEST); - digitalWrite(kPinLed0, LOW); + //digitalWrite(kPinLed0, HIGH); + //GGWave::send_text(kPinSpeaker, "Hello!", GGWave::TX_ARDUINO_512_FASTEST); + //digitalWrite(kPinLed0, LOW); - delay(2000); + //delay(2000); - digitalWrite(kPinLed0, HIGH); - GGWave::send_text(kPinSpeaker, "This is a", GGWave::TX_ARDUINO_512_FASTEST); - GGWave::send_text(kPinSpeaker, "ggwave demo", GGWave::TX_ARDUINO_512_FASTEST); - digitalWrite(kPinLed0, LOW); + //digitalWrite(kPinLed0, HIGH); + //GGWave::send_text(kPinSpeaker, "This is a", GGWave::TX_ARDUINO_512_FASTEST); + //GGWave::send_text(kPinSpeaker, "ggwave demo", GGWave::TX_ARDUINO_512_FASTEST); + //digitalWrite(kPinLed0, LOW); - delay(2000); + //delay(2000); - digitalWrite(kPinLed0, HIGH); - GGWave::send_text(kPinSpeaker, "The arduino", GGWave::TX_ARDUINO_512_FASTEST); - delay(200); - GGWave::send_text(kPinSpeaker, "transmits data", GGWave::TX_ARDUINO_512_FASTEST); - delay(200); - GGWave::send_text(kPinSpeaker, "using sound", GGWave::TX_ARDUINO_512_FASTEST); - delay(200); - GGWave::send_text(kPinSpeaker, "through a buzzer", GGWave::TX_ARDUINO_512_FASTEST); - digitalWrite(kPinLed0, LOW); + //digitalWrite(kPinLed0, HIGH); + //GGWave::send_text(kPinSpeaker, "The arduino", GGWave::TX_ARDUINO_512_FASTEST); + //delay(200); + //GGWave::send_text(kPinSpeaker, "transmits data", GGWave::TX_ARDUINO_512_FASTEST); + //delay(200); + //GGWave::send_text(kPinSpeaker, "using sound", GGWave::TX_ARDUINO_512_FASTEST); + //delay(200); + //GGWave::send_text(kPinSpeaker, "through a buzzer", GGWave::TX_ARDUINO_512_FASTEST); + //digitalWrite(kPinLed0, LOW); - delay(1000); + //delay(1000); - digitalWrite(kPinLed0, HIGH); - GGWave::send_text(kPinSpeaker, "The sound is", GGWave::TX_ARDUINO_512_FASTEST); - delay(200); - GGWave::send_text(kPinSpeaker, "decoded in a", GGWave::TX_ARDUINO_512_FASTEST); - delay(200); - GGWave::send_text(kPinSpeaker, "web page.", GGWave::TX_ARDUINO_512_FASTEST); - digitalWrite(kPinLed0, LOW); + //digitalWrite(kPinLed0, HIGH); + //GGWave::send_text(kPinSpeaker, "The sound is", GGWave::TX_ARDUINO_512_FASTEST); + //delay(200); + //GGWave::send_text(kPinSpeaker, "decoded in a", GGWave::TX_ARDUINO_512_FASTEST); + //delay(200); + //GGWave::send_text(kPinSpeaker, "web page.", GGWave::TX_ARDUINO_512_FASTEST); + //digitalWrite(kPinLed0, LOW); - delay(1000); + //delay(1000); - digitalWrite(kPinLed0, HIGH); - GGWave::send_text(kPinSpeaker, "Press the button!", GGWave::TX_ARDUINO_512_FASTEST); - digitalWrite(kPinLed0, LOW); + //digitalWrite(kPinLed0, HIGH); + //GGWave::send_text(kPinSpeaker, "Press the button!", GGWave::TX_ARDUINO_512_FASTEST); + //digitalWrite(kPinLed0, LOW); } char txt[16]; @@ -62,23 +64,23 @@ bool isDown = false; void loop() { Serial.println("hello"); - int but0 = digitalRead(kPinButton0); - int but1 = digitalRead(kPinButton1); + //int but0 = digitalRead(kPinButton0); + //int but1 = digitalRead(kPinButton1); - if (but1 == LOW && isDown == false) { - delay(200); - ++pressed; - isDown = true; - } else if (but1 == HIGH) { - isDown = false; - } + //if (but1 == LOW && isDown == false) { + // delay(200); + // ++pressed; + // isDown = true; + //} else if (but1 == HIGH) { + // isDown = false; + //} - if (but0 == LOW) { - snprintf(txt, 16, "Pressed: %d", pressed); + //if (but0 == LOW) { + // snprintf(txt, 16, "Pressed: %d", pressed); - digitalWrite(kPinLed0, HIGH); - GGWave::send_text(kPinSpeaker, txt, GGWave::TX_ARDUINO_512_FASTEST); - digitalWrite(kPinLed0, LOW); - pressed = 0; - } + // digitalWrite(kPinLed0, HIGH); + // GGWave::send_text(kPinSpeaker, txt, GGWave::TX_ARDUINO_512_FASTEST); + // digitalWrite(kPinLed0, LOW); + // pressed = 0; + //} } diff --git a/examples/ggwave-cli/main.cpp b/examples/ggwave-cli/main.cpp index ddd9d2a..9ed5b35 100644 --- a/examples/ggwave-cli/main.cpp +++ b/examples/ggwave-cli/main.cpp @@ -62,11 +62,11 @@ int main(int argc, char** argv) { if (printTones) { printf("Printing generated waveform tones (Hz):\n"); - auto waveformTones = ggWave->getWaveformTones(); - for (int i = 0; i < (int) waveformTones.size(); ++i) { + const auto tones = ggWave->txTones(); + for (int i = 0; i < (int) tones.size(); ++i) { printf(" - frame %3d: ", i); - for (int j = 0; j < (int) waveformTones[i].size(); ++j) { - printf("%8.2f ", waveformTones[i][j].freq_hz); + for (int j = 0; j < (int) tones[i].size(); ++j) { + printf("%8.2f ", tones[i][j].freq_hz); } printf("\n"); } diff --git a/examples/ggwave-common-sdl2.cpp b/examples/ggwave-common-sdl2.cpp index 27a82bc..68b03c9 100644 --- a/examples/ggwave-common-sdl2.cpp +++ b/examples/ggwave-common-sdl2.cpp @@ -240,14 +240,6 @@ bool GGWave_mainLoop() { return false; } - static GGWave::CBWaveformOut cbWaveformOut = [&](const void * data, uint32_t nBytes) { - SDL_QueueAudio(g_devIdOut, data, nBytes); - }; - - static GGWave::CBWaveformInp cbWaveformInp = [&](void * data, uint32_t nMaxBytes) { - return SDL_DequeueAudio(g_devIdInp, data, nMaxBytes); - }; - if (g_ggWave->hasTxData() == false) { SDL_PauseAudioDevice(g_devIdOut, SDL_FALSE); @@ -256,9 +248,17 @@ bool GGWave_mainLoop() { if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesOut()) { SDL_PauseAudioDevice(g_devIdInp, SDL_FALSE); - if (::getTime_ms(tLastNoData, tNow) > 500.0f) { - g_ggWave->decode(cbWaveformInp); - if ((int) SDL_GetQueuedAudioSize(g_devIdInp) > 32*g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp()) { + const int nHave = (int) SDL_GetQueuedAudioSize(g_devIdInp); + const int nNeed = g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp(); + if (::getTime_ms(tLastNoData, tNow) > 500.0f && nHave >= nNeed) { + static std::vector dataInp(nNeed); + SDL_DequeueAudio(g_devIdInp, dataInp.data(), nNeed); + + if (g_ggWave->decode(dataInp.data(), dataInp.size()) == false) { + fprintf(stderr, "Warning: failed to decode input data!\n"); + } + + if (nHave > 32*nNeed) { fprintf(stderr, "Warning: slow processing, clearing queued audio buffer of %d bytes ...\n", SDL_GetQueuedAudioSize(g_devIdInp)); SDL_ClearQueuedAudio(g_devIdInp); } @@ -272,7 +272,8 @@ bool GGWave_mainLoop() { SDL_PauseAudioDevice(g_devIdOut, SDL_TRUE); SDL_PauseAudioDevice(g_devIdInp, SDL_TRUE); - g_ggWave->encode(cbWaveformOut); + const auto nBytes = g_ggWave->encode(); + SDL_QueueAudio(g_devIdOut, g_ggWave->txData(), nBytes); } return true; diff --git a/examples/ggwave-to-file/main.cpp b/examples/ggwave-to-file/main.cpp index 9a7e14f..5e53a6b 100644 --- a/examples/ggwave-to-file/main.cpp +++ b/examples/ggwave-to-file/main.cpp @@ -84,17 +84,15 @@ int main(int argc, char** argv) { }); ggWave.init(message.size(), message.data(), ggWave.getTxProtocol(protocolId), volume); - std::vector bufferPCM; - GGWave::CBWaveformOut cbWaveformOut = [&](const void * data, uint32_t nBytes) { - bufferPCM.resize(nBytes); - std::memcpy(bufferPCM.data(), data, nBytes); - }; - - if (ggWave.encode(cbWaveformOut) == false) { + const auto nBytes = ggWave.encode(); + if (nBytes == 0) { fprintf(stderr, "Failed to generate waveform!\n"); return -4; } + std::vector bufferPCM(nBytes); + std::memcpy(bufferPCM.data(), ggWave.txData(), nBytes); + fprintf(stderr, "Output size = %d bytes\n", (int) bufferPCM.size()); drwav_data_format format; diff --git a/examples/r2t2/main.cpp b/examples/r2t2/main.cpp index 7d6d1ea..670413e 100644 --- a/examples/r2t2/main.cpp +++ b/examples/r2t2/main.cpp @@ -132,14 +132,12 @@ int main(int argc, char** argv) { } ggWave.init(message.size(), message.data(), protocols.at(GGWave::TxProtocolId(txProtocolId)), 10); - - GGWave::CBWaveformOut tmp = [](const void * , uint32_t ){}; - ggWave.encode(tmp); + ggWave.encode(); int nFrames = 0; double lastF = -1.0f; - auto tones = ggWave.getWaveformTones(); + auto tones = ggWave.txTones(); for (auto & tonesCur : tones) { if (tonesCur.size() == 0) continue; const auto & tone = tonesCur.front(); diff --git a/examples/r2t2/r2t2-rx.cpp b/examples/r2t2/r2t2-rx.cpp index d479758..cfee5e2 100644 --- a/examples/r2t2/r2t2-rx.cpp +++ b/examples/r2t2/r2t2-rx.cpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace { @@ -247,14 +248,6 @@ bool GGWave_mainLoop() { return false; } - static GGWave::CBWaveformOut cbWaveformOut = [&](const void * data, uint32_t nBytes) { - SDL_QueueAudio(g_devIdOut, data, nBytes); - }; - - static GGWave::CBWaveformInp cbWaveformInp = [&](void * data, uint32_t nMaxBytes) { - return SDL_DequeueAudio(g_devIdInp, data, nMaxBytes); - }; - if (g_ggWave->hasTxData() == false) { SDL_PauseAudioDevice(g_devIdOut, SDL_FALSE); @@ -263,10 +256,18 @@ bool GGWave_mainLoop() { if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesOut()) { SDL_PauseAudioDevice(g_devIdInp, SDL_FALSE); - if (::getTime_ms(tLastNoData, tNow) > 500.0f) { - g_ggWave->decode(cbWaveformInp); - if ((int) SDL_GetQueuedAudioSize(g_devIdInp) > 32*g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp()) { - fprintf(stderr, "Warning: slow processing, clearing queued audio buffer of %d bytes ...", SDL_GetQueuedAudioSize(g_devIdInp)); + const int nHave = (int) SDL_GetQueuedAudioSize(g_devIdInp); + const int nNeed = g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp(); + if (::getTime_ms(tLastNoData, tNow) > 500.0f && nHave >= nNeed) { + static std::vector dataInp(nNeed); + SDL_DequeueAudio(g_devIdInp, dataInp.data(), nNeed); + + if (g_ggWave->decode(dataInp.data(), dataInp.size()) == false) { + fprintf(stderr, "Warning: failed to decode input data!\n"); + } + + if (nHave > 32*nNeed) { + fprintf(stderr, "Warning: slow processing, clearing queued audio buffer of %d bytes ...\n", SDL_GetQueuedAudioSize(g_devIdInp)); SDL_ClearQueuedAudio(g_devIdInp); } } else { @@ -279,7 +280,8 @@ bool GGWave_mainLoop() { SDL_PauseAudioDevice(g_devIdOut, SDL_TRUE); SDL_PauseAudioDevice(g_devIdInp, SDL_TRUE); - g_ggWave->encode(cbWaveformOut); + const auto nBytes = g_ggWave->encode(); + SDL_QueueAudio(g_devIdOut, g_ggWave->txData(), nBytes); } return true; diff --git a/examples/spectrogram/main.cpp b/examples/spectrogram/main.cpp index 9595ff1..be15c05 100644 --- a/examples/spectrogram/main.cpp +++ b/examples/spectrogram/main.cpp @@ -173,14 +173,6 @@ bool GGWave_mainLoop() { return false; } - static GGWave::CBWaveformOut cbQueueAudio = [&](const void * data, uint32_t nBytes) { - SDL_QueueAudio(g_devIdOut, data, nBytes); - }; - - static GGWave::CBWaveformInp cbWaveformInp = [&](void * data, uint32_t nMaxBytes) { - return SDL_DequeueAudio(g_devIdInp, data, nMaxBytes); - }; - SDL_PauseAudioDevice(g_devIdInp, SDL_FALSE); if (!g_isCapturing) { SDL_ClearQueuedAudio(g_devIdInp); @@ -190,7 +182,7 @@ bool GGWave_mainLoop() { static float data[g_nSamplesPerFrame]; static float out[2*g_nSamplesPerFrame]; do { - n = cbWaveformInp(data, sizeof(float)*g_nSamplesPerFrame); + n = SDL_DequeueAudio(g_devIdInp, data, sizeof(float)*g_nSamplesPerFrame); if (n <= 0) break; FFT(data, out, g_nSamplesPerFrame, 1.0); diff --git a/include/ggwave/ggwave.h b/include/ggwave/ggwave.h index 971fef0..0720b1b 100644 --- a/include/ggwave/ggwave.h +++ b/include/ggwave/ggwave.h @@ -152,7 +152,8 @@ extern "C" { // volume - the volume of the generated waveform [0, 100] // usually 25 is OK and you should not go over 50 // outputBuffer - the generated audio waveform. must be big enough to fit the generated data - // query - if != 0, do not perform encoding. + // query - if == 0, encode data in to outputBuffer, returns number of bytes + // if != 0, do not perform encoding. // if == 1, return waveform size in bytes // if != 1, return waveform size in samples // @@ -300,7 +301,6 @@ extern "C" { // #include -#include #include #include @@ -367,8 +367,8 @@ public: float duration_ms; }; - using Tones = std::vector; - using WaveformTones = std::vector; + using TonesPerFrame = std::vector; + using Tones = std::vector; using AmplitudeData = std::vector; using AmplitudeDataI16 = std::vector; @@ -376,9 +376,6 @@ public: using RecordedData = std::vector; using TxRxData = std::vector; - using CBWaveformOut = std::function; - using CBWaveformInp = std::function; - GGWave(const Parameters & parameters); ~GGWave(); @@ -425,14 +422,16 @@ public: // // returns false if the encoding fails // - bool encode(const CBWaveformOut & cbWaveformOut); + uint32_t encode(); + + const void * txData() const; // decode an audio waveform // // This methods calls cbWaveformInp multiple times (at least once) until it returns 0. // Use the Rx methods to check if any data was decoded successfully. // - void decode(const CBWaveformInp & cbWaveformInp); + bool decode(const void * data, uint32_t nBytes); // instance state bool hasTxData() const; @@ -456,7 +455,7 @@ public: // // Call this method after calling encode() to get a list of the tones participating in the generated waveform // - const WaveformTones & getWaveformTones() const; + const Tones & txTones() const; bool takeTxAmplitudeI16(AmplitudeDataI16 & dst); diff --git a/src/ggwave.cpp b/src/ggwave.cpp index e0c4133..908d025 100644 --- a/src/ggwave.cpp +++ b/src/ggwave.cpp @@ -94,21 +94,16 @@ int ggwave_encode( return ggWave->encodeSize_samples(); } - int nSamples = 0; - - GGWave::CBWaveformOut cbWaveformOut = [&](const void * data, uint32_t nBytes) { - char * p = (char *) data; - std::copy(p, p + nBytes, outputBuffer); - - nSamples = nBytes/ggWave->getSampleSizeBytesOut(); - }; - - if (ggWave->encode(cbWaveformOut) == false) { + const int nBytes = ggWave->encode(); + if (nBytes == 0) { ggprintf("Failed to encode data - GGWave instance %d\n", instance); return -1; } - return nSamples; + const auto p = (char *) ggWave->txData(); + std::copy(p, p + nBytes, outputBuffer); + + return nBytes; } extern "C" @@ -119,17 +114,10 @@ int ggwave_decode( char * outputBuffer) { GGWave * ggWave = (GGWave *) g_instances[instance]; - GGWave::CBWaveformInp cbWaveformInp = [&](void * data, uint32_t nMaxBytes) -> uint32_t { - uint32_t nCopied = std::min((uint32_t) dataSize, nMaxBytes); - std::copy(dataBuffer, dataBuffer + nCopied, (char *) data); - - dataSize -= nCopied; - dataBuffer += nCopied; - - return nCopied; - }; - - ggWave->decode(cbWaveformInp); + if (ggWave->decode(dataBuffer, dataSize) == false) { + ggprintf("Failed to decode data - GGWave instance %d\n", instance); + return -1; + } // TODO : avoid allocation GGWave::TxRxData rxData; @@ -155,17 +143,10 @@ int ggwave_ndecode( // TODO : avoid duplicated code GGWave * ggWave = (GGWave *) g_instances[instance]; - GGWave::CBWaveformInp cbWaveformInp = [&](void * data, uint32_t nMaxBytes) -> uint32_t { - uint32_t nCopied = std::min((uint32_t) dataSize, nMaxBytes); - std::copy(dataBuffer, dataBuffer + nCopied, (char *) data); - - dataSize -= nCopied; - dataBuffer += nCopied; - - return nCopied; - }; - - ggWave->decode(cbWaveformInp); + if (ggWave->decode(dataBuffer, dataSize) == false) { + ggprintf("Failed to decode data - GGWave instance %d\n", instance); + return -1; + } // TODO : avoid allocation GGWave::TxRxData rxData; @@ -411,7 +392,7 @@ struct GGWave::Tx { TxRxData outputBlockTmp; AmplitudeDataI16 outputBlockI16; - WaveformTones waveformTones; + Tones tones; }; void GGWave::setLogFile(FILE * fptr) { @@ -460,7 +441,11 @@ GGWave::GGWave(const Parameters & parameters) : m_txOnlyTones (parameters.operatingMode & GGWAVE_OPERATING_MODE_TX_ONLY_TONES), // common - m_dataEncoded (kMaxDataSize) { + m_dataEncoded (kMaxDataSize), + + m_rx(nullptr), + m_tx(nullptr), + m_resampler(nullptr) { if (m_sampleSizeBytesInp == 0) { ggprintf("Invalid or unsupported capture sample format: %d\n", (int) parameters.sampleFormatInp); @@ -561,7 +546,7 @@ GGWave::GGWave(const Parameters & parameters) : } // TODO - // m_tx->waveformTones; + // m_tx->tones; } // pre-allocate Reed-Solomon memory buffers @@ -715,10 +700,10 @@ uint32_t GGWave::encodeSize_samples() const { )*samplesPerFrameOut; } -bool GGWave::encode(const CBWaveformOut & cbWaveformOut) { +uint32_t GGWave::encode() { if (m_isTxEnabled == false) { ggprintf("Tx is disabled - cannot transmit data with this ggwave instance\n"); - return false; + return 0; } if (m_resampler) { @@ -744,18 +729,18 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) { int frameId = 0; bool hasNewData = m_tx->hasNewTxData; - m_tx->waveformTones.clear(); + m_tx->tones.clear(); while (hasNewData) { - m_tx->waveformTones.push_back({}); + m_tx->tones.push_back({}); if (frameId < m_nMarkerFrames) { for (int i = 0; i < m_nBitsInMarker; ++i) { - m_tx->waveformTones.back().push_back({}); - m_tx->waveformTones.back().back().duration_ms = (1000.0*m_samplesPerFrame)/m_sampleRate; + m_tx->tones.back().push_back({}); + m_tx->tones.back().back().duration_ms = (1000.0*m_samplesPerFrame)/m_sampleRate; if (i%2 == 0) { - m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i); + m_tx->tones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i); } else { - m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i) + m_hzPerSample; + m_tx->tones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i) + m_hzPerSample; } } } else if (frameId < m_nMarkerFrames + totalDataFrames) { @@ -789,22 +774,22 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) { for (int k = 0; k < 2*m_tx->txProtocol.bytesPerTx*16; ++k) { if (m_tx->dataBits[k] == 0) continue; - m_tx->waveformTones.back().push_back({}); - m_tx->waveformTones.back().back().duration_ms = (1000.0*m_samplesPerFrame)/m_sampleRate; + m_tx->tones.back().push_back({}); + m_tx->tones.back().back().duration_ms = (1000.0*m_samplesPerFrame)/m_sampleRate; if (k%2) { - m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, k/2) + m_hzPerSample; + m_tx->tones.back().back().freq_hz = bitFreq(m_tx->txProtocol, k/2) + m_hzPerSample; } else { - m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, k/2); + m_tx->tones.back().back().freq_hz = bitFreq(m_tx->txProtocol, k/2); } } } else if (frameId < m_nMarkerFrames + totalDataFrames + m_nMarkerFrames) { for (int i = 0; i < m_nBitsInMarker; ++i) { - m_tx->waveformTones.back().push_back({}); - m_tx->waveformTones.back().back().duration_ms = (1000.0*m_samplesPerFrame)/m_sampleRate; + m_tx->tones.back().push_back({}); + m_tx->tones.back().back().duration_ms = (1000.0*m_samplesPerFrame)/m_sampleRate; if (i%2 == 0) { - m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i) + m_hzPerSample; + m_tx->tones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i) + m_hzPerSample; } else { - m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i); + m_tx->tones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i); } } } else { @@ -988,35 +973,53 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) { offset += samplesPerFrameOut; } + m_tx->lastAmplitudeSize = offset; + + // the encoded waveform can be accessed via the txData() method + // we return the size of the waveform in bytes: + return offset*m_sampleSizeBytesOut; +} + +const void * GGWave::txData() const { + if (m_tx == nullptr) { + ggprintf("Tx is disabled - cannot transmit data with this ggwave instance\n"); + return nullptr; + } + switch (m_sampleFormatOut) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: break; case GGWAVE_SAMPLE_FORMAT_I16: { - cbWaveformOut(m_tx->outputBlockI16.data(), offset*m_sampleSizeBytesOut); + return m_tx->outputBlockI16.data(); } break; case GGWAVE_SAMPLE_FORMAT_U8: case GGWAVE_SAMPLE_FORMAT_I8: case GGWAVE_SAMPLE_FORMAT_U16: case GGWAVE_SAMPLE_FORMAT_F32: { - cbWaveformOut(m_tx->outputBlockTmp.data(), offset*m_sampleSizeBytesOut); + return m_tx->outputBlockTmp.data(); } break; } - m_tx->lastAmplitudeSize = offset; - - return true; + return nullptr; } -void GGWave::decode(const CBWaveformInp & cbWaveformInp) { +bool GGWave::decode(const void * data, uint32_t nBytes) { if (m_isRxEnabled == false) { ggprintf("Rx is disabled - cannot receive data with this ggwave instance\n"); - return; + return false; } - while (!m_tx || m_tx->hasNewTxData == false) { + if (m_tx && m_tx->hasNewTxData) { + ggprintf("Cannot decode while transmitting\n"); + return false; + } + + auto dataBuffer = (uint8_t *) data; + const float factor = m_sampleRateInp/m_sampleRate; + + while (true) { // read capture data - float factor = m_sampleRateInp/m_sampleRate; uint32_t nBytesNeeded = m_rx->samplesNeeded*m_sampleSizeBytesInp; if (m_sampleRateInp != m_sampleRate) { @@ -1024,7 +1027,11 @@ void GGWave::decode(const CBWaveformInp & cbWaveformInp) { nBytesNeeded = (m_resampler->resample(1.0f/factor, m_rx->samplesNeeded, m_rx->sampleAmplitudeResampled.data(), nullptr) + 4)*m_sampleSizeBytesInp; } - uint32_t nBytesRecorded = 0; + const uint32_t nBytesRecorded = std::min(nBytes, nBytesNeeded); + + if (nBytesRecorded == 0) { + break; + } switch (m_sampleFormatInp) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: break; @@ -1033,14 +1040,17 @@ void GGWave::decode(const CBWaveformInp & cbWaveformInp) { case GGWAVE_SAMPLE_FORMAT_U16: case GGWAVE_SAMPLE_FORMAT_I16: { - nBytesRecorded = cbWaveformInp(m_rx->sampleAmplitudeTmp.data(), nBytesNeeded); + std::copy(dataBuffer, dataBuffer + nBytesRecorded, m_rx->sampleAmplitudeTmp.data()); } break; case GGWAVE_SAMPLE_FORMAT_F32: { - nBytesRecorded = cbWaveformInp(m_rx->sampleAmplitudeResampled.data(), nBytesNeeded); + std::copy(dataBuffer, dataBuffer + nBytesRecorded, (uint8_t *) m_rx->sampleAmplitudeResampled.data()); } break; } + dataBuffer += nBytesRecorded; + nBytes -= nBytesRecorded; + if (nBytesRecorded % m_sampleSizeBytesInp != 0) { ggprintf("Failure during capture - provided bytes (%d) are not multiple of sample size (%d)\n", nBytesRecorded, m_sampleSizeBytesInp); @@ -1048,13 +1058,6 @@ void GGWave::decode(const CBWaveformInp & cbWaveformInp) { break; } - if (nBytesRecorded > nBytesNeeded) { - ggprintf("Failure during capture - more samples were provided (%d) than requested (%d)\n", - nBytesRecorded/m_sampleSizeBytesInp, nBytesNeeded/m_sampleSizeBytesInp); - m_rx->samplesNeeded = m_samplesPerFrame; - break; - } - // convert to 32-bit float int nSamplesRecorded = nBytesRecorded/m_sampleSizeBytesInp; switch (m_sampleFormatInp) { @@ -1094,10 +1097,6 @@ void GGWave::decode(const CBWaveformInp & cbWaveformInp) { case GGWAVE_SAMPLE_FORMAT_F32: break; } - if (nSamplesRecorded == 0) { - break; - } - uint32_t offset = m_samplesPerFrame - m_rx->samplesNeeded; if (m_sampleRateInp != m_sampleRate) { @@ -1140,6 +1139,8 @@ void GGWave::decode(const CBWaveformInp & cbWaveformInp) { break; } } + + return true; } // @@ -1161,7 +1162,7 @@ GGWave::SampleFormat GGWave::getSampleFormatOut() const { return m_sampleFormatO // Tx // -const GGWave::WaveformTones & GGWave::getWaveformTones() const { return m_tx->waveformTones; } +const GGWave::Tones & GGWave::txTones() const { return m_tx->tones; } bool GGWave::takeTxAmplitudeI16(AmplitudeDataI16 & dst) { if (m_tx->lastAmplitudeSize == 0) return false; @@ -1506,7 +1507,7 @@ void GGWave::decode_variable() { uint8_t curByte = 0; for (int i = 0; i < 2*rxProtocol.bytesPerTx; ++i) { double freq = m_hzPerSample*rxProtocol.freqStart; - int bin = std::round(freq*m_ihzPerSample) + 16*i; + int bin = round(freq*m_ihzPerSample) + 16*i; int kmax = 0; double amax = 0.0; @@ -1604,7 +1605,7 @@ void GGWave::decode_variable() { for (int i = 0; i < m_nBitsInMarker; ++i) { double freq = bitFreq(rxProtocol.second, i); - int bin = std::round(freq*m_ihzPerSample); + int bin = round(freq*m_ihzPerSample); if (i%2 == 0) { if (m_rx->sampleSpectrum[bin] <= m_soundMarkerThreshold*m_rx->sampleSpectrum[bin + m_freqDelta_bin]) --nDetectedMarkerBits; @@ -1653,7 +1654,7 @@ void GGWave::decode_variable() { for (int i = 0; i < m_nBitsInMarker; ++i) { double freq = bitFreq(rxProtocol.second, i); - int bin = std::round(freq*m_ihzPerSample); + int bin = round(freq*m_ihzPerSample); if (i%2 == 0) { if (m_rx->sampleSpectrum[bin] >= m_soundMarkerThreshold*m_rx->sampleSpectrum[bin + m_freqDelta_bin]) nDetectedMarkerBits--; @@ -1708,7 +1709,7 @@ void GGWave::decode_fixed() { // float -> uint8_t //m_rx->spectrumHistoryFixed[m_rx->historyIdFixed] = m_rx->sampleSpectrum; for (int i = 0; i < m_samplesPerFrame; ++i) { - m_rx->spectrumHistoryFixed[m_rx->historyIdFixed][i] = std::min(255.0f, std::max(0.0f, std::round(m_rx->sampleSpectrum[i]/amax*255.0f))); + m_rx->spectrumHistoryFixed[m_rx->historyIdFixed][i] = std::min(255.0, std::max(0.0, round(m_rx->sampleSpectrum[i]/amax*255.0f))); } if (++m_rx->historyIdFixed >= (int) m_rx->spectrumHistoryFixed.size()) { diff --git a/tests/test-ggwave.c b/tests/test-ggwave.c index 9f30f22..b972936 100644 --- a/tests/test-ggwave.c +++ b/tests/test-ggwave.c @@ -34,25 +34,25 @@ int main() { CHECK(ne > 0); // not enough output buffer size to store the decoded message - ret = ggwave_ndecode(instance, waveform, sizeof(signed short)*ne, decoded, 3); + ret = ggwave_ndecode(instance, waveform, ne, decoded, 3); CHECK(ret == -2); // fail // just enough size to store it - ret = ggwave_ndecode(instance, waveform, sizeof(signed short)*ne, decoded, 4); + ret = ggwave_ndecode(instance, waveform, ne, decoded, 4); CHECK(ret == 4); // success // unsafe method - will write the decoded output to the output buffer regardless of the size - ret = ggwave_decode(instance, waveform, sizeof(signed short)*ne, decoded); + ret = ggwave_decode(instance, waveform, ne, decoded); CHECK(ret == 4); // disable Rx protocol ggwave_toggleRxProtocol(instance, GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST, 0); - ret = ggwave_ndecode(instance, waveform, sizeof(signed short)*ne, decoded, 4); + ret = ggwave_ndecode(instance, waveform, ne, decoded, 4); CHECK(ret == -1); // fail // enable Rx protocol ggwave_toggleRxProtocol(instance, GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST, 1); - ret = ggwave_ndecode(instance, waveform, sizeof(signed short)*ne, decoded, 4); + ret = ggwave_ndecode(instance, waveform, ne, decoded, 4); CHECK(ret == 4); // success decoded[ret] = 0; // null-terminate the received data diff --git a/tests/test-ggwave.cpp b/tests/test-ggwave.cpp index 83d4ff3..5b4ef53 100644 --- a/tests/test-ggwave.cpp +++ b/tests/test-ggwave.cpp @@ -44,35 +44,18 @@ const std::set kFormats = { GGWAVE_SAMPLE_FORMAT_F32, }; -template -GGWave::CBWaveformOut getCBWaveformOut(uint32_t & nSamples, std::vector & buffer) { - return [&nSamples, &buffer](const void * data, uint32_t nBytes) { - nSamples = nBytes/sizeof(T); - CHECK(nSamples*sizeof(T) == nBytes); - buffer.resize(nSamples); - std::copy((char *) data, (char *) data + nBytes, (char *) buffer.data()); - }; -} - -template -GGWave::CBWaveformInp getCBWaveformInp(uint32_t & nSamples, std::vector & buffer) { - return [&nSamples, &buffer](void * data, uint32_t nMaxBytes) { - uint32_t nCopied = std::min((uint32_t) (nSamples*sizeof(T)), nMaxBytes); - const char * p = (char *) (buffer.data() + buffer.size() - nSamples); - std::copy(p, p + nCopied, (char *) data); - nSamples -= nCopied/sizeof(T); - - return nCopied; - }; -} - template -void convert(const std::vector & src, std::vector & dst) { - int n = src.size(); - dst.resize(n); +void convert(std::vector & src) { + const int n = src.size()/sizeof(S); + std::vector dst(n); + S v; for (int i = 0; i < n; ++i) { - dst[i] = ((float(src[i]) - kSampleOffset.at(typeid(S)))/kSampleScale.at(typeid(S)))*kSampleScale.at(typeid(D)) + kSampleOffset.at(typeid(D)); + std::memcpy(&v, &src[i*sizeof(S)], sizeof(S)); + dst[i] = ((float(v) - kSampleOffset.at(typeid(S)))/kSampleScale.at(typeid(S)))*kSampleScale.at(typeid(D)) + kSampleOffset.at(typeid(D)); } + + src.resize(n*sizeof(D)); + std::memcpy(&src[0], &dst[0], n*sizeof(D)); } int main(int argc, char ** argv) { @@ -83,11 +66,7 @@ int main(int argc, char ** argv) { } } - std::vector bufferU8; - std::vector bufferI8; - std::vector bufferU16; - std::vector bufferI16; - std::vector bufferF32; + std::vector buffer; auto convertHelper = [&](GGWave::SampleFormat formatOut, GGWave::SampleFormat formatInp) { switch (formatOut) { @@ -97,53 +76,53 @@ int main(int argc, char ** argv) { switch (formatInp) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: CHECK(false); break; case GGWAVE_SAMPLE_FORMAT_U8: break; - case GGWAVE_SAMPLE_FORMAT_I8: convert(bufferU8, bufferI8); break; - case GGWAVE_SAMPLE_FORMAT_U16: convert(bufferU8, bufferU16); break; - case GGWAVE_SAMPLE_FORMAT_I16: convert(bufferU8, bufferI16); break; - case GGWAVE_SAMPLE_FORMAT_F32: convert(bufferU8, bufferF32); break; + case GGWAVE_SAMPLE_FORMAT_I8: convert (buffer); break; + case GGWAVE_SAMPLE_FORMAT_U16: convert(buffer); break; + case GGWAVE_SAMPLE_FORMAT_I16: convert (buffer); break; + case GGWAVE_SAMPLE_FORMAT_F32: convert (buffer); break; }; } break; case GGWAVE_SAMPLE_FORMAT_I8: { switch (formatInp) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: CHECK(false); break; - case GGWAVE_SAMPLE_FORMAT_U8: convert(bufferI8, bufferU8); break; + case GGWAVE_SAMPLE_FORMAT_U8: convert (buffer); break; case GGWAVE_SAMPLE_FORMAT_I8: break; - case GGWAVE_SAMPLE_FORMAT_U16: convert(bufferI8, bufferU16); break; - case GGWAVE_SAMPLE_FORMAT_I16: convert(bufferI8, bufferI16); break; - case GGWAVE_SAMPLE_FORMAT_F32: convert(bufferI8, bufferF32); break; + case GGWAVE_SAMPLE_FORMAT_U16: convert(buffer); break; + case GGWAVE_SAMPLE_FORMAT_I16: convert (buffer); break; + case GGWAVE_SAMPLE_FORMAT_F32: convert (buffer); break; }; } break; case GGWAVE_SAMPLE_FORMAT_U16: { switch (formatInp) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: CHECK(false); break; - case GGWAVE_SAMPLE_FORMAT_U8: convert(bufferU16, bufferU8); break; - case GGWAVE_SAMPLE_FORMAT_I8: convert(bufferU16, bufferI8); break; + case GGWAVE_SAMPLE_FORMAT_U8: convert(buffer); break; + case GGWAVE_SAMPLE_FORMAT_I8: convert (buffer); break; case GGWAVE_SAMPLE_FORMAT_U16: break; - case GGWAVE_SAMPLE_FORMAT_I16: convert(bufferU16, bufferI16); break; - case GGWAVE_SAMPLE_FORMAT_F32: convert(bufferU16, bufferF32); break; + case GGWAVE_SAMPLE_FORMAT_I16: convert(buffer); break; + case GGWAVE_SAMPLE_FORMAT_F32: convert (buffer); break; }; } break; case GGWAVE_SAMPLE_FORMAT_I16: { switch (formatInp) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: CHECK(false); break; - case GGWAVE_SAMPLE_FORMAT_U8: convert(bufferI16, bufferU8); break; - case GGWAVE_SAMPLE_FORMAT_I8: convert(bufferI16, bufferI8); break; - case GGWAVE_SAMPLE_FORMAT_U16: convert(bufferI16, bufferU16); break; + case GGWAVE_SAMPLE_FORMAT_U8: convert (buffer); break; + case GGWAVE_SAMPLE_FORMAT_I8: convert (buffer); break; + case GGWAVE_SAMPLE_FORMAT_U16: convert(buffer); break; case GGWAVE_SAMPLE_FORMAT_I16: break; - case GGWAVE_SAMPLE_FORMAT_F32: convert(bufferI16, bufferF32); break; + case GGWAVE_SAMPLE_FORMAT_F32: convert (buffer); break; }; } break; case GGWAVE_SAMPLE_FORMAT_F32: { switch (formatInp) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: CHECK(false); break; - case GGWAVE_SAMPLE_FORMAT_U8: convert(bufferF32, bufferU8); break; - case GGWAVE_SAMPLE_FORMAT_I8: convert(bufferF32, bufferI8); break; - case GGWAVE_SAMPLE_FORMAT_U16: convert(bufferF32, bufferU16); break; - case GGWAVE_SAMPLE_FORMAT_I16: convert(bufferF32, bufferI16); break; + case GGWAVE_SAMPLE_FORMAT_U8: convert (buffer); break; + case GGWAVE_SAMPLE_FORMAT_I8: convert (buffer); break; + case GGWAVE_SAMPLE_FORMAT_U16: convert(buffer); break; + case GGWAVE_SAMPLE_FORMAT_I16: convert (buffer); break; case GGWAVE_SAMPLE_FORMAT_F32: break; }; } break; @@ -155,55 +134,47 @@ int main(int argc, char ** argv) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: CHECK(false); break; case GGWAVE_SAMPLE_FORMAT_U8: { - for (auto & s : bufferU8) { - s = std::max(0.0f, std::min(255.0f, (float) s + (frand() - 0.5f)*(level*256))); + const int n = buffer.size()/sizeof(uint8_t); + auto p = (uint8_t *) buffer.data(); + for (int i = 0; i < n; ++i) { + p[i] = std::max(0.0f, std::min(255.0f, (float) p[i] + (frand() - 0.5f)*(level*256))); } } break; case GGWAVE_SAMPLE_FORMAT_I8: { - for (auto & s : bufferI8) { - s = std::max(-128.0f, std::min(127.0f, (float) s + (frand() - 0.5f)*(level*256))); + const int n = buffer.size()/sizeof(int8_t); + auto p = (int8_t *) buffer.data(); + for (int i = 0; i < n; ++i) { + p[i] = std::max(-128.0f, std::min(127.0f, (float) p[i] + (frand() - 0.5f)*(level*256))); } } break; case GGWAVE_SAMPLE_FORMAT_U16: { - for (auto & s : bufferU16) { - s = std::max(0.0f, std::min(65535.0f, (float) s + (frand() - 0.5f)*(level*65536))); + const int n = buffer.size()/sizeof(uint16_t); + auto p = (uint16_t *) buffer.data(); + for (int i = 0; i < n; ++i) { + p[i] = std::max(0.0f, std::min(65535.0f, (float) p[i] + (frand() - 0.5f)*(level*65536))); } } break; case GGWAVE_SAMPLE_FORMAT_I16: { - for (auto & s : bufferI16) { - s = std::max(-32768.0f, std::min(32767.0f, (float) s + (frand() - 0.5f)*(level*65536))); + const int n = buffer.size()/sizeof(int16_t); + auto p = (int16_t *) buffer.data(); + for (int i = 0; i < n; ++i) { + p[i] = std::max(-32768.0f, std::min(32767.0f, (float) p[i] + (frand() - 0.5f)*(level*65536))); } } break; case GGWAVE_SAMPLE_FORMAT_F32: { - for (auto & s : bufferF32) { - s = std::max(-1.0f, std::min(1.0f, (float) s + (frand() - 0.5f)*(level))); + const int n = buffer.size()/sizeof(float); + auto p = (float *) buffer.data(); + for (int i = 0; i < n; ++i) { + p[i] = std::max(-1.0f, std::min(1.0f, p[i] + (frand() - 0.5f)*(level))); } } break; }; }; - uint32_t nSamples = 0; - - const std::map kCBWaveformOut = { - { GGWAVE_SAMPLE_FORMAT_U8, getCBWaveformOut(nSamples, bufferU8) }, - { GGWAVE_SAMPLE_FORMAT_I8, getCBWaveformOut(nSamples, bufferI8) }, - { GGWAVE_SAMPLE_FORMAT_U16, getCBWaveformOut(nSamples, bufferU16) }, - { GGWAVE_SAMPLE_FORMAT_I16, getCBWaveformOut(nSamples, bufferI16) }, - { GGWAVE_SAMPLE_FORMAT_F32, getCBWaveformOut(nSamples, bufferF32) }, - }; - - const std::map kCBWaveformInp = { - { GGWAVE_SAMPLE_FORMAT_U8, getCBWaveformInp(nSamples, bufferU8) }, - { GGWAVE_SAMPLE_FORMAT_I8, getCBWaveformInp(nSamples, bufferI8) }, - { GGWAVE_SAMPLE_FORMAT_U16, getCBWaveformInp(nSamples, bufferU16) }, - { GGWAVE_SAMPLE_FORMAT_I16, getCBWaveformInp(nSamples, bufferI16) }, - { GGWAVE_SAMPLE_FORMAT_F32, getCBWaveformInp(nSamples, bufferF32) }, - }; - { GGWave instance(GGWave::getDefaultParameters()); @@ -234,7 +205,7 @@ int main(int argc, char ** argv) { auto parameters = GGWave::getDefaultParameters(); parameters.soundMarkerThreshold = 3.0f; - std::string payload = "hello123"; + const std::string payload = "hello123"; // encode { @@ -242,10 +213,11 @@ int main(int argc, char ** argv) { GGWave instanceOut(parameters); instanceOut.init(payload.c_str(), instanceOut.getTxProtocol(GGWAVE_TX_PROTOCOL_DT_FASTEST), 25); - auto expectedSize = instanceOut.encodeSize_samples(); - instanceOut.encode(kCBWaveformOut.at(parameters.sampleFormatOut)); - printf("Expected = %d, actual = %d\n", expectedSize, nSamples); - CHECK(expectedSize >= nSamples); + const auto expectedSize = instanceOut.encodeSize_bytes(); + const auto nBytes = instanceOut.encode(); + printf("Expected = %d, actual = %d\n", expectedSize, nBytes); + CHECK(expectedSize >= nBytes); + { auto p = (const uint8_t *)(instanceOut.txData()); buffer.resize(nBytes); memcpy(buffer.data(), p, nBytes); } addNoiseHelper(0.01, parameters.sampleFormatOut); // add some artificial noise convertHelper(parameters.sampleFormatOut, parameters.sampleFormatInp); } @@ -256,7 +228,7 @@ int main(int argc, char ** argv) { GGWave instanceInp(parameters); instanceInp.setRxProtocols({{GGWAVE_TX_PROTOCOL_DT_FASTEST, instanceInp.getTxProtocol(GGWAVE_TX_PROTOCOL_DT_FASTEST)}}); - instanceInp.decode(kCBWaveformInp.at(parameters.sampleFormatInp)); + instanceInp.decode(buffer.data(), buffer.size()); GGWave::TxRxData result; CHECK(instanceInp.takeRxData(result) == (int) payload.size()); @@ -266,7 +238,7 @@ int main(int argc, char ** argv) { } } - std::string payload = "a0Z5kR2g"; + const std::string payload = "a0Z5kR2g"; // encode / decode using different sample formats and Tx protocols for (const auto & formatOut : kFormats) { @@ -293,12 +265,13 @@ int main(int argc, char ** argv) { instance.setRxProtocols({{txProtocol.first, txProtocol.second}}); instance.init(length, payload.data(), txProtocol.second, 25); - auto expectedSize = instance.encodeSize_samples(); - instance.encode(kCBWaveformOut.at(formatOut)); - printf("Expected = %d, actual = %d\n", expectedSize, nSamples); - CHECK(expectedSize == nSamples); + const auto expectedSize = instance.encodeSize_bytes(); + const auto nBytes = instance.encode(); + printf("Expected = %d, actual = %d\n", expectedSize, nBytes); + CHECK(expectedSize == nBytes); + { auto p = (const uint8_t *)(instance.txData()); buffer.resize(nBytes); memcpy(buffer.data(), p, nBytes); } convertHelper(formatOut, formatInp); - instance.decode(kCBWaveformInp.at(formatInp)); + instance.decode(buffer.data(), buffer.size()); GGWave::TxRxData result; CHECK(instance.takeRxData(result) == length); @@ -319,12 +292,13 @@ int main(int argc, char ** argv) { instance.setRxProtocols({{txProtocol.first, txProtocol.second}}); instance.init(length, payload.data(), txProtocol.second, 10); - auto expectedSize = instance.encodeSize_samples(); - instance.encode(kCBWaveformOut.at(formatOut)); - printf("Expected = %d, actual = %d\n", expectedSize, nSamples); - CHECK(expectedSize == nSamples); + const auto expectedSize = instance.encodeSize_bytes(); + const auto nBytes = instance.encode(); + printf("Expected = %d, actual = %d\n", expectedSize, nBytes); + CHECK(expectedSize == nBytes); + { auto p = (const uint8_t *)(instance.txData()); buffer.resize(nBytes); memcpy(buffer.data(), p, nBytes); } convertHelper(formatOut, formatInp); - instance.decode(kCBWaveformInp.at(formatInp)); + instance.decode(buffer.data(), buffer.size()); GGWave::TxRxData result; CHECK(instance.takeRxData(result) == length);