New threads partly implemented

Mid transition from 1 to 3 threads: SDR IQ, Demod and Audio separated,
AppFrame routes.
This commit is contained in:
Charles J. Cliffe 2014-11-16 16:50:37 -05:00
parent 9705d293f9
commit 16a9add9ef
8 changed files with 291 additions and 1 deletions

View File

@ -91,6 +91,12 @@ SET (cubicsdr_sources
src/SDRThreadQueue.cpp src/SDRThreadQueue.cpp
src/SDRThreadTask.cpp src/SDRThreadTask.cpp
src/Demodulator.cpp src/Demodulator.cpp
src/DemodulatorThread.cpp
src/DemodulatorThreadQueue.cpp
src/DemodulatorThreadTask.cpp
src/AudioThread.cpp
src/AudioThreadQueue.cpp
src/AudioThreadTask.cpp
src/Gradient.cpp src/Gradient.cpp
src/visual/ScopeCanvas.cpp src/visual/ScopeCanvas.cpp
src/visual/ScopeContext.cpp src/visual/ScopeContext.cpp
@ -110,6 +116,12 @@ SET (cubicsdr_headers
src/SDRThreadQueue.h src/SDRThreadQueue.h
src/SDRThreadTask.h src/SDRThreadTask.h
src/Demodulator.h src/Demodulator.h
src/DemodulatorThread.h
src/DemodulatorThreadQueue.h
src/DemodulatorThreadTask.h
src/AudioThread.h
src/AudioThreadQueue.h
src/AudioThreadTask.h
src/Gradient.h src/Gradient.h
src/visual/ScopeCanvas.h src/visual/ScopeCanvas.h
src/visual/ScopeContext.h src/visual/ScopeContext.h

124
src/AudioThread.cpp Normal file
View File

@ -0,0 +1,124 @@
#include "AudioThread.h"
#include "CubicSDRDefs.h"
#include <vector>
//wxDEFINE_EVENT(wxEVT_COMMAND_AudioThread_INPUT, wxThreadEvent);
AudioThread::AudioThread(AudioThreadQueue* pQueue, int id) :
wxThread(wxTHREAD_DETACHED), m_pQueue(pQueue), m_ID(id) {
}
AudioThread::~AudioThread() {
PaError err;
err = Pa_StopStream(stream);
err = Pa_CloseStream(stream);
Pa_Terminate();
}
static int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags, void *userData) {
AudioThread *src = (AudioThread *) userData;
float *out = (float*) outputBuffer;
if (!src->audio_queue.size()) {
for (int i = 0; i < framesPerBuffer * 2; i++) {
out[i] = 0;
}
return paContinue;
}
std::vector<float> *nextBuffer = src->audio_queue.front();
for (int i = 0; i < framesPerBuffer * 2; i++) {
out[i] = (*nextBuffer)[src->audio_queue_ptr];
src->audio_queue_ptr++;
if (src->audio_queue_ptr == nextBuffer->size()) {
src->audio_queue.pop();
delete nextBuffer;
src->audio_queue_ptr = 0;
if (!src->audio_queue.size()) {
break;
}
nextBuffer = src->audio_queue.front();
}
}
return paContinue;
}
wxThread::ExitCode AudioThread::Entry() {
PaError err;
err = Pa_Initialize();
if (err != paNoError) {
std::cout << "Error starting :(\n";
return (wxThread::ExitCode) 1;
}
int preferred_device = -1;
#ifdef WIN32
wchar_t dev_str[255];
memset(dev_str, 0, sizeof(wchar_t) * 255);
std::wstring env_name(L"PA_RECOMMENDED_OUTPUT_DEVICE");
GetEnvironmentVariable(env_name.c_str(), dev_str, 255);
std::wstring env_result(dev_str);
int env_dev = _wtoi(env_result.c_str());
if (env_dev || env_result.length()) {
std::cout << "Using preferred PortAudio device PA_RECOMMENDED_OUTPUT_DEVICE=" << env_result.c_str() << std::endl;
preferred_device = env_dev;
} else {
std::cout << "Environment variable PA_RECOMMENDED_OUTPUT_DEVICE not set, using PortAudio defaults." << std::endl;
}
#endif
outputParameters.device = (preferred_device != -1) ? preferred_device : Pa_GetDefaultOutputDevice();
if (outputParameters.device == paNoDevice) {
std::cout << "Error: No default output device.\n";
}
outputParameters.channelCount = 2; /* Stereo output, most likely supported. */
outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output. */
outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;
stream = NULL;
err = Pa_OpenStream(&stream, NULL, &outputParameters, AUDIO_FREQUENCY, 1024, paClipOff, &patestCallback, this);
err = Pa_StartStream(stream);
if (err != paNoError) {
std::cout << "Error starting stream: " << Pa_GetErrorText(err) << std::endl;
std::cout << "\tPortAudio error: " << Pa_GetErrorText(err) << std::endl;
}
while (!TestDestroy()) {
if (m_pQueue->stackSize()) {
while (m_pQueue->stackSize()) {
AudioThreadTask task = m_pQueue->pop(); // pop a task from the queue. this will block the worker thread if queue is empty
switch (task.m_cmd) {
// case AudioThreadTask::AUDIO_THREAD_TUNING:
//
// audio_queue.push(newBuffer);
}
}
}
Sleep(1000);
}
std::cout << std::endl << "Audio Thread Done." << std::endl << std::endl;
return (wxThread::ExitCode) 0;
}

47
src/AudioThread.h Normal file
View File

@ -0,0 +1,47 @@
#pragma once
#include <queue>
#include <vector>
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/thread.h"
#include "AudioThreadQueue.h"
#include "portaudio.h"
#ifdef WIN32
#include "pa_stream.h"
#include "pa_debugprint.h"
#endif
static int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags, void *userData);
// declare a new type of event, to be used by our AudioThread class:
//wxDECLARE_EVENT(wxEVT_COMMAND_AudioThread_COMPLETED, wxThreadEvent);
//wxDECLARE_EVENT(wxEVT_COMMAND_AudioThread_UPDATE, wxThreadEvent);
//wxDECLARE_EVENT(wxEVT_COMMAND_AudioThread_INPUT, wxThreadEvent);
enum {
EVENT_AUDIO_INPUT = wxID_HIGHEST + 1
};
class AudioThread: public wxThread {
public:
std::queue<std::vector<float> *> audio_queue;
unsigned int audio_queue_ptr;
AudioThread(AudioThreadQueue* pQueue, int id = 0);
~AudioThread();
protected:
virtual ExitCode Entry();
AudioThreadQueue* m_pQueue;
int m_ID;
PaStreamParameters outputParameters;
PaStream *stream;
};

