diff --git a/bindings/python/cggwave.pxd b/bindings/python/cggwave.pxd index 5bb7b74..fcade25 100644 --- a/bindings/python/cggwave.pxd +++ b/bindings/python/cggwave.pxd @@ -37,7 +37,8 @@ cdef extern from "ggwave.h" nogil: int dataSize, ggwave_TxProtocolId txProtocolId, int volume, - char * outputBuffer); + char * outputBuffer, + int query); int ggwave_decode( ggwave_Instance instance, diff --git a/bindings/python/ggwave.pyx b/bindings/python/ggwave.pyx index 2a05d55..e5e16a2 100644 --- a/bindings/python/ggwave.pyx +++ b/bindings/python/ggwave.pyx @@ -1,4 +1,5 @@ cimport cython + from cpython.mem cimport PyMem_Malloc, PyMem_Free import re @@ -27,22 +28,21 @@ def encode(payload, txProtocolId = 1, volume = 10, instance = None): cdef bytes data_bytes = payload.encode() cdef char* cdata = data_bytes - cdef bytes output_bytes = bytes(1024*1024) - cdef char* coutput = output_bytes - own = False if (instance is None): own = True instance = init(getDefaultParameters()) - n = cggwave.ggwave_encode(instance, cdata, len(data_bytes), txProtocolId, volume, coutput) + n = cggwave.ggwave_encode(instance, cdata, len(data_bytes), txProtocolId, 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) if (own): free(instance) - # add short silence at the end - n += 16*1024 - return struct.unpack("h"*n, output_bytes[0:2*n]) def decode(instance, waveform): diff --git a/bindings/python/test.py b/bindings/python/test.py index e426bf8..0dee94f 100644 --- a/bindings/python/test.py +++ b/bindings/python/test.py @@ -3,9 +3,9 @@ import ggwave testFailed = False -n, samples = ggwave.encode("hello python") +samples = ggwave.encode("hello python") -if not (samples and n > 1024): +if not (samples): testFailed = True if testFailed: diff --git a/examples/ggwave-common-sdl2.cpp b/examples/ggwave-common-sdl2.cpp index d7b7bf5..41228a3 100644 --- a/examples/ggwave-common-sdl2.cpp +++ b/examples/ggwave-common-sdl2.cpp @@ -192,8 +192,8 @@ bool GGWave_init( GGWave::SampleFormat sampleFormatOut = GGWAVE_SAMPLE_FORMAT_UNDEFINED; switch (g_obtainedSpecInp.format) { - case AUDIO_U8: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_U8; break; - case AUDIO_S8: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I8; break; + case AUDIO_U8: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_U8; break; + case AUDIO_S8: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I8; break; case AUDIO_U16SYS: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_U16; break; case AUDIO_S16SYS: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I16; break; case AUDIO_S32SYS: sampleFormatInp = GGWAVE_SAMPLE_FORMAT_F32; break; @@ -201,8 +201,8 @@ bool GGWave_init( } switch (g_obtainedSpecOut.format) { - case AUDIO_U8: sampleFormatOut = GGWAVE_SAMPLE_FORMAT_U8; break; - case AUDIO_S8: sampleFormatOut = GGWAVE_SAMPLE_FORMAT_I8; break; + case AUDIO_U8: sampleFormatOut = GGWAVE_SAMPLE_FORMAT_U8; break; + case AUDIO_S8: sampleFormatOut = GGWAVE_SAMPLE_FORMAT_I8; break; case AUDIO_U16SYS: sampleFormatOut = GGWAVE_SAMPLE_FORMAT_U16; break; case AUDIO_S16SYS: sampleFormatOut = GGWAVE_SAMPLE_FORMAT_I16; break; case AUDIO_S32SYS: sampleFormatOut = GGWAVE_SAMPLE_FORMAT_F32; break; diff --git a/examples/ggwave-py/send.py b/examples/ggwave-py/send.py index 613e9cb..0552373 100644 --- a/examples/ggwave-py/send.py +++ b/examples/ggwave-py/send.py @@ -10,6 +10,7 @@ waveform = ggwave.encode("hello python", txProtocolId = 1, volume = 20) print("Transmitting text 'hello python' ...") stream = p.open(format=pyaudio.paInt16, channels=1, rate=48000, output=True, frames_per_buffer=4096) stream.write(np.array(waveform).astype(np.int16), len(waveform)) +stream.write(np.zeros(16*1024), 16*1024) # short silence at the end stream.stop_stream() stream.close() diff --git a/include/ggwave/ggwave.h b/include/ggwave/ggwave.h index 966e9b9..797348a 100644 --- a/include/ggwave/ggwave.h +++ b/include/ggwave/ggwave.h @@ -73,8 +73,11 @@ extern "C" { // txProtocolId - the protocol to use for encoding // volume - the volume of the generated waveform [0, 100] // outputBuffer - the generated audio waveform. must be big enough to fit the generated data + // query - if != 0, do not perform encoding. + // if == 1, return waveform size in bytes + // if != 1, return waveform size in samples // - // returns the number of generated samples + // returns the number of generated bytes or samples (see query) // // returns -1 if there was an error // @@ -87,7 +90,8 @@ extern "C" { int dataSize, ggwave_TxProtocolId txProtocolId, int volume, - char * outputBuffer); + char * outputBuffer, + int query); // Decode an audio waveform into data // instance - the GGWave instance to use @@ -182,24 +186,39 @@ public: static const Parameters & getDefaultParameters(); // set Tx data to encode + // + // This prepares the GGWave instance for transmission. + // To perform the actual encoding, the encode() method must be called + // + // returns false upon invalid parameters or failure to initialize + // bool init(const std::string & text, const int volume = kDefaultVolume); bool init(const std::string & 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); - // expected waveform size of the encoded Tx data + // expected waveform size of the encoded Tx data in bytes uint32_t encodeSize_bytes() const; + + // expected waveform size of the encoded Tx data in samples uint32_t encodeSize_samples() const; // encode Tx data into an audio waveform // + // The generated waveform is returned by calling the cbWaveformOut callback. + // // returns false if the encoding fails // bool encode(const CBWaveformOut & cbWaveformOut); // decode an audio waveform + // + // This methods calls cbWaveformInp multiple times (at least once) until it returns 0. + // Use the Rx methods to check if any data was decoded successfully. + // void decode(const CBWaveformInp & cbWaveformInp); + // instance state const bool & hasTxData() const { return m_hasNewTxData; } const bool & isReceiving() const { return m_receivingData; } const bool & isAnalyzing() const { return m_analyzingData; } @@ -215,17 +234,22 @@ public: const float & getSampleRateInp() const { return m_sampleRateInp; } const float & getSampleRateOut() const { return m_sampleRateOut; } + // Tx + static TxProtocolId getDefaultTxProtocolId() { return GGWAVE_TX_PROTOCOL_AUDIBLE_FAST; } static const TxProtocol & getDefaultTxProtocol() { return getTxProtocols().at(getDefaultTxProtocolId()); } static const TxProtocol & getTxProtocol(int id) { return getTxProtocols().at(TxProtocolId(id)); } static const TxProtocol & getTxProtocol(TxProtocolId id) { return getTxProtocols().at(id); } + int takeTxAmplitudeDataI16(AmplitudeDataI16 & dst); + + // Rx + const TxRxData & getRxData() const { return m_rxData; } const TxProtocol & getRxProtocol() const { return m_rxProtocol; } const TxProtocolId & getRxProtocolId() const { return m_rxProtocolId; } int takeRxData(TxRxData & dst); - int takeTxAmplitudeDataI16(AmplitudeDataI16 & dst); bool takeSpectrum(SpectrumData & dst); private: diff --git a/src/ggwave.cpp b/src/ggwave.cpp index 614bf15..163ad6e 100644 --- a/src/ggwave.cpp +++ b/src/ggwave.cpp @@ -49,7 +49,8 @@ int ggwave_encode( int dataSize, ggwave_TxProtocolId txProtocolId, int volume, - char * outputBuffer) { + char * outputBuffer, + int query) { GGWave * ggWave = (GGWave *) g_instances[instance]; if (ggWave == nullptr) { @@ -62,6 +63,14 @@ int ggwave_encode( return -1; } + if (query != 0) { + if (query == 1) { + return ggWave->encodeSize_bytes(); + } + + return ggWave->encodeSize_samples(); + } + int nSamples = 0; GGWave::CBWaveformOut cbWaveformOut = [&](const void * data, uint32_t nBytes) { diff --git a/tests/test-ggwave.c b/tests/test-ggwave.c index 1b82d6b..54a812a 100644 --- a/tests/test-ggwave.c +++ b/tests/test-ggwave.c @@ -21,11 +21,13 @@ int main() { ggwave_Instance instance = ggwave_init(parameters); int ret; - char waveform[1024*1024]; const char * payload = "test"; char decoded[256]; - ret = ggwave_encode(instance, payload, 4, GGWAVE_TX_PROTOCOL_AUDIBLE_FAST, 50, waveform); + int n = ggwave_encode(instance, payload, 4, GGWAVE_TX_PROTOCOL_AUDIBLE_FAST, 50, NULL, 1); + char waveform[n]; + + ret = ggwave_encode(instance, payload, 4, GGWAVE_TX_PROTOCOL_AUDIBLE_FAST, 50, waveform, 0); CHECK(ret > 0); ret = ggwave_decode(instance, waveform, sizeof(int16_t)*ret, decoded);