mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-02-24 16:16:10 +08:00
core : refactoring + bug fix
- rename callback types - fix calculation of data frames
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -74,12 +74,12 @@ int main(int argc, char** argv) {
|
||||
ggWave.init(message.size(), message.data(), ggWave.getTxProtocol(protocolId), volume);
|
||||
|
||||
std::vector<char> 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<float>;
|
||||
using TxRxData = std::vector<std::uint8_t>;
|
||||
|
||||
using CBEnqueueAudio = std::function<void(const void * data, uint32_t nBytes)>;
|
||||
using CBDequeueAudio = std::function<uint32_t(void * data, uint32_t nMaxBytes)>;
|
||||
using CBWaveformOut = std::function<void(const void * data, uint32_t nBytes)>;
|
||||
using CBWaveformInp = std::function<uint32_t(void * data, uint32_t nMaxBytes)>;
|
||||
|
||||
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<float> m_fftIn; // real
|
||||
std::vector<float> m_fftInp; // real
|
||||
std::vector<float> 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;
|
||||
|
||||
121
src/ggwave.cpp
121
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<uint8_t *>(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<int8_t *>(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<uint16_t *>(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<int16_t *>(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -41,7 +41,7 @@ const std::set<GGWave::SampleFormat> kFormats = {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GGWave::CBEnqueueAudio getCBEnqueueAudio(uint32_t & nSamples, std::vector<T> & buffer) {
|
||||
GGWave::CBWaveformOut getCBWaveformOut(uint32_t & nSamples, std::vector<T> & 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<T> & b
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GGWave::CBDequeueAudio getCBDequeueAudio(uint32_t & nSamples, std::vector<T> & buffer) {
|
||||
GGWave::CBWaveformInp getCBWaveformInp(uint32_t & nSamples, std::vector<T> & 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<int16_t> bufferI16;
|
||||
std::vector<float> 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<GGWave::SampleFormat, GGWave::CBEnqueueAudio> 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<GGWave::SampleFormat, GGWave::CBWaveformOut> 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<GGWave::SampleFormat, GGWave::CBDequeueAudio> 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<GGWave::SampleFormat, GGWave::CBWaveformInp> 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;
|
||||
|
||||
Reference in New Issue
Block a user