diff options
author | Christian Daniel <cd@maintech.de> | 2014-08-15 11:37:26 +0200 |
---|---|---|
committer | Christian Daniel <cd@maintech.de> | 2014-08-16 22:32:45 +0200 |
commit | 5864e48bd8d559223bed4a9eabbc4f894dc128ef (patch) | |
tree | e2a6d36abad80e0bcccbd79c48b34b4b4ecf80bc /sdrbase | |
parent | 78201046667987b25ade0b4023805a93353133fe (diff) |
major rewrite
Diffstat (limited to 'sdrbase')
-rw-r--r-- | sdrbase/audio/audiodeviceinfo.cpp | 28 | ||||
-rw-r--r-- | sdrbase/audio/audiofifo.cpp | 4 | ||||
-rw-r--r-- | sdrbase/audio/audiooutput.cpp | 71 | ||||
-rw-r--r-- | sdrbase/dsp/channelizer.cpp | 164 | ||||
-rw-r--r-- | sdrbase/dsp/dspcommands.cpp | 1 | ||||
-rw-r--r-- | sdrbase/dsp/dspengine.cpp | 97 | ||||
-rw-r--r-- | sdrbase/dsp/fftwengine.cpp | 2 | ||||
-rw-r--r-- | sdrbase/dsp/nco.cpp | 17 | ||||
-rw-r--r-- | sdrbase/dsp/pidcontroller.cpp | 2 | ||||
-rw-r--r-- | sdrbase/dsp/pidcontroller.h | 28 | ||||
-rw-r--r-- | sdrbase/dsp/samplefifo.cpp | 31 | ||||
-rw-r--r-- | sdrbase/dsp/spectrumvis.cpp | 2 | ||||
-rw-r--r-- | sdrbase/dsp/threadedsamplesink.cpp | 33 | ||||
-rw-r--r-- | sdrbase/gui/glspectrumgui.cpp | 2 | ||||
-rw-r--r-- | sdrbase/gui/glspectrumgui.ui | 16 | ||||
-rw-r--r-- | sdrbase/gui/preferencesdialog.cpp | 77 | ||||
-rw-r--r-- | sdrbase/gui/preferencesdialog.ui | 110 | ||||
-rw-r--r-- | sdrbase/gui/scopewindow.cpp | 8 | ||||
-rw-r--r-- | sdrbase/mainwindow.cpp | 34 | ||||
-rw-r--r-- | sdrbase/plugin/pluginmanager.cpp | 6 | ||||
-rw-r--r-- | sdrbase/settings/preferences.cpp | 20 | ||||
-rw-r--r-- | sdrbase/util/message.cpp | 2 |
22 files changed, 334 insertions, 421 deletions
diff --git a/sdrbase/audio/audiodeviceinfo.cpp b/sdrbase/audio/audiodeviceinfo.cpp deleted file mode 100644 index e422878..0000000 --- a/sdrbase/audio/audiodeviceinfo.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // -// written by Christian Daniel // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see <http://www.gnu.org/licenses/>. // -/////////////////////////////////////////////////////////////////////////////////// - -#include "audio/audiodeviceinfo.h" - -AudioDeviceInfo::AudioDeviceInfo() -{ -} - -int AudioDeviceInfo::match(const QString& api, const QString device) const -{ - // nothing found - fall back to default - return 0; -} diff --git a/sdrbase/audio/audiofifo.cpp b/sdrbase/audio/audiofifo.cpp index dd475ca..41d19df 100644 --- a/sdrbase/audio/audiofifo.cpp +++ b/sdrbase/audio/audiofifo.cpp @@ -22,7 +22,9 @@ #define MIN(x, y) ((x) < (y) ? (x) : (y)) AudioFifo::AudioFifo() : - m_fifo(NULL) + m_fifo(NULL), + m_sampleRate(0), + m_stopped(true) { m_size = 0; m_fill = 0; diff --git a/sdrbase/audio/audiooutput.cpp b/sdrbase/audio/audiooutput.cpp index 455241a..b5e1792 100644 --- a/sdrbase/audio/audiooutput.cpp +++ b/sdrbase/audio/audiooutput.cpp @@ -24,6 +24,9 @@ AudioOutput::AudioOutput() : m_mutex(), + m_error(), + m_deviceName(), + m_rate(0), m_audioOutput(NULL), m_audioFifos() { @@ -39,17 +42,38 @@ AudioOutput::~AudioOutput() m_audioFifos.clear(); } -bool AudioOutput::start(int device, int rate) +void AudioOutput::configure(const QString& deviceName, uint rate) { QMutexLocker mutexLocker(&m_mutex); - Q_UNUSED(device); - Q_UNUSED(rate); + m_deviceName = deviceName; + m_rate = rate; +} + +bool AudioOutput::start() +{ + QMutexLocker mutexLocker(&m_mutex); QAudioFormat format; QAudioDeviceInfo devInfo(QAudioDeviceInfo::defaultOutputDevice()); - format.setSampleRate(41000); + if(!m_deviceName.isEmpty()) { + QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); + bool found = false; + for(int i = 0; i < devices.count(); ++i) { + if(devices[i].deviceName() == m_deviceName) { + devInfo = devices[i]; + found = true; + break; + } + } + if(!found) { + m_error = tr("Audio output device %1 not available").arg(m_deviceName); + return false; + } + } + + format.setSampleRate(m_rate); format.setChannelCount(2); format.setSampleSize(16); format.setCodec("audio/pcm"); @@ -60,26 +84,33 @@ bool AudioOutput::start(int device, int rate) qDebug("default format not supported - try to use nearest"); format = devInfo.nearestFormat(format); } + qDebug("Audio output %s using samplerate %d", qPrintable(devInfo.deviceName()), format.sampleRate()); if(format.sampleSize() != 16) { - qDebug("audio device doesn't support 16 bit samples (%s)", qPrintable(devInfo.defaultOutputDevice().deviceName())); + m_error = tr("Audio output %1 doesn't support 16 bit samples").arg(devInfo.deviceName()); return false; } - m_audioOutput = new QAudioOutput(format); + m_audioOutput = new QAudioOutput(devInfo, format); QIODevice::open(QIODevice::ReadOnly); + //m_audioOutput->setBufferSize(3 * 4096); m_audioOutput->start(this); - return true; + for(AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it) + (*it)->setSampleRate(m_audioOutput->format().sampleRate()); + return true; } void AudioOutput::stop() { QMutexLocker mutexLocker(&m_mutex); + for(AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it) + (*it)->setSampleRate(0); + if(m_audioOutput != NULL) { m_audioOutput->stop(); delete m_audioOutput; @@ -92,6 +123,10 @@ void AudioOutput::addFifo(AudioFifo* audioFifo) { QMutexLocker mutexLocker(&m_mutex); + if(m_audioOutput == NULL) + audioFifo->setSampleRate(0); + else audioFifo->setSampleRate(m_audioOutput->format().sampleRate()); + m_audioFifos.push_back(audioFifo); } @@ -99,9 +134,19 @@ void AudioOutput::removeFifo(AudioFifo* audioFifo) { QMutexLocker mutexLocker(&m_mutex); + audioFifo->setSampleRate(0); m_audioFifos.remove(audioFifo); } +quint32 AudioOutput::getCurrentRate() +{ + QMutexLocker mutexLocker(&m_mutex); + + if(m_audioOutput == NULL) + return 0; + else return m_audioOutput->format().sampleRate(); +} + bool AudioOutput::open(OpenMode mode) { Q_UNUSED(mode); @@ -110,9 +155,6 @@ bool AudioOutput::open(OpenMode mode) qint64 AudioOutput::readData(char* data, qint64 maxLen) { - if(maxLen == 0) - return 0; - QMutexLocker mutexLocker(&m_mutex); maxLen -= maxLen % 4; @@ -120,13 +162,18 @@ qint64 AudioOutput::readData(char* data, qint64 maxLen) if((int)m_mixBuffer.size() < framesPerBuffer * 2) { m_mixBuffer.resize(framesPerBuffer * 2); // allocate 2 qint32 per frame (stereo) - if(m_mixBuffer.size() != framesPerBuffer * 2) + if(m_mixBuffer.size() != framesPerBuffer * 2) { + qDebug("KAPUTT"); return 0; + } } memset(&m_mixBuffer[0], 0x00, 2 * framesPerBuffer * sizeof(m_mixBuffer[0])); // start with silence // sum up a block from all fifos for(AudioFifos::iterator it = m_audioFifos.begin(); it != m_audioFifos.end(); ++it) { + if((*it)->isStopped()) + continue; + // use outputBuffer as temp - yes, one memcpy could be saved uint samples = (*it)->read((quint8*)data, framesPerBuffer, 1); const qint16* src = (const qint16*)data; @@ -141,7 +188,7 @@ qint64 AudioOutput::readData(char* data, qint64 maxLen) } } - // convert to int16 + // convert to int16 and do saturation std::vector<qint32>::const_iterator src = m_mixBuffer.begin(); qint16* dst = (qint16*)data; for(int i = 0; i < framesPerBuffer; ++i) { diff --git a/sdrbase/dsp/channelizer.cpp b/sdrbase/dsp/channelizer.cpp index 2028a0f..41300e1 100644 --- a/sdrbase/dsp/channelizer.cpp +++ b/sdrbase/dsp/channelizer.cpp @@ -27,13 +27,15 @@ void Channelizer::feed(SampleVector::const_iterator begin, SampleVector::const_i { for(SampleVector::const_iterator sample = begin; sample != end; ++sample) { Sample s(*sample); + bool haveSample = true; FilterStages::iterator stage = m_filterStages.begin(); while(stage != m_filterStages.end()) { - if(!(*stage)->work(&s)) + haveSample = (*stage)->work(&s); + if(!haveSample) break; ++stage; } - if(stage == m_filterStages.end()) + if((stage == m_filterStages.end()) && haveSample) m_sampleBuffer.push_back(s); } @@ -58,7 +60,7 @@ void Channelizer::stop() bool Channelizer::handleMessage(Message* cmd) { if(DSPSignalNotification::match(cmd)) { - DSPSignalNotification* signal = (DSPSignalNotification*)cmd; + DSPSignalNotification* signal = DSPSignalNotification::cast(cmd); m_inputSampleRate = signal->getSampleRate(); applyConfiguration(); cmd->completed(); @@ -69,7 +71,7 @@ bool Channelizer::handleMessage(Message* cmd) } return true; } else if(DSPConfigureChannelizer::match(cmd)) { - DSPConfigureChannelizer* chan = (DSPConfigureChannelizer*)cmd; + DSPConfigureChannelizer* chan = DSPConfigureChannelizer::cast(cmd); m_requestedOutputSampleRate = chan->getSampleRate(); m_requestedCenterFrequency = chan->getCenterFrequency(); applyConfiguration(); @@ -172,157 +174,3 @@ void Channelizer::freeFilterChain() delete *it; m_filterStages.clear(); } - -#if 0 - -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // -// written by Christian Daniel // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see <http://www.gnu.org/licenses/>. // -/////////////////////////////////////////////////////////////////////////////////// - -#include <QTime> -#include <stdio.h> -#include "channelizer.h" -#include "hardware/audiooutput.h" - -Channelizer::Channelizer() -{ -#if 0 - m_spectrum.configure(128 , 25, FFTWindow::Bartlett); - m_buffer.resize(2048); - m_bufferFill = 0; - m_nco.setFreq(-100000, 500000); - m_interpolator.create(51, 32, 32 * 500000, 150000 / 2); - m_distance = 500000.0 / 176400.0; - - m_interpolator2.create(19, 8, 8 * 176400, 15000 / 2); - m_distance2 = 4; - - m_audioFifo.setSize(4, 44100 / 2 * 4); - m_audioOutput = new AudioOutput; - m_audioOutput->start(0, 44100, &m_audioFifo); - m_resampler = 1.0; - - m_resamplerCtrl.setup(0.00001, 0, -0.00001); -#endif -} - -Channelizer::~Channelizer() -{ -#if 0 - m_audioOutput->stop(); - delete m_audioOutput; -#endif -} - -#if 0 -void Channelizer::setGLSpectrum(GLSpectrum* glSpectrum) -{ - m_spectrum.setGLSpectrum(glSpectrum); -} -#endif - -size_t Channelizer::workUnitSize() -{ -#if 0 - return m_buffer.size(); -#endif - return 0; -} - -size_t Channelizer::work(SampleVector::const_iterator begin, SampleVector::const_iterator end) -{ -#if 0 - int buffered = m_audioOutput->bufferedSamples(); - - if(m_audioFifo.fill() < (m_audioFifo.size() / 6)) { - while(m_audioFifo.fill() < (m_audioFifo.size() / 2)) { - quint32 d = 0; - m_audioFifo.write((quint8*)&d, 4); - } - qDebug("underflow - fill %d (vs %d)", m_audioFifo.fill(), m_audioFifo.size() / 4 / 2); - } - - buffered = m_audioOutput->bufferedSamples(); - int fill = m_audioFifo.fill() / 4 + buffered; - float err = (float)fill / ((m_audioFifo.size() / 4) / 2); - - float ctrl = m_resamplerCtrl.feed(err); - //float resamplerRate = (ctrl / 1.0); - float resamplerRate = err; - - if(resamplerRate < 0.9999) - resamplerRate = 0.9999; - else if(resamplerRate > 1.0001) - resamplerRate = 1.0001; - m_resampler = m_resampler * 0.99 + resamplerRate * 0.01; - //m_resampler = resamplerRate; - - if(m_resampler < 0.995) - m_resampler = 0.995; - else if(m_resampler > 1.005) - m_resampler = 1.005; - - //qDebug("%lld %5d %f %f %f", QDateTime::currentMSecsSinceEpoch(), fill, ctrl, m_resampler, err); - - struct AudioSample { - qint16 l; - qint16 r; - }; - - size_t count = end - begin; - Complex ci; - bool consumed; - bool consumed2; - - for(SampleVector::const_iterator it = begin; it < end; it++) { - Complex c(it->real() / 32768.0, it->imag() / 32768.0); - c *= m_nco.nextIQ(); - - consumed = false; - if(m_interpolator.interpolate(&m_distance, c, &consumed, &ci)) { - - Complex d = ci * conj(m_lastSample); - m_lastSample = ci; - //Complex demod(atan2(d.imag(), d.real()) * 0.5, 0); - Real demod = atan2(d.imag(), d.real()) / M_PI; - - consumed2 = false; - c = Complex(demod, 0); - while(!consumed2) { - if(m_interpolator2.interpolate(&m_distance2, c, &consumed2, &ci)) { - m_buffer[m_bufferFill++] = Sample(ci.real() * 32767.0, 0.0); - - AudioSample s; - s.l = ci.real() * 32767.0; - s.r = s.l; - m_audioFifo.write((quint8*)&s, 4, 1); - - if(m_bufferFill >= m_buffer.size()) { - m_spectrum.feed(m_buffer.begin(), m_buffer.end()); - m_bufferFill = 0; - } - m_distance2 += 4.0 * m_resampler; - } - } - m_distance += 500000 / 176400.0; - } - } - - return count; -#endif -} - -#endif diff --git a/sdrbase/dsp/dspcommands.cpp b/sdrbase/dsp/dspcommands.cpp index 21bdddc..9e19da2 100644 --- a/sdrbase/dsp/dspcommands.cpp +++ b/sdrbase/dsp/dspcommands.cpp @@ -13,6 +13,7 @@ MESSAGE_CLASS_DEFINITION(DSPAddAudioSource, Message) MESSAGE_CLASS_DEFINITION(DSPRemoveAudioSource, Message) MESSAGE_CLASS_DEFINITION(DSPConfigureSpectrumVis, Message) MESSAGE_CLASS_DEFINITION(DSPConfigureCorrection, Message) +MESSAGE_CLASS_DEFINITION(DSPConfigureAudioOutput, Message) MESSAGE_CLASS_DEFINITION(DSPEngineReport, Message) MESSAGE_CLASS_DEFINITION(DSPConfigureScopeVis, Message) MESSAGE_CLASS_DEFINITION(DSPSignalNotification, Message) diff --git a/sdrbase/dsp/dspengine.cpp b/sdrbase/dsp/dspengine.cpp index 369403f..63b3f58 100644 --- a/sdrbase/dsp/dspengine.cpp +++ b/sdrbase/dsp/dspengine.cpp @@ -109,6 +109,12 @@ void DSPEngine::configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCo cmd->submit(&m_messageQueue); } +void DSPEngine::configureAudioOutput(const QString& audioOutput, quint32 audioOutputRate) +{ + Message* cmd = DSPConfigureAudioOutput::create(audioOutput, audioOutputRate); + cmd->submit(&m_messageQueue); +} + QString DSPEngine::errorMessage() { DSPGetErrorMessage cmd; @@ -174,7 +180,6 @@ void DSPEngine::imbalance(SampleVector::iterator begin, SampleVector::iterator e qMin = it->imag(); else if(it->imag() > qMax) qMax = it->imag(); - } else { iMin = it->real(); iMax = it->real(); @@ -202,7 +207,7 @@ void DSPEngine::work() size_t samplesDone = 0; bool firstOfBurst = true; - while((sampleFifo->fill() > 0) && (m_messageQueue.countPending() == 0) && (samplesDone < m_sampleRate)) { + while((sampleFifo->fill() > 0) && (m_messageQueue.countPending() == 0) && (samplesDone < m_sampleRate / 2)) { SampleVector::iterator part1begin; SampleVector::iterator part1end; SampleVector::iterator part2begin; @@ -218,7 +223,7 @@ void DSPEngine::work() if(m_iqImbalanceCorrection) imbalance(part1begin, part1end); // feed data to handlers - for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) + for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); ++it) (*it)->feed(part1begin, part1end, firstOfBurst); firstOfBurst = false; } @@ -230,7 +235,7 @@ void DSPEngine::work() if(m_iqImbalanceCorrection) imbalance(part2begin, part2end); // feed data to handlers - for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) + for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); ++it) (*it)->feed(part2begin, part2end, firstOfBurst); firstOfBurst = false; } @@ -239,69 +244,6 @@ void DSPEngine::work() sampleFifo->readCommit(count); samplesDone += count; } - -#if 0 - size_t wus; - size_t maxWorkUnitSize = 0; - size_t samplesDone = 0; - - wus = m_spectrum.workUnitSize(); - if(wus > maxWorkUnitSize) - maxWorkUnitSize = wus; - for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) { - wus = (*it)->workUnitSize(); - if(wus > maxWorkUnitSize) - maxWorkUnitSize = wus; - } - - while((m_sampleFifo.fill() > maxWorkUnitSize) && (m_commandQueue.countPending() == 0) && (samplesDone < m_sampleRate)) { - SampleVector::iterator part1begin; - SampleVector::iterator part1end; - SampleVector::iterator part2begin; - SampleVector::iterator part2end; - - size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end); - - // first part of FIFO data - if(part1begin != part1end) { - // correct stuff - if(m_settings.dcOffsetCorrection()) - dcOffset(part1begin, part1end); - if(m_settings.iqImbalanceCorrection()) - imbalance(part1begin, part1end); - // feed data to handlers - m_spectrum.feed(part1begin, part1end); - for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) - (*it)->feed(part1begin, part1end); - } - // second part of FIFO data (used when block wraps around) - if(part2begin != part2end) { - // correct stuff - if(m_settings.dcOffsetCorrection()) - dcOffset(part2begin, part2end); - if(m_settings.iqImbalanceCorrection()) - imbalance(part2begin, part2end); - // feed data to handlers - m_spectrum.feed(part2begin, part2end); - for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) - (*it)->feed(part1begin, part1end); - } - - // adjust FIFO pointers - m_sampleFifo.readCommit(count); - samplesDone += count; - } - - // check if the center frequency has changed (has to be responsive) - if(m_settings.isModifiedCenterFreq()) - m_sampleSource->setCenterFrequency(m_settings.centerFreq()); - // check if decimation has changed (needed to be done here, because to high a sample rate can clog the switch) - if(m_settings.isModifiedDecimation()) { - m_sampleSource->setDecimation(m_settings.decimation()); - m_sampleRate = 4000000 / (1 << m_settings.decimation()); - qDebug("New rate: %d", m_sampleRate); - } -#endif } DSPEngine::State DSPEngine::gotoIdle() @@ -357,7 +299,11 @@ DSPEngine::State DSPEngine::gotoRunning() return gotoError("Could not start sample source"); m_deviceDescription = m_sampleSource->getDeviceDescription(); - m_audioOutput.start(0, 44100); + if(!m_audioOutput.start()) { + m_sampleSource->stopInput(); + return gotoError(m_audioOutput.getError()); + } + for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) (*it)->start(); m_sampleRate = 0; // make sure, report is sent @@ -447,7 +393,7 @@ void DSPEngine::handleMessages() { Message* message; while((message = m_messageQueue.accept()) != NULL) { - qDebug("Message: %s", message->getIdentifier()); + //qDebug("Message: %s", message->getIdentifier()); if(DSPPing::match(message)) { message->completed(m_state); @@ -465,16 +411,16 @@ void DSPEngine::handleMessages() m_state = gotoIdle(); message->completed(m_state); } else if(DSPGetDeviceDescription::match(message)) { - ((DSPGetDeviceDescription*)message)->setDeviceDescription(m_deviceDescription); + DSPGetDeviceDescription::cast(message)->setDeviceDescription(m_deviceDescription); message->completed(); } else if(DSPGetErrorMessage::match(message)) { ((DSPGetErrorMessage*)message)->setErrorMessage(m_errorMessage); message->completed(); } else if(DSPSetSource::match(message)) { - handleSetSource(((DSPSetSource*)message)->getSampleSource()); + handleSetSource(DSPSetSource::cast(message)->getSampleSource()); message->completed(); } else if(DSPAddSink::match(message)) { - SampleSink* sink = ((DSPAddSink*)message)->getSampleSink(); + SampleSink* sink = DSPAddSink::cast(message)->getSampleSink(); if(m_state == StRunning) { DSPSignalNotification* signal = DSPSignalNotification::create(m_sampleRate, 0); signal->submit(&m_messageQueue, sink); @@ -489,13 +435,16 @@ void DSPEngine::handleMessages() m_sampleSinks.remove(sink); message->completed(); } else if(DSPAddAudioSource::match(message)) { - m_audioOutput.addFifo(((DSPAddAudioSource*)message)->getAudioFifo()); + m_audioOutput.addFifo(DSPAddAudioSource::cast(message)->getAudioFifo()); message->completed(); } else if(DSPRemoveAudioSource::match(message)) { m_audioOutput.removeFifo(((DSPAddAudioSource*)message)->getAudioFifo()); message->completed(); + } else if(DSPConfigureAudioOutput::match(message)) { + DSPConfigureAudioOutput* conf = DSPConfigureAudioOutput::cast(message); + m_audioOutput.configure(conf->getAudioOutputDevice(), conf->getAudioOutputRate()); } else if(DSPConfigureCorrection::match(message)) { - DSPConfigureCorrection* conf = (DSPConfigureCorrection*)message; + DSPConfigureCorrection* conf = DSPConfigureCorrection::cast(message); m_iqImbalanceCorrection = conf->getIQImbalanceCorrection(); if(m_dcOffsetCorrection != conf->getDCOffsetCorrection()) { m_dcOffsetCorrection = conf->getDCOffsetCorrection(); diff --git a/sdrbase/dsp/fftwengine.cpp b/sdrbase/dsp/fftwengine.cpp index 76b189e..f5062fb 100644 --- a/sdrbase/dsp/fftwengine.cpp +++ b/sdrbase/dsp/fftwengine.cpp @@ -21,6 +21,7 @@ void FFTWEngine::configure(int n, bool inverse) } } + m_globalPlanMutex.lock(); m_currentPlan = new Plan; m_currentPlan->n = n; m_currentPlan->inverse = inverse; @@ -28,7 +29,6 @@ void FFTWEngine::configure(int n, bool inverse) m_currentPlan->out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * n); QTime t; t.start(); - m_globalPlanMutex.lock(); m_currentPlan->plan = fftwf_plan_dft_1d(n, m_currentPlan->in, m_currentPlan->out, inverse ? FFTW_BACKWARD : FFTW_FORWARD, FFTW_PATIENT); m_globalPlanMutex.unlock(); qDebug("FFT: creating FFTW plan (n=%d,%s) took %dms", n, inverse ? "inverse" : "forward", t.elapsed()); diff --git a/sdrbase/dsp/nco.cpp b/sdrbase/dsp/nco.cpp index 1143cf8..1982750 100644 --- a/sdrbase/dsp/nco.cpp +++ b/sdrbase/dsp/nco.cpp @@ -30,7 +30,7 @@ void NCO::initTable() return; for(int i = 0; i < TableSize; i++) - m_table[i] = cos((2.0 * M_PI * i) / TableSize); + m_table[i] = cos((2.0 * M_PI * (Real)i) / ((Real)TableSize)); m_tableInitialized = true; } @@ -43,8 +43,15 @@ NCO::NCO() void NCO::setFreq(Real freq, Real sampleRate) { - m_phaseIncrement = (freq * TableSize) / sampleRate; - qDebug("NCO phase inc %d", m_phaseIncrement); + if(sampleRate > 0) { + m_phaseIncrement = (freq * TableSize) / sampleRate; + if(m_phaseIncrement != 0) + qDebug("NCO phase inc %d (period %f)", m_phaseIncrement, (Real)TableSize / (Real)m_phaseIncrement); + else qDebug("NCO phase inc %d (period oo)", m_phaseIncrement); + } else { + qDebug("cannot calculate NCO phase increment since samplerate is 0"); + m_phaseIncrement = 1; + } } float NCO::next() @@ -66,5 +73,7 @@ Complex NCO::nextIQ() while(m_phase < 0) m_phase += TableSize; - return Complex(m_table[m_phase], -m_table[(m_phase + TableSize / 4) % TableSize]); + int idxQuad = (m_phase + (TableSize / 4) + (TableSize / 2)) % TableSize; + + return Complex(m_table[m_phase], m_table[idxQuad]); } diff --git a/sdrbase/dsp/pidcontroller.cpp b/sdrbase/dsp/pidcontroller.cpp index 8b015f6..a5d5356 100644 --- a/sdrbase/dsp/pidcontroller.cpp +++ b/sdrbase/dsp/pidcontroller.cpp @@ -1,4 +1,4 @@ -#include "pidcontroller.h" +#include "dsp/pidcontroller.h" PIDController::PIDController() : m_p(0.0), diff --git a/sdrbase/dsp/pidcontroller.h b/sdrbase/dsp/pidcontroller.h deleted file mode 100644 index 7b96793..0000000 --- a/sdrbase/dsp/pidcontroller.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef INCLUDE_PIDCONTROLLER_H -#define INCLUDE_PIDCONTROLLER_H - -#include "dsp/dsptypes.h" - -class PIDController { -private: - Real m_p; - Real m_i; - Real m_d; - Real m_int; - Real m_diff; - -public: - PIDController(); - - void setup(Real p, Real i, Real d); - - Real feed(Real v) - { - m_int += v * m_i; - Real d = m_d * (m_diff - v); - m_diff = v; - return (v * m_p) + m_int + d; - } -}; - -#endif // INCLUDE_PIDCONTROLLER_H diff --git a/sdrbase/dsp/samplefifo.cpp b/sdrbase/dsp/samplefifo.cpp index caa4969..e9d29b8 100644 --- a/sdrbase/dsp/samplefifo.cpp +++ b/sdrbase/dsp/samplefifo.cpp @@ -64,17 +64,21 @@ bool SampleFifo::setSize(int size) { create(size); - return m_data.size() == (uint)size; + return m_size == (uint)size; } uint SampleFifo::write(const quint8* data, uint count) { + return write(SampleVector::const_iterator((Sample*)data), SampleVector::const_iterator((Sample*)(data + count))); +#if 0 QMutexLocker mutexLocker(&m_mutex); uint total; uint remaining; uint len; const Sample* begin = (const Sample*)data; - count /= 4; + count /= sizeof(Sample); + + //qDebug("write pre count %d %u", count, m_fill); total = MIN(count, m_size - m_fill); if(total < count) { @@ -96,6 +100,7 @@ uint SampleFifo::write(const quint8* data, uint count) remaining = total; while(remaining > 0) { len = MIN(remaining, m_size - m_tail); + //qDebug("write remaining %u, len %u", remaining, len); std::copy(begin, begin + len, m_data.begin() + m_tail); m_tail += len; m_tail %= m_size; @@ -104,10 +109,13 @@ uint SampleFifo::write(const quint8* data, uint count) remaining -= len; } + //qDebug("write post count %d %u [%u;%u]", count, m_fill, m_head, m_tail); + if(m_fill > 0) emit dataReady(); return total; +#endif } uint SampleFifo::write(SampleVector::const_iterator begin, SampleVector::const_iterator end) @@ -139,8 +147,7 @@ uint SampleFifo::write(SampleVector::const_iterator begin, SampleVector::const_i while(remaining > 0) { len = MIN(remaining, m_size - m_tail); std::copy(begin, begin + len, m_data.begin() + m_tail); - m_tail += len; - m_tail %= m_size; + m_tail = (m_tail + len) % m_size; m_fill += len; begin += len; remaining -= len; @@ -151,7 +158,7 @@ uint SampleFifo::write(SampleVector::const_iterator begin, SampleVector::const_i return total; } - +/* uint SampleFifo::read(SampleVector::iterator begin, SampleVector::iterator end) { QMutexLocker mutexLocker(&m_mutex); @@ -177,13 +184,14 @@ uint SampleFifo::read(SampleVector::iterator begin, SampleVector::iterator end) return total; } - +*/ uint SampleFifo::readBegin(uint count, SampleVector::iterator* part1Begin, SampleVector::iterator* part1End, SampleVector::iterator* part2Begin, SampleVector::iterator* part2End) { QMutexLocker mutexLocker(&m_mutex); uint total; + uint done = 0; uint remaining; uint len; uint head = m_head; @@ -196,10 +204,10 @@ uint SampleFifo::readBegin(uint count, if(remaining > 0) { len = MIN(remaining, m_size - head); *part1Begin = m_data.begin() + head; - *part1End = m_data.begin() + head + len; - head += len; - head %= m_size; + *part1End = *part1Begin + len; + head = (head + len) % m_size; remaining -= len; + done += len; } else { *part1Begin = m_data.end(); *part1End = m_data.end(); @@ -207,13 +215,14 @@ uint SampleFifo::readBegin(uint count, if(remaining > 0) { len = MIN(remaining, m_size - head); *part2Begin = m_data.begin() + head; - *part2End = m_data.begin() + head + len; + *part2End = *part2Begin + len; + done += len; } else { *part2Begin = m_data.end(); *part2End = m_data.end(); } - return total; + return done; } uint SampleFifo::readCommit(uint count) diff --git a/sdrbase/dsp/spectrumvis.cpp b/sdrbase/dsp/spectrumvis.cpp index 01c7dbe..627a093 100644 --- a/sdrbase/dsp/spectrumvis.cpp +++ b/sdrbase/dsp/spectrumvis.cpp @@ -3,7 +3,7 @@ #include "dsp/dspcommands.h" #include "util/messagequeue.h" -#define MAX_FFT_SIZE 4096 +#define MAX_FFT_SIZE 8192 #ifdef _WIN32 double log2f(double n) diff --git a/sdrbase/dsp/threadedsamplesink.cpp b/sdrbase/dsp/threadedsamplesink.cpp index ad157b9..313ed24 100644 --- a/sdrbase/dsp/threadedsamplesink.cpp +++ b/sdrbase/dsp/threadedsamplesink.cpp @@ -15,7 +15,7 @@ ThreadedSampleSink::ThreadedSampleSink(SampleSink* sampleSink) : m_sampleFifo.moveToThread(m_thread); connect(&m_sampleFifo, SIGNAL(dataReady()), this, SLOT(handleData())); - m_sampleFifo.setSize(262144); + m_sampleFifo.setSize(128 * 1024); sampleSink->moveToThread(m_thread); } @@ -55,8 +55,11 @@ bool ThreadedSampleSink::handleMessage(Message* cmd) void ThreadedSampleSink::handleData() { bool firstOfBurst = true; + QTime time; - while((m_sampleFifo.fill() > 0) && (m_messageQueue.countPending() == 0)) { + time.start(); + + while((m_sampleFifo.fill() > 0) && (m_messageQueue.countPending() == 0) && (time.elapsed() < 250)) { SampleVector::iterator part1begin; SampleVector::iterator part1end; SampleVector::iterator part2begin; @@ -64,19 +67,19 @@ void ThreadedSampleSink::handleData() size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end); - // first part of FIFO data - if(part1begin != part1end) { - // handle data - if(m_sampleSink != NULL) - m_sampleSink->feed(part1begin, part1end, firstOfBurst); - firstOfBurst = false; - } - // second part of FIFO data (used when block wraps around) - if(part2begin != part2end) { - // handle data - if(m_sampleSink != NULL) + if(m_sampleSink != NULL) { + // first part of FIFO data + if(part1begin != part1end) { + // handle data m_sampleSink->feed(part1begin, part1end, firstOfBurst); - firstOfBurst = false; + firstOfBurst = false; + } + // second part of FIFO data (used when block wraps around) + if(part2begin != part2end) { + // handle data + m_sampleSink->feed(part2begin, part2end, firstOfBurst); + firstOfBurst = false; + } } // adjust FIFO pointers @@ -88,7 +91,7 @@ void ThreadedSampleSink::handleMessages() { Message* message; while((message = m_messageQueue.accept()) != NULL) { - qDebug("CMD: %s", message->getIdentifier()); + //qDebug("CMD: %s", message->getIdentifier()); if(m_sampleSink != NULL) { if(!m_sampleSink->handleMessage(message)) message->completed(); diff --git a/sdrbase/gui/glspectrumgui.cpp b/sdrbase/gui/glspectrumgui.cpp index 1fbaaf2..6231e8d 100644 --- a/sdrbase/gui/glspectrumgui.cpp +++ b/sdrbase/gui/glspectrumgui.cpp @@ -112,7 +112,7 @@ bool GLSpectrumGUI::deserialize(const QByteArray& data) void GLSpectrumGUI::applySettings() { ui->fftWindow->setCurrentIndex(m_fftWindow); - for(int i = 0; i < 6; i++) { + for(int i = 0; i < 7; i++) { if(m_fftSize == (1 << (i + 7))) { ui->fftSize->setCurrentIndex(i); break; diff --git a/sdrbase/gui/glspectrumgui.ui b/sdrbase/gui/glspectrumgui.ui index 2a9babe..a738255 100644 --- a/sdrbase/gui/glspectrumgui.ui +++ b/sdrbase/gui/glspectrumgui.ui @@ -14,7 +14,16 @@ <string>Oscilloscope</string> </property> <layout class="QGridLayout" name="gridLayout" columnstretch="1,1,1,1"> - <property name="margin"> + <property name="leftMargin"> + <number>2</number> + </property> + <property name="topMargin"> + <number>2</number> + </property> + <property name="rightMargin"> + <number>2</number> + </property> + <property name="bottomMargin"> <number>2</number> </property> <property name="spacing"> @@ -162,6 +171,11 @@ <string>4096</string> </property> </item> + <item> + <property name="text"> + <string>8192</string> + </property> + </item> </widget> </item> <item row="1" column="2"> diff --git a/sdrbase/gui/preferencesdialog.cpp b/sdrbase/gui/preferencesdialog.cpp index 077ef45..5394150 100644 --- a/sdrbase/gui/preferencesdialog.cpp +++ b/sdrbase/gui/preferencesdialog.cpp @@ -1,47 +1,61 @@ #include <QTreeWidgetItem> +#include <QAudioDeviceInfo> #include "gui/preferencesdialog.h" #include "ui_preferencesdialog.h" -#include "audio/audiodeviceinfo.h" +#include "settings/preferences.h" -PreferencesDialog::PreferencesDialog(AudioDeviceInfo* audioDeviceInfo, QWidget* parent) : +PreferencesDialog::PreferencesDialog(Preferences* preferences, QWidget* parent) : QDialog(parent), ui(new Ui::PreferencesDialog), - m_audioDeviceInfo(audioDeviceInfo) + m_preferences(preferences) { ui->setupUi(this); - const AudioDeviceInfo::Devices& devices = audioDeviceInfo->getDevices(); - - QTreeWidgetItem* api; QStringList sl; - sl.append(tr("Default (use first suitable device)")); - api = new QTreeWidgetItem(ui->audioTree, sl, ATDefault); - api->setFirstColumnSpanned(true); - for(AudioDeviceInfo::Devices::const_iterator it = devices.begin(); it != devices.end(); ++it) { - int apiIndex; - sl.clear(); + bool found; - for(apiIndex = 0; apiIndex < ui->audioTree->topLevelItemCount(); ++apiIndex) { - if(ui->audioTree->topLevelItem(apiIndex)->text(0) == it->api) - break; - } - if(apiIndex >= ui->audioTree->topLevelItemCount()) { - sl.append(it->api); - api = new QTreeWidgetItem(ui->audioTree, sl, ATInterface); - api->setExpanded(true); - api->setFirstColumnSpanned(true); - sl.clear(); - } else { - api = ui->audioTree->topLevelItem(apiIndex); - } + QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); - sl.append(it->name); - new QTreeWidgetItem(api, sl, ATDevice); + sl.clear(); + sl.append(tr("Default output device (use first suitable)")); + QTreeWidgetItem* dev = new QTreeWidgetItem(ui->audioTree, sl); + dev->setFirstColumnSpanned(true); + dev->setData(0, Qt::UserRole, ""); + for(QList<QAudioDeviceInfo>::ConstIterator it = devices.begin(); it != devices.end(); ++it) { + sl.clear(); + sl.append(it->deviceName()); + QTreeWidgetItem* dev = new QTreeWidgetItem(ui->audioTree, sl); + dev->setFirstColumnSpanned(true); + dev->setData(0, Qt::UserRole, it->deviceName()); } - if(ui->audioTree->currentItem() == NULL) + found = false; + for(int i = 0; i < ui->audioTree->topLevelItemCount(); ++i) { + if(ui->audioTree->topLevelItem(i)->data(0, Qt::UserRole).toString() == m_preferences->getAudioOutput()) { + ui->audioTree->setCurrentItem(ui->audioTree->topLevelItem(i)); + found = true; + break; + } + } + if(!found) ui->audioTree->setCurrentItem(ui->audioTree->topLevelItem(0)); - ui->tabWidget->setCurrentIndex(0); + ui->audioRate->addItem(tr("48000 Hz"), 48000); + ui->audioRate->addItem(tr("44100 Hz"), 44100); + ui->audioRate->addItem(tr("24000 Hz"), 24000); + ui->audioRate->addItem(tr("22050 Hz"), 22050); + found = false; + for(int i = 0; i < ui->audioRate->count(); ++i) { + if(ui->audioRate->itemData(i).toInt() == m_preferences->getAudioOutputRate()) { + ui->audioRate->setCurrentIndex(i); + found = true; + break; + } + } + if(!found) + ui->audioRate->setCurrentIndex(1); + + ui->stackedWidget->setCurrentIndex(0); + ui->configTree->setCurrentItem(ui->configTree->topLevelItem(0)); } PreferencesDialog::~PreferencesDialog() @@ -51,5 +65,10 @@ PreferencesDialog::~PreferencesDialog() void PreferencesDialog::accept() { + if(ui->audioTree->currentItem() != NULL) + m_preferences->setAudioOutput(ui->audioTree->currentItem()->data(0, Qt::UserRole).toString()); + else m_preferences->setAudioOutput(QString()); + m_preferences->setAudioOutputRate(ui->audioRate->itemData(ui->audioRate->currentIndex()).toInt()); + QDialog::accept(); } diff --git a/sdrbase/gui/preferencesdialog.ui b/sdrbase/gui/preferencesdialog.ui index 0545931..f98a149 100644 --- a/sdrbase/gui/preferencesdialog.ui +++ b/sdrbase/gui/preferencesdialog.ui @@ -6,42 +6,55 @@ <rect> <x>0</x> <y>0</y> - <width>400</width> - <height>300</height> + <width>454</width> + <height>435</height> </rect> </property> <property name="windowTitle"> <string>Dialog</string> </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QTabWidget" name="tabWidget"> - <property name="currentIndex"> - <number>0</number> + <layout class="QGridLayout" name="gridLayout" columnstretch="1,3"> + <item row="0" column="0"> + <widget class="QTreeWidget" name="configTree"> + <property name="rootIsDecorated"> + <bool>false</bool> </property> - <widget class="QWidget" name="tab"> - <attribute name="title"> - <string>Receiver Hardware</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QTreeWidget" name="treeWidget"> - <column> - <property name="text"> - <string notr="true">1</string> - </property> - </column> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_2"> - <attribute name="title"> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> + <column> + <property name="text"> + <string notr="true">Section</string> + </property> + </column> + <item> + <property name="text"> <string>Audio Output</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_3"> + </property> + <property name="flags"> + <set>ItemIsSelectable|ItemIsEnabled</set> + </property> + </item> + </widget> + </item> + <item row="0" column="1"> + <widget class="QStackedWidget" name="stackedWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <widget class="QWidget" name="page"> + <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QTreeWidget" name="audioTree"> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> <column> <property name="text"> <string notr="true">Device</string> @@ -49,11 +62,49 @@ </column> </widget> </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Sample rate</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="audioRate"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToContents</enum> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> </layout> </widget> + <widget class="QWidget" name="page_2"/> </widget> </item> - <item> + <item row="1" column="0" colspan="2"> <widget class="QDialogButtonBox" name="buttonBox"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -67,9 +118,6 @@ </widget> <tabstops> <tabstop>buttonBox</tabstop> - <tabstop>tabWidget</tabstop> - <tabstop>treeWidget</tabstop> - <tabstop>audioTree</tabstop> </tabstops> <resources/> <connections> diff --git a/sdrbase/gui/scopewindow.cpp b/sdrbase/gui/scopewindow.cpp index 2f6200f..486242a 100644 --- a/sdrbase/gui/scopewindow.cpp +++ b/sdrbase/gui/scopewindow.cpp @@ -19,14 +19,13 @@ #include "ui_scopewindow.h" #include "util/simpleserializer.h" -ScopeWindow::ScopeWindow(DSPEngine* dspEngine, QWidget* parent) : +ScopeWindow::ScopeWindow(QWidget* parent) : QWidget(parent), ui(new Ui::ScopeWindow), m_sampleRate(0), m_timeBase(1) { ui->setupUi(this); - ui->scope->setDSPEngine(dspEngine); } ScopeWindow::~ScopeWindow() @@ -34,6 +33,11 @@ ScopeWindow::~ScopeWindow() delete ui; } +void ScopeWindow::setDSPEngine(DSPEngine* dspEngine) +{ + ui->scope->setDSPEngine(dspEngine); +} + void ScopeWindow::setSampleRate(int sampleRate) { m_sampleRate = sampleRate; diff --git a/sdrbase/mainwindow.cpp b/sdrbase/mainwindow.cpp index 9cbfb0f..904b3c9 100644 --- a/sdrbase/mainwindow.cpp +++ b/sdrbase/mainwindow.cpp @@ -20,7 +20,6 @@ #include <QLabel> #include "mainwindow.h" #include "ui_mainwindow.h" -#include "audio/audiodeviceinfo.h" #include "gui/indicator.h" #include "gui/presetitem.h" #include "gui/scopewindow.h" @@ -39,7 +38,6 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow), - m_audioDeviceInfo(new AudioDeviceInfo), m_messageQueue(new MessageQueue), m_settings(), m_dspEngine(new DSPEngine(m_messageQueue)), @@ -196,6 +194,8 @@ void MainWindow::loadSettings(const Preset* preset) m_pluginManager->loadSettings(preset); + m_dspEngine->configureAudioOutput(m_settings.getPreferences()->getAudioOutput(), m_settings.getPreferences()->getAudioOutputRate()); + // has to be last step restoreState(preset->getLayout()); } @@ -306,12 +306,12 @@ void MainWindow::handleMessages() { Message* message; while((message = m_messageQueue->accept()) != NULL) { - qDebug("Message: %s", message->getIdentifier()); + //qDebug("Message: %s", message->getIdentifier()); if(DSPEngineReport::match(message)) { - DSPEngineReport* rep = (DSPEngineReport*)message; + DSPEngineReport* rep = DSPEngineReport::cast(message); m_sampleRate = rep->getSampleRate(); m_centerFrequency = rep->getCenterFrequency(); - qDebug("SampleRate:%d, CenterFrequency:%llu", rep->getSampleRate(), rep->getCenterFrequency()); + //qDebug("SampleRate:%d, CenterFrequency:%llu", rep->getSampleRate(), rep->getCenterFrequency()); updateCenterFreqDisplay(); updateSampleRate(); message->completed(); @@ -332,6 +332,7 @@ void MainWindow::updateStatus() m_engineRunning->setColor(Qt::gray); m_engineError->setColor(Qt::gray); statusBar()->clearMessage(); + updateEnables(false); break; case DSPEngine::StIdle: @@ -339,6 +340,7 @@ void MainWindow::updateStatus() m_engineRunning->setColor(Qt::gray); m_engineError->setColor(Qt::gray); statusBar()->clearMessage(); + updateEnables(false); if(m_startOsmoSDRUpdateAfterStop) on_actionOsmoSDR_Firmware_Upgrade_triggered(); break; @@ -348,6 +350,7 @@ void MainWindow::updateStatus() m_engineRunning->setColor(Qt::green); m_engineError->setColor(Qt::gray); statusBar()->showMessage(tr("Sampling from %1").arg(m_dspEngine->deviceDescription())); + updateEnables(true); break; case DSPEngine::StError: @@ -355,6 +358,8 @@ void MainWindow::updateStatus() m_engineRunning->setColor(Qt::gray); m_engineError->setColor(Qt::red); statusBar()->showMessage(tr("Error: %1").arg(m_dspEngine->errorMessage())); + QMessageBox::critical(this, tr("Engine Error"), tr("%1").arg(m_dspEngine->errorMessage()), QMessageBox::Ok); + updateEnables(false); if(m_startOsmoSDRUpdateAfterStop) on_actionOsmoSDR_Firmware_Upgrade_triggered(); break; @@ -363,6 +368,15 @@ void MainWindow::updateStatus() } } +void MainWindow::updateEnables(bool running) +{ + if(running) { + ui->action_Preferences->setEnabled(false); + } else { + ui->action_Preferences->setEnabled(true); + } +} + void MainWindow::scopeWindowDestroyed() { ui->action_Oscilloscope->setChecked(false); @@ -490,7 +504,9 @@ void MainWindow::on_action_Oscilloscope_triggered() QDockWidget* dock = new QDockWidget(tr("Signalscope"), this); dock->setObjectName(QString::fromUtf8("scopeDock")); - m_scopeWindow = new ScopeWindow(m_dspEngine); + + m_scopeWindow = new ScopeWindow(); + m_scopeWindow->setDSPEngine(m_dspEngine); connect(m_scopeWindow, SIGNAL(destroyed()), this, SLOT(scopeWindowDestroyed())); m_scopeWindow->setSampleRate(m_sampleRate); dock->setWidget(m_scopeWindow); @@ -509,9 +525,11 @@ void MainWindow::on_action_Loaded_Plugins_triggered() void MainWindow::on_action_Preferences_triggered() { - PreferencesDialog preferencesDialog(m_audioDeviceInfo, this); + PreferencesDialog preferencesDialog(m_settings.getPreferences(), this); - preferencesDialog.exec(); + if(preferencesDialog.exec() == QDialog::Accepted) { + m_dspEngine->configureAudioOutput(m_settings.getPreferences()->getAudioOutput(), m_settings.getPreferences()->getAudioOutputRate()); + } } void MainWindow::on_sampleSource_currentIndexChanged(int index) diff --git a/sdrbase/plugin/pluginmanager.cpp b/sdrbase/plugin/pluginmanager.cpp index 3338c01..325fb8b 100644 --- a/sdrbase/plugin/pluginmanager.cpp +++ b/sdrbase/plugin/pluginmanager.cpp @@ -72,7 +72,7 @@ void PluginManager::registerSampleSource(const QString& sourceName, PluginInterf void PluginManager::loadSettings(const Preset* preset) { - qDebug("-------- [%s | %s] --------", qPrintable(preset->getGroup()), qPrintable(preset->getDescription())); + //qDebug("-------- [%s | %s] --------", qPrintable(preset->getGroup()), qPrintable(preset->getDescription())); // copy currently open channels and clear list ChannelInstanceRegistrations openChannels = m_channelInstanceRegistrations; @@ -83,7 +83,7 @@ void PluginManager::loadSettings(const Preset* preset) ChannelInstanceRegistration reg; // if we have one instance available already, use it for(int i = 0; i < openChannels.count(); i++) { - qDebug("compare [%s] vs [%s]", qPrintable(openChannels[i].m_channelName), qPrintable(channelConfig.m_channel)); + //qDebug("compare [%s] vs [%s]", qPrintable(openChannels[i].m_channelName), qPrintable(channelConfig.m_channel)); if(openChannels[i].m_channelName == channelConfig.m_channel) { qDebug("channel [%s] found", qPrintable(openChannels[i].m_channelName)); reg = openChannels.takeAt(i); @@ -235,7 +235,7 @@ int PluginManager::selectSampleSource(const QString& source) qDebug("finding sample source [%s]", qPrintable(source)); for(int i = 0; i < m_sampleSourceDevices.count(); i++) { - qDebug("*** %s vs %s", qPrintable(m_sampleSourceDevices[i].m_sourceName), qPrintable(source)); + //qDebug("*** %s vs %s", qPrintable(m_sampleSourceDevices[i].m_sourceName), qPrintable(source)); if(m_sampleSourceDevices[i].m_sourceName == source) { index = i; break; diff --git a/sdrbase/settings/preferences.cpp b/sdrbase/settings/preferences.cpp index c649cda..e1391fb 100644 --- a/sdrbase/settings/preferences.cpp +++ b/sdrbase/settings/preferences.cpp @@ -8,19 +8,15 @@ Preferences::Preferences() void Preferences::resetToDefaults() { - m_sourceType.clear(); - m_sourceDevice.clear(); - m_audioType.clear(); - m_audioDevice.clear(); + m_audioOutput.clear(); + m_audioOutputRate = 44100; } QByteArray Preferences::serialize() const { SimpleSerializer s(1); - s.writeString(1, m_sourceType); - s.writeString(2, m_sourceDevice); - s.writeString(3, m_audioType); - s.writeString(4, m_audioDevice); + s.writeString(1, m_audioOutput); + s.writeU32(2, m_audioOutputRate); return s.final(); } @@ -34,10 +30,10 @@ bool Preferences::deserialize(const QByteArray& data) } if(d.getVersion() == 1) { - d.readString(1, &m_sourceType); - d.readString(2, &m_sourceDevice); - d.readString(3, &m_audioType); - d.readString(4, &m_audioDevice); + d.readString(1, &m_audioOutput); + quint32 tmp; + d.readU32(2, &tmp, 44100); + m_audioOutputRate = tmp; return true; } else { resetToDefaults(); diff --git a/sdrbase/util/message.cpp b/sdrbase/util/message.cpp index 8431ca7..1ddf7af 100644 --- a/sdrbase/util/message.cpp +++ b/sdrbase/util/message.cpp @@ -29,6 +29,8 @@ const char* Message::getIdentifier() const bool Message::matchIdentifier(const char* identifier) const { + // Warning: this compares POINTERS - make sure, that each message has a unique name + // otherwise the linker might "optimize" stuff return m_identifier == identifier; } |