waterfall optimize, fm demod audio filtering

Moved waterfall increment into rendering to reduce audio processing
impact.

Added another test filter and resample stage to FM demod experiment to
clean up audio and remove high pitch on stereo channels until it can be
demodulated.
This commit is contained in:
Charles J. Cliffe 2014-11-11 21:42:18 -05:00
parent 86dadb8f2c
commit 810533750f
4 changed files with 64 additions and 28 deletions

View File

@ -41,10 +41,12 @@ static int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned
Demodulator::Demodulator() {
bandwidth = 800000;
bandwidth = 300000;
resample_ratio = (float) (bandwidth) / (float) SRATE;
audio_frequency = 44100;
audio_resample_ratio = (float) (audio_frequency) / (float) bandwidth;
wbfm_frequency = 32000;
wbfm_resample_ratio = (float) (wbfm_frequency) / (float) bandwidth;
audio_frequency = 48000;
audio_resample_ratio = (float) (audio_frequency) / (float) wbfm_frequency;
PaError err;
err = Pa_Initialize();
@ -83,7 +85,7 @@ Demodulator::Demodulator() {
stream = NULL;
err = Pa_OpenStream(&stream, NULL, &outputParameters, 44100, 256, paClipOff, &patestCallback, this);
err = Pa_OpenStream(&stream, NULL, &outputParameters, audio_frequency, 256, paClipOff, &patestCallback, this);
err = Pa_StartStream(stream);
if (err != paNoError) {
@ -103,14 +105,22 @@ Demodulator::Demodulator() {
fir_filter = firfilt_crcf_create(h, h_len);
h_len = estimate_req_filter_len(ft, As);
liquid_firdes_kaiser(h_len, 0.3f, As, mu, h);
fir_audio_filter = firfilt_crcf_create(h, h_len);
// create multi-stage arbitrary resampler object
resampler = msresamp_crcf_create(resample_ratio, As);
msresamp_crcf_print(resampler);
wbfm_resampler = msresamp_crcf_create(wbfm_resample_ratio, As);
msresamp_crcf_print(wbfm_resampler);
audio_resampler = msresamp_crcf_create(audio_resample_ratio, As);
msresamp_crcf_print(audio_resampler);
float kf = 0.1f; // modulation factor
float kf = 0.5f; // modulation factor
fdem = freqdem_create(kf);
freqdem_print(fdem);
@ -166,17 +176,32 @@ void Demodulator::writeBuffer(std::vector<signed char> *data) {
}
}
int audio_out_size = ceil((float) (num_written) * audio_resample_ratio);
int wbfm_out_size = ceil((float) (num_written) * wbfm_resample_ratio);
liquid_float_complex resampled_wbfm_output[wbfm_out_size];
unsigned int num_wbfm_written;
msresamp_crcf_execute(wbfm_resampler, resampled_output, num_written, resampled_wbfm_output, &num_wbfm_written);
for (int i = 0; i < num_wbfm_written; i++) {
firfilt_crcf_push(fir_audio_filter, resampled_wbfm_output[i]);
firfilt_crcf_execute(fir_audio_filter, &resampled_wbfm_output[i]);
}
int audio_out_size = ceil((float) (num_wbfm_written) * audio_resample_ratio);
liquid_float_complex resampled_audio_output[audio_out_size];
unsigned int num_audio_written; // number of values written to buffer
msresamp_crcf_execute(audio_resampler, resampled_output, num_written, resampled_audio_output, &num_audio_written);
unsigned int num_audio_written;
msresamp_crcf_execute(audio_resampler, resampled_wbfm_output, num_wbfm_written, resampled_audio_output, &num_audio_written);
std::vector<float> *newBuffer = new std::vector<float>;
newBuffer->resize(num_audio_written * 2);
for (int i = 0; i < num_audio_written; i++) {
(*newBuffer)[i * 2] = resampled_audio_output[i].real;
(*newBuffer)[i * 2 + 1] = resampled_audio_output[i].real;
liquid_float_complex y = resampled_audio_output[i];
(*newBuffer)[i * 2] = y.real;
(*newBuffer)[i * 2 + 1] = y.real;
}
audio_queue.push(newBuffer);

View File

@ -31,14 +31,22 @@ public:
private:
firfilt_crcf fir_filter;
firfilt_crcf fir_audio_filter;
unsigned int bandwidth;
msresamp_crcf resampler;
msresamp_crcf audio_resampler;
float resample_ratio;
unsigned int bandwidth;
unsigned int audio_frequency;
msresamp_crcf wbfm_resampler;
float wbfm_resample_ratio;
unsigned int wbfm_frequency;
msresamp_crcf audio_resampler;
float audio_resample_ratio;
unsigned int audio_frequency;
PaStreamParameters outputParameters;
PaStream *stream;
freqdem fdem;

View File

@ -95,12 +95,25 @@ PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas) :
CheckGLError();
}
void PrimaryGLContext::Plot(std::vector<float> &points, std::vector<float> &points2, unsigned char *waterfall_tex) {
void PrimaryGLContext::Plot(std::vector<float> &points, std::vector<float> &points2) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (points.size()) {
memmove(waterfall_tex + FFT_SIZE, waterfall_tex, (NUM_WATERFALL_LINES - 1) * FFT_SIZE);
for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) {
float v = points[i*2+1];
float wv = v;
if (wv<0.0) wv = 0.0;
if (wv>1.0) wv = 1.0;
waterfall_tex[i] = (unsigned char) floor(wv * 255.0);
}
}
glBindTexture(GL_TEXTURE_2D, waterfall);
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, FFT_SIZE, NUM_WATERFALL_LINES, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, waterfall_tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, FFT_SIZE, NUM_WATERFALL_LINES, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_tex);
@ -132,6 +145,7 @@ void PrimaryGLContext::Plot(std::vector<float> &points, std::vector<float> &poin
glPopMatrix();
}
glEnable(GL_TEXTURE_2D);
// glEnable(GL_COLOR_TABLE);
glBindTexture(GL_TEXTURE_2D, waterfall);
@ -184,7 +198,7 @@ void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
PrimaryGLContext& canvas = wxGetApp().GetContext(this);
glViewport(0, 0, ClientSize.x, ClientSize.y);
canvas.Plot(spectrum_points, test_demod.waveform_points, waterfall_tex);
canvas.Plot(spectrum_points, test_demod.waveform_points);
SwapBuffers();
}
@ -281,16 +295,8 @@ void TestGLCanvas::setData(std::vector<signed char> *data) {
// fftw_execute(plan[1]);
memmove(waterfall_tex + FFT_SIZE, waterfall_tex, (NUM_WATERFALL_LINES - 1) * FFT_SIZE);
for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) {
float v = log10(fft_result_maa[i]) / log10(fft_ceil_maa);
float wv = v;
if (wv<0.0) wv = 0.0;
if (wv>1.0) wv = 1.0;
waterfall_tex[i] = (unsigned char) floor(wv * 255.0);
spectrum_points[i * 2] = ((float) i / (float) iMax);
spectrum_points[i * 2 + 1] = v;
}

View File

@ -18,13 +18,14 @@ class PrimaryGLContext: public wxGLContext {
public:
PrimaryGLContext(wxGLCanvas *canvas);
void Plot(std::vector<float> &points, std::vector<float> &points2, unsigned char *waterfall_tex);
void Plot(std::vector<float> &points, std::vector<float> &points2);
private:
Gradient grad;
GLuint waterfall;
unsigned char waterfall_tex[FFT_SIZE * NUM_WATERFALL_LINES];
};
class TestGLCanvas: public wxGLCanvas {
@ -52,10 +53,6 @@ private:
std::vector<float> fft_result_ma;
std::vector<float> fft_result_maa;
unsigned char waterfall_tex[FFT_SIZE * NUM_WATERFALL_LINES];
Demodulator test_demod;
wxDECLARE_EVENT_TABLE();
};