mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-09-05 01:17:41 +08:00
ggwave : big refactoring / renaming
This commit is contained in:
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(×tamp));
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,5 +1,6 @@
|
||||
ggwave
|
||||
ggwave.cpp
|
||||
fft.h
|
||||
resampler.h
|
||||
resampler.cpp
|
||||
reed-solomon
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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(¶meters);
|
||||
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
@@ -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
File diff suppressed because it is too large
Load Diff
+24
-2
@@ -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
@@ -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
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user