mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-02-07 01:11:22 +08:00
ggwave : reduce memory allocations on Tx
This commit is contained in:
@@ -313,7 +313,6 @@ public:
|
||||
static constexpr auto kDefaultMarkerFrames = 16;
|
||||
static constexpr auto kDefaultEncodedDataOffset = 3;
|
||||
static constexpr auto kMaxSamplesPerFrame = 1024;
|
||||
static constexpr auto kMaxDataBits = 256;
|
||||
static constexpr auto kMaxDataSize = 256;
|
||||
static constexpr auto kMaxLengthVariable = 140;
|
||||
static constexpr auto kMaxLengthFixed = 16;
|
||||
@@ -334,6 +333,16 @@ public:
|
||||
int bytesPerTx; // number of bytes in a chunk of data
|
||||
|
||||
int nDataBitsPerTx() const { return 8*bytesPerTx; }
|
||||
|
||||
bool operator==(const TxProtocol & other) const {
|
||||
return freqStart == other.freqStart &&
|
||||
framesPerTx == other.framesPerTx &&
|
||||
bytesPerTx == other.bytesPerTx;
|
||||
}
|
||||
|
||||
bool operator!=(const TxProtocol & other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
using RxProtocol = TxProtocol;
|
||||
@@ -575,6 +584,7 @@ private:
|
||||
const bool m_isRxEnabled;
|
||||
const bool m_isTxEnabled;
|
||||
const bool m_needResampling;
|
||||
const bool m_txOnlyTones;
|
||||
|
||||
// common
|
||||
TxRxData m_dataEncoded;
|
||||
|
||||
133
src/ggwave.cpp
133
src/ggwave.cpp
@@ -301,14 +301,15 @@ inline void addAmplitudeSmooth(
|
||||
const GGWave::AmplitudeData & src,
|
||||
GGWave::AmplitudeData & dst,
|
||||
float scalar, int startId, int finalId, int cycleMod, int nPerCycle) {
|
||||
int nTotal = nPerCycle*finalId;
|
||||
float frac = 0.15f;
|
||||
float ds = frac*nTotal;
|
||||
float ids = 1.0f/ds;
|
||||
int nBegin = frac*nTotal;
|
||||
int nEnd = (1.0f - frac)*nTotal;
|
||||
const int nTotal = nPerCycle*finalId;
|
||||
const float frac = 0.15f;
|
||||
const float ds = frac*nTotal;
|
||||
const float ids = 1.0f/ds;
|
||||
const int nBegin = frac*nTotal;
|
||||
const int nEnd = (1.0f - frac)*nTotal;
|
||||
|
||||
for (int i = startId; i < finalId; i++) {
|
||||
float k = cycleMod*finalId + i;
|
||||
const float k = cycleMod*finalId + i;
|
||||
if (k < nBegin) {
|
||||
dst[i] += scalar*src[i]*(k*ids);
|
||||
} else if (k > nEnd) {
|
||||
@@ -401,8 +402,15 @@ struct GGWave::Tx {
|
||||
int txDataLength = 0;
|
||||
int lastAmplitudeSize = 0;
|
||||
|
||||
std::vector<bool> dataBits;
|
||||
std::vector<double> phaseOffsets;
|
||||
|
||||
std::vector<AmplitudeData> bit1Amplitude;
|
||||
std::vector<AmplitudeData> bit0Amplitude;
|
||||
|
||||
TxRxData txData;
|
||||
TxProtocol txProtocol;
|
||||
TxProtocol txProtocolLast;
|
||||
|
||||
AmplitudeData outputBlock;
|
||||
AmplitudeData outputBlockResampled;
|
||||
@@ -455,6 +463,7 @@ GGWave::GGWave(const Parameters & parameters) :
|
||||
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),
|
||||
|
||||
// common
|
||||
m_dataEncoded (kMaxDataSize) {
|
||||
@@ -514,7 +523,7 @@ GGWave::GGWave(const Parameters & parameters) :
|
||||
|
||||
m_rx->spectrumHistoryFixed.resize(totalTxs*maxFramesPerTx());
|
||||
m_rx->detectedBins.resize(2*totalLength);
|
||||
m_rx->detectedTones.resize(2*maxBytesPerTx()*16);
|
||||
m_rx->detectedTones.resize(2*16*maxBytesPerTx());
|
||||
} else {
|
||||
// variable payload length
|
||||
m_rx->recordedAmplitude.resize(kMaxRecordedFrames*m_samplesPerFrame);
|
||||
@@ -534,6 +543,23 @@ GGWave::GGWave(const Parameters & parameters) :
|
||||
if (m_isTxEnabled) {
|
||||
m_tx = std::unique_ptr<Tx>(new Tx());
|
||||
|
||||
m_tx->txProtocolLast = {};
|
||||
|
||||
{
|
||||
const int maxDataBits = 2*16*maxBytesPerTx();
|
||||
|
||||
m_tx->dataBits.resize(maxDataBits);
|
||||
m_tx->phaseOffsets.resize(maxDataBits);
|
||||
m_tx->bit0Amplitude.resize(maxDataBits);
|
||||
for (auto & a : m_tx->bit0Amplitude) {
|
||||
a.resize(m_samplesPerFrame);
|
||||
}
|
||||
m_tx->bit1Amplitude.resize(maxDataBits);
|
||||
for (auto & a : m_tx->bit1Amplitude) {
|
||||
a.resize(m_samplesPerFrame);
|
||||
}
|
||||
}
|
||||
|
||||
m_tx->txData.resize(kMaxDataSize);
|
||||
m_tx->outputBlock.resize(m_samplesPerFrame),
|
||||
m_tx->outputBlockResampled.resize(2*m_samplesPerFrame),
|
||||
@@ -679,46 +705,41 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) {
|
||||
m_resampler->reset();
|
||||
}
|
||||
|
||||
std::vector<double> phaseOffsets(kMaxDataBits);
|
||||
|
||||
for (int k = 0; k < (int) phaseOffsets.size(); ++k) {
|
||||
phaseOffsets[k] = (M_PI*k)/(m_tx->txProtocol.nDataBitsPerTx());
|
||||
}
|
||||
|
||||
// note : what is the purpose of this shuffle ? I forgot .. :(
|
||||
//std::random_device rd;
|
||||
//std::mt19937 g(rd());
|
||||
|
||||
//std::shuffle(phaseOffsets.begin(), phaseOffsets.end(), g);
|
||||
|
||||
std::vector<bool> dataBits(kMaxDataBits);
|
||||
|
||||
std::vector<AmplitudeData> bit1Amplitude(kMaxDataBits);
|
||||
std::vector<AmplitudeData> bit0Amplitude(kMaxDataBits);
|
||||
|
||||
for (int k = 0; k < (int) dataBits.size(); ++k) {
|
||||
double freq = bitFreq(m_tx->txProtocol, k);
|
||||
|
||||
bit1Amplitude[k].resize(m_samplesPerFrame);
|
||||
bit0Amplitude[k].resize(m_samplesPerFrame);
|
||||
|
||||
double phaseOffset = phaseOffsets[k];
|
||||
double curHzPerSample = m_hzPerSample;
|
||||
double curIHzPerSample = 1.0/curHzPerSample;
|
||||
for (int i = 0; i < m_samplesPerFrame; i++) {
|
||||
double curi = i;
|
||||
bit1Amplitude[k][i] = std::sin((2.0*M_PI)*(curi*m_isamplesPerFrame)*(freq*curIHzPerSample) + phaseOffset);
|
||||
if (m_tx->txProtocol != m_tx->txProtocolLast) {
|
||||
for (int k = 0; k < (int) m_tx->phaseOffsets.size(); ++k) {
|
||||
m_tx->phaseOffsets[k] = (M_PI*k)/(m_tx->txProtocol.nDataBitsPerTx());
|
||||
}
|
||||
for (int i = 0; i < m_samplesPerFrame; i++) {
|
||||
double curi = i;
|
||||
bit0Amplitude[k][i] = std::sin((2.0*M_PI)*(curi*m_isamplesPerFrame)*((freq + m_hzPerSample*m_freqDelta_bin)*curIHzPerSample) + phaseOffset);
|
||||
|
||||
// note : what is the purpose of this shuffle ? I forgot .. :(
|
||||
//std::random_device rd;
|
||||
//std::mt19937 g(rd());
|
||||
|
||||
//std::shuffle(phaseOffsets.begin(), phaseOffsets.end(), g);
|
||||
|
||||
for (int k = 0; k < (int) m_tx->dataBits.size(); ++k) {
|
||||
const double freq = bitFreq(m_tx->txProtocol, k);
|
||||
|
||||
const double phaseOffset = m_tx->phaseOffsets[k];
|
||||
const double curHzPerSample = m_hzPerSample;
|
||||
const double curIHzPerSample = 1.0/curHzPerSample;
|
||||
|
||||
for (int i = 0; i < m_samplesPerFrame; i++) {
|
||||
const double curi = i;
|
||||
m_tx->bit1Amplitude[k][i] = std::sin((2.0*M_PI)*(curi*m_isamplesPerFrame)*(freq*curIHzPerSample) + phaseOffset);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_samplesPerFrame; i++) {
|
||||
const double curi = i;
|
||||
m_tx->bit0Amplitude[k][i] = std::sin((2.0*M_PI)*(curi*m_isamplesPerFrame)*((freq + m_hzPerSample*m_freqDelta_bin)*curIHzPerSample) + phaseOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_tx->txProtocolLast = m_tx->txProtocol;
|
||||
|
||||
int nECCBytesPerTx = getECCBytesForLength(m_tx->txDataLength);
|
||||
int sendDataLength = m_tx->txDataLength + m_encodedDataOffset;
|
||||
int totalBytes = sendDataLength + nECCBytesPerTx;
|
||||
int totalDataFrames = ((totalBytes + m_tx->txProtocol.bytesPerTx - 1)/m_tx->txProtocol.bytesPerTx)*m_tx->txProtocol.framesPerTx;
|
||||
const int nECCBytesPerTx = getECCBytesForLength(m_tx->txDataLength);
|
||||
const int sendDataLength = m_tx->txDataLength + m_encodedDataOffset;
|
||||
const int totalBytes = sendDataLength + nECCBytesPerTx;
|
||||
const int totalDataFrames = ((totalBytes + m_tx->txProtocol.bytesPerTx - 1)/m_tx->txProtocol.bytesPerTx)*m_tx->txProtocol.framesPerTx;
|
||||
|
||||
if (m_isFixedPayloadLength == false) {
|
||||
RS::ReedSolomon rsLength(1, m_encodedDataOffset - 1, m_workRSLength.data());
|
||||
@@ -747,10 +768,10 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) {
|
||||
m_tx->waveformTones.back().push_back({});
|
||||
m_tx->waveformTones.back().back().duration_ms = (1000.0*m_samplesPerFrame)/m_sampleRate;
|
||||
if (i%2 == 0) {
|
||||
::addAmplitudeSmooth(bit1Amplitude[i], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, frameId, m_nMarkerFrames);
|
||||
::addAmplitudeSmooth(m_tx->bit1Amplitude[i], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, frameId, m_nMarkerFrames);
|
||||
m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i);
|
||||
} else {
|
||||
::addAmplitudeSmooth(bit0Amplitude[i], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, frameId, m_nMarkerFrames);
|
||||
::addAmplitudeSmooth(m_tx->bit0Amplitude[i], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, frameId, m_nMarkerFrames);
|
||||
m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i) + m_hzPerSample;
|
||||
}
|
||||
}
|
||||
@@ -760,45 +781,45 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) {
|
||||
dataOffset /= m_tx->txProtocol.framesPerTx;
|
||||
dataOffset *= m_tx->txProtocol.bytesPerTx;
|
||||
|
||||
std::fill(dataBits.begin(), dataBits.end(), 0);
|
||||
std::fill(m_tx->dataBits.begin(), m_tx->dataBits.end(), 0);
|
||||
|
||||
for (int j = 0; j < m_tx->txProtocol.bytesPerTx; ++j) {
|
||||
{
|
||||
uint8_t d = m_dataEncoded[dataOffset + j] & 15;
|
||||
dataBits[(2*j + 0)*16 + d] = 1;
|
||||
m_tx->dataBits[(2*j + 0)*16 + d] = 1;
|
||||
}
|
||||
{
|
||||
uint8_t d = m_dataEncoded[dataOffset + j] & 240;
|
||||
dataBits[(2*j + 1)*16 + (d >> 4)] = 1;
|
||||
m_tx->dataBits[(2*j + 1)*16 + (d >> 4)] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k < 2*m_tx->txProtocol.bytesPerTx*16; ++k) {
|
||||
if (dataBits[k] == 0) continue;
|
||||
if (m_tx->dataBits[k] == 0) continue;
|
||||
|
||||
++nFreq;
|
||||
m_tx->waveformTones.back().push_back({});
|
||||
m_tx->waveformTones.back().back().duration_ms = (1000.0*m_samplesPerFrame)/m_sampleRate;
|
||||
if (k%2) {
|
||||
::addAmplitudeSmooth(bit0Amplitude[k/2], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, cycleModMain, m_tx->txProtocol.framesPerTx);
|
||||
::addAmplitudeSmooth(m_tx->bit0Amplitude[k/2], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, cycleModMain, m_tx->txProtocol.framesPerTx);
|
||||
m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, k/2) + m_hzPerSample;
|
||||
} else {
|
||||
::addAmplitudeSmooth(bit1Amplitude[k/2], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, cycleModMain, m_tx->txProtocol.framesPerTx);
|
||||
::addAmplitudeSmooth(m_tx->bit1Amplitude[k/2], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, cycleModMain, m_tx->txProtocol.framesPerTx);
|
||||
m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, k/2);
|
||||
}
|
||||
}
|
||||
} else if (frameId < m_nMarkerFrames + totalDataFrames + m_nMarkerFrames) {
|
||||
nFreq = m_nBitsInMarker;
|
||||
|
||||
int fId = frameId - (m_nMarkerFrames + totalDataFrames);
|
||||
const int fId = frameId - (m_nMarkerFrames + totalDataFrames);
|
||||
for (int i = 0; i < m_nBitsInMarker; ++i) {
|
||||
m_tx->waveformTones.back().push_back({});
|
||||
m_tx->waveformTones.back().back().duration_ms = (1000.0*m_samplesPerFrame)/m_sampleRate;
|
||||
if (i%2 == 0) {
|
||||
addAmplitudeSmooth(bit0Amplitude[i], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, fId, m_nMarkerFrames);
|
||||
addAmplitudeSmooth(m_tx->bit0Amplitude[i], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, fId, m_nMarkerFrames);
|
||||
m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i) + m_hzPerSample;
|
||||
} else {
|
||||
addAmplitudeSmooth(bit1Amplitude[i], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, fId, m_nMarkerFrames);
|
||||
addAmplitudeSmooth(m_tx->bit1Amplitude[i], m_tx->outputBlock, m_tx->sendVolume, 0, m_samplesPerFrame, fId, m_nMarkerFrames);
|
||||
m_tx->waveformTones.back().back().freq_hz = bitFreq(m_tx->txProtocol, i);
|
||||
}
|
||||
}
|
||||
@@ -808,7 +829,7 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) {
|
||||
}
|
||||
|
||||
if (nFreq == 0) nFreq = 1;
|
||||
float scale = 1.0f/nFreq;
|
||||
const float scale = 1.0f/nFreq;
|
||||
for (int i = 0; i < m_samplesPerFrame; ++i) {
|
||||
m_tx->outputBlock[i] *= scale;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user