43
src/AudioThreadQueue.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "AudioThreadQueue.h"
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
AudioThreadQueue::AudioThreadQueue(wxEvtHandler* pParent) :
m_pParent(pParent) {
}
void AudioThreadQueue::addTask(const AudioThreadTask& task, const AUDIO_PRIORITY& priority) {
wxMutexLocker lock(m_MutexQueue);
m_Tasks.insert(std::make_pair(priority, task));
m_QueueCount.Post();
}
AudioThreadTask AudioThreadQueue::pop() {
AudioThreadTask element;
m_QueueCount.Wait();
m_MutexQueue.Lock();
element = (m_Tasks.begin())->second;
m_Tasks.erase(m_Tasks.begin());
m_MutexQueue.Unlock();
return element;
}
void AudioThreadQueue::report(const AudioThreadTask::AUDIO_THREAD_COMMAND& cmd, const wxString& sArg, int iArg) {
wxCommandEvent evt(wxEVT_THREAD, cmd);
evt.SetString(sArg);
evt.SetInt(iArg);
m_pParent->AddPendingEvent(evt);
}
size_t AudioThreadQueue::stackSize() {
wxMutexLocker lock(m_MutexQueue);
return m_Tasks.size();
}
wxEvtHandler* AudioThreadQueue::getHandler() {
return m_pParent;
}

28
src/AudioThreadQueue.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <map>
#include "AudioThreadTask.h"
#include "wx/event.h"
class AudioThreadQueue {
public:
enum AUDIO_PRIORITY {
AUDIO_PRIORITY_HIGHEST, AUDIO_PRIORITY_HIGHER, AUDIO_PRIORITY_NORMAL, AUDIO_PRIORITY_BELOW_NORMAL, AUDIO_PRIORITY_LOW, AUDIO_PRIORITY_IDLE
};
AudioThreadQueue(wxEvtHandler* pParent);
void addTask(const AudioThreadTask& task, const AUDIO_PRIORITY& priority = AUDIO_PRIORITY_NORMAL);
void report(const AudioThreadTask::AUDIO_THREAD_COMMAND& cmd, const wxString& sArg = wxEmptyString, int iArg = 0);
AudioThreadTask pop();
size_t stackSize();
wxEvtHandler* getHandler();
private:
wxEvtHandler* m_pParent;
std::multimap<AUDIO_PRIORITY, AudioThreadTask> m_Tasks;
wxMutex m_MutexQueue;
wxSemaphore m_QueueCount;
};

9
src/AudioThreadTask.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "AudioThreadTask.h"
void AudioThreadTask::setData(std::vector<float> &data_in) {
data = data_in;
}
std::vector<float> &AudioThreadTask::getData() {
return data;
}

28
src/AudioThreadTask.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <vector>
#include "wx/defs.h"
#include "wx/string.h"
class AudioThreadTask {
public:
enum AUDIO_THREAD_COMMAND {
AUDIO_THREAD_EXIT = wxID_EXIT, AUDIO_THREAD_NULL = wxID_HIGHEST + 1, AUDIO_THREAD_STARTED, AUDIO_THREAD_PROCESS, AUDIO_THREAD_ERROR, AUDIO_THREAD_DATA
};
AudioThreadTask() :
m_cmd(AUDIO_THREAD_NULL) {
}
AudioThreadTask(AUDIO_THREAD_COMMAND cmd) :
m_cmd(cmd) {
}
void setData(std::vector<float> &data_in);
std::vector<float> &getData();
std::vector<float> data;
AUDIO_THREAD_COMMAND m_cmd;
};

View File

@ -9,7 +9,6 @@
#include "wx/thread.h" #include "wx/thread.h"
#include "SDRThread.h"
#include "IQBufferThread.h" #include "IQBufferThread.h"
#include "SDRThreadQueue.h" #include "SDRThreadQueue.h"