mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-02-08 01:58:02 +08:00
ggwave : add default constructor
This commit is contained in:
@@ -520,13 +520,13 @@ public:
|
||||
|
||||
// generated tones
|
||||
//
|
||||
// Each Tone is the bin index of the tone frequency.
|
||||
// For protocol p:
|
||||
// - freq_hz = (p.freqStart + Tone) * hzPerSample
|
||||
// - duration_ms = p.txDuration_ms(samplesPerFrame, sampleRate)
|
||||
// Each Tone is the bin index of the tone frequency.
|
||||
// For protocol p:
|
||||
// - freq_hz = (p.freqStart + Tone) * hzPerSample
|
||||
// - duration_ms = p.txDuration_ms(samplesPerFrame, sampleRate)
|
||||
//
|
||||
// If the protocol is mono-tone, each element of the vector corresponds to a single tone.
|
||||
// Otherwise, the tones within a single Tx are separated by value of -1
|
||||
// If the protocol is mono-tone, each element of the vector corresponds to a single tone.
|
||||
// Otherwise, the tones within a single Tx are separated by value of -1
|
||||
//
|
||||
using Tones = ggvector<Tone>;
|
||||
|
||||
@@ -537,51 +537,68 @@ public:
|
||||
using RecordedData = ggvector<float>;
|
||||
using TxRxData = ggvector<uint8_t>;
|
||||
|
||||
// constructor
|
||||
// default constructor
|
||||
//
|
||||
// All memory buffers used by the GGWave instance are allocated upon construction.
|
||||
// No memory allocations occur after that.
|
||||
// The GGWave object is not ready to use until you call prepare()
|
||||
// No memory is allocated with this constructor.
|
||||
//
|
||||
// The sizes of the buffers are determined by the parameters and the contents of:
|
||||
GGWave() = default;
|
||||
|
||||
// constructor with parameters
|
||||
//
|
||||
// - 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(...);
|
||||
// Construct and prepare the GGWave object using the given parameters.
|
||||
// The constructor calls prepare() for you.
|
||||
//
|
||||
GGWave(const Parameters & parameters);
|
||||
|
||||
~GGWave();
|
||||
|
||||
bool prepare(const Parameters & parameters);
|
||||
bool alloc(void * p, int & n);
|
||||
// prepare the GGWave object
|
||||
//
|
||||
// All memory buffers used by the GGWave instance are allocated with this function.
|
||||
// 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(...);
|
||||
//
|
||||
// If "allocate" is false, the memory buffers are not allocated and only the required size
|
||||
// is computed. This is useful if you want to just see how much memory is needed for the
|
||||
// specific set of parameters and protocols. Do not use this function after you have already
|
||||
// prepared the instance. Instead, use the heapSize() method to see how much memory is used.
|
||||
//
|
||||
bool prepare(const Parameters & parameters, bool allocate = true);
|
||||
|
||||
// set file stream for the internal ggwave logging
|
||||
//
|
||||
// By default, ggwave prints internal log messages to stderr.
|
||||
// To disable logging all together, call this method with nullptr.
|
||||
// By default, ggwave prints internal log messages to stderr.
|
||||
// To disable logging all together, call this method with nullptr.
|
||||
//
|
||||
// Note: not thread-safe. Do not call while any GGWave instances are running
|
||||
// Note: not thread-safe. Do not call while any GGWave instances are running
|
||||
//
|
||||
static void setLogFile(FILE * fptr);
|
||||
|
||||
@@ -589,10 +606,10 @@ public:
|
||||
|
||||
// set Tx data to encode
|
||||
//
|
||||
// This prepares the GGWave instance for transmission.
|
||||
// To perform the actual encoding, the encode() method must be called
|
||||
// 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
|
||||
// returns false upon invalid parameters or failure to initialize
|
||||
//
|
||||
bool init(const char * text, TxProtocolId protocolId, const int volume = kDefaultVolume);
|
||||
bool init(int dataSize, const char * dataBuffer, TxProtocolId protocolId, const int volume = kDefaultVolume);
|
||||
@@ -765,15 +782,17 @@ public:
|
||||
|
||||
struct State {
|
||||
int nSamplesTotal = 0;
|
||||
int timeInt = 0;
|
||||
int timeLast = 0;
|
||||
double timeNow = 0.0;
|
||||
int timeInt = 0;
|
||||
int timeLast = 0;
|
||||
double timeNow = 0.0;
|
||||
};
|
||||
|
||||
State m_state;
|
||||
};
|
||||
|
||||
private:
|
||||
bool alloc(void * p, int & n);
|
||||
|
||||
void decode_fixed();
|
||||
void decode_variable();
|
||||
|
||||
@@ -784,36 +803,37 @@ private:
|
||||
|
||||
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_sampleSizeInp;
|
||||
const int m_sampleSizeOut;
|
||||
const SampleFormat m_sampleFormatInp;
|
||||
const SampleFormat m_sampleFormatOut;
|
||||
// initialized via prepare()
|
||||
float m_sampleRateInp = -1.0f;
|
||||
float m_sampleRateOut = -1.0f;
|
||||
float m_sampleRate = -1.0f;
|
||||
int m_samplesPerFrame = -1;
|
||||
float m_isamplesPerFrame = -1.0f;
|
||||
int m_sampleSizeInp = -1;
|
||||
int m_sampleSizeOut = -1;
|
||||
SampleFormat m_sampleFormatInp = GGWAVE_SAMPLE_FORMAT_UNDEFINED;
|
||||
SampleFormat m_sampleFormatOut = GGWAVE_SAMPLE_FORMAT_UNDEFINED;
|
||||
|
||||
const float m_hzPerSample;
|
||||
const float m_ihzPerSample;
|
||||
float m_hzPerSample = -1.0f;
|
||||
float m_ihzPerSample = -1.0f;
|
||||
|
||||
const int m_freqDelta_bin;
|
||||
const float m_freqDelta_hz;
|
||||
int m_freqDelta_bin = -1;
|
||||
float m_freqDelta_hz = -1.0f;
|
||||
|
||||
const int m_nBitsInMarker;
|
||||
const int m_nMarkerFrames;
|
||||
const int m_encodedDataOffset;
|
||||
int m_nBitsInMarker = -1;
|
||||
int m_nMarkerFrames = -1;
|
||||
int m_encodedDataOffset = -1;
|
||||
|
||||
const float m_soundMarkerThreshold;
|
||||
float m_soundMarkerThreshold = -1.0f;
|
||||
|
||||
const bool m_isFixedPayloadLength;
|
||||
const int m_payloadLength;
|
||||
bool m_isFixedPayloadLength = false;
|
||||
int m_payloadLength = -1;
|
||||
|
||||
const bool m_isRxEnabled;
|
||||
const bool m_isTxEnabled;
|
||||
const bool m_needResampling;
|
||||
const bool m_txOnlyTones;
|
||||
const bool m_isDSSEnabled;
|
||||
bool m_isRxEnabled = false;
|
||||
bool m_isTxEnabled = false;
|
||||
bool m_needResampling = false;
|
||||
bool m_txOnlyTones = false;
|
||||
bool m_isDSSEnabled = false;
|
||||
|
||||
// common
|
||||
TxRxData m_dataEncoded;
|
||||
@@ -900,8 +920,8 @@ private:
|
||||
|
||||
mutable Resampler m_resampler;
|
||||
|
||||
void * m_heap;
|
||||
int m_heapSize;
|
||||
void * m_heap = nullptr;
|
||||
int m_heapSize = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
118
src/ggwave.cpp
118
src/ggwave.cpp
@@ -433,57 +433,7 @@ void ggalloc(ggmatrix<T> & v, int n, int m, void * buf, int & bufSize) {
|
||||
// GGWave
|
||||
//
|
||||
|
||||
GGWave::GGWave(const Parameters & parameters) :
|
||||
m_sampleRateInp (parameters.sampleRateInp),
|
||||
m_sampleRateOut (parameters.sampleRateOut),
|
||||
m_sampleRate (parameters.sampleRate),
|
||||
m_samplesPerFrame (parameters.samplesPerFrame),
|
||||
m_isamplesPerFrame (1.0f/m_samplesPerFrame),
|
||||
m_sampleSizeInp (bytesForSampleFormat(parameters.sampleFormatInp)),
|
||||
m_sampleSizeOut (bytesForSampleFormat(parameters.sampleFormatOut)),
|
||||
m_sampleFormatInp (parameters.sampleFormatInp),
|
||||
m_sampleFormatOut (parameters.sampleFormatOut),
|
||||
m_hzPerSample (m_sampleRate/m_samplesPerFrame),
|
||||
m_ihzPerSample (1.0f/m_hzPerSample),
|
||||
m_freqDelta_bin (1),
|
||||
m_freqDelta_hz (2*m_hzPerSample),
|
||||
m_nBitsInMarker (16),
|
||||
m_nMarkerFrames (parameters.payloadLength > 0 ? 0 : kDefaultMarkerFrames),
|
||||
m_encodedDataOffset (parameters.payloadLength > 0 ? 0 : kDefaultEncodedDataOffset),
|
||||
m_soundMarkerThreshold(parameters.soundMarkerThreshold),
|
||||
m_isFixedPayloadLength(parameters.payloadLength > 0),
|
||||
m_payloadLength (parameters.payloadLength),
|
||||
m_isRxEnabled (parameters.operatingMode & GGWAVE_OPERATING_MODE_RX),
|
||||
m_isTxEnabled (parameters.operatingMode & GGWAVE_OPERATING_MODE_TX),
|
||||
m_needResampling (m_sampleRateInp != m_sampleRate || m_sampleRateOut != m_sampleRate),
|
||||
m_txOnlyTones (parameters.operatingMode & GGWAVE_OPERATING_MODE_TX_ONLY_TONES),
|
||||
m_isDSSEnabled (parameters.operatingMode & GGWAVE_OPERATING_MODE_USE_DSS) {
|
||||
|
||||
if (m_sampleSizeInp == 0) {
|
||||
ggprintf("Invalid or unsupported capture sample format: %d\n", (int) parameters.sampleFormatInp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sampleSizeOut == 0) {
|
||||
ggprintf("Invalid or unsupported playback sample format: %d\n", (int) parameters.sampleFormatOut);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parameters.samplesPerFrame > kMaxSamplesPerFrame) {
|
||||
ggprintf("Invalid samples per frame: %d, max: %d\n", parameters.samplesPerFrame, kMaxSamplesPerFrame);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sampleRateInp < kSampleRateMin) {
|
||||
ggprintf("Error: capture sample rate (%g Hz) must be >= %g Hz\n", m_sampleRateInp, kSampleRateMin);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sampleRateInp > kSampleRateMax) {
|
||||
ggprintf("Error: capture sample rate (%g Hz) must be <= %g Hz\n", m_sampleRateInp, kSampleRateMax);
|
||||
return;
|
||||
}
|
||||
|
||||
GGWave::GGWave(const Parameters & parameters) {
|
||||
prepare(parameters);
|
||||
}
|
||||
|
||||
@@ -493,8 +443,66 @@ GGWave::~GGWave() {
|
||||
}
|
||||
}
|
||||
|
||||
bool GGWave::prepare(const Parameters & parameters) {
|
||||
// TODO: initialize members from parameters
|
||||
bool GGWave::prepare(const Parameters & parameters, bool allocate) {
|
||||
if (m_heap) {
|
||||
free(m_heap);
|
||||
m_heap = nullptr;
|
||||
m_heapSize = 0;
|
||||
}
|
||||
|
||||
// parameter initialization:
|
||||
|
||||
m_sampleRateInp = parameters.sampleRateInp;
|
||||
m_sampleRateOut = parameters.sampleRateOut;
|
||||
m_sampleRate = parameters.sampleRate;
|
||||
m_samplesPerFrame = parameters.samplesPerFrame;
|
||||
m_isamplesPerFrame = 1.0f/m_samplesPerFrame;
|
||||
m_sampleSizeInp = bytesForSampleFormat(parameters.sampleFormatInp);
|
||||
m_sampleSizeOut = bytesForSampleFormat(parameters.sampleFormatOut);
|
||||
m_sampleFormatInp = parameters.sampleFormatInp;
|
||||
m_sampleFormatOut = parameters.sampleFormatOut;
|
||||
m_hzPerSample = m_sampleRate/m_samplesPerFrame;
|
||||
m_ihzPerSample = 1.0f/m_hzPerSample;
|
||||
m_freqDelta_bin = 1;
|
||||
m_freqDelta_hz = 2*m_hzPerSample;
|
||||
m_nBitsInMarker = 16;
|
||||
m_nMarkerFrames = parameters.payloadLength > 0 ? 0 : kDefaultMarkerFrames;
|
||||
m_encodedDataOffset = parameters.payloadLength > 0 ? 0 : kDefaultEncodedDataOffset;
|
||||
m_soundMarkerThreshold = parameters.soundMarkerThreshold;
|
||||
m_isFixedPayloadLength = parameters.payloadLength > 0;
|
||||
m_payloadLength = parameters.payloadLength;
|
||||
m_isRxEnabled = parameters.operatingMode & GGWAVE_OPERATING_MODE_RX;
|
||||
m_isTxEnabled = parameters.operatingMode & GGWAVE_OPERATING_MODE_TX;
|
||||
m_needResampling = m_sampleRateInp != m_sampleRate || m_sampleRateOut != m_sampleRate;
|
||||
m_txOnlyTones = parameters.operatingMode & GGWAVE_OPERATING_MODE_TX_ONLY_TONES;
|
||||
m_isDSSEnabled = parameters.operatingMode & GGWAVE_OPERATING_MODE_USE_DSS;
|
||||
|
||||
if (m_sampleSizeInp == 0) {
|
||||
ggprintf("Invalid or unsupported capture sample format: %d\n", (int) parameters.sampleFormatInp);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_sampleSizeOut == 0) {
|
||||
ggprintf("Invalid or unsupported playback sample format: %d\n", (int) parameters.sampleFormatOut);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parameters.samplesPerFrame > kMaxSamplesPerFrame) {
|
||||
ggprintf("Invalid samples per frame: %d, max: %d\n", parameters.samplesPerFrame, kMaxSamplesPerFrame);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_sampleRateInp < kSampleRateMin) {
|
||||
ggprintf("Error: capture sample rate (%g Hz) must be >= %g Hz\n", m_sampleRateInp, kSampleRateMin);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_sampleRateInp > kSampleRateMax) {
|
||||
ggprintf("Error: capture sample rate (%g Hz) must be <= %g Hz\n", m_sampleRateInp, kSampleRateMax);
|
||||
return false;
|
||||
}
|
||||
|
||||
// memory allocation:
|
||||
|
||||
m_heap = nullptr;
|
||||
m_heapSize = 0;
|
||||
@@ -504,6 +512,10 @@ bool GGWave::prepare(const Parameters & parameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (allocate == false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto heapSize0 = m_heapSize;
|
||||
|
||||
m_heap = calloc(m_heapSize, 1);
|
||||
|
||||
Reference in New Issue
Block a user