mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-03-16 15:35:58 +08:00
ggwave : remove <functional> header dependency
This commit is contained in:
@@ -88,6 +88,7 @@ else()
|
||||
add_subdirectory(ggwave-to-file)
|
||||
|
||||
add_subdirectory(arduino-rx)
|
||||
add_subdirectory(arduino-tx)
|
||||
endif()
|
||||
|
||||
if (GGWAVE_SUPPORT_SDL2)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
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<uint8_t> 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;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "ggwave.h"
|
||||
#include <ArduinoSTL.h>
|
||||
|
||||
#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;
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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<uint8_t> 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;
|
||||
|
||||
@@ -84,17 +84,15 @@ int main(int argc, char** argv) {
|
||||
});
|
||||
ggWave.init(message.size(), message.data(), ggWave.getTxProtocol(protocolId), volume);
|
||||
|
||||
std::vector<char> 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<char> bufferPCM(nBytes);
|
||||
std::memcpy(bufferPCM.data(), ggWave.txData(), nBytes);
|
||||
|
||||
fprintf(stderr, "Output size = %d bytes\n", (int) bufferPCM.size());
|
||||
|
||||
drwav_data_format format;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
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<uint8_t> 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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 <cstdint>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
@@ -367,8 +367,8 @@ public:
|
||||
float duration_ms;
|
||||
};
|
||||
|
||||
using Tones = std::vector<ToneData>;
|
||||
using WaveformTones = std::vector<Tones>;
|
||||
using TonesPerFrame = std::vector<ToneData>;
|
||||
using Tones = std::vector<TonesPerFrame>;
|
||||
|
||||
using AmplitudeData = std::vector<float>;
|
||||
using AmplitudeDataI16 = std::vector<int16_t>;
|
||||
@@ -376,9 +376,6 @@ public:
|
||||
using RecordedData = std::vector<float>;
|
||||
using TxRxData = std::vector<uint8_t>;
|
||||
|
||||
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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
161
src/ggwave.cpp
161
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()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -44,35 +44,18 @@ const std::set<GGWave::SampleFormat> kFormats = {
|
||||
GGWAVE_SAMPLE_FORMAT_F32,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
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);
|
||||
buffer.resize(nSamples);
|
||||
std::copy((char *) data, (char *) data + nBytes, (char *) buffer.data());
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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);
|
||||
std::copy(p, p + nCopied, (char *) data);
|
||||
nSamples -= nCopied/sizeof(T);
|
||||
|
||||
return nCopied;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename S, typename D>
|
||||
void convert(const std::vector<S> & src, std::vector<D> & dst) {
|
||||
int n = src.size();
|
||||
dst.resize(n);
|
||||
void convert(std::vector<uint8_t> & src) {
|
||||
const int n = src.size()/sizeof(S);
|
||||
std::vector<D> 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<uint8_t> bufferU8;
|
||||
std::vector<int8_t> bufferI8;
|
||||
std::vector<uint16_t> bufferU16;
|
||||
std::vector<int16_t> bufferI16;
|
||||
std::vector<float> bufferF32;
|
||||
std::vector<uint8_t> 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<uint8_t, int8_t> (buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_U16: convert<uint8_t, uint16_t>(buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_I16: convert<uint8_t, int16_t> (buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_F32: convert<uint8_t, float> (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<int8_t, uint8_t> (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<int8_t, uint16_t>(buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_I16: convert<int8_t, int16_t> (buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_F32: convert<int8_t, float> (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<uint16_t, uint8_t>(buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_I8: convert<uint16_t, int8_t> (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<uint16_t, int16_t>(buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_F32: convert<uint16_t, float> (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<int16_t, uint8_t> (buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_I8: convert<int16_t, int8_t> (buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_U16: convert<int16_t, uint16_t>(buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_I16: break;
|
||||
case GGWAVE_SAMPLE_FORMAT_F32: convert(bufferI16, bufferF32); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_F32: convert<int16_t, float> (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<float, uint8_t> (buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_I8: convert<float, int8_t> (buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_U16: convert<float, uint16_t>(buffer); break;
|
||||
case GGWAVE_SAMPLE_FORMAT_I16: convert<float, int16_t> (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<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::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) },
|
||||
};
|
||||
|
||||
{
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user