diff --git a/CMakeLists.txt b/CMakeLists.txt index 7564505..0cc67cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,7 +67,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) if (GGWAVE_ALL_WARNINGS) if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") else() # todo : windows diff --git a/bindings/python/cggwave.pxd b/bindings/python/cggwave.pxd index e8d325d..5bb7b74 100644 --- a/bindings/python/cggwave.pxd +++ b/bindings/python/cggwave.pxd @@ -17,10 +17,10 @@ cdef extern from "ggwave.h" nogil: GGWAVE_TX_PROTOCOL_ULTRASOUND_FASTEST ctypedef struct ggwave_Parameters: - int sampleRateIn + int sampleRateInp int sampleRateOut int samplesPerFrame - ggwave_SampleFormat sampleFormatIn + ggwave_SampleFormat sampleFormatInp ggwave_SampleFormat sampleFormatOut ctypedef int ggwave_Instance diff --git a/examples/ggwave-common-sdl2.cpp b/examples/ggwave-common-sdl2.cpp index 0e0a202..d7b7bf5 100644 --- a/examples/ggwave-common-sdl2.cpp +++ b/examples/ggwave-common-sdl2.cpp @@ -19,10 +19,10 @@ namespace { std::string g_defaultCaptureDeviceName = ""; -SDL_AudioDeviceID g_devIdIn = 0; +SDL_AudioDeviceID g_devIdInp = 0; SDL_AudioDeviceID g_devIdOut = 0; -SDL_AudioSpec g_obtainedSpecIn; +SDL_AudioSpec g_obtainedSpecInp; SDL_AudioSpec g_obtainedSpecOut; GGWave *g_ggWave = nullptr; @@ -45,7 +45,7 @@ extern "C" { } EMSCRIPTEN_KEEPALIVE - int getSampleRate() { return g_ggWave->getSampleRateIn(); } + int getSampleRate() { return g_ggWave->getSampleRateInp(); } EMSCRIPTEN_KEEPALIVE int getFramesToRecord() { return g_ggWave->getFramesToRecord(); } @@ -63,7 +63,7 @@ extern "C" { int hasDeviceOutput() { return g_devIdOut; } EMSCRIPTEN_KEEPALIVE - int hasDeviceCapture() { return g_devIdIn; } + int hasDeviceCapture() { return g_devIdInp; } EMSCRIPTEN_KEEPALIVE int doInit() { @@ -79,11 +79,11 @@ bool GGWave_init( const int playbackId, const int captureId) { - if (g_devIdIn && g_devIdOut) { + if (g_devIdInp && g_devIdOut) { return false; } - if (g_devIdIn == 0 && g_devIdOut == 0) { + if (g_devIdInp == 0 && g_devIdOut == 0) { SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); if (SDL_Init(SDL_INIT_AUDIO) < 0) { @@ -157,47 +157,47 @@ bool GGWave_init( } } - if (g_devIdIn == 0) { + if (g_devIdInp == 0) { SDL_AudioSpec captureSpec; captureSpec = g_obtainedSpecOut; captureSpec.freq = GGWave::kBaseSampleRate; captureSpec.format = AUDIO_F32SYS; captureSpec.samples = 4096; - SDL_zero(g_obtainedSpecIn); + SDL_zero(g_obtainedSpecInp); if (captureId >= 0) { printf("Attempt to open capture device %d : '%s' ...\n", captureId, SDL_GetAudioDeviceName(captureId, SDL_FALSE)); - g_devIdIn = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(captureId, SDL_TRUE), SDL_TRUE, &captureSpec, &g_obtainedSpecIn, 0); + g_devIdInp = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(captureId, SDL_TRUE), SDL_TRUE, &captureSpec, &g_obtainedSpecInp, 0); } else { printf("Attempt to open default capture device ...\n"); - g_devIdIn = SDL_OpenAudioDevice(g_defaultCaptureDeviceName.empty() ? nullptr : g_defaultCaptureDeviceName.c_str(), - SDL_TRUE, &captureSpec, &g_obtainedSpecIn, 0); + g_devIdInp = SDL_OpenAudioDevice(g_defaultCaptureDeviceName.empty() ? nullptr : g_defaultCaptureDeviceName.c_str(), + SDL_TRUE, &captureSpec, &g_obtainedSpecInp, 0); } - if (!g_devIdIn) { + if (!g_devIdInp) { printf("Couldn't open an audio device for capture: %s!\n", SDL_GetError()); - g_devIdIn = 0; + g_devIdInp = 0; } else { - printf("Obtained spec for input device (SDL Id = %d):\n", g_devIdIn); - printf(" - Sample rate: %d\n", g_obtainedSpecIn.freq); - printf(" - Format: %d (required: %d)\n", g_obtainedSpecIn.format, captureSpec.format); - printf(" - Channels: %d (required: %d)\n", g_obtainedSpecIn.channels, captureSpec.channels); - printf(" - Samples per frame: %d\n", g_obtainedSpecIn.samples); + printf("Obtained spec for input device (SDL Id = %d):\n", g_devIdInp); + printf(" - Sample rate: %d\n", g_obtainedSpecInp.freq); + printf(" - Format: %d (required: %d)\n", g_obtainedSpecInp.format, captureSpec.format); + printf(" - Channels: %d (required: %d)\n", g_obtainedSpecInp.channels, captureSpec.channels); + printf(" - Samples per frame: %d\n", g_obtainedSpecInp.samples); reinit = true; } } - GGWave::SampleFormat sampleFormatIn = GGWAVE_SAMPLE_FORMAT_UNDEFINED; + GGWave::SampleFormat sampleFormatInp = GGWAVE_SAMPLE_FORMAT_UNDEFINED; GGWave::SampleFormat sampleFormatOut = GGWAVE_SAMPLE_FORMAT_UNDEFINED; - switch (g_obtainedSpecIn.format) { - case AUDIO_U8: sampleFormatIn = GGWAVE_SAMPLE_FORMAT_U8; break; - case AUDIO_S8: sampleFormatIn = GGWAVE_SAMPLE_FORMAT_I8; break; - case AUDIO_U16SYS: sampleFormatIn = GGWAVE_SAMPLE_FORMAT_U16; break; - case AUDIO_S16SYS: sampleFormatIn = GGWAVE_SAMPLE_FORMAT_I16; break; - case AUDIO_S32SYS: sampleFormatIn = GGWAVE_SAMPLE_FORMAT_F32; break; - case AUDIO_F32SYS: sampleFormatIn = GGWAVE_SAMPLE_FORMAT_F32; break; + switch (g_obtainedSpecInp.format) { + case AUDIO_U8: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_U8; break; + case AUDIO_S8: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I8; break; + case AUDIO_U16SYS: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_U16; break; + case AUDIO_S16SYS: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I16; break; + case AUDIO_S32SYS: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_F32; break; + case AUDIO_F32SYS: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_F32; break; } switch (g_obtainedSpecOut.format) { @@ -214,10 +214,10 @@ bool GGWave_init( if (g_ggWave) delete g_ggWave; g_ggWave = new GGWave({ - g_obtainedSpecIn.freq, + g_obtainedSpecInp.freq, g_obtainedSpecOut.freq, GGWave::kDefaultSamplesPerFrame, - sampleFormatIn, + sampleFormatInp, sampleFormatOut}); } @@ -227,16 +227,16 @@ bool GGWave_init( GGWave * GGWave_instance() { return g_ggWave; } bool GGWave_mainLoop() { - if (g_devIdIn == 0 && g_devIdOut == 0) { + if (g_devIdInp == 0 && g_devIdOut == 0) { return false; } - static GGWave::CBEnqueueAudio cbQueueAudio = [&](const void * data, uint32_t nBytes) { + static GGWave::CBWaveformOut cbQueueAudio = [&](const void * data, uint32_t nBytes) { SDL_QueueAudio(g_devIdOut, data, nBytes); }; - static GGWave::CBDequeueAudio cbDequeueAudio = [&](void * data, uint32_t nMaxBytes) { - return SDL_DequeueAudio(g_devIdIn, data, nMaxBytes); + static GGWave::CBWaveformInp cbWaveformInp = [&](void * data, uint32_t nMaxBytes) { + return SDL_DequeueAudio(g_devIdInp, data, nMaxBytes); }; if (g_ggWave->hasTxData() == false) { @@ -246,21 +246,21 @@ bool GGWave_mainLoop() { auto tNow = std::chrono::high_resolution_clock::now(); if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesOut()) { - SDL_PauseAudioDevice(g_devIdIn, SDL_FALSE); + SDL_PauseAudioDevice(g_devIdInp, SDL_FALSE); if (::getTime_ms(tLastNoData, tNow) > 500.0f) { - g_ggWave->decode(cbDequeueAudio); - if ((int) SDL_GetQueuedAudioSize(g_devIdIn) > 32*g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesIn()) { - SDL_ClearQueuedAudio(g_devIdIn); + g_ggWave->decode(cbWaveformInp); + if ((int) SDL_GetQueuedAudioSize(g_devIdInp) > 32*g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp()) { + SDL_ClearQueuedAudio(g_devIdInp); } } else { - SDL_ClearQueuedAudio(g_devIdIn); + SDL_ClearQueuedAudio(g_devIdInp); } } else { tLastNoData = tNow; } } else { SDL_PauseAudioDevice(g_devIdOut, SDL_TRUE); - SDL_PauseAudioDevice(g_devIdIn, SDL_TRUE); + SDL_PauseAudioDevice(g_devIdInp, SDL_TRUE); g_ggWave->encode(cbQueueAudio); } @@ -269,15 +269,15 @@ bool GGWave_mainLoop() { } bool GGWave_deinit() { - if (g_devIdIn == 0 && g_devIdOut == 0) { + if (g_devIdInp == 0 && g_devIdOut == 0) { return false; } delete g_ggWave; g_ggWave = nullptr; - SDL_PauseAudioDevice(g_devIdIn, 1); - SDL_CloseAudioDevice(g_devIdIn); + SDL_PauseAudioDevice(g_devIdInp, 1); + SDL_CloseAudioDevice(g_devIdInp); SDL_PauseAudioDevice(g_devIdOut, 1); SDL_CloseAudioDevice(g_devIdOut); SDL_CloseAudio(); diff --git a/examples/ggwave-to-file/main.cpp b/examples/ggwave-to-file/main.cpp index c87937d..1d708d6 100644 --- a/examples/ggwave-to-file/main.cpp +++ b/examples/ggwave-to-file/main.cpp @@ -74,12 +74,12 @@ int main(int argc, char** argv) { ggWave.init(message.size(), message.data(), ggWave.getTxProtocol(protocolId), volume); std::vector bufferPCM; - GGWave::CBEnqueueAudio cbEnqueueAudio = [&](const void * data, uint32_t nBytes) { + GGWave::CBWaveformOut cbWaveformOut = [&](const void * data, uint32_t nBytes) { bufferPCM.resize(nBytes); std::memcpy(bufferPCM.data(), data, nBytes); }; - if (ggWave.encode(cbEnqueueAudio) == false) { + if (ggWave.encode(cbWaveformOut) == false) { fprintf(stderr, "Failed to generate waveform!\n"); return -4; } diff --git a/examples/waver/common.cpp b/examples/waver/common.cpp index 798af50..1911e49 100644 --- a/examples/waver/common.cpp +++ b/examples/waver/common.cpp @@ -821,7 +821,7 @@ void renderMain() { ImGui::Separator(); ImGui::Text("%s", ""); - ImGui::Text("Sample rate (capture): %g, %d B/sample", g_ggWave->getSampleRateIn(), g_ggWave->getSampleSizeBytesIn()); + ImGui::Text("Sample rate (capture): %g, %d B/sample", g_ggWave->getSampleRateInp(), g_ggWave->getSampleSizeBytesInp()); ImGui::Text("Sample rate (playback): %g, %d B/sample", g_ggWave->getSampleRateOut(), g_ggWave->getSampleSizeBytesOut()); const float kLabelWidth = ImGui::CalcTextSize("Tx Protocol: ").x; diff --git a/include/ggwave/ggwave.h b/include/ggwave/ggwave.h index daba36d..e7a6b4c 100644 --- a/include/ggwave/ggwave.h +++ b/include/ggwave/ggwave.h @@ -45,10 +45,10 @@ extern "C" { // GGWave instance parameters typedef struct { - int sampleRateIn; // capture sample rate + int sampleRateInp; // capture sample rate int sampleRateOut; // playback sample rate int samplesPerFrame; // number of samples per audio frame - ggwave_SampleFormat sampleFormatIn; // format of the captured audio samples + ggwave_SampleFormat sampleFormatInp; // format of the captured audio samples ggwave_SampleFormat sampleFormatOut; // format of the playback audio samples } ggwave_Parameters; @@ -138,9 +138,9 @@ public: static constexpr auto kMaxSpectrumHistory = 4; static constexpr auto kMaxRecordedFrames = 1024; - using Parameters = ggwave_Parameters; - using SampleFormat = ggwave_SampleFormat; - using TxProtocolId = ggwave_TxProtocolId; + using Parameters = ggwave_Parameters; + using SampleFormat = ggwave_SampleFormat; + using TxProtocolId = ggwave_TxProtocolId; struct TxProtocol { const char * name; // string identifier of the protocol @@ -173,8 +173,8 @@ public: using RecordedData = std::vector; using TxRxData = std::vector; - using CBEnqueueAudio = std::function; - using CBDequeueAudio = std::function; + using CBWaveformOut = std::function; + using CBWaveformInp = std::function; GGWave(const Parameters & parameters); ~GGWave(); @@ -186,8 +186,11 @@ public: bool init(int dataSize, const char * dataBuffer, const int volume = kDefaultVolume); bool init(int dataSize, const char * dataBuffer, const TxProtocol & txProtocol, const int volume = kDefaultVolume); - bool encode(const CBEnqueueAudio & cbEnqueueAudio); - void decode(const CBDequeueAudio & cbDequeueAudio); + uint32_t encodeSize_bytes() const; + uint32_t encodeSize_samples() const; + + bool encode(const CBWaveformOut & cbWaveformOut); + void decode(const CBWaveformInp & cbWaveformInp); const bool & hasTxData() const { return m_hasNewTxData; } const bool & isReceiving() const { return m_receivingData; } @@ -198,10 +201,10 @@ public: const int & getFramesToAnalyze() const { return m_framesToAnalyze; } const int & getFramesLeftToAnalyze() const { return m_framesLeftToAnalyze; } const int & getSamplesPerFrame() const { return m_samplesPerFrame; } - const int & getSampleSizeBytesIn() const { return m_sampleSizeBytesIn; } + const int & getSampleSizeBytesInp() const { return m_sampleSizeBytesInp; } const int & getSampleSizeBytesOut() const { return m_sampleSizeBytesOut; } - const float & getSampleRateIn() const { return m_sampleRateIn; } + const float & getSampleRateInp() const { return m_sampleRateInp; } const float & getSampleRateOut() const { return m_sampleRateOut; } static TxProtocolId getDefaultTxProtocolId() { return GGWAVE_TX_PROTOCOL_AUDIBLE_FAST; } @@ -225,13 +228,13 @@ private: return m_hzPerSample*p.freqStart + m_freqDelta_hz*bit; } - const float m_sampleRateIn; + const float m_sampleRateInp; const float m_sampleRateOut; const int m_samplesPerFrame; const float m_isamplesPerFrame; - const int m_sampleSizeBytesIn; + const int m_sampleSizeBytesInp; const int m_sampleSizeBytesOut; - const SampleFormat m_sampleFormatIn; + const SampleFormat m_sampleFormatInp; const SampleFormat m_sampleFormatOut; const float m_hzPerSample; @@ -258,7 +261,7 @@ private: int m_framesToRecord; int m_samplesNeeded; - std::vector m_fftIn; // real + std::vector m_fftInp; // real std::vector m_fftOut; // complex bool m_hasNewSpectrum; @@ -280,8 +283,6 @@ private: // Tx bool m_hasNewTxData; - int m_nECCBytesPerTx; - int m_sendDataLength; float m_sendVolume; int m_txDataLength; diff --git a/src/ggwave.cpp b/src/ggwave.cpp index 68bb22d..799a860 100644 --- a/src/ggwave.cpp +++ b/src/ggwave.cpp @@ -27,10 +27,10 @@ ggwave_Instance ggwave_init(const ggwave_Parameters parameters) { static ggwave_Instance curId = 0; g_instances[curId] = new GGWave({ - parameters.sampleRateIn, + parameters.sampleRateInp, parameters.sampleRateOut, parameters.samplesPerFrame, - parameters.sampleFormatIn, + parameters.sampleFormatInp, parameters.sampleFormatOut}); return curId++; @@ -64,14 +64,14 @@ int ggwave_encode( int nSamples = 0; - GGWave::CBEnqueueAudio cbEnqueueAudio = [&](const void * data, uint32_t nBytes) { + 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(cbEnqueueAudio) == false) { + if (ggWave->encode(cbWaveformOut) == false) { fprintf(stderr, "Failed to encode data - GGWave instance %d\n", instance); return -1; } @@ -87,7 +87,7 @@ int ggwave_decode( char * outputBuffer) { GGWave * ggWave = (GGWave *) g_instances[instance]; - GGWave::CBDequeueAudio cbDequeueAudio = [&](void * data, uint32_t nMaxBytes) -> uint32_t { + 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); @@ -97,7 +97,7 @@ int ggwave_decode( return nCopied; }; - ggWave->decode(cbDequeueAudio); + ggWave->decode(cbWaveformInp); // todo : avoid allocation GGWave::TxRxData rxData; @@ -266,15 +266,15 @@ const GGWave::Parameters & GGWave::getDefaultParameters() { } GGWave::GGWave(const Parameters & parameters) : - m_sampleRateIn(parameters.sampleRateIn), + m_sampleRateInp(parameters.sampleRateInp), m_sampleRateOut(parameters.sampleRateOut), m_samplesPerFrame(parameters.samplesPerFrame), m_isamplesPerFrame(1.0f/m_samplesPerFrame), - m_sampleSizeBytesIn(bytesForSampleFormat(parameters.sampleFormatIn)), + m_sampleSizeBytesInp(bytesForSampleFormat(parameters.sampleFormatInp)), m_sampleSizeBytesOut(bytesForSampleFormat(parameters.sampleFormatOut)), - m_sampleFormatIn(parameters.sampleFormatIn), + m_sampleFormatInp(parameters.sampleFormatInp), m_sampleFormatOut(parameters.sampleFormatOut), - m_hzPerSample(m_sampleRateIn/parameters.samplesPerFrame), + m_hzPerSample(m_sampleRateInp/parameters.samplesPerFrame), m_ihzPerSample(1.0f/m_hzPerSample), m_freqDelta_bin(1), m_freqDelta_hz(2*m_hzPerSample), @@ -283,12 +283,12 @@ GGWave::GGWave(const Parameters & parameters) : m_nPostMarkerFrames(0), m_encodedDataOffset(3), m_samplesNeeded(m_samplesPerFrame), - m_fftIn(kMaxSamplesPerFrame), + m_fftInp(kMaxSamplesPerFrame), m_fftOut(2*kMaxSamplesPerFrame), m_hasNewSpectrum(false), m_sampleSpectrum(kMaxSamplesPerFrame), m_sampleAmplitude(kMaxSamplesPerFrame), - m_sampleAmplitudeTmp(kMaxSamplesPerFrame*m_sampleSizeBytesIn), + m_sampleAmplitudeTmp(kMaxSamplesPerFrame*m_sampleSizeBytesInp), m_hasNewRxData(false), m_lastRxDataLength(0), m_rxData(kMaxDataSize), @@ -301,7 +301,7 @@ GGWave::GGWave(const Parameters & parameters) : m_outputBlockTmp(kMaxRecordedFrames*kMaxSamplesPerFrame*m_sampleSizeBytesOut), m_outputBlockI16(kMaxRecordedFrames*kMaxSamplesPerFrame) { - if (m_sampleSizeBytesIn == 0) { + if (m_sampleSizeBytesInp == 0) { throw std::runtime_error("Invalid or unsupported capture sample format"); } @@ -390,14 +390,33 @@ bool GGWave::init(int dataSize, const char * dataBuffer, const TxProtocol & txPr return true; } -bool GGWave::encode(const CBEnqueueAudio & cbEnqueueAudio) { - int samplesPerFrameOut = (m_sampleRateOut/m_sampleRateIn)*m_samplesPerFrame; - if (m_sampleRateOut > m_sampleRateIn) { - fprintf(stderr, "Error: capture sample rate (%d Hz) must be <= playback sample rate (%d Hz)\n", (int) m_sampleRateIn, (int) m_sampleRateOut); +uint32_t GGWave::encodeSize_bytes() const { + return encodeSize_samples()*m_sampleSizeBytesOut; +} + +uint32_t GGWave::encodeSize_samples() const { + if (m_hasNewTxData == false) { + return 0; + } + + int nECCBytesPerTx = getECCBytesForLength(m_txDataLength); + int sendDataLength = m_txDataLength + m_encodedDataOffset; + int totalBytes = sendDataLength + nECCBytesPerTx; + int totalDataFrames = ((totalBytes + m_txProtocol.bytesPerTx - 1)/m_txProtocol.bytesPerTx)*m_txProtocol.framesPerTx; + + return ( + m_nMarkerFrames + m_nPostMarkerFrames + totalDataFrames + m_nMarkerFrames + )*m_samplesPerFrame; +} + +bool GGWave::encode(const CBWaveformOut & cbWaveformOut) { + int samplesPerFrameOut = (m_sampleRateOut/m_sampleRateInp)*m_samplesPerFrame; + if (m_sampleRateOut > m_sampleRateInp) { + fprintf(stderr, "Error: capture sample rate (%d Hz) must be <= playback sample rate (%d Hz)\n", (int) m_sampleRateInp, (int) m_sampleRateOut); return false; } - if (m_sampleRateOut != m_sampleRateIn) { - fprintf(stderr, "Resampling from %d Hz to %d Hz\n", (int) m_sampleRateIn, (int) m_sampleRateOut); + if (m_sampleRateOut != m_sampleRateInp) { + fprintf(stderr, "Resampling from %d Hz to %d Hz\n", (int) m_sampleRateInp, (int) m_sampleRateOut); } int frameId = 0; @@ -438,10 +457,12 @@ bool GGWave::encode(const CBEnqueueAudio & cbEnqueueAudio) { } } - m_nECCBytesPerTx = getECCBytesForLength(m_txDataLength); - m_sendDataLength = m_txDataLength + m_encodedDataOffset; + int nECCBytesPerTx = getECCBytesForLength(m_txDataLength); + int sendDataLength = m_txDataLength + m_encodedDataOffset; + int totalBytes = sendDataLength + nECCBytesPerTx; + int totalDataFrames = ((totalBytes + m_txProtocol.bytesPerTx - 1)/m_txProtocol.bytesPerTx)*m_txProtocol.framesPerTx; - RS::ReedSolomon rsData = RS::ReedSolomon(m_txDataLength, m_nECCBytesPerTx); + RS::ReedSolomon rsData = RS::ReedSolomon(m_txDataLength, nECCBytesPerTx); RS::ReedSolomon rsLength(1, m_encodedDataOffset - 1); rsLength.Encode(m_txData.data(), m_txDataEncoded.data()); @@ -450,7 +471,7 @@ bool GGWave::encode(const CBEnqueueAudio & cbEnqueueAudio) { while (m_hasNewTxData) { std::fill(m_outputBlock.begin(), m_outputBlock.end(), 0.0f); - if (m_sampleRateOut != m_sampleRateIn) { + if (m_sampleRateOut != m_sampleRateInp) { for (int k = 0; k < m_txProtocol.nDataBitsPerTx(); ++k) { double freq = bitFreq(m_txProtocol, k); @@ -489,9 +510,7 @@ bool GGWave::encode(const CBEnqueueAudio & cbEnqueueAudio) { ::addAmplitudeSmooth(bit1Amplitude[i], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, frameId - m_nMarkerFrames, m_nPostMarkerFrames); } } - } else if (frameId < - (m_nMarkerFrames + m_nPostMarkerFrames) + - ((m_sendDataLength + m_nECCBytesPerTx)/m_txProtocol.bytesPerTx + 2)*m_txProtocol.framesPerTx) { + } else if (frameId < m_nMarkerFrames + m_nPostMarkerFrames + totalDataFrames) { int dataOffset = frameId - m_nMarkerFrames - m_nPostMarkerFrames; int cycleModMain = dataOffset%m_txProtocol.framesPerTx; dataOffset /= m_txProtocol.framesPerTx; @@ -520,13 +539,10 @@ bool GGWave::encode(const CBEnqueueAudio & cbEnqueueAudio) { ::addAmplitudeSmooth(bit1Amplitude[k/2], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, cycleModMain, m_txProtocol.framesPerTx); } } - } else if (frameId < - (m_nMarkerFrames + m_nPostMarkerFrames) + - ((m_sendDataLength + m_nECCBytesPerTx)/m_txProtocol.bytesPerTx + 2)*m_txProtocol.framesPerTx + - (m_nMarkerFrames)) { + } else if (frameId < m_nMarkerFrames + m_nPostMarkerFrames + totalDataFrames + m_nMarkerFrames) { nFreq = m_nBitsInMarker; - int fId = frameId - ((m_nMarkerFrames + m_nPostMarkerFrames) + ((m_sendDataLength + m_nECCBytesPerTx)/m_txProtocol.bytesPerTx + 2)*m_txProtocol.framesPerTx); + int fId = frameId - (m_nMarkerFrames + m_nPostMarkerFrames + totalDataFrames); for (int i = 0; i < m_nBitsInMarker; ++i) { if (i%2 == 0) { addAmplitudeSmooth(bit0Amplitude[i], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, fId, m_nMarkerFrames); @@ -536,6 +552,7 @@ bool GGWave::encode(const CBEnqueueAudio & cbEnqueueAudio) { } } else { m_hasNewTxData = false; + break; } if (nFreq == 0) nFreq = 1; @@ -599,14 +616,14 @@ bool GGWave::encode(const CBEnqueueAudio & cbEnqueueAudio) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: break; case GGWAVE_SAMPLE_FORMAT_I16: { - cbEnqueueAudio(m_outputBlockI16.data(), frameId*samplesPerFrameOut*m_sampleSizeBytesOut); + cbWaveformOut(m_outputBlockI16.data(), frameId*samplesPerFrameOut*m_sampleSizeBytesOut); } break; case GGWAVE_SAMPLE_FORMAT_U8: case GGWAVE_SAMPLE_FORMAT_I8: case GGWAVE_SAMPLE_FORMAT_U16: case GGWAVE_SAMPLE_FORMAT_F32: { - cbEnqueueAudio(m_outputBlockTmp.data(), frameId*samplesPerFrameOut*m_sampleSizeBytesOut); + cbWaveformOut(m_outputBlockTmp.data(), frameId*samplesPerFrameOut*m_sampleSizeBytesOut); } break; } @@ -618,49 +635,49 @@ bool GGWave::encode(const CBEnqueueAudio & cbEnqueueAudio) { return true; } -void GGWave::decode(const CBDequeueAudio & cbDequeueAudio) { +void GGWave::decode(const CBWaveformInp & cbWaveformInp) { while (m_hasNewTxData == false) { // read capture data - uint32_t nBytesNeeded = m_samplesNeeded*m_sampleSizeBytesIn; + uint32_t nBytesNeeded = m_samplesNeeded*m_sampleSizeBytesInp; uint32_t nBytesRecorded = 0; uint32_t offset = m_samplesPerFrame - m_samplesNeeded; - switch (m_sampleFormatIn) { + switch (m_sampleFormatInp) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: break; case GGWAVE_SAMPLE_FORMAT_U8: case GGWAVE_SAMPLE_FORMAT_I8: case GGWAVE_SAMPLE_FORMAT_U16: case GGWAVE_SAMPLE_FORMAT_I16: { - nBytesRecorded = cbDequeueAudio(m_sampleAmplitudeTmp.data() + offset, nBytesNeeded); + nBytesRecorded = cbWaveformInp(m_sampleAmplitudeTmp.data() + offset, nBytesNeeded); } break; case GGWAVE_SAMPLE_FORMAT_F32: { - nBytesRecorded = cbDequeueAudio(m_sampleAmplitude.data() + offset, nBytesNeeded); + nBytesRecorded = cbWaveformInp(m_sampleAmplitude.data() + offset, nBytesNeeded); } break; } - if (nBytesRecorded % m_sampleSizeBytesIn != 0) { + if (nBytesRecorded % m_sampleSizeBytesInp != 0) { fprintf(stderr, "Failure during capture - provided bytes (%d) are not multiple of sample size (%d)\n", - nBytesRecorded, m_sampleSizeBytesIn); + nBytesRecorded, m_sampleSizeBytesInp); m_samplesNeeded = m_samplesPerFrame; break; } if (nBytesRecorded > nBytesNeeded) { fprintf(stderr, "Failure during capture - more samples were provided (%d) than requested (%d)\n", - nBytesRecorded/m_sampleSizeBytesIn, nBytesNeeded/m_sampleSizeBytesIn); + nBytesRecorded/m_sampleSizeBytesInp, nBytesNeeded/m_sampleSizeBytesInp); m_samplesNeeded = m_samplesPerFrame; break; } // convert to 32-bit float - switch (m_sampleFormatIn) { + switch (m_sampleFormatInp) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: break; case GGWAVE_SAMPLE_FORMAT_U8: { constexpr float scale = 1.0f/128; - int nSamplesRecorded = nBytesRecorded/m_sampleSizeBytesIn; + int nSamplesRecorded = nBytesRecorded/m_sampleSizeBytesInp; auto p = reinterpret_cast(m_sampleAmplitudeTmp.data()); for (int i = 0; i < nSamplesRecorded; ++i) { m_sampleAmplitude[offset + i] = float(int16_t(*(p + offset + i)) - 128)*scale; @@ -669,7 +686,7 @@ void GGWave::decode(const CBDequeueAudio & cbDequeueAudio) { case GGWAVE_SAMPLE_FORMAT_I8: { constexpr float scale = 1.0f/128; - int nSamplesRecorded = nBytesRecorded/m_sampleSizeBytesIn; + int nSamplesRecorded = nBytesRecorded/m_sampleSizeBytesInp; auto p = reinterpret_cast(m_sampleAmplitudeTmp.data()); for (int i = 0; i < nSamplesRecorded; ++i) { m_sampleAmplitude[offset + i] = float(*(p + offset + i))*scale; @@ -678,7 +695,7 @@ void GGWave::decode(const CBDequeueAudio & cbDequeueAudio) { case GGWAVE_SAMPLE_FORMAT_U16: { constexpr float scale = 1.0f/32768; - int nSamplesRecorded = nBytesRecorded/m_sampleSizeBytesIn; + int nSamplesRecorded = nBytesRecorded/m_sampleSizeBytesInp; auto p = reinterpret_cast(m_sampleAmplitudeTmp.data()); for (int i = 0; i < nSamplesRecorded; ++i) { m_sampleAmplitude[offset + i] = float(int32_t(*(p + offset + i)) - 32768)*scale; @@ -687,7 +704,7 @@ void GGWave::decode(const CBDequeueAudio & cbDequeueAudio) { case GGWAVE_SAMPLE_FORMAT_I16: { constexpr float scale = 1.0f/32768; - int nSamplesRecorded = nBytesRecorded/m_sampleSizeBytesIn; + int nSamplesRecorded = nBytesRecorded/m_sampleSizeBytesInp; auto p = reinterpret_cast(m_sampleAmplitudeTmp.data()); for (int i = 0; i < nSamplesRecorded; ++i) { m_sampleAmplitude[offset + i] = float(*(p + offset + i))*scale; @@ -721,9 +738,9 @@ void GGWave::decode(const CBDequeueAudio & cbDequeueAudio) { } // calculate spectrum - std::copy(m_sampleAmplitudeAverage.begin(), m_sampleAmplitudeAverage.begin() + m_samplesPerFrame, m_fftIn.data()); + std::copy(m_sampleAmplitudeAverage.begin(), m_sampleAmplitudeAverage.begin() + m_samplesPerFrame, m_fftInp.data()); - FFT(m_fftIn.data(), m_fftOut.data(), m_samplesPerFrame, 1.0); + FFT(m_fftInp.data(), m_fftOut.data(), m_samplesPerFrame, 1.0); for (int i = 0; i < m_samplesPerFrame; ++i) { m_sampleSpectrum[i] = (m_fftOut[2*i + 0]*m_fftOut[2*i + 0] + m_fftOut[2*i + 1]*m_fftOut[2*i + 1]); @@ -775,15 +792,15 @@ void GGWave::decode(const CBDequeueAudio & cbDequeueAudio) { std::copy( m_recordedAmplitude.begin() + offsetTx*step, - m_recordedAmplitude.begin() + offsetTx*step + m_samplesPerFrame, m_fftIn.data()); + m_recordedAmplitude.begin() + offsetTx*step + m_samplesPerFrame, m_fftInp.data()); for (int k = 1; k < rxProtocol.framesPerTx - 1; ++k) { for (int i = 0; i < m_samplesPerFrame; ++i) { - m_fftIn[i] += m_recordedAmplitude[(offsetTx + k*stepsPerFrame)*step + i]; + m_fftInp[i] += m_recordedAmplitude[(offsetTx + k*stepsPerFrame)*step + i]; } } - FFT(m_fftIn.data(), m_fftOut.data(), m_samplesPerFrame, 1.0); + FFT(m_fftInp.data(), m_fftOut.data(), m_samplesPerFrame, 1.0); for (int i = 0; i < m_samplesPerFrame; ++i) { m_sampleSpectrum[i] = (m_fftOut[2*i + 0]*m_fftOut[2*i + 0] + m_fftOut[2*i + 1]*m_fftOut[2*i + 1]); @@ -950,7 +967,7 @@ void GGWave::decode(const CBDequeueAudio & cbDequeueAudio) { } } } else { - m_samplesNeeded -= nBytesRecorded/m_sampleSizeBytesIn; + m_samplesNeeded -= nBytesRecorded/m_sampleSizeBytesInp; break; } } diff --git a/tests/test-ggwave.c b/tests/test-ggwave.c index f5521d8..1b82d6b 100644 --- a/tests/test-ggwave.c +++ b/tests/test-ggwave.c @@ -15,7 +15,7 @@ int main() { ggwave_Parameters parameters = ggwave_getDefaultParameters(); - parameters.sampleFormatIn = GGWAVE_SAMPLE_FORMAT_I16; + parameters.sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I16; parameters.sampleFormatOut = GGWAVE_SAMPLE_FORMAT_I16; ggwave_Instance instance = ggwave_init(parameters); diff --git a/tests/test-ggwave.cpp b/tests/test-ggwave.cpp index 93be817..b860d26 100644 --- a/tests/test-ggwave.cpp +++ b/tests/test-ggwave.cpp @@ -41,7 +41,7 @@ const std::set kFormats = { }; template -GGWave::CBEnqueueAudio getCBEnqueueAudio(uint32_t & nSamples, std::vector & buffer) { +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); @@ -51,7 +51,7 @@ GGWave::CBEnqueueAudio getCBEnqueueAudio(uint32_t & nSamples, std::vector & b } template -GGWave::CBDequeueAudio getCBDequeueAudio(uint32_t & nSamples, std::vector & buffer) { +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); @@ -78,12 +78,12 @@ int main() { std::vector bufferI16; std::vector bufferF32; - auto convertHelper = [&](GGWave::SampleFormat formatOut, GGWave::SampleFormat formatIn) { + auto convertHelper = [&](GGWave::SampleFormat formatOut, GGWave::SampleFormat formatInp) { switch (formatOut) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: CHECK(false); break; case GGWAVE_SAMPLE_FORMAT_U8: { - switch (formatIn) { + 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; @@ -94,7 +94,7 @@ int main() { } break; case GGWAVE_SAMPLE_FORMAT_I8: { - switch (formatIn) { + switch (formatInp) { case GGWAVE_SAMPLE_FORMAT_UNDEFINED: CHECK(false); break; case GGWAVE_SAMPLE_FORMAT_U8: convert(bufferI8, bufferU8); break; case GGWAVE_SAMPLE_FORMAT_I8: break; @@ -105,7 +105,7 @@ int main() { } break; case GGWAVE_SAMPLE_FORMAT_U16: { - switch (formatIn) { + 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; @@ -116,7 +116,7 @@ int main() { } break; case GGWAVE_SAMPLE_FORMAT_I16: { - switch (formatIn) { + 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; @@ -127,7 +127,7 @@ int main() { } break; case GGWAVE_SAMPLE_FORMAT_F32: { - switch (formatIn) { + 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; @@ -142,20 +142,20 @@ int main() { uint32_t nSamples = 0; - const std::map kCBEnqueueAudio = { - { GGWAVE_SAMPLE_FORMAT_U8, getCBEnqueueAudio(nSamples, bufferU8) }, - { GGWAVE_SAMPLE_FORMAT_I8, getCBEnqueueAudio(nSamples, bufferI8) }, - { GGWAVE_SAMPLE_FORMAT_U16, getCBEnqueueAudio(nSamples, bufferU16) }, - { GGWAVE_SAMPLE_FORMAT_I16, getCBEnqueueAudio(nSamples, bufferI16) }, - { GGWAVE_SAMPLE_FORMAT_F32, getCBEnqueueAudio(nSamples, bufferF32) }, + 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 kCBDequeueAudio = { - { GGWAVE_SAMPLE_FORMAT_U8, getCBDequeueAudio(nSamples, bufferU8) }, - { GGWAVE_SAMPLE_FORMAT_I8, getCBDequeueAudio(nSamples, bufferI8) }, - { GGWAVE_SAMPLE_FORMAT_U16, getCBDequeueAudio(nSamples, bufferU16) }, - { GGWAVE_SAMPLE_FORMAT_I16, getCBDequeueAudio(nSamples, bufferI16) }, - { GGWAVE_SAMPLE_FORMAT_F32, getCBDequeueAudio(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) }, }; { @@ -183,20 +183,23 @@ int main() { for (const auto & txProtocol : GGWave::getTxProtocols()) { for (const auto & formatOut : kFormats) { - for (const auto & formatIn : kFormats) { - printf("Testing: protocol = %s, in = %d, out = %d\n", txProtocol.second.name, formatIn, formatOut); + for (const auto & formatInp : kFormats) { + printf("Testing: protocol = %s, in = %d, out = %d\n", txProtocol.second.name, formatInp, formatOut); auto parameters = GGWave::getDefaultParameters(); - parameters.sampleFormatIn = formatIn; + parameters.sampleFormatInp = formatInp; parameters.sampleFormatOut = formatOut; GGWave instance(parameters); - std::string payload = "test message xxxxxxxxxxxx"; + std::string payload = "test"; instance.init(payload, txProtocol.second, 25); - instance.encode(kCBEnqueueAudio.at(formatOut)); - convertHelper(formatOut, formatIn); - instance.decode(kCBDequeueAudio.at(formatIn)); + auto expectedSize = instance.encodeSize_samples(); + instance.encode(kCBWaveformOut.at(formatOut)); + printf("Expected = %d, actual = %d\n", expectedSize, nSamples); + CHECK(expectedSize == nSamples); + convertHelper(formatOut, formatInp); + instance.decode(kCBWaveformInp.at(formatInp)); { GGWave::TxRxData result;