ggwave : big refactoring / renaming

This commit is contained in:
Georgi Gerganov
2022-06-05 11:05:34 +03:00
parent 05f1b4750b
commit 7c5b614c16
26 changed files with 1097 additions and 834 deletions
+32 -27
View File
@@ -13,27 +13,27 @@ EMSCRIPTEN_BINDINGS(ggwave) {
.value("GGWAVE_SAMPLE_FORMAT_F32", GGWAVE_SAMPLE_FORMAT_F32)
;
emscripten::enum_<ggwave_TxProtocolId>("TxProtocolId")
.value("GGWAVE_TX_PROTOCOL_AUDIBLE_NORMAL", GGWAVE_TX_PROTOCOL_AUDIBLE_NORMAL)
.value("GGWAVE_TX_PROTOCOL_AUDIBLE_FAST", GGWAVE_TX_PROTOCOL_AUDIBLE_FAST)
.value("GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST", GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST)
.value("GGWAVE_TX_PROTOCOL_ULTRASOUND_NORMAL", GGWAVE_TX_PROTOCOL_ULTRASOUND_NORMAL)
.value("GGWAVE_TX_PROTOCOL_ULTRASOUND_FAST", GGWAVE_TX_PROTOCOL_ULTRASOUND_FAST)
.value("GGWAVE_TX_PROTOCOL_ULTRASOUND_FASTEST", GGWAVE_TX_PROTOCOL_ULTRASOUND_FASTEST)
.value("GGWAVE_TX_PROTOCOL_DT_NORMAL", GGWAVE_TX_PROTOCOL_DT_NORMAL)
.value("GGWAVE_TX_PROTOCOL_DT_FAST", GGWAVE_TX_PROTOCOL_DT_FAST)
.value("GGWAVE_TX_PROTOCOL_DT_FASTEST", GGWAVE_TX_PROTOCOL_DT_FASTEST)
emscripten::enum_<ggwave_ProtocolId>("ProtocolId")
.value("GGWAVE_PROTOCOL_AUDIBLE_NORMAL", GGWAVE_PROTOCOL_AUDIBLE_NORMAL)
.value("GGWAVE_PROTOCOL_AUDIBLE_FAST", GGWAVE_PROTOCOL_AUDIBLE_FAST)
.value("GGWAVE_PROTOCOL_AUDIBLE_FASTEST", GGWAVE_PROTOCOL_AUDIBLE_FASTEST)
.value("GGWAVE_PROTOCOL_ULTRASOUND_NORMAL", GGWAVE_PROTOCOL_ULTRASOUND_NORMAL)
.value("GGWAVE_PROTOCOL_ULTRASOUND_FAST", GGWAVE_PROTOCOL_ULTRASOUND_FAST)
.value("GGWAVE_PROTOCOL_ULTRASOUND_FASTEST", GGWAVE_PROTOCOL_ULTRASOUND_FASTEST)
.value("GGWAVE_PROTOCOL_DT_NORMAL", GGWAVE_PROTOCOL_DT_NORMAL)
.value("GGWAVE_PROTOCOL_DT_FAST", GGWAVE_PROTOCOL_DT_FAST)
.value("GGWAVE_PROTOCOL_DT_FASTEST", GGWAVE_PROTOCOL_DT_FASTEST)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_0", GGWAVE_TX_PROTOCOL_CUSTOM_0)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_1", GGWAVE_TX_PROTOCOL_CUSTOM_1)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_2", GGWAVE_TX_PROTOCOL_CUSTOM_2)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_3", GGWAVE_TX_PROTOCOL_CUSTOM_3)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_4", GGWAVE_TX_PROTOCOL_CUSTOM_4)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_5", GGWAVE_TX_PROTOCOL_CUSTOM_5)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_6", GGWAVE_TX_PROTOCOL_CUSTOM_6)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_7", GGWAVE_TX_PROTOCOL_CUSTOM_7)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_8", GGWAVE_TX_PROTOCOL_CUSTOM_8)
.value("GGWAVE_TX_PROTOCOL_CUSTOM_9", GGWAVE_TX_PROTOCOL_CUSTOM_9)
.value("GGWAVE_PROTOCOL_CUSTOM_0", GGWAVE_PROTOCOL_CUSTOM_0)
.value("GGWAVE_PROTOCOL_CUSTOM_1", GGWAVE_PROTOCOL_CUSTOM_1)
.value("GGWAVE_PROTOCOL_CUSTOM_2", GGWAVE_PROTOCOL_CUSTOM_2)
.value("GGWAVE_PROTOCOL_CUSTOM_3", GGWAVE_PROTOCOL_CUSTOM_3)
.value("GGWAVE_PROTOCOL_CUSTOM_4", GGWAVE_PROTOCOL_CUSTOM_4)
.value("GGWAVE_PROTOCOL_CUSTOM_5", GGWAVE_PROTOCOL_CUSTOM_5)
.value("GGWAVE_PROTOCOL_CUSTOM_6", GGWAVE_PROTOCOL_CUSTOM_6)
.value("GGWAVE_PROTOCOL_CUSTOM_7", GGWAVE_PROTOCOL_CUSTOM_7)
.value("GGWAVE_PROTOCOL_CUSTOM_8", GGWAVE_PROTOCOL_CUSTOM_8)
.value("GGWAVE_PROTOCOL_CUSTOM_9", GGWAVE_PROTOCOL_CUSTOM_9)
;
emscripten::enum_<ggwave_OperatingMode>("OperatingMode")
@@ -64,12 +64,12 @@ EMSCRIPTEN_BINDINGS(ggwave) {
emscripten::function("encode", emscripten::optional_override(
[](ggwave_Instance instance,
const std::string & data,
ggwave_TxProtocolId txProtocolId,
ggwave_ProtocolId protocolId,
int volume) {
auto n = ggwave_encode(instance, data.data(), data.size(), txProtocolId, volume, nullptr, 1);
auto n = ggwave_encode(instance, data.data(), data.size(), protocolId, volume, nullptr, 1);
std::vector<char> result(n);
result.resize(n);
ggwave_encode(instance, data.data(), data.size(), txProtocolId, volume, result.data(), 0);
ggwave_encode(instance, data.data(), data.size(), protocolId, volume, result.data(), 0);
return emscripten::val(emscripten::typed_memory_view(result.size(), result.data()));
}));
@@ -97,10 +97,15 @@ EMSCRIPTEN_BINDINGS(ggwave) {
ggwave_setLogFile(stderr);
}));
emscripten::function("toggleRxProtocol", emscripten::optional_override(
[](ggwave_Instance instance,
ggwave_TxProtocolId rxProtocolId,
emscripten::function("rxToggleProtocol", emscripten::optional_override(
[](ggwave_ProtocolId protocolId,
int state) {
ggwave_toggleRxProtocol(instance, rxProtocolId, state);
ggwave_rxToggleProtocol(protocolId, state);
}));
emscripten::function("txToggleProtocol", emscripten::optional_override(
[](ggwave_ProtocolId protocolId,
int state) {
ggwave_txToggleProtocol(protocolId, state);
}));
}
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -69,7 +69,7 @@ encode()
.. code:: python
encode(payload, [txProtocolId], [volume], [instance])
encode(payload, [protocolId], [volume], [instance])
Encodes ``payload`` into an audio waveform.
@@ -138,7 +138,7 @@ Usage
p = pyaudio.PyAudio()
# generate audio waveform for string "hello python"
waveform = ggwave.encode("hello python", txProtocolId = 1, volume = 20)
waveform = ggwave.encode("hello python", protocolId = 1, volume = 20)
print("Transmitting text 'hello python' ...")
stream = p.open(format=pyaudio.paFloat32, channels=1, rate=48000, output=True, frames_per_buffer=4096)
+33 -30
View File
@@ -8,27 +8,27 @@ cdef extern from "ggwave.h" nogil:
GGWAVE_SAMPLE_FORMAT_I16,
GGWAVE_SAMPLE_FORMAT_F32
ctypedef enum ggwave_TxProtocolId:
GGWAVE_TX_PROTOCOL_AUDIBLE_NORMAL,
GGWAVE_TX_PROTOCOL_AUDIBLE_FAST,
GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST,
GGWAVE_TX_PROTOCOL_ULTRASOUND_NORMAL,
GGWAVE_TX_PROTOCOL_ULTRASOUND_FAST,
GGWAVE_TX_PROTOCOL_ULTRASOUND_FASTEST,
GGWAVE_TX_PROTOCOL_DT_NORMAL,
GGWAVE_TX_PROTOCOL_DT_FAST,
GGWAVE_TX_PROTOCOL_DT_FASTEST,
ctypedef enum ggwave_ProtocolId:
GGWAVE_PROTOCOL_AUDIBLE_NORMAL,
GGWAVE_PROTOCOL_AUDIBLE_FAST,
GGWAVE_PROTOCOL_AUDIBLE_FASTEST,
GGWAVE_PROTOCOL_ULTRASOUND_NORMAL,
GGWAVE_PROTOCOL_ULTRASOUND_FAST,
GGWAVE_PROTOCOL_ULTRASOUND_FASTEST,
GGWAVE_PROTOCOL_DT_NORMAL,
GGWAVE_PROTOCOL_DT_FAST,
GGWAVE_PROTOCOL_DT_FASTEST,
GGWAVE_TX_PROTOCOL_CUSTOM_0,
GGWAVE_TX_PROTOCOL_CUSTOM_1,
GGWAVE_TX_PROTOCOL_CUSTOM_2,
GGWAVE_TX_PROTOCOL_CUSTOM_3,
GGWAVE_TX_PROTOCOL_CUSTOM_4,
GGWAVE_TX_PROTOCOL_CUSTOM_5,
GGWAVE_TX_PROTOCOL_CUSTOM_6,
GGWAVE_TX_PROTOCOL_CUSTOM_7,
GGWAVE_TX_PROTOCOL_CUSTOM_8,
GGWAVE_TX_PROTOCOL_CUSTOM_9
GGWAVE_PROTOCOL_CUSTOM_0,
GGWAVE_PROTOCOL_CUSTOM_1,
GGWAVE_PROTOCOL_CUSTOM_2,
GGWAVE_PROTOCOL_CUSTOM_3,
GGWAVE_PROTOCOL_CUSTOM_4,
GGWAVE_PROTOCOL_CUSTOM_5,
GGWAVE_PROTOCOL_CUSTOM_6,
GGWAVE_PROTOCOL_CUSTOM_7,
GGWAVE_PROTOCOL_CUSTOM_8,
GGWAVE_PROTOCOL_CUSTOM_9
ctypedef enum ggwave_OperatingMode:
GGWAVE_OPERATING_MODE_RX,
@@ -58,22 +58,25 @@ cdef extern from "ggwave.h" nogil:
int ggwave_encode(
ggwave_Instance instance,
const char * dataBuffer,
int dataSize,
ggwave_TxProtocolId txProtocolId,
const void * payloadBuffer,
int payloadSize,
ggwave_ProtocolId protocolId,
int volume,
char * outputBuffer,
void * waveformBuffer,
int query);
int ggwave_decode(
ggwave_Instance instance,
const char * dataBuffer,
int dataSize,
char * outputBuffer);
const void * waveformBuffer,
int waveformSize,
void * payloadBuffer);
void ggwave_setLogFile(void * fptr);
void ggwave_toggleRxProtocol(
ggwave_Instance instance,
ggwave_TxProtocolId rxProtocolId,
void ggwave_rxToggleProtocol(
ggwave_ProtocolId protocolId,
int state);
void ggwave_txToggleProtocol(
ggwave_ProtocolId protocolId,
int state);
+8 -5
View File
@@ -19,7 +19,7 @@ def init(parameters = None):
def free(instance):
return cggwave.ggwave_free(instance)
def encode(payload, txProtocolId = 1, volume = 10, instance = None):
def encode(payload, protocolId = 1, volume = 10, instance = None):
""" Encode payload into an audio waveform.
@param {string} payload, the data to be encoded
@return Generated audio waveform bytes representing 16-bit signed integer samples.
@@ -33,12 +33,12 @@ def encode(payload, txProtocolId = 1, volume = 10, instance = None):
own = True
instance = init(getDefaultParameters())
n = cggwave.ggwave_encode(instance, cdata, len(data_bytes), txProtocolId, volume, NULL, 1)
n = cggwave.ggwave_encode(instance, cdata, len(data_bytes), protocolId, volume, NULL, 1)
cdef bytes output_bytes = bytes(n)
cdef char* coutput = output_bytes
n = cggwave.ggwave_encode(instance, cdata, len(data_bytes), txProtocolId, volume, coutput, 0)
n = cggwave.ggwave_encode(instance, cdata, len(data_bytes), protocolId, volume, coutput, 0)
if (own):
free(instance)
@@ -70,5 +70,8 @@ def disableLog():
def enableLog():
cggwave.ggwave_setLogFile(stderr);
def toggleRxProtocol(instance, rxProtocolId, state):
cggwave.ggwave_toggleRxProtocol(instance, rxProtocolId, state);
def rxToggleProtocol(protocolId, state):
cggwave.ggwave_rxToggleProtocol(protocolId, state);
def txToggleProtocol(protocolId, state):
cggwave.ggwave_txToggleProtocol(protocolId, state);
+16 -19
View File
@@ -45,41 +45,39 @@ void mainUpdate(void *) {
extern "C" {
EMSCRIPTEN_KEEPALIVE
int sendData(int textLength, const char * text, int protocolId, int volume) {
g_ggWave->init(textLength, text, g_ggWave->getTxProtocol(protocolId), volume);
g_ggWave->init(textLength, text, GGWave::TxProtocolId(protocolId), volume);
return 0;
}
EMSCRIPTEN_KEEPALIVE
int getText(char * text) {
std::copy(g_ggWave->getRxData().begin(), g_ggWave->getRxData().end(), text);
std::copy(g_ggWave->rxData().begin(), g_ggWave->rxData().end(), text);
return 0;
}
EMSCRIPTEN_KEEPALIVE
float getSampleRate() { return g_ggWave->getSampleRateInp(); }
float sampleRate() { return g_ggWave->sampleRateInp(); }
EMSCRIPTEN_KEEPALIVE
int getFramesToRecord() { return g_ggWave->getFramesToRecord(); }
int framesToRecord() { return g_ggWave->rxFramesToRecord(); }
EMSCRIPTEN_KEEPALIVE
int getFramesLeftToRecord() { return g_ggWave->getFramesLeftToRecord(); }
int framesLeftToRecord() { return g_ggWave->rxFramesLeftToRecord(); }
EMSCRIPTEN_KEEPALIVE
int getFramesToAnalyze() { return g_ggWave->getFramesToAnalyze(); }
int framesToAnalyze() { return g_ggWave->rxFramesToAnalyze(); }
EMSCRIPTEN_KEEPALIVE
int getFramesLeftToAnalyze() { return g_ggWave->getFramesLeftToAnalyze(); }
int framesLeftToAnalyze() { return g_ggWave->rxFramesLeftToAnalyze(); }
EMSCRIPTEN_KEEPALIVE
int hasDeviceOutput() { return g_devIdOut; }
int hasDeviceOutput() { return g_devIdOut; }
EMSCRIPTEN_KEEPALIVE
int hasDeviceCapture() { return g_devIdInp; }
int hasDeviceCapture() { return g_devIdInp; }
EMSCRIPTEN_KEEPALIVE
int doInit() {
return g_doInit();
}
int doInit() { return g_doInit(); }
}
void GGWave_setDefaultCaptureDeviceName(std::string name) {
@@ -253,16 +251,16 @@ bool GGWave_mainLoop() {
return false;
}
if (g_ggWave->hasTxData() == false) {
if (g_ggWave->txHasData() == false) {
SDL_PauseAudioDevice(g_devIdOut, SDL_FALSE);
static auto tLastNoData = std::chrono::high_resolution_clock::now();
auto tNow = std::chrono::high_resolution_clock::now();
if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesOut()) {
if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->samplesPerFrame()*g_ggWave->sampleSizeOut()) {
SDL_PauseAudioDevice(g_devIdInp, SDL_FALSE);
const int nHave = (int) SDL_GetQueuedAudioSize(g_devIdInp);
const int nNeed = g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp();
const int nNeed = g_ggWave->samplesPerFrame()*g_ggWave->sampleSizeInp();
if (::getTime_ms(tLastNoData, tNow) > 500.0f && nHave >= nNeed) {
static std::vector<uint8_t> dataInp(nNeed);
SDL_DequeueAudio(g_devIdInp, dataInp.data(), nNeed);
@@ -271,7 +269,7 @@ bool GGWave_mainLoop() {
fprintf(stderr, "Warning: failed to decode input data!\n");
} else {
GGWave::TxRxData rxData;
int n = g_ggWave->takeRxData(rxData);
int n = g_ggWave->rxTakeData(rxData);
if (n > 0) {
std::time_t timestamp = std::time(nullptr);
std::string tstr = std::asctime(std::localtime(&timestamp));
@@ -335,7 +333,8 @@ int main(int argc, char** argv) {
printf("\n");
#endif
const GGWave::TxProtocols protocols = {
auto & protocols = GGWave::Protocols::rx();
protocols = {
{ "[R2T2] Normal", 64, 9, 1, 2, true, },
{ "[R2T2] Fast", 64, 6, 1, 2, true, },
{ "[R2T2] Fastest", 64, 3, 1, 2, true, },
@@ -356,8 +355,6 @@ int main(int argc, char** argv) {
return false;
}
g_ggWave->setRxProtocols(protocols);
isInitialized = true;
printf("Listening for payload with length = %d bytes ..\n", payloadLength);
+2 -1
View File
@@ -101,6 +101,7 @@
parameters.samplesPerFrame = 512;
parameters.sampleRateInp = context.sampleRate;
parameters.sampleRateOut = context.sampleRate;
parameters.operatingMode = GGWAVE_OPERATING_MODE_RX_AND_TX | GGWAVE_OPERATING_MODE_USE_DSS;
instance = ggwave.init(parameters);
}
}
@@ -122,7 +123,7 @@
}
// generate audio waveform
var waveform = ggwave.encode(instance, payload, ggwave.TxProtocolId.GGWAVE_TX_PROTOCOL_MT_FASTEST, 25)
var waveform = ggwave.encode(instance, payload, ggwave.TxProtocolId.GGWAVE_PROTOCOL_MT_FASTEST, 25)
// play audio
var buf = convertTypedArray(waveform, Float32Array);
+11 -20
View File
@@ -48,29 +48,20 @@ void loop() {
Serial.println("trying to create ggwave instance");
auto p = GGWave::getDefaultParameters();
p.sampleRateInp = frequency;
p.sampleRateOut = frequency;
p.sampleRate = frequency;
p.sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I16;
p.payloadLength = 16;
p.sampleRateInp = frequency;
p.sampleRateOut = frequency;
p.sampleRate = frequency;
p.samplesPerFrame = 128;
p.payloadLength = 16;
p.operatingMode = (ggwave_OperatingMode) (GGWAVE_OPERATING_MODE_RX | GGWAVE_OPERATING_MODE_TX | GGWAVE_OPERATING_MODE_USE_DSS | GGWAVE_OPERATING_MODE_TX_ONLY_TONES);
p.sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I16;
p.sampleFormatOut = GGWAVE_SAMPLE_FORMAT_I16;
p.operatingMode = (ggwave_OperatingMode) (GGWAVE_OPERATING_MODE_RX | GGWAVE_OPERATING_MODE_TX | GGWAVE_OPERATING_MODE_USE_DSS | GGWAVE_OPERATING_MODE_TX_ONLY_TONES);
{
auto & protocols = GGWave::getTxProtocols();
for (auto & p : protocols) {
p.enabled = false;
}
protocols[GGWAVE_TX_PROTOCOL_MT_FASTEST].enabled = true;
protocols[GGWAVE_TX_PROTOCOL_DT_FASTEST].enabled = true;
}
GGWave::Protocols::tx().only({GGWAVE_PROTOCOL_MT_FASTEST, GGWAVE_PROTOCOL_DT_FASTEST});
GGWave::Protocols::rx().only({GGWAVE_PROTOCOL_MT_FASTEST, GGWAVE_PROTOCOL_DT_FASTEST});
GGWave ggwave(p);
ggwave.setLogFile(nullptr);
ggwave.setRxProtocols({
ggwave.getTxProtocol(GGWAVE_TX_PROTOCOL_MT_FASTEST),
ggwave.getTxProtocol(GGWAVE_TX_PROTOCOL_DT_FASTEST),
});
Serial.println("Instance initialized");
@@ -103,14 +94,14 @@ void loop() {
Serial.println(tEnd - tStart);
}
nr = ggwave.takeRxData(result);
nr = ggwave.rxTakeData(result);
if (nr > 0) {
Serial.println(tEnd - tStart);
Serial.println(nr);
Serial.println((char *)result.data());
if (strcmp((char *)result.data(), "test") == 0) {
ggwave.init("hello", ggwave.getTxProtocol(GGWAVE_TX_PROTOCOL_MT_FASTEST));
ggwave.init("hello", GGWave::TxProtocolId(GGWAVE_PROTOCOL_MT_FASTEST));
ggwave.encode();
const auto & tones = ggwave.txTones();
+1
View File
@@ -1,5 +1,6 @@
ggwave
ggwave.cpp
fft.h
resampler.h
resampler.cpp
reed-solomon
+6 -5
View File
@@ -1,9 +1,10 @@
#
# arduino-tx
configure_file(${CMAKE_SOURCE_DIR}/include/ggwave/ggwave.h ${CMAKE_CURRENT_SOURCE_DIR}/ggwave/ggwave.h COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/ggwave.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ggwave.cpp COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/reed-solomon/gf.hpp ${CMAKE_CURRENT_SOURCE_DIR}/reed-solomon/gf.hpp COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/reed-solomon/rs.hpp ${CMAKE_CURRENT_SOURCE_DIR}/reed-solomon/rs.hpp COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/include/ggwave/ggwave.h ${CMAKE_CURRENT_SOURCE_DIR}/ggwave/ggwave.h COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/ggwave.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ggwave.cpp COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/fft.h ${CMAKE_CURRENT_SOURCE_DIR}/fft.h COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/reed-solomon/gf.hpp ${CMAKE_CURRENT_SOURCE_DIR}/reed-solomon/gf.hpp COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/reed-solomon/rs.hpp ${CMAKE_CURRENT_SOURCE_DIR}/reed-solomon/rs.hpp COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/reed-solomon/poly.hpp ${CMAKE_CURRENT_SOURCE_DIR}/reed-solomon/poly.hpp COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/reed-solomon/LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/reed-solomon/LICENSE COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/src/reed-solomon/LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/reed-solomon/LICENSE COPYONLY)
+31 -5
View File
@@ -1,4 +1,4 @@
#include <ArduinoSTL.h>
#include "Arduino_AVRSTL.h"
#include "ggwave/ggwave.h"
@@ -9,6 +9,7 @@ const int kPinButton1 = 4;
void setup() {
Serial.begin(57600);
display_freeram();
//pinMode(kPinLed0, OUTPUT);
//pinMode(kPinSpeaker, OUTPUT);
@@ -61,17 +62,42 @@ char txt[16];
int pressed = 0;
bool isDown = false;
void display_freeram() {
Serial.print(F("- SRAM left: "));
Serial.println(freeRam());
}
int freeRam() {
extern int __heap_start,*__brkval;
int v;
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);
}
void loop() {
Serial.println("hello");
auto p = GGWave::getDefaultParameters();
p.sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I16;
p.payloadLength = 4;
p.sampleRateInp = 6000;
p.sampleRateOut = 6000;
p.sampleRate = 6000;
p.samplesPerFrame = 128;
p.payloadLength = 4;
p.operatingMode = (ggwave_OperatingMode) (GGWAVE_OPERATING_MODE_TX | GGWAVE_OPERATING_MODE_TX_ONLY_TONES);
p.sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I16;
p.sampleFormatOut = GGWAVE_SAMPLE_FORMAT_U8;
p.operatingMode = (ggwave_OperatingMode) (GGWAVE_OPERATING_MODE_TX | GGWAVE_OPERATING_MODE_TX_ONLY_TONES);
GGWave::getTxProtocols() = GGWave::TxProtocols({{ "[MT] Fastest", 24, 3, 1, 2, true, }});
delay(1000);
GGWave::Protocols::kDefault() = {};
Serial.println("aaaaaaaaaaaa");
GGWave::Protocols::tx() = { { "[MT] Fastest", 24, 3, 1, 2, true, } };
delay(1000);
display_freeram();
Serial.println("xxxxxxxxxxx");
delay(1000);
Serial.println("yyyyyyyyyyyy");
GGWave ggwave(p);
display_freeram();
while (true) {
delay(1000);
+10 -10
View File
@@ -40,17 +40,17 @@
<script type="text/javascript" src="ggwave.js"></script>
<script type='text/javascript'>
window.AudioContext = window.AudioContext || window.webkitAudioContext;
window.AudioContext = window.AudioContext || window.webkitAudioContext;
window.OfflineAudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext;
var context = null;
var context = null;
var recorder = null;
// the ggwave module instance
var ggwave = null;
var ggwave = null;
var ggwave_FluentPet = null;
var parameters = null;
var instance = null;
var parameters = null;
var instance = null;
const kPayloadLength = 3;
@@ -65,10 +65,10 @@
ggwave_FluentPet = obj;
});
var txData = document.getElementById("txData");
var rxData = document.getElementById("rxData");
var txData = document.getElementById("txData");
var rxData = document.getElementById("rxData");
var captureStart = document.getElementById("captureStart");
var captureStop = document.getElementById("captureStop");
var captureStop = document.getElementById("captureStop");
// helper function
function convertTypedArray(src, type) {
@@ -113,9 +113,9 @@
// generate audio waveform
var waveform = null;
if (document.getElementById("checkbox-fp").checked) {
waveform = ggwave_FluentPet.encode(instance, payload, ggwave_FluentPet.TxProtocolId.GGWAVE_TX_PROTOCOL_DT_FAST, 25)
waveform = ggwave_FluentPet.encode(instance, payload, ggwave_FluentPet.TxProtocolId.GGWAVE_PROTOCOL_DT_FAST, 25)
} else {
waveform = ggwave.encode(instance, payload, ggwave.TxProtocolId.GGWAVE_TX_PROTOCOL_DT_FAST, 25)
waveform = ggwave.encode(instance, payload, ggwave.TxProtocolId.GGWAVE_PROTOCOL_DT_FAST, 25)
}
// play audio
+8 -8
View File
@@ -22,13 +22,13 @@ int main(int argc, char** argv) {
printf(" -v - print generated tones on resend\n");
printf("\n");
const auto argm = parseCmdArguments(argc, argv);
const int captureId = argm.count("c") == 0 ? 0 : std::stoi(argm.at("c"));
const int playbackId = argm.count("p") == 0 ? 0 : std::stoi(argm.at("p"));
const int txProtocolId = argm.count("t") == 0 ? 1 : std::stoi(argm.at("t"));
const auto argm = parseCmdArguments(argc, argv);
const int captureId = argm.count("c") == 0 ? 0 : std::stoi(argm.at("c"));
const int playbackId = argm.count("p") == 0 ? 0 : std::stoi(argm.at("p"));
const int txProtocolId = argm.count("t") == 0 ? 1 : std::stoi(argm.at("t"));
const int payloadLength = argm.count("l") == 0 ? -1 : std::stoi(argm.at("l"));
const bool useDSS = argm.count("s") > 0;
const bool printTones = argm.count("v") > 0;
const bool useDSS = argm.count("s") > 0;
const bool printTones = argm.count("v") > 0;
if (GGWave_init(playbackId, captureId, payloadLength, 0.0f, useDSS) == false) {
fprintf(stderr, "Failed to initialize GGWave\n");
@@ -38,7 +38,7 @@ int main(int argc, char** argv) {
auto ggWave = GGWave_instance();
printf("Available Tx protocols:\n");
const auto & protocols = GGWave::getTxProtocols();
const auto & protocols = GGWave::Protocols::kDefault();
for (int i = 0; i < (int) protocols.size(); ++i) {
const auto & protocol = protocols[i];
if (protocol.enabled == false) {
@@ -82,7 +82,7 @@ int main(int argc, char** argv) {
}
{
std::lock_guard<std::mutex> lock(mutex);
ggWave->init(input.size(), input.data(), ggWave->getTxProtocol(txProtocolId), 10);
ggWave->init(input.size(), input.data(), GGWave::TxProtocolId(txProtocolId), 10);
}
inputOld = input;
}
+13 -15
View File
@@ -34,41 +34,39 @@ std::shared_ptr<GGWave> g_ggWave = nullptr;
extern "C" {
EMSCRIPTEN_KEEPALIVE
int sendData(int textLength, const char * text, int protocolId, int volume) {
g_ggWave->init(textLength, text, g_ggWave->getTxProtocol(protocolId), volume);
g_ggWave->init(textLength, text, GGWave::TxProtocolId(protocolId), volume);
return 0;
}
EMSCRIPTEN_KEEPALIVE
int getText(char * text) {
std::copy(g_ggWave->getRxData().begin(), g_ggWave->getRxData().end(), text);
std::copy(g_ggWave->rxData().begin(), g_ggWave->rxData().end(), text);
return 0;
}
EMSCRIPTEN_KEEPALIVE
float getSampleRate() { return g_ggWave->getSampleRateInp(); }
float sampleRate() { return g_ggWave->sampleRateInp(); }
EMSCRIPTEN_KEEPALIVE
int getFramesToRecord() { return g_ggWave->getFramesToRecord(); }
int framesToRecord() { return g_ggWave->rxFramesToRecord(); }
EMSCRIPTEN_KEEPALIVE
int getFramesLeftToRecord() { return g_ggWave->getFramesLeftToRecord(); }
int framesLeftToRecord() { return g_ggWave->rxFramesLeftToRecord(); }
EMSCRIPTEN_KEEPALIVE
int getFramesToAnalyze() { return g_ggWave->getFramesToAnalyze(); }
int framesToAnalyze() { return g_ggWave->rxFramesToAnalyze(); }
EMSCRIPTEN_KEEPALIVE
int getFramesLeftToAnalyze() { return g_ggWave->getFramesLeftToAnalyze(); }
int framesLeftToAnalyze() { return g_ggWave->rxFramesLeftToAnalyze(); }
EMSCRIPTEN_KEEPALIVE
int hasDeviceOutput() { return g_devIdOut; }
int hasDeviceOutput() { return g_devIdOut; }
EMSCRIPTEN_KEEPALIVE
int hasDeviceCapture() { return g_devIdInp; }
int hasDeviceCapture() { return g_devIdInp; }
EMSCRIPTEN_KEEPALIVE
int doInit() {
return GGWave_init(-1, -1);
}
int doInit() { return GGWave_init(-1, -1); }
}
void GGWave_setDefaultCaptureDeviceName(std::string name) {
@@ -244,16 +242,16 @@ bool GGWave_mainLoop() {
return false;
}
if (g_ggWave->hasTxData() == false) {
if (g_ggWave->txHasData() == false) {
SDL_PauseAudioDevice(g_devIdOut, SDL_FALSE);
static auto tLastNoData = std::chrono::high_resolution_clock::now();
auto tNow = std::chrono::high_resolution_clock::now();
if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesOut()) {
if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->samplesPerFrame()*g_ggWave->sampleSizeOut()) {
SDL_PauseAudioDevice(g_devIdInp, SDL_FALSE);
const int nHave = (int) SDL_GetQueuedAudioSize(g_devIdInp);
const int nNeed = g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp();
const int nNeed = g_ggWave->samplesPerFrame()*g_ggWave->sampleSizeInp();
if (::getTime_ms(tLastNoData, tNow) > 500.0f && nHave >= nNeed) {
static std::vector<uint8_t> dataInp(nNeed);
SDL_DequeueAudio(g_devIdInp, dataInp.data(), nNeed);
+1 -1
View File
@@ -4,7 +4,7 @@ import pyaudio
p = pyaudio.PyAudio()
# generate audio waveform for string "hello python"
waveform = ggwave.encode("hello python", txProtocolId = 1, volume = 20)
waveform = ggwave.encode("hello python", protocolId = 1, volume = 20)
print("Transmitting text 'hello python' ...")
stream = p.open(format=pyaudio.paFloat32, channels=1, rate=48000, output=True, frames_per_buffer=4096)
+21 -11
View File
@@ -12,13 +12,14 @@
int main(int argc, char** argv) {
fprintf(stderr, "Usage: %s [-vN] [-sN] [-pN] [-lN]\n", argv[0]);
fprintf(stderr, " -vN - output volume, N in (0, 100], (default: 50)\n");
fprintf(stderr, " -sN - output sample rate, N in [%d, %d], (default: %d)\n", (int) GGWave::kSampleRateMin, (int) GGWave::kSampleRateMax, (int) GGWave::kDefaultSampleRate);
fprintf(stderr, " -SN - output sample rate, N in [%d, %d], (default: %d)\n", (int) GGWave::kSampleRateMin, (int) GGWave::kSampleRateMax, (int) GGWave::kDefaultSampleRate);
fprintf(stderr, " -pN - select the transmission protocol id (default: 1)\n");
fprintf(stderr, " -lN - fixed payload length of size N, N in [1, %d]\n", GGWave::kMaxLengthFixed);
fprintf(stderr, " -s - use Direct Sequence Spread (DSS)\n");
fprintf(stderr, "\n");
fprintf(stderr, " Available protocols:\n");
const auto & protocols = GGWave::getTxProtocols();
const auto & protocols = GGWave::Protocols::kDefault();
for (int i = 0; i < (int) protocols.size(); ++i) {
const auto & protocol = protocols[i];
fprintf(stderr, " %d - %s\n", i, protocol.name);
@@ -29,16 +30,17 @@ int main(int argc, char** argv) {
return -1;
}
auto argm = parseCmdArguments(argc, argv);
const auto argm = parseCmdArguments(argc, argv);
if (argm.find("h") != argm.end()) {
if (argm.count("h") > 0) {
return 0;
}
int volume = argm["v"].empty() ? 50 : std::stoi(argm["v"]);
float sampleRateOut = argm["s"].empty() ? GGWave::kDefaultSampleRate : std::stof(argm["s"]);
int protocolId = argm["p"].empty() ? 1 : std::stoi(argm["p"]);
int payloadLength = argm["l"].empty() ? -1 : std::stoi(argm["l"]);
const int volume = argm.count("v") == 0 ? 50 : std::stoi(argm.at("v"));
const float sampleRateOut = argm.count("S") == 0 ? GGWave::kDefaultSampleRate : std::stof(argm.at("S"));
const int protocolId = argm.count("p") == 0 ? 1 : std::stoi(argm.at("p"));
const int payloadLength = argm.count("l") == 0 ? -1 : std::stoi(argm.at("l"));
const bool useDSS = argm.count("s") > 0;
if (volume <= 0 || volume > 100) {
fprintf(stderr, "Invalid volume\n");
@@ -50,11 +52,16 @@ int main(int argc, char** argv) {
return -1;
}
if (protocolId < 0 || protocolId >= (int) GGWave::getTxProtocols().size()) {
if (protocolId < 0 || protocolId >= (int) protocols.size()) {
fprintf(stderr, "Invalid transmission protocol id\n");
return -1;
}
if (protocols[protocolId].enabled == false) {
fprintf(stderr, "Protocol %d is not enabled\n", protocolId);
return -1;
}
fprintf(stderr, "Enter a text message:\n");
std::string message;
@@ -72,6 +79,9 @@ int main(int argc, char** argv) {
fprintf(stderr, "Generating waveform for message '%s' ...\n", message.c_str());
ggwave_OperatingMode mode = GGWAVE_OPERATING_MODE_RX_AND_TX;
if (useDSS) mode = ggwave_OperatingMode(mode | GGWAVE_OPERATING_MODE_USE_DSS);
GGWave ggWave({
payloadLength,
GGWave::kDefaultSampleRate,
@@ -81,9 +91,9 @@ int main(int argc, char** argv) {
GGWave::kDefaultSoundMarkerThreshold,
GGWAVE_SAMPLE_FORMAT_F32,
GGWAVE_SAMPLE_FORMAT_I16,
GGWAVE_OPERATING_MODE_RX_AND_TX,
mode,
});
ggWave.init(message.size(), message.data(), ggWave.getTxProtocol(protocolId), volume);
ggWave.init(message.size(), message.data(), GGWave::TxProtocolId(protocolId), volume);
const auto nBytes = ggWave.encode();
if (nBytes == 0) {
+13 -7
View File
@@ -48,11 +48,13 @@ int main(int argc, char** argv) {
printf(" -p - print tones, no playback\n");
printf(" -A - print Arduino code\n");
printf(" -b - use 'beep' command\n");
printf(" -s - use Direct Sequence Spread (DSS)\n");
printf(" -tN - transmission protocol\n");
printf(" -lN - fixed payload length of size N, N in [1, %d]\n", GGWave::kMaxLengthFixed);
printf("\n");
const GGWave::TxProtocols protocols = {
auto & protocols = GGWave::Protocols::tx();
protocols = {
{ "[R2T2] Normal", 64, 9, 1, 2, true, },
{ "[R2T2] Fast", 64, 6, 1, 2, true, },
{ "[R2T2] Fastest", 64, 3, 1, 2, true, },
@@ -61,13 +63,17 @@ int main(int argc, char** argv) {
{ "[R2T2] Low Fastest", 16, 3, 1, 2, true, },
};
const auto argm = parseCmdArguments(argc, argv);
const bool printTones = argm.count("p") > 0;
const auto argm = parseCmdArguments(argc, argv);
const bool printTones = argm.count("p") > 0;
const bool printArduino = argm.count("A") > 0;
const bool useBeep = argm.count("b") > 0;
const int txProtocolId = argm.count("t") == 0 ? GGWAVE_TX_PROTOCOL_CUSTOM_0 : std::stoi(argm.at("t"));
const bool useBeep = argm.count("b") > 0;
const bool useDSS = argm.count("s") > 0;
const int txProtocolId = argm.count("t") == 0 ? 0 : std::stoi(argm.at("t"));
const int payloadLength = argm.count("l") == 0 ? 16 : std::stoi(argm.at("l"));
ggwave_OperatingMode mode = ggwave_OperatingMode(GGWAVE_OPERATING_MODE_TX | GGWAVE_OPERATING_MODE_TX_ONLY_TONES);
if (useDSS) mode = ggwave_OperatingMode(mode | GGWAVE_OPERATING_MODE_USE_DSS);
GGWave ggWave({
payloadLength,
GGWave::kDefaultSampleRate,
@@ -77,7 +83,7 @@ int main(int argc, char** argv) {
GGWave::kDefaultSoundMarkerThreshold,
GGWAVE_SAMPLE_FORMAT_F32,
GGWAVE_SAMPLE_FORMAT_F32,
(ggwave_OperatingMode) (GGWAVE_OPERATING_MODE_TX | GGWAVE_OPERATING_MODE_TX_ONLY_TONES),
mode,
});
printf("Available Tx protocols:\n");
@@ -123,7 +129,7 @@ int main(int argc, char** argv) {
return -3;
}
ggWave.init(message.size(), message.data(), protocols.at(GGWave::TxProtocolId(txProtocolId)), 10);
ggWave.init(message.size(), message.data(), GGWave::TxProtocolId(txProtocolId), 10);
ggWave.encode();
int nFrames = 0;
+26 -23
View File
@@ -44,41 +44,39 @@ void mainUpdate(void *) {
extern "C" {
EMSCRIPTEN_KEEPALIVE
int sendData(int textLength, const char * text, int protocolId, int volume) {
g_ggWave->init(textLength, text, g_ggWave->getTxProtocol(protocolId), volume);
g_ggWave->init(textLength, text, GGWave::TxProtocolId(protocolId), volume);
return 0;
}
EMSCRIPTEN_KEEPALIVE
int getText(char * text) {
std::copy(g_ggWave->getRxData().begin(), g_ggWave->getRxData().end(), text);
std::copy(g_ggWave->rxData().begin(), g_ggWave->rxData().end(), text);
return 0;
}
EMSCRIPTEN_KEEPALIVE
float getSampleRate() { return g_ggWave->getSampleRateInp(); }
float sampleRate() { return g_ggWave->sampleRateInp(); }
EMSCRIPTEN_KEEPALIVE
int getFramesToRecord() { return g_ggWave->getFramesToRecord(); }
int framesToRecord() { return g_ggWave->rxFramesToRecord(); }
EMSCRIPTEN_KEEPALIVE
int getFramesLeftToRecord() { return g_ggWave->getFramesLeftToRecord(); }
int framesLeftToRecord() { return g_ggWave->rxFramesLeftToRecord(); }
EMSCRIPTEN_KEEPALIVE
int getFramesToAnalyze() { return g_ggWave->getFramesToAnalyze(); }
int framesToAnalyze() { return g_ggWave->rxFramesToAnalyze(); }
EMSCRIPTEN_KEEPALIVE
int getFramesLeftToAnalyze() { return g_ggWave->getFramesLeftToAnalyze(); }
int framesLeftToAnalyze() { return g_ggWave->rxFramesLeftToAnalyze(); }
EMSCRIPTEN_KEEPALIVE
int hasDeviceOutput() { return g_devIdOut; }
int hasDeviceOutput() { return g_devIdOut; }
EMSCRIPTEN_KEEPALIVE
int hasDeviceCapture() { return g_devIdInp; }
int hasDeviceCapture() { return g_devIdInp; }
EMSCRIPTEN_KEEPALIVE
int doInit() {
return g_doInit();
}
int doInit() { return g_doInit(); }
}
void GGWave_setDefaultCaptureDeviceName(std::string name) {
@@ -89,7 +87,8 @@ bool GGWave_init(
const int playbackId,
const int captureId,
const int payloadLength,
const float sampleRateOffset) {
const float sampleRateOffset,
const bool useDSS) {
if (g_devIdInp && g_devIdOut) {
return false;
@@ -225,6 +224,9 @@ bool GGWave_init(
if (reinit) {
if (g_ggWave) delete g_ggWave;
ggwave_OperatingMode mode = GGWAVE_OPERATING_MODE_RX;
if (useDSS) mode = ggwave_OperatingMode(mode | GGWAVE_OPERATING_MODE_USE_DSS);
g_ggWave = new GGWave({
payloadLength,
(float) g_obtainedSpecInp.freq,
@@ -234,7 +236,7 @@ bool GGWave_init(
GGWave::kDefaultSoundMarkerThreshold,
sampleFormatInp,
sampleFormatOut,
GGWAVE_OPERATING_MODE_RX,
mode,
});
}
@@ -248,16 +250,16 @@ bool GGWave_mainLoop() {
return false;
}
if (g_ggWave->hasTxData() == false) {
if (g_ggWave->txHasData() == false) {
SDL_PauseAudioDevice(g_devIdOut, SDL_FALSE);
static auto tLastNoData = std::chrono::high_resolution_clock::now();
auto tNow = std::chrono::high_resolution_clock::now();
if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesOut()) {
if ((int) SDL_GetQueuedAudioSize(g_devIdOut) < g_ggWave->samplesPerFrame()*g_ggWave->sampleSizeOut()) {
SDL_PauseAudioDevice(g_devIdInp, SDL_FALSE);
const int nHave = (int) SDL_GetQueuedAudioSize(g_devIdInp);
const int nNeed = g_ggWave->getSamplesPerFrame()*g_ggWave->getSampleSizeBytesInp();
const int nNeed = g_ggWave->samplesPerFrame()*g_ggWave->sampleSizeInp();
if (::getTime_ms(tLastNoData, tNow) > 500.0f && nHave >= nNeed) {
static std::vector<uint8_t> dataInp(nNeed);
SDL_DequeueAudio(g_devIdInp, dataInp.data(), nNeed);
@@ -318,10 +320,12 @@ int main(int argc, char** argv) {
printf("Usage: %s [-cN] [-lN]\n", argv[0]);
printf(" -cN - select capture device N\n");
printf(" -lN - fixed payload length of size N, N in [1, %d]\n", GGWave::kMaxLengthFixed);
printf(" -s - use Direct Sequence Spread (DSS)\n");
printf("\n");
#endif
const GGWave::TxProtocols protocols = {
auto & protocols = GGWave::Protocols::rx();
protocols = {
{ "[R2T2] Normal", 64, 9, 1, 2, true, },
{ "[R2T2] Fast", 64, 6, 1, 2, true, },
{ "[R2T2] Fastest", 64, 3, 1, 2, true, },
@@ -330,20 +334,19 @@ int main(int argc, char** argv) {
{ "[R2T2] Low Fastest", 16, 3, 1, 2, true, },
};
const auto argm = parseCmdArguments(argc, argv);
const int captureId = argm.count("c") == 0 ? 0 : std::stoi(argm.at("c"));
const auto argm = parseCmdArguments(argc, argv);
const int captureId = argm.count("c") == 0 ? 0 : std::stoi(argm.at("c"));
const int payloadLength = argm.count("l") == 0 ? 16 : std::stoi(argm.at("l"));
const bool useDSS = argm.count("s") > 0;
bool isInitialized = false;
g_doInit = [&]() {
if (GGWave_init(0, captureId, payloadLength, 0) == false) {
if (GGWave_init(0, captureId, payloadLength, 0, useDSS) == false) {
fprintf(stderr, "Failed to initialize GGWave\n");
return false;
}
g_ggWave->setRxProtocols(protocols);
isInitialized = true;
printf("Listening for payload with length = %d bytes ..\n", payloadLength);
+62 -60
View File
@@ -136,8 +136,8 @@ struct Message {
};
struct GGWaveStats {
bool isReceiving;
bool isAnalyzing;
bool receiving;
bool analyzing;
int framesToRecord;
int framesLeftToRecord;
int framesToAnalyze;
@@ -146,8 +146,8 @@ struct GGWaveStats {
float sampleRateInp;
float sampleRateOut;
float sampleRate;
int sampleSizeBytesInp;
int sampleSizeBytesOut;
int sampleSizeInp;
int sampleSizeOut;
};
struct State {
@@ -201,9 +201,11 @@ struct State {
}
Message message;
GGWave::SpectrumData rxSpectrum;
GGWave::AmplitudeData rxAmplitude;
GGWave::AmplitudeDataI16 txAmplitude;
GGWave::Spectrum rxSpectrum;
GGWave::Amplitude rxAmplitude;
GGWave::AmplitudeI16 txAmplitude;
GGWaveStats stats;
GGWave::TxProtocols txProtocols;
};
@@ -302,7 +304,7 @@ GGSock::FileServer g_fileServer;
// file received data
struct FileInfoExtended {
bool isReceiving = false;
bool receiving = false;
bool readyToShare = false;
bool requestToShare = false;
int nReceivedChunks = 0;
@@ -614,16 +616,16 @@ void updateCore() {
ggWave->init(
n, inputCurrent.message.data.data(),
ggWave->getTxProtocol(inputCurrent.message.protocolId),
GGWave::TxProtocolId(inputCurrent.message.protocolId),
100*inputCurrent.message.volume);
}
if (inputCurrent.flags.needReinit) {
static auto sampleRateInpOld = ggWave->getSampleRateInp();
static auto sampleRateOutOld = ggWave->getSampleRateOut();
GGWave::SampleFormat sampleFormatInpOld = ggWave->getSampleFormatInp();
GGWave::SampleFormat sampleFormatOutOld = ggWave->getSampleFormatOut();
auto rxProtocolsOld = ggWave->getRxProtocols();
static auto sampleRateInpOld = ggWave->sampleRateInp();
static auto sampleRateOutOld = ggWave->sampleRateOut();
GGWave::SampleFormat sampleFormatInpOld = ggWave->sampleFormatInp();
GGWave::SampleFormat sampleFormatOutOld = ggWave->sampleFormatOut();
auto rxProtocolsOld = ggWave->rxProtocols();
GGWave::OperatingMode mode = GGWAVE_OPERATING_MODE_RX_AND_TX;
if (inputCurrent.directSequenceSpread) mode = GGWave::OperatingMode(mode | GGWAVE_OPERATING_MODE_USE_DSS);
@@ -643,7 +645,7 @@ void updateCore() {
GGWave_reset(&parameters);
ggWave = GGWave_instance();
ggWave->setRxProtocols(rxProtocolsOld);
ggWave->rxProtocols() = rxProtocolsOld;
}
if (inputCurrent.flags.changeNeedSpectrum) {
@@ -651,11 +653,11 @@ void updateCore() {
}
if (inputCurrent.flags.stopReceiving) {
ggWave->stopReceiving();
ggWave->rxStopReceiving();
}
if (inputCurrent.flags.changeRxProtocols) {
ggWave->setRxProtocols(inputCurrent.rxProtocols);
ggWave->rxProtocols() = inputCurrent.rxProtocols;
}
inputCurrent.flags.clear();
@@ -664,7 +666,7 @@ void updateCore() {
GGWave_mainLoop();
rxDataLengthLast = ggWave->takeRxData(rxDataLast);
rxDataLengthLast = ggWave->rxTakeData(rxDataLast);
if (rxDataLengthLast == -1) {
g_buffer.stateCore.update = true;
g_buffer.stateCore.flags.newMessage = true;
@@ -672,7 +674,7 @@ void updateCore() {
true,
std::chrono::system_clock::now(),
"",
ggWave->getRxProtocolId(),
ggWave->rxProtocolId(),
ggWave->isDSSEnabled(),
0,
Message::Error,
@@ -687,7 +689,7 @@ void updateCore() {
true,
std::chrono::system_clock::now(),
std::move(message),
ggWave->getRxProtocolId(),
ggWave->rxProtocolId(),
ggWave->isDSSEnabled(),
0,
type,
@@ -697,11 +699,11 @@ void updateCore() {
}
if (needSpectrum) {
if (ggWave->takeRxAmplitude(g_buffer.stateCore.rxAmplitude)) {
if (ggWave->rxTakeAmplitude(g_buffer.stateCore.rxAmplitude)) {
static const int NMax = GGWave::kMaxSamplesPerFrame;
static float tmp[2*NMax];
int N = ggWave->getSamplesPerFrame();
int N = ggWave->samplesPerFrame();
ggWave->computeFFTR(g_buffer.stateCore.rxAmplitude.data(), tmp, N);
g_buffer.stateCore.rxSpectrum.resize(N);
@@ -717,7 +719,7 @@ void updateCore() {
}
}
if (ggWave->takeTxAmplitudeI16(g_buffer.stateCore.txAmplitude)) {
if (ggWave->txTakeAmplitudeI16(g_buffer.stateCore.txAmplitude)) {
g_buffer.stateCore.update = true;
g_buffer.stateCore.flags.newTxAmplitude = true;
}
@@ -725,24 +727,24 @@ void updateCore() {
if (true) {
g_buffer.stateCore.update = true;
g_buffer.stateCore.flags.newStats = true;
g_buffer.stateCore.stats.isReceiving = ggWave->isReceiving();
g_buffer.stateCore.stats.isAnalyzing = ggWave->isAnalyzing();
g_buffer.stateCore.stats.framesToRecord = ggWave->getFramesToRecord();
g_buffer.stateCore.stats.framesLeftToRecord = ggWave->getFramesLeftToRecord();
g_buffer.stateCore.stats.framesToAnalyze = ggWave->getFramesToAnalyze();
g_buffer.stateCore.stats.framesLeftToAnalyze = ggWave->getFramesLeftToAnalyze();
g_buffer.stateCore.stats.samplesPerFrame = ggWave->getSamplesPerFrame();
g_buffer.stateCore.stats.sampleRateInp = ggWave->getSampleRateInp();
g_buffer.stateCore.stats.sampleRateOut = ggWave->getSampleRateOut();
g_buffer.stateCore.stats.sampleRate = GGWave::kDefaultSampleRate;
g_buffer.stateCore.stats.sampleSizeBytesInp = ggWave->getSampleSizeBytesInp();
g_buffer.stateCore.stats.sampleSizeBytesOut = ggWave->getSampleSizeBytesOut();
g_buffer.stateCore.stats.receiving = ggWave->rxReceiving();
g_buffer.stateCore.stats.analyzing = ggWave->rxAnalyzing();
g_buffer.stateCore.stats.framesToRecord = ggWave->rxFramesToRecord();
g_buffer.stateCore.stats.framesLeftToRecord = ggWave->rxFramesLeftToRecord();
g_buffer.stateCore.stats.framesToAnalyze = ggWave->rxFramesToAnalyze();
g_buffer.stateCore.stats.framesLeftToAnalyze = ggWave->rxFramesLeftToAnalyze();
g_buffer.stateCore.stats.samplesPerFrame = ggWave->samplesPerFrame();
g_buffer.stateCore.stats.sampleRateInp = ggWave->sampleRateInp();
g_buffer.stateCore.stats.sampleRateOut = ggWave->sampleRateOut();
g_buffer.stateCore.stats.sampleRate = GGWave::kDefaultSampleRate;
g_buffer.stateCore.stats.sampleSizeInp = ggWave->sampleSizeInp();
g_buffer.stateCore.stats.sampleSizeOut = ggWave->sampleSizeOut();
}
if (isFirstCall) {
g_buffer.stateCore.update = true;
g_buffer.stateCore.flags.newTxProtocols = true;
g_buffer.stateCore.txProtocols = ggWave->getTxProtocols();
g_buffer.stateCore.txProtocols = GGWave::Protocols::tx();
isFirstCall = false;
}
@@ -773,7 +775,7 @@ void renderMain() {
const auto & uri = fileInfo.second.uri;
auto & fileInfoExtended = g_receivedFileInfosExtended[uri];
if (fileInfoExtended.isReceiving == false) {
if (fileInfoExtended.receiving == false) {
continue;
}
@@ -835,7 +837,7 @@ void renderMain() {
};
struct Settings {
int protocolId = GGWAVE_TX_PROTOCOL_AUDIBLE_FAST;
int protocolId = GGWAVE_PROTOCOL_AUDIBLE_FAST;
bool isSampleRateOffset = false;
float sampleRateOffset = -512.0f;
bool isFixedLength = false;
@@ -882,8 +884,8 @@ void renderMain() {
static double tLengthTx = 0.0f;
static GGWaveStats statsCurrent;
static GGWave::SpectrumData spectrumCurrent;
static GGWave::AmplitudeDataI16 txAmplitudeDataCurrent;
static GGWave::Spectrum spectrumCurrent;
static GGWave::AmplitudeI16 txAmplitudeCurrent;
static std::vector<Message> messageHistory;
static std::string inputLast = "";
@@ -912,12 +914,12 @@ void renderMain() {
hasAudioCaptureData = !spectrumCurrent.empty();
}
if (stateCurrent.flags.newTxAmplitude) {
txAmplitudeDataCurrent = std::move(stateCurrent.txAmplitude);
txAmplitudeCurrent = std::move(stateCurrent.txAmplitude);
tStartTx = ImGui::GetTime() + (16.0f*1024.0f)/statsCurrent.sampleRateOut;
tLengthTx = txAmplitudeDataCurrent.size()/statsCurrent.sampleRateOut;
tLengthTx = txAmplitudeCurrent.size()/statsCurrent.sampleRateOut;
{
auto & ampl = txAmplitudeDataCurrent;
auto & ampl = txAmplitudeCurrent;
int nBins = 512;
int nspb = (int) ampl.size()/nBins;
for (int i = 0; i < nBins; ++i) {
@@ -1043,8 +1045,8 @@ void renderMain() {
ImGui::Separator();
ImGui::Text("%s", "");
ImGui::Text("Sample rate (capture): %g, %d B/sample", statsCurrent.sampleRateInp, statsCurrent.sampleSizeBytesInp);
ImGui::Text("Sample rate (playback): %g, %d B/sample", statsCurrent.sampleRateOut, statsCurrent.sampleSizeBytesOut);
ImGui::Text("Sample rate (capture): %g, %d B/sample", statsCurrent.sampleRateInp, statsCurrent.sampleSizeInp);
ImGui::Text("Sample rate (playback): %g, %d B/sample", statsCurrent.sampleRateOut, statsCurrent.sampleSizeOut);
const float kLabelWidth = ImGui::CalcTextSize("Inp. SR Offset: ").x;
@@ -1501,8 +1503,8 @@ void renderMain() {
}
ImGui::EndChild();
if (statsCurrent.isReceiving) {
if (statsCurrent.isAnalyzing) {
if (statsCurrent.receiving) {
if (statsCurrent.analyzing) {
ImGui::TextColored({ 0.0f, 1.0f, 0.0f, 1.0f }, "Analyzing ...");
ImGui::SameLine();
ImGui::ProgressBar(1.0f - float(statsCurrent.framesLeftToAnalyze)/statsCurrent.framesToAnalyze,
@@ -1525,7 +1527,7 @@ void renderMain() {
amax = 0.0f;
frac = (ImGui::GetTime() - tStartTx)/tLengthTx;
if (txAmplitudeDataCurrent.size() && frac <= 1.0f) {
if (txAmplitudeCurrent.size() && frac <= 1.0f) {
struct Funcs {
static float Sample(void * data, int i) {
auto res = std::fabs(((int16_t *)(data))[i]) ;
@@ -1534,7 +1536,7 @@ void renderMain() {
}
static float SampleFrac(void * data, int i) {
if (i > frac*txAmplitudeDataCurrent.size()) {
if (i > frac*txAmplitudeCurrent.size()) {
return 0.0f;
}
return std::fabs(((int16_t *)(data))[i]);
@@ -1550,8 +1552,8 @@ void renderMain() {
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
ImGui::PlotHistogram("##plotSpectrumCurrent",
Funcs::Sample,
txAmplitudeDataCurrent.data(),
(int) txAmplitudeDataCurrent.size(), 0,
txAmplitudeCurrent.data(),
(int) txAmplitudeCurrent.size(), 0,
(std::string("")).c_str(),
0.0f, FLT_MAX, wSize);
ImGui::PopStyleColor(2);
@@ -1562,8 +1564,8 @@ void renderMain() {
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, { 0.0f, 1.0f, 0.0f, 1.0f });
ImGui::PlotHistogram("##plotSpectrumCurrent",
Funcs::SampleFrac,
txAmplitudeDataCurrent.data(),
(int) txAmplitudeDataCurrent.size(), 0,
txAmplitudeCurrent.data(),
(int) txAmplitudeCurrent.size(), 0,
(std::string("")).c_str(),
0.0f, amax, wSize);
ImGui::PopStyleColor(2);
@@ -1835,14 +1837,14 @@ void renderMain() {
if (fileInfoExtended.readyToShare) {
ImGui::TextColored({ 0.0f, 1.0f, 0.0f, 1.0f }, "Ready to share!");
}
} else if (g_fileClient.isConnected() && (fileInfoExtended.isReceiving || fileInfoExtended.nReceivedChunks > 0)) {
if (fileInfoExtended.isReceiving) {
} else if (g_fileClient.isConnected() && (fileInfoExtended.receiving || fileInfoExtended.nReceivedChunks > 0)) {
if (fileInfoExtended.receiving) {
if (ImGui::Button(ICON_FA_PAUSE " Pause")) {
fileInfoExtended.isReceiving = false;
fileInfoExtended.receiving = false;
}
} else {
if (ImGui::Button(ICON_FA_PLAY " Resume")) {
fileInfoExtended.isReceiving = true;
fileInfoExtended.receiving = true;
}
}
@@ -1850,7 +1852,7 @@ void renderMain() {
ImGui::ProgressBar(float(fileInfoExtended.nReceivedChunks)/fileInfo.second.nChunks);
} else if (g_fileClient.isConnected()) {
if (ImGui::Button(ICON_FA_DOWNLOAD " Receive")) {
fileInfoExtended.isReceiving = true;
fileInfoExtended.receiving = true;
fileInfoExtended.isChunkReceived.resize(fileInfo.second.nChunks);
fileInfoExtended.isChunkRequested.resize(fileInfo.second.nChunks);
}
@@ -1858,7 +1860,7 @@ void renderMain() {
ImGui::Text("%s", "");
}
if ((fileInfoExtended.isReceiving == false || isReceived) && fileInfoExtended.requestToShare == false) {
if ((fileInfoExtended.receiving == false || isReceived) && fileInfoExtended.requestToShare == false) {
ImGui::SameLine();
if (ImGui::Button(ICON_FA_TRASH " Clear")) {
toErase = fileInfo.first;
@@ -2034,7 +2036,7 @@ void renderMain() {
}
auto wSize = ImGui::GetContentRegionAvail();
ImGui::PushStyleColor(ImGuiCol_FrameBg, { 0.3f, 0.3f, 0.3f, 0.3f });
if (statsCurrent.isReceiving) {
if (statsCurrent.receiving) {
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, { 1.0f, 0.0f, 0.0f, 1.0f });
} else {
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, { 0.0f, 1.0f, 0.0f, 1.0f });
+255 -157
View File
@@ -33,36 +33,50 @@ extern "C" {
GGWAVE_SAMPLE_FORMAT_F32,
} ggwave_SampleFormat;
// TxProtocol ids
// Protocol ids
typedef enum {
GGWAVE_TX_PROTOCOL_AUDIBLE_NORMAL,
GGWAVE_TX_PROTOCOL_AUDIBLE_FAST,
GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST,
GGWAVE_TX_PROTOCOL_ULTRASOUND_NORMAL,
GGWAVE_TX_PROTOCOL_ULTRASOUND_FAST,
GGWAVE_TX_PROTOCOL_ULTRASOUND_FASTEST,
GGWAVE_TX_PROTOCOL_DT_NORMAL,
GGWAVE_TX_PROTOCOL_DT_FAST,
GGWAVE_TX_PROTOCOL_DT_FASTEST,
GGWAVE_TX_PROTOCOL_MT_NORMAL,
GGWAVE_TX_PROTOCOL_MT_FAST,
GGWAVE_TX_PROTOCOL_MT_FASTEST,
GGWAVE_PROTOCOL_AUDIBLE_NORMAL,
GGWAVE_PROTOCOL_AUDIBLE_FAST,
GGWAVE_PROTOCOL_AUDIBLE_FASTEST,
GGWAVE_PROTOCOL_ULTRASOUND_NORMAL,
GGWAVE_PROTOCOL_ULTRASOUND_FAST,
GGWAVE_PROTOCOL_ULTRASOUND_FASTEST,
GGWAVE_PROTOCOL_DT_NORMAL,
GGWAVE_PROTOCOL_DT_FAST,
GGWAVE_PROTOCOL_DT_FASTEST,
GGWAVE_PROTOCOL_MT_NORMAL,
GGWAVE_PROTOCOL_MT_FAST,
GGWAVE_PROTOCOL_MT_FASTEST,
GGWAVE_TX_PROTOCOL_CUSTOM_0,
GGWAVE_TX_PROTOCOL_CUSTOM_1,
GGWAVE_TX_PROTOCOL_CUSTOM_2,
GGWAVE_TX_PROTOCOL_CUSTOM_3,
GGWAVE_TX_PROTOCOL_CUSTOM_4,
GGWAVE_TX_PROTOCOL_CUSTOM_5,
GGWAVE_TX_PROTOCOL_CUSTOM_6,
GGWAVE_TX_PROTOCOL_CUSTOM_7,
GGWAVE_TX_PROTOCOL_CUSTOM_8,
GGWAVE_TX_PROTOCOL_CUSTOM_9,
GGWAVE_PROTOCOL_CUSTOM_0,
GGWAVE_PROTOCOL_CUSTOM_1,
GGWAVE_PROTOCOL_CUSTOM_2,
GGWAVE_PROTOCOL_CUSTOM_3,
GGWAVE_PROTOCOL_CUSTOM_4,
GGWAVE_PROTOCOL_CUSTOM_5,
GGWAVE_PROTOCOL_CUSTOM_6,
GGWAVE_PROTOCOL_CUSTOM_7,
GGWAVE_PROTOCOL_CUSTOM_8,
GGWAVE_PROTOCOL_CUSTOM_9,
GGWAVE_TX_PROTOCOL_COUNT,
} ggwave_TxProtocolId;
GGWAVE_PROTOCOL_COUNT,
} ggwave_ProtocolId;
// Operating modes of ggwave
//
// GGWAVE_OPERATING_MODE_RX:
// The instance will be able to receive audio data
//
// GGWAVE_OPERATING_MODE_TX:
// The instance will be able generate audio waveforms for transmission
//
// GGWAVE_OPERATING_MODE_TX_ONLY_TONES:
// The encoding process generates only a list of tones instead of full audio
// waveform. This is useful for low-memory devices and embedded systems.
//
// GGWAVE_OPERATING_MODE_USE_DSS:
// Enable the built-in Direct Sequence Spread (DSS) algorithm
//
typedef enum {
GGWAVE_OPERATING_MODE_RX = 1 << 1,
GGWAVE_OPERATING_MODE_TX = 1 << 2,
@@ -149,13 +163,13 @@ extern "C" {
// Encode data into audio waveform
//
// instance - the GGWave instance to use
// dataBuffer - the data to encode
// dataSize - number of bytes in the input dataBuffer
// txProtocolId - the protocol to use for encoding
// payloadBuffer - the data to encode
// payloadSize - number of bytes in the input payloadBuffer
// protocolId - the protocol to use for encoding
// 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, encode data in to outputBuffer, returns number of bytes
// waveformBuffer - the generated audio waveform. must be big enough to fit the generated data
// query - if == 0, encode data in to waveformBuffer, returns number of bytes
// if != 0, do not perform encoding.
// if == 1, return waveform size in bytes
// if != 1, return waveform size in samples
@@ -168,7 +182,7 @@ extern "C" {
//
// payload -> waveform
//
// When calling it, make sure that the outputBuffer is big enough to store the
// When calling it, make sure that the waveformBuffer is big enough to store the
// generated waveform. This means that its size must be at least:
//
// nSamples*sizeOfSample_bytes
@@ -180,45 +194,38 @@ extern "C" {
// If query != 0, then this function does not perform the actual encoding and just
// outputs the expected size of the waveform that would be generated if you call it
// with query == 0. This mechanism can be used to ask ggwave how much memory to
// allocate for the outputBuffer. For example:
// allocate for the waveformBuffer. For example:
//
// // this is the data to encode
// const char * payload = "test";
//
// // query the number of bytes in the waveform
// int n = ggwave_encode(instance, payload, 4, GGWAVE_TX_PROTOCOL_AUDIBLE_FAST, 25, NULL, 1);
// int n = ggwave_encode(instance, payload, 4, GGWAVE_PROTOCOL_AUDIBLE_FAST, 25, NULL, 1);
//
// // allocate the output buffer
// char waveform[n];
//
// // generate the waveform
// ggwave_encode(instance, payload, 4, GGWAVE_TX_PROTOCOL_AUDIBLE_FAST, 25, waveform, 0);
// ggwave_encode(instance, payload, 4, GGWAVE_PROTOCOL_AUDIBLE_FAST, 25, waveform, 0);
//
// The dataBuffer can be any binary data that you would like to transmit (i.e. the payload).
// The payloadBuffer can be any binary data that you would like to transmit (i.e. the payload).
// Usually, this is some text, but it can be any sequence of bytes.
//
// todo:
// - change the type of dataBuffer to const void *
// - change the type of outputBuffer to void *
// - rename dataBuffer to payloadBuffer
// - rename dataSize to payloadSize
// - rename outputBuffer to waveformBuffer
//
GGWAVE_API int ggwave_encode(
ggwave_Instance instance,
const char * dataBuffer,
int dataSize,
ggwave_TxProtocolId txProtocolId,
const void * payloadBuffer,
int payloadSize,
ggwave_ProtocolId protocolId,
int volume,
char * outputBuffer,
void * waveformBuffer,
int query);
// Decode an audio waveform into data
//
// instance - the GGWave instance to use
// dataBuffer - the audio waveform
// dataSize - number of bytes in the input dataBuffer
// outputBuffer - stores the decoded data on success
// waveformBuffer - the audio waveform
// waveformSize - number of bytes in the input waveformBuffer
// payloadBuffer - stores the decoded data on success
// the maximum size of the output is GGWave::kMaxDataSize
//
// returns the number of decoded bytes
@@ -235,7 +242,7 @@ extern "C" {
// If the return value is greater than 0, then there are that number of bytes decoded.
//
// IMPORTANT:
// Notice that the decoded data written to the outputBuffer is NOT null terminated.
// Notice that the decoded data written to the payloadBuffer is NOT null terminated.
//
// Example:
//
@@ -250,50 +257,60 @@ extern "C" {
// }
// }
//
// todo:
// - change the type of dataBuffer to const void *
// - change the type of outputBuffer to void *
// - rename dataBuffer to waveformBuffer
// - rename dataSize to waveformSize
// - rename outputBuffer to payloadBuffer
//
GGWAVE_API int ggwave_decode(
ggwave_Instance instance,
const char * dataBuffer,
int dataSize,
char * outputBuffer);
const void * waveformBuffer,
int waveformSize,
void * payloadBuffer);
// Memory-safe overload of ggwave_decode
//
// outputSize - optionally specify the size of the output buffer
// payloadSize - optionally specify the size of the output buffer
//
// If the return value is -2 then the provided outputBuffer was not big enough to
// If the return value is -2 then the provided payloadBuffer was not big enough to
// store the decoded data.
//
// See ggwave_decode for more information
//
GGWAVE_API int ggwave_ndecode(
ggwave_Instance instance,
const char * dataBuffer,
int dataSize,
char * outputBuffer,
int outputSize);
const void * waveformBuffer,
int waveformSize,
void * payloadBuffer,
int payloadSize);
// Toggle Rx protocols on and off
//
// instance - the GGWave instance to use
// rxProtocolId - Id of the Rx protocol to modify
// state - 0 - disable, 1 - enable
// protocolId - Id of the Rx protocol to modify
// state - 0 - disable, 1 - enable
//
// If an Rx protocol is enabled, the GGWave instance will attempt to decode received
// data using this protocol. By default, all protocols are enabled.
// If an Rx protocol is enabled, newly constructued GGWave instances will attempt to decode
// received data using this protocol. By default, all protocols are enabled.
// Use this function to restrict the number of Rx protocols used in the decoding
// process. This helps to reduce the number of false positives and improves the transmission
// accuracy, especially when the Tx/Rx protocol is known in advance.
//
GGWAVE_API void ggwave_toggleRxProtocol(
ggwave_Instance instance,
ggwave_TxProtocolId rxProtocolId,
// Note that this function does not affect the decoding process of instances that have
// already been created.
//
GGWAVE_API void ggwave_rxToggleProtocol(
ggwave_ProtocolId protocolId,
int state);
// Toggle Tx protocols on and off
//
// protocolId - Id of the Tx protocol to modify
// state - 0 - disable, 1 - enable
//
// If an Tx protocol is enabled, newly constructued GGWave instances will be able to transmit
// data using this protocol. By default, all protocols are enabled.
// Use this function to restrict the number of Tx protocols used for transmission.
// This can reduce the required memory by the GGWave instance.
//
// Note that this function does not affect instances that have already been created.
//
GGWAVE_API void ggwave_txToggleProtocol(
ggwave_ProtocolId protocolId,
int state);
#ifdef __cplusplus
@@ -326,11 +343,12 @@ public:
using Parameters = ggwave_Parameters;
using SampleFormat = ggwave_SampleFormat;
using TxProtocolId = ggwave_TxProtocolId;
using RxProtocolId = ggwave_TxProtocolId;
using ProtocolId = ggwave_ProtocolId;
using TxProtocolId = ggwave_ProtocolId;
using RxProtocolId = ggwave_ProtocolId;
using OperatingMode = ggwave_OperatingMode;
struct TxProtocol {
struct Protocol {
const char * name; // string identifier of the protocol
int freqStart; // FFT bin index of the lowest frequency
@@ -343,37 +361,56 @@ public:
int nDataBitsPerTx() const { return 8*bytesPerTx; }
};
using RxProtocol = TxProtocol;
using TxProtocol = Protocol;
using RxProtocol = Protocol;
using TxProtocols = std::vector<TxProtocol>;
using RxProtocols = std::vector<RxProtocol>;
struct Protocols;
static TxProtocols & getTxProtocols() {
static TxProtocols kTxProtocols(GGWAVE_TX_PROTOCOL_COUNT);
using TxProtocols = Protocols;
using RxProtocols = Protocols;
static bool kInitialized = false;
if (kInitialized == false) {
for (auto & txProtocol : kTxProtocols) {
txProtocol.enabled = false;
struct Protocols : public std::vector<Protocol> {
using std::vector<Protocol>::vector;
void enableAll();
void disableAll();
void toggle(ProtocolId id, bool state);
void only(ProtocolId id);
void only(std::initializer_list<ProtocolId> ids);
static Protocols & kDefault() {
static Protocols kProtocols(GGWAVE_PROTOCOL_COUNT);
static bool kInitialized = false;
if (kInitialized == false) {
for (auto & protocol : kProtocols) {
protocol.name = nullptr;
protocol.enabled = false;
}
kProtocols[GGWAVE_PROTOCOL_AUDIBLE_NORMAL] = { "Normal", 40, 9, 3, 1, true, };
kProtocols[GGWAVE_PROTOCOL_AUDIBLE_FAST] = { "Fast", 40, 6, 3, 1, true, };
kProtocols[GGWAVE_PROTOCOL_AUDIBLE_FASTEST] = { "Fastest", 40, 3, 3, 1, true, };
kProtocols[GGWAVE_PROTOCOL_ULTRASOUND_NORMAL] = { "[U] Normal", 320, 9, 3, 1, true, };
kProtocols[GGWAVE_PROTOCOL_ULTRASOUND_FAST] = { "[U] Fast", 320, 6, 3, 1, true, };
kProtocols[GGWAVE_PROTOCOL_ULTRASOUND_FASTEST] = { "[U] Fastest", 320, 3, 3, 1, true, };
kProtocols[GGWAVE_PROTOCOL_DT_NORMAL] = { "[DT] Normal", 24, 9, 1, 1, true, };
kProtocols[GGWAVE_PROTOCOL_DT_FAST] = { "[DT] Fast", 24, 6, 1, 1, true, };
kProtocols[GGWAVE_PROTOCOL_DT_FASTEST] = { "[DT] Fastest", 24, 3, 1, 1, true, };
kProtocols[GGWAVE_PROTOCOL_MT_NORMAL] = { "[MT] Normal", 24, 9, 1, 2, true, };
kProtocols[GGWAVE_PROTOCOL_MT_FAST] = { "[MT] Fast", 24, 6, 1, 2, true, };
kProtocols[GGWAVE_PROTOCOL_MT_FASTEST] = { "[MT] Fastest", 24, 3, 1, 2, true, };
kInitialized = true;
}
kTxProtocols[GGWAVE_TX_PROTOCOL_AUDIBLE_NORMAL] = { "Normal", 40, 9, 3, 1, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_AUDIBLE_FAST] = { "Fast", 40, 6, 3, 1, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST] = { "Fastest", 40, 3, 3, 1, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_ULTRASOUND_NORMAL] = { "[U] Normal", 320, 9, 3, 1, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_ULTRASOUND_FAST] = { "[U] Fast", 320, 6, 3, 1, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_ULTRASOUND_FASTEST] = { "[U] Fastest", 320, 3, 3, 1, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_DT_NORMAL] = { "[DT] Normal", 24, 9, 1, 1, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_DT_FAST] = { "[DT] Fast", 24, 6, 1, 1, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_DT_FASTEST] = { "[DT] Fastest", 24, 3, 1, 1, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_MT_NORMAL] = { "[MT] Normal", 24, 9, 1, 2, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_MT_FAST] = { "[MT] Fast", 24, 6, 1, 2, true, };
kTxProtocols[GGWAVE_TX_PROTOCOL_MT_FASTEST] = { "[MT] Fastest", 24, 3, 1, 2, true, };
kInitialized = true;
return kProtocols;
}
return kTxProtocols;
}
static TxProtocols & tx();
static RxProtocols & rx();
};
struct ToneData {
float freq_hz;
@@ -381,14 +418,46 @@ public:
};
using TonesPerFrame = std::vector<ToneData>;
using Tones = std::vector<TonesPerFrame>;
using Tones = std::vector<TonesPerFrame>;
using AmplitudeData = std::vector<float>;
using AmplitudeDataI16 = std::vector<int16_t>;
using SpectrumData = std::vector<float>;
using RecordedData = std::vector<float>;
using TxRxData = std::vector<uint8_t>;
using Amplitude = std::vector<float>;
using AmplitudeI16 = std::vector<int16_t>;
using Spectrum = std::vector<float>;
using RecordedData = std::vector<float>;
using TxRxData = std::vector<uint8_t>;
// constructor
//
// All memory buffers used by the GGWave instance are allocated upon construction.
// No memory allocations occur after that.
//
// The sizes of the buffers are determined by the parameters and the contents of:
//
// - GGWave::Protocols::rx()
// - GGWave::Protocols::tx()
//
// For optimal performance and minimum memory usage, make sure to enable only the
// Rx and Tx protocols that you need. For example, using a single protocol for Tx
// is achieved like this:
//
// Parameters parameters;
// parameters.operatingMode = GGWAVE_OPERATING_MODE_TX;
// GGWave::Protocols::tx().only(GGWave::ProtocolId::GGWAVE_PROTOCOL_AUDIBLE_NORMAL);
// GGWave instance(parameters);
// instance.init(...);
// instance.encode();
//
// The created instance will only be able to transmit data using the "Normal"
// protocol. Rx will be disabled.
//
// To create a corresponding Rx-only instance, use the following:
//
// Parameters parameters;
// parameters.operatingMode = GGWAVE_OPERATING_MODE_RX;
// GGWave::Protocols::rx().only(GGWave::ProtocolId::GGWAVE_PROTOCOL_AUDIBLE_NORMAL);
// GGWave instance(parameters);
// instance.decode(...);
//
GGWave(const Parameters & parameters);
~GGWave();
@@ -410,10 +479,8 @@ public:
//
// returns false upon invalid parameters or failure to initialize
//
bool init(const char * text, const int volume = kDefaultVolume);
bool init(const char * text, const TxProtocol & txProtocol, const int volume = kDefaultVolume);
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 init(const char * text, TxProtocolId protocolId, const int volume = kDefaultVolume);
bool init(int dataSize, const char * dataBuffer, TxProtocolId protocolId, const int volume = kDefaultVolume);
// expected waveform size of the encoded Tx data in bytes
//
@@ -431,9 +498,9 @@ public:
// encode Tx data into an audio waveform
//
// The generated waveform is returned by calling the cbWaveformOut callback.
// After calling this method, the generated waveform is available through the txData() method
//
// returns false if the encoding fails
// returns the number of bytes in the generated waveform
//
uint32_t encode();
@@ -441,73 +508,106 @@ public:
// 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.
// data - pointer to the waveform data
// nBytes - number of bytes in the waveform
//
// After calling this method, use the Rx methods to check if any data was decoded successfully.
//
// returns false if the provided waveform is somehow invalid
//
bool decode(const void * data, uint32_t nBytes);
//
// instance state
bool hasTxData() const;
//
bool isDSSEnabled() const;
int getSamplesPerFrame() const;
int getSampleSizeBytesInp() const;
int getSampleSizeBytesOut() const;
int samplesPerFrame() const;
int sampleSizeInp() const;
int sampleSizeOut() const;
float getSampleRateInp() const;
float getSampleRateOut() const;
SampleFormat getSampleFormatInp() const;
SampleFormat getSampleFormatOut() const;
float sampleRateInp() const;
float sampleRateOut() const;
SampleFormat sampleFormatInp() const;
SampleFormat sampleFormatOut() const;
//
// Tx
static TxProtocolId getDefaultTxProtocolId() { return GGWAVE_TX_PROTOCOL_AUDIBLE_FAST; }
static const TxProtocol & getDefaultTxProtocol() { return getTxProtocols()[getDefaultTxProtocolId()]; }
static const TxProtocol & getTxProtocol(int id) { return getTxProtocols()[id]; }
static const TxProtocol & getTxProtocol(TxProtocolId id) { return getTxProtocols()[id]; }
//
// get a list of the tones generated for the last waveform
//
// Call this method after calling encode() to get a list of the tones participating in the generated waveform
// Call this method after calling encode() to get a list of the tones
// participating in the generated waveform
//
const Tones & txTones() const;
bool takeTxAmplitudeI16(AmplitudeDataI16 & dst);
// true if there is data pending to be transmitted
bool txHasData() const;
// consume the amplitude data from the last generated waveform
bool txTakeAmplitudeI16(AmplitudeI16 & dst);
// the instance will allow Tx only with these protocols
// they are determined upon construction, using GGWave::Protocols::tx()
const TxProtocols & txProtocols() const;
//
// Rx
bool isReceiving() const;
bool isAnalyzing() const;
//
int getSamplesNeeded() const;
int getFramesToRecord() const;
int getFramesLeftToRecord() const;
int getFramesToAnalyze() const;
int getFramesLeftToAnalyze() const;
bool rxReceiving() const;
bool rxAnalyzing() const;
bool stopReceiving();
void setRxProtocols(const RxProtocols & rxProtocols);
const RxProtocols & getRxProtocols() const;
int rxSamplesNeeded() const;
int rxFramesToRecord() const;
int rxFramesLeftToRecord() const;
int rxFramesToAnalyze() const;
int rxFramesLeftToAnalyze() const;
int lastRxDataLength() const;
bool rxStopReceiving();
const TxRxData & getRxData() const;
const RxProtocol & getRxProtocol() const;
const RxProtocolId & getRxProtocolId() const;
// the instance will attempt to decode only these protocols
// they are determined upon construction, using GGWave::Protocols::rx()
//
// note: do not enable protocols that were not enabled upon construction of the GGWave
// instance, or the decoding will likely crash
RxProtocols & rxProtocols();
int takeRxData(TxRxData & dst);
bool takeRxSpectrum(SpectrumData & dst);
bool takeRxAmplitude(AmplitudeData & dst);
// information about last received data
int rxDataLength() const;
const TxRxData & rxData() const;
const RxProtocol & rxProtocol() const;
const RxProtocolId & rxProtocolId() const;
const Spectrum & rxSpectrum() const;
const Amplitude & rxAmplitude() const;
// consume the received data
//
// returns the data length in bytes
int rxTakeData(TxRxData & dst);
// consume the received spectrum / amplitude data
//
// returns true if there was new data available
bool rxTakeSpectrum(Spectrum & dst);
bool rxTakeAmplitude(Amplitude & dst);
//
// Utils
//
// compute FFT of real values
//
// src - input real-valued data, size is N
// dst - output complex-valued data, size is 2*N
//
// N must be <= kMaxSamplesPerFrame
// N must be == samplesPerFrame()
//
bool computeFFTR(const float * src, float * dst, int N);
// resample audio waveforms from one sample rate to another using
// sinc interpolation
// resample audio waveforms from one sample rate to another using sinc interpolation
class Resampler {
public:
// this controls the number of neighboring samples
@@ -557,21 +657,19 @@ private:
void decode_fixed();
void decode_variable();
int maxFramesPerTx() const;
int minBytesPerTx() const;
int maxBytesPerTx() const;
int maxFramesPerTx(const Protocols & protocols, bool excludeMT) const;
int minBytesPerTx(const Protocols & protocols) const;
int maxBytesPerTx(const Protocols & protocols) const;
double bitFreq(const TxProtocol & p, int bit) const {
return m_hzPerSample*p.freqStart + m_freqDelta_hz*bit;
}
double bitFreq(const Protocol & p, int bit) const;
const float m_sampleRateInp;
const float m_sampleRateOut;
const float m_sampleRate;
const int m_samplesPerFrame;
const float m_isamplesPerFrame;
const int m_sampleSizeBytesInp;
const int m_sampleSizeBytesOut;
const int m_sampleSizeInp;
const int m_sampleSizeOut;
const SampleFormat m_sampleFormatInp;
const SampleFormat m_sampleFormatOut;
+458 -384
View File
File diff suppressed because it is too large Load Diff
+24 -2
View File
@@ -12,6 +12,12 @@
#include <string.h>
#include <assert.h>
#if !defined(ARDUINO) && !defined(PROGMEM)
#define PROGMEM
#else
#include <avr/pgmspace.h>
#endif
namespace RS {
namespace gf {
@@ -19,7 +25,7 @@ namespace gf {
/* GF tables pre-calculated for 0x11d primitive polynomial */
const uint8_t exp[512] = {
const uint8_t exp[512] PROGMEM = {
0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 0x4c,
0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x3, 0x6, 0xc, 0x18, 0x30, 0x60, 0xc0, 0x9d,
0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, 0x46,
@@ -54,7 +60,7 @@ const uint8_t exp[512] = {
0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x1, 0x2
};
const uint8_t log[256] = {
const uint8_t log[256] PROGMEM = {
0x0, 0x0, 0x1, 0x19, 0x2, 0x32, 0x1a, 0xc6, 0x3, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 0x4,
0x64, 0xe0, 0xe, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x8, 0x4c, 0x71, 0x5,
0x8a, 0x65, 0x2f, 0xe1, 0x24, 0xf, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, 0x1d,
@@ -103,7 +109,11 @@ inline uint8_t sub(uint8_t x, uint8_t y) {
inline uint8_t mul(uint16_t x, uint16_t y){
if (x == 0 || y == 0)
return 0;
#ifdef ARDUINO
return pgm_read_byte(exp + pgm_read_byte(log + x) + pgm_read_byte(log + y));
#else
return exp[log[x] + log[y]];
#endif
}
/* @brief Division in Galua Fields
@@ -113,7 +123,11 @@ inline uint8_t mul(uint16_t x, uint16_t y){
inline uint8_t div(uint8_t x, uint8_t y){
assert(y != 0);
if(x == 0) return 0;
#ifdef ARDUINO
return pgm_read_byte(exp + (pgm_read_byte(log + x) + 255 - pgm_read_byte(log + y)) % 255);
#else
return exp[(log[x] + 255 - log[y]) % 255];
#endif
}
/* @brief X in power Y w
@@ -125,14 +139,22 @@ inline uint8_t pow(uint8_t x, intmax_t power){
i *= power;
i %= 255;
if(i < 0) i = i + 255;
#ifdef ARDUINO
return pgm_read_byte(exp + i);
#else
return exp[i];
#endif
}
/* @brief Inversion in Galua Fields
* @param x - number
* @return inversion of x */
inline uint8_t inverse(uint8_t x){
#ifdef ARDUINO
return pgm_read_byte(exp + 255 - pgm_read_byte(log + x)); /* == div(1, x); */
#else
return exp[255 - log[x]]; /* == div(1, x); */
#endif
}
/* ##########################
+20 -8
View File
@@ -27,10 +27,10 @@ int main() {
const char * payload = "test";
char decoded[16];
int n = ggwave_encode(instance, payload, 4, GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST, 50, NULL, 1);
int n = ggwave_encode(instance, payload, 4, GGWAVE_PROTOCOL_AUDIBLE_FASTEST, 50, NULL, 1);
char waveform[n];
int ne = ggwave_encode(instance, payload, 4, GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST, 50, waveform, 0);
int ne = ggwave_encode(instance, payload, 4, GGWAVE_PROTOCOL_AUDIBLE_FASTEST, 50, waveform, 0);
CHECK(ne > 0);
// not enough output buffer size to store the decoded message
@@ -46,14 +46,26 @@ int main() {
CHECK(ret == 4);
// disable Rx protocol
ggwave_toggleRxProtocol(instance, GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST, 0);
ret = ggwave_ndecode(instance, waveform, ne, decoded, 4);
CHECK(ret == -1); // fail
{
ggwave_rxToggleProtocol(GGWAVE_PROTOCOL_AUDIBLE_FASTEST, 0);
ggwave_Instance instanceTmp = ggwave_init(parameters);
ret = ggwave_ndecode(instanceTmp, waveform, ne, decoded, 4);
CHECK(ret == -1); // fail
ggwave_free(instanceTmp);
}
// enable Rx protocol
ggwave_toggleRxProtocol(instance, GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST, 1);
ret = ggwave_ndecode(instance, waveform, ne, decoded, 4);
CHECK(ret == 4); // success
{
ggwave_rxToggleProtocol(GGWAVE_PROTOCOL_AUDIBLE_FASTEST, 1);
ggwave_Instance instanceTmp = ggwave_init(parameters);
ret = ggwave_ndecode(instanceTmp, waveform, ne, decoded, 4);
CHECK(ret == 4); // success
ggwave_free(instanceTmp);
}
decoded[ret] = 0; // null-terminate the received data
CHECK(strcmp(decoded, payload) == 0);
+28 -26
View File
@@ -10,7 +10,8 @@
#include <cstdint>
#include <map>
float frand() { return float(rand()%RAND_MAX)/RAND_MAX; }
constexpr float iRandMax = 1.0f/float(RAND_MAX);
float frand() { return float(rand()%RAND_MAX)*iRandMax; }
#define CHECK(cond) \
if (!(cond)) { \
@@ -181,22 +182,22 @@ int main(int argc, char ** argv) {
std::string payload = "hello";
CHECK(instance.init(payload.c_str()));
CHECK(instance.init(payload.c_str(), GGWAVE_PROTOCOL_AUDIBLE_FAST));
// data
CHECK_F(instance.init(-1, "asd"));
CHECK_T(instance.init(0, nullptr));
CHECK_T(instance.init(0, "asd"));
CHECK_T(instance.init(1, "asd"));
CHECK_T(instance.init(2, "asd"));
CHECK_T(instance.init(3, "asd"));
CHECK_F(instance.init(-1, "asd", GGWAVE_PROTOCOL_AUDIBLE_FAST));
CHECK_T(instance.init(0, nullptr, GGWAVE_PROTOCOL_AUDIBLE_FAST));
CHECK_T(instance.init(0, "asd", GGWAVE_PROTOCOL_AUDIBLE_FAST));
CHECK_T(instance.init(1, "asd", GGWAVE_PROTOCOL_AUDIBLE_FAST));
CHECK_T(instance.init(2, "asd", GGWAVE_PROTOCOL_AUDIBLE_FAST));
CHECK_T(instance.init(3, "asd", GGWAVE_PROTOCOL_AUDIBLE_FAST));
// volume
CHECK_F(instance.init(payload.size(), payload.c_str(), -1));
CHECK_T(instance.init(payload.size(), payload.c_str(), 0));
CHECK_T(instance.init(payload.size(), payload.c_str(), 50));
CHECK_T(instance.init(payload.size(), payload.c_str(), 100));
CHECK_F(instance.init(payload.size(), payload.c_str(), 101));
CHECK_F(instance.init(payload.size(), payload.c_str(), GGWAVE_PROTOCOL_AUDIBLE_FAST, -1));
CHECK_T(instance.init(payload.size(), payload.c_str(), GGWAVE_PROTOCOL_AUDIBLE_FAST, 0));
CHECK_T(instance.init(payload.size(), payload.c_str(), GGWAVE_PROTOCOL_AUDIBLE_FAST, 50));
CHECK_T(instance.init(payload.size(), payload.c_str(), GGWAVE_PROTOCOL_AUDIBLE_FAST, 100));
CHECK_F(instance.init(payload.size(), payload.c_str(), GGWAVE_PROTOCOL_AUDIBLE_FAST, 101));
}
// playback / capture at different sample rates
@@ -213,7 +214,7 @@ int main(int argc, char ** argv) {
parameters.sampleRateOut = srInp;
GGWave instanceOut(parameters);
instanceOut.init(payload.c_str(), instanceOut.getTxProtocol(GGWAVE_TX_PROTOCOL_DT_FASTEST), 25);
instanceOut.init(payload.c_str(), GGWAVE_PROTOCOL_DT_FASTEST, 25);
const auto expectedSize = instanceOut.encodeSize_bytes();
const auto nBytes = instanceOut.encode();
printf("Expected = %d, actual = %d\n", expectedSize, nBytes);
@@ -227,12 +228,12 @@ int main(int argc, char ** argv) {
{
parameters.sampleRateInp = srInp;
GGWave instanceInp(parameters);
instanceInp.rxProtocols().only(GGWAVE_PROTOCOL_DT_FASTEST);
instanceInp.setRxProtocols({instanceInp.getTxProtocol(GGWAVE_TX_PROTOCOL_DT_FASTEST)});
instanceInp.decode(buffer.data(), buffer.size());
GGWave::TxRxData result;
CHECK(instanceInp.takeRxData(result) == (int) payload.size());
CHECK(instanceInp.rxTakeData(result) == (int) payload.size());
for (int i = 0; i < (int) payload.size(); ++i) {
CHECK(payload[i] == result[i]);
}
@@ -248,13 +249,14 @@ int main(int argc, char ** argv) {
if (formatOut != GGWAVE_SAMPLE_FORMAT_I16) continue;
if (formatInp != GGWAVE_SAMPLE_FORMAT_F32) continue;
}
for (const auto & txProtocol : GGWave::getTxProtocols()) {
if (txProtocol.enabled == false) continue;
printf("Testing: protocol = %s, in = %d, out = %d\n", txProtocol.name, formatInp, formatOut);
for (int protocolId = 0; protocolId < GGWAVE_PROTOCOL_COUNT; ++protocolId) {
const auto & protocol = GGWave::Protocols::kDefault()[protocolId];
if (protocol.enabled == false) continue;
printf("Testing: protocol = %s, in = %d, out = %d\n", protocol.name, formatInp, formatOut);
for (int length = 1; length <= (int) payload.size(); ++length) {
// mono-tone protocols with variable length are not supported
if (txProtocol.extra == 2) {
if (protocol.extra == 2) {
break;
}
@@ -264,9 +266,9 @@ int main(int argc, char ** argv) {
parameters.sampleFormatInp = formatInp;
parameters.sampleFormatOut = formatOut;
GGWave instance(parameters);
instance.rxProtocols().only(GGWave::ProtocolId(protocolId));
instance.setRxProtocols({txProtocol});
instance.init(length, payload.data(), txProtocol, 25);
instance.init(length, payload.data(), GGWave::ProtocolId(protocolId), 25);
const auto expectedSize = instance.encodeSize_bytes();
const auto nBytes = instance.encode();
printf("Expected = %d, actual = %d\n", expectedSize, nBytes);
@@ -276,7 +278,7 @@ int main(int argc, char ** argv) {
instance.decode(buffer.data(), buffer.size());
GGWave::TxRxData result;
CHECK(instance.takeRxData(result) == length);
CHECK(instance.rxTakeData(result) == length);
for (int i = 0; i < length; ++i) {
CHECK(payload[i] == result[i]);
}
@@ -291,9 +293,9 @@ int main(int argc, char ** argv) {
parameters.sampleFormatInp = formatInp;
parameters.sampleFormatOut = formatOut;
GGWave instance(parameters);
instance.rxProtocols().only(GGWave::ProtocolId(protocolId));
instance.setRxProtocols({txProtocol});
instance.init(length, payload.data(), txProtocol, 10);
instance.init(length, payload.data(), GGWave::ProtocolId(protocolId), 10);
const auto expectedSize = instance.encodeSize_bytes();
const auto nBytes = instance.encode();
printf("Expected = %d, actual = %d\n", expectedSize, nBytes);
@@ -303,7 +305,7 @@ int main(int argc, char ** argv) {
instance.decode(buffer.data(), buffer.size());
GGWave::TxRxData result;
CHECK(instance.takeRxData(result) == length);
CHECK(instance.rxTakeData(result) == length);
for (int i = 0; i < length; ++i) {
CHECK(payload[i] == result[i]);
}
+1 -1
View File
@@ -8,7 +8,7 @@ factory().then(function(ggwave) {
var payload = 'hello js';
// generate audio waveform for string "hello js"
var waveform = ggwave.encode(instance, payload, ggwave.TxProtocolId.GGWAVE_TX_PROTOCOL_AUDIBLE_FAST, 10);
var waveform = ggwave.encode(instance, payload, ggwave.TxProtocolId.GGWAVE_PROTOCOL_AUDIBLE_FAST, 10);
// decode the audio waveform back to text
var res = ggwave.decode(instance, waveform);
+14 -6
View File
@@ -10,7 +10,7 @@ instance = ggwave.init()
payload = 'hello python'
# generate audio waveform for string "hello python"
waveform = ggwave.encode(payload, txProtocolId = 1, volume = 20, instance = instance)
waveform = ggwave.encode(payload, protocolId = 1, volume = 20, instance = instance)
# decode the audio waveform back to text
res = ggwave.decode(instance, waveform)
@@ -19,15 +19,23 @@ if res != payload.encode():
sys.exit(1)
# disable the Rx protocol - the decoding should fail
ggwave.toggleRxProtocol(instance, rxProtocolId = 1, state = 0)
res = ggwave.decode(instance, waveform)
ggwave.rxToggleProtocol(protocolId = 1, state = 0)
instanceTmp = ggwave.init()
res = ggwave.decode(instanceTmp, waveform)
if res != None:
sys.exit(1)
# re-enable the Rx protocol - the decoding should succeed
ggwave.toggleRxProtocol(instance, rxProtocolId = 1, state = 1)
res = ggwave.decode(instance, waveform)
ggwave.free(instanceTmp);
# re-enable the Rx protocol - the decoding should succeed
ggwave.rxToggleProtocol( protocolId = 1, state = 1)
instanceTmp = ggwave.init()
res = ggwave.decode(instance, waveform)
if res != payload.encode():
sys.exit(1)
ggwave.free(instanceTmp);
ggwave.free(instance);