c, python : add option to query encode size

This commit is contained in:
Georgi Gerganov
2021-01-23 17:13:13 +02:00
parent 0c746c1b15
commit ba8e0cd2b1
8 changed files with 58 additions and 21 deletions

View File

@@ -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,

View File

@@ -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):

View File

@@ -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:

View File

@@ -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;

View File

@@ -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()

View File

@@ -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:

View File

@@ -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) {

View File

@@ -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);