mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-02-06 16:47:59 +08:00
ggwave-gui : adding tx waveform display
This commit is contained in:
@@ -120,7 +120,7 @@ bool GGWave_init(
|
||||
playbackSpec.freq = ::kBaseSampleRate;
|
||||
playbackSpec.format = AUDIO_S16SYS;
|
||||
playbackSpec.channels = 1;
|
||||
playbackSpec.samples = 16*1024;
|
||||
playbackSpec.samples = 1024;
|
||||
playbackSpec.callback = NULL;
|
||||
|
||||
SDL_zero(g_obtainedSpecOut);
|
||||
|
||||
@@ -49,6 +49,7 @@ struct State {
|
||||
struct Flags {
|
||||
bool newMessage = false;
|
||||
bool newSpectrum = false;
|
||||
bool newTxAmplitudeData = false;
|
||||
bool newStats = false;
|
||||
|
||||
void clear() { memset(this, 0, sizeof(Flags)); }
|
||||
@@ -69,6 +70,12 @@ struct State {
|
||||
dst.spectrum = std::move(this->spectrum);
|
||||
}
|
||||
|
||||
if (this->flags.newTxAmplitudeData) {
|
||||
dst.update = true;
|
||||
dst.flags.newTxAmplitudeData = true;
|
||||
dst.txAmplitudeData = std::move(this->txAmplitudeData);
|
||||
}
|
||||
|
||||
if (this->flags.newStats) {
|
||||
dst.update = true;
|
||||
dst.flags.newStats = true;
|
||||
@@ -81,6 +88,7 @@ struct State {
|
||||
|
||||
Message message;
|
||||
GGWave::SpectrumData spectrum;
|
||||
GGWave::AmplitudeData16 txAmplitudeData;
|
||||
GGWaveStats stats;
|
||||
};
|
||||
|
||||
@@ -174,6 +182,11 @@ std::thread initMain() {
|
||||
g_buffer.stateCore.flags.newSpectrum = true;
|
||||
}
|
||||
|
||||
if (g_ggWave->takeTxAmplitudeData16(g_buffer.stateCore.txAmplitudeData)) {
|
||||
g_buffer.stateCore.update = true;
|
||||
g_buffer.stateCore.flags.newTxAmplitudeData = true;
|
||||
}
|
||||
|
||||
if (true) {
|
||||
g_buffer.stateCore.update = true;
|
||||
g_buffer.stateCore.flags.newStats = true;
|
||||
@@ -227,9 +240,12 @@ void renderMain() {
|
||||
|
||||
static double tStartInput = 0.0f;
|
||||
static double tEndInput = -100.0f;
|
||||
static double tStartTx = 0.0f;
|
||||
static double tLengthTx = 0.0f;
|
||||
|
||||
static GGWaveStats statsCurrent;
|
||||
static GGWave::SpectrumData spectrumCurrent;
|
||||
static GGWave::AmplitudeData16 txAmplitudeDataCurrent;
|
||||
static std::vector<Message> messageHistory;
|
||||
|
||||
if (stateCurrent.update) {
|
||||
@@ -240,6 +256,25 @@ void renderMain() {
|
||||
if (stateCurrent.flags.newSpectrum) {
|
||||
spectrumCurrent = std::move(stateCurrent.spectrum);
|
||||
}
|
||||
if (stateCurrent.flags.newTxAmplitudeData) {
|
||||
txAmplitudeDataCurrent = std::move(stateCurrent.txAmplitudeData);
|
||||
|
||||
tStartTx = ImGui::GetTime();
|
||||
tLengthTx = txAmplitudeDataCurrent.size()/g_ggWave->getSampleRateOut();
|
||||
{
|
||||
auto & ampl = txAmplitudeDataCurrent;
|
||||
int nBins = 512;
|
||||
int nspb = ampl.size()/nBins;
|
||||
for (int i = 0; i < nBins; ++i) {
|
||||
double sum = 0.0;
|
||||
for (int j = 0; j < nspb; ++j) {
|
||||
sum += std::abs(ampl[i*nspb + j]);
|
||||
}
|
||||
ampl[i] = sum/nspb;
|
||||
}
|
||||
ampl.resize(nBins);
|
||||
}
|
||||
}
|
||||
if (stateCurrent.flags.newStats) {
|
||||
statsCurrent = std::move(stateCurrent.stats);
|
||||
}
|
||||
@@ -499,7 +534,56 @@ void renderMain() {
|
||||
{ ImGui::GetContentRegionAvailWidth(), ImGui::GetTextLineHeight() });
|
||||
}
|
||||
} else {
|
||||
ImGui::TextDisabled("Listening for waves ...\n");
|
||||
static float amax = 0.0f;
|
||||
static float frac = 0.0f;
|
||||
|
||||
amax = 0.0f;
|
||||
frac = (ImGui::GetTime() - tStartTx)/tLengthTx;
|
||||
|
||||
if (txAmplitudeDataCurrent.size() && frac <= 1.0f) {
|
||||
struct Funcs {
|
||||
static float Sample(void * data, int i) {
|
||||
auto res = std::fabs(((int16_t *)(data))[i]) ;
|
||||
if (res > amax) amax = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
static float SampleFrac(void * data, int i) {
|
||||
if (i > frac*txAmplitudeDataCurrent.size()) {
|
||||
return 0.0f;
|
||||
}
|
||||
return std::fabs(((int16_t *)(data))[i]);
|
||||
}
|
||||
};
|
||||
|
||||
auto posSave = ImGui::GetCursorScreenPos();
|
||||
auto wSize = ImGui::GetContentRegionAvail();
|
||||
wSize.y = ImGui::GetTextLineHeight();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, { 0.3f, 0.3f, 0.3f, 0.3f });
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
|
||||
ImGui::PlotHistogram("##plotSpectrumCurrent",
|
||||
Funcs::Sample,
|
||||
txAmplitudeDataCurrent.data(),
|
||||
txAmplitudeDataCurrent.size(), 0,
|
||||
(std::string("")).c_str(),
|
||||
0.0f, FLT_MAX, wSize);
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
ImGui::SetCursorScreenPos(posSave);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, { 0.0f, 0.0f, 0.0f, 0.0f });
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, { 0.0f, 1.0f, 0.0f, 1.0f });
|
||||
ImGui::PlotHistogram("##plotSpectrumCurrent",
|
||||
Funcs::SampleFrac,
|
||||
txAmplitudeDataCurrent.data(),
|
||||
txAmplitudeDataCurrent.size(), 0,
|
||||
(std::string("")).c_str(),
|
||||
0.0f, amax, wSize);
|
||||
ImGui::PopStyleColor(2);
|
||||
} else {
|
||||
ImGui::TextDisabled("Listening for waves ...\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (doInputFocus) {
|
||||
|
||||
@@ -78,6 +78,7 @@ public:
|
||||
const int & getRxProtocolId() const { return m_rxProtocolId; }
|
||||
|
||||
int takeRxData(TxRxData & dst);
|
||||
int takeTxAmplitudeData16(AmplitudeData16 & dst);
|
||||
bool takeSpectrum(SpectrumData & dst);
|
||||
|
||||
private:
|
||||
@@ -148,4 +149,8 @@ private:
|
||||
TxRxData m_txDataEncoded;
|
||||
|
||||
TxProtocol m_txProtocol;
|
||||
|
||||
AmplitudeData m_outputBlock;
|
||||
AmplitudeData16 m_outputBlock16;
|
||||
AmplitudeData16 m_txAmplitudeData16;
|
||||
};
|
||||
|
||||
@@ -159,7 +159,9 @@ GGWave::GGWave(
|
||||
m_sampleAmplitudeHistory(kMaxSpectrumHistory),
|
||||
m_recordedAmplitude(kMaxRecordedFrames*kMaxSamplesPerFrame),
|
||||
m_txData(kMaxDataSize),
|
||||
m_txDataEncoded(kMaxDataSize)
|
||||
m_txDataEncoded(kMaxDataSize),
|
||||
m_outputBlock(kMaxSamplesPerFrame),
|
||||
m_outputBlock16(kMaxRecordedFrames*kMaxSamplesPerFrame)
|
||||
{
|
||||
init(0, "", getDefultTxProtocol(), 0);
|
||||
}
|
||||
@@ -224,9 +226,6 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
|
||||
int frameId = 0;
|
||||
|
||||
AmplitudeData outputBlock(kMaxSamplesPerFrame);
|
||||
AmplitudeData16 outputBlock16(kMaxRecordedFrames*kMaxSamplesPerFrame);
|
||||
|
||||
std::vector<double> phaseOffsets(kMaxDataBits);
|
||||
|
||||
for (int k = 0; k < (int) phaseOffsets.size(); ++k) {
|
||||
@@ -273,7 +272,7 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
rsData.Encode(m_txData.data() + 1, m_txDataEncoded.data() + m_encodedDataOffset);
|
||||
|
||||
while (m_hasNewTxData) {
|
||||
std::fill(outputBlock.begin(), outputBlock.end(), 0.0f);
|
||||
std::fill(m_outputBlock.begin(), m_outputBlock.end(), 0.0f);
|
||||
|
||||
if (m_sampleRateOut != m_sampleRateIn) {
|
||||
for (int k = 0; k < m_txProtocol.nDataBitsPerTx(); ++k) {
|
||||
@@ -299,9 +298,9 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
|
||||
for (int i = 0; i < m_nBitsInMarker; ++i) {
|
||||
if (i%2 == 0) {
|
||||
::addAmplitudeSmooth(bit1Amplitude[i], outputBlock, m_sendVolume, 0, samplesPerFrameOut, frameId, m_nMarkerFrames);
|
||||
::addAmplitudeSmooth(bit1Amplitude[i], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, frameId, m_nMarkerFrames);
|
||||
} else {
|
||||
::addAmplitudeSmooth(bit0Amplitude[i], outputBlock, m_sendVolume, 0, samplesPerFrameOut, frameId, m_nMarkerFrames);
|
||||
::addAmplitudeSmooth(bit0Amplitude[i], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, frameId, m_nMarkerFrames);
|
||||
}
|
||||
}
|
||||
} else if (frameId < m_nMarkerFrames + m_nPostMarkerFrames) {
|
||||
@@ -309,9 +308,9 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
|
||||
for (int i = 0; i < m_nBitsInMarker; ++i) {
|
||||
if (i%2 == 0) {
|
||||
::addAmplitudeSmooth(bit0Amplitude[i], outputBlock, m_sendVolume, 0, samplesPerFrameOut, frameId - m_nMarkerFrames, m_nPostMarkerFrames);
|
||||
::addAmplitudeSmooth(bit0Amplitude[i], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, frameId - m_nMarkerFrames, m_nPostMarkerFrames);
|
||||
} else {
|
||||
::addAmplitudeSmooth(bit1Amplitude[i], outputBlock, m_sendVolume, 0, samplesPerFrameOut, frameId - m_nMarkerFrames, m_nPostMarkerFrames);
|
||||
::addAmplitudeSmooth(bit1Amplitude[i], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, frameId - m_nMarkerFrames, m_nPostMarkerFrames);
|
||||
}
|
||||
}
|
||||
} else if (frameId <
|
||||
@@ -340,9 +339,9 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
|
||||
++nFreq;
|
||||
if (k%2) {
|
||||
::addAmplitudeSmooth(bit0Amplitude[k/2], outputBlock, m_sendVolume, 0, samplesPerFrameOut, cycleModMain, m_txProtocol.framesPerTx);
|
||||
::addAmplitudeSmooth(bit0Amplitude[k/2], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, cycleModMain, m_txProtocol.framesPerTx);
|
||||
} else {
|
||||
::addAmplitudeSmooth(bit1Amplitude[k/2], outputBlock, m_sendVolume, 0, samplesPerFrameOut, cycleModMain, m_txProtocol.framesPerTx);
|
||||
::addAmplitudeSmooth(bit1Amplitude[k/2], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, cycleModMain, m_txProtocol.framesPerTx);
|
||||
}
|
||||
}
|
||||
} else if (frameId <
|
||||
@@ -354,9 +353,9 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
int fId = frameId - ((m_nMarkerFrames + m_nPostMarkerFrames) + ((m_sendDataLength + m_nECCBytesPerTx)/m_txProtocol.bytesPerTx + 2)*m_txProtocol.framesPerTx);
|
||||
for (int i = 0; i < m_nBitsInMarker; ++i) {
|
||||
if (i%2 == 0) {
|
||||
addAmplitudeSmooth(bit0Amplitude[i], outputBlock, m_sendVolume, 0, samplesPerFrameOut, fId, m_nMarkerFrames);
|
||||
addAmplitudeSmooth(bit0Amplitude[i], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, fId, m_nMarkerFrames);
|
||||
} else {
|
||||
addAmplitudeSmooth(bit1Amplitude[i], outputBlock, m_sendVolume, 0, samplesPerFrameOut, fId, m_nMarkerFrames);
|
||||
addAmplitudeSmooth(bit1Amplitude[i], m_outputBlock, m_sendVolume, 0, samplesPerFrameOut, fId, m_nMarkerFrames);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -366,18 +365,23 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
if (nFreq == 0) nFreq = 1;
|
||||
float scale = 1.0f/nFreq;
|
||||
for (int i = 0; i < samplesPerFrameOut; ++i) {
|
||||
outputBlock[i] *= scale;
|
||||
m_outputBlock[i] *= scale;
|
||||
}
|
||||
|
||||
// todo : support for non-int16 output
|
||||
for (int i = 0; i < samplesPerFrameOut; ++i) {
|
||||
outputBlock16[frameId*samplesPerFrameOut + i] = std::round(32000.0*outputBlock[i]);
|
||||
m_outputBlock16[frameId*samplesPerFrameOut + i] = std::round(32000.0*m_outputBlock[i]);
|
||||
}
|
||||
|
||||
++frameId;
|
||||
}
|
||||
|
||||
cbQueueAudio(outputBlock16.data(), frameId*samplesPerFrameOut*m_sampleSizeBytesOut);
|
||||
cbQueueAudio(m_outputBlock16.data(), frameId*samplesPerFrameOut*m_sampleSizeBytesOut);
|
||||
|
||||
m_txAmplitudeData16.resize(frameId*samplesPerFrameOut);
|
||||
for (int i = 0; i < frameId*samplesPerFrameOut; ++i) {
|
||||
m_txAmplitudeData16[i] = m_outputBlock16[i];
|
||||
}
|
||||
}
|
||||
|
||||
void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) {
|
||||
@@ -653,6 +657,15 @@ int GGWave::takeRxData(TxRxData & dst) {
|
||||
return res;
|
||||
}
|
||||
|
||||
int GGWave::takeTxAmplitudeData16(AmplitudeData16 & dst) {
|
||||
if (m_txAmplitudeData16.size() == 0) return 0;
|
||||
|
||||
auto res = m_txAmplitudeData16.size();
|
||||
dst = std::move(m_txAmplitudeData16);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool GGWave::takeSpectrum(SpectrumData & dst) {
|
||||
if (m_hasNewSpectrum == false) return false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user