From 8972e877654434b87532945506f0c5eb57073e24 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 19 Nov 2014 23:41:57 -0500 Subject: [PATCH] switch from portaudio -> libao --- CMakeLists.txt | 7 +- src/audio/AudioThread.cpp | 179 +++++++++----------------------------- src/audio/AudioThread.h | 12 +-- 3 files changed, 46 insertions(+), 152 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f5f39d..1a7a1e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,10 +62,6 @@ if (DEFINED WIN32) include_directories ( ${PROJECT_SOURCE_DIR}/external/fftw-3.3.4-dll32 ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release ) link_directories ( ${PROJECT_SOURCE_DIR}/external/fftw-3.3.4-dll32 ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/x32 ) set(FFTW_LIB fftw3-3) - - include_directories ( ${PROJECT_SOURCE_DIR}/external/portaudio/include ) - link_directories ( ${PROJECT_SOURCE_DIR}/external/portaudio/libs ) - SET (PORTAUDIO_LIBRARY portaudio.dll winmm) link_directories ( ${PROJECT_SOURCE_DIR}/external/liquid-dsp/lib ) include_directories ( ${PROJECT_SOURCE_DIR}/external/liquid-dsp/include ) @@ -77,7 +73,6 @@ else (DEFINED WIN32) set(FFTW_LIB fftw3) - SET (PORTAUDIO_LIBRARY portaudio) endif (DEFINED WIN32) @@ -147,7 +142,7 @@ ADD_DEFINITIONS( add_executable(CubicSDR ${cubicsdr_sources} ${cubicsdr_headers}) -target_link_libraries(CubicSDR rtlsdr liquid ${FFTW_LIB} ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${PORTAUDIO_LIBRARY}) +target_link_libraries(CubicSDR rtlsdr liquid ao ${FFTW_LIB} ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES}) # cubicvr2 glfw ${GLFW_LIBRARIES} diff --git a/src/audio/AudioThread.cpp b/src/audio/AudioThread.cpp index b5a6f4b..28bbe5c 100644 --- a/src/audio/AudioThread.cpp +++ b/src/audio/AudioThread.cpp @@ -2,165 +2,70 @@ #include "CubicSDRDefs.h" #include -#ifdef WIN32 - #include - #include - #include - #include - #include - - // trim from start - static inline std::wstring &wltrim(std::wstring &s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); - return s; - } - - // trim from end - static inline std::wstring &wrtrim(std::wstring &s) { - s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); - return s; - } - - // trim from both ends - static inline std::wstring &wtrim(std::wstring &s) { - return wltrim(wrtrim(s)); - } -#endif - //wxDEFINE_EVENT(wxEVT_COMMAND_AudioThread_INPUT, wxThreadEvent); AudioThread::AudioThread(AudioThreadQueue* pQueue, int id) : - wxThread(wxTHREAD_DETACHED), m_pQueue(pQueue), m_ID(id), audio_queue_ptr(0), stream(NULL) { + wxThread(wxTHREAD_DETACHED), m_pQueue(pQueue), m_ID(id), audio_queue_ptr( + 0) { //, stream(NULL) } AudioThread::~AudioThread() { - PaError err; - err = Pa_StopStream(stream); - err = Pa_CloseStream(stream); - Pa_Terminate(); + ao_close(device); + ao_shutdown(); } - -static int audioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, void *userData) { - - AudioThread *src = (AudioThread *) userData; - - float *out = (float*) outputBuffer; - - if (statusFlags & paOutputOverflow) { - std::cout << "Audio buffer overflow.." << std::endl; - } - - if (statusFlags & paOutputUnderflow) { - std::cout << "Audio buffer underflow.." << std::endl; - } - - if ((statusFlags & paPrimingOutput) || (statusFlags & paOutputOverflow) || !src->audio_queue.size()) { - for (int i = 0; i < framesPerBuffer * 2; i++) { - out[i] = 0; - } - return paContinue; - } - - std::vector 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(); - 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; - } + ao_initialize(); - int preferred_device = -1; + /* -- Setup for default driver -- */ -#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(wtrim(env_name).c_str(), dev_str, 255); - std::wistringstream env_result(dev_str); + int default_driver; - if (!env_result.eof()) { - int env_dev = -1; - env_result >> env_dev; + default_driver = ao_default_driver_id(); - if (env_result.eof()) { // read everything, was all a number - if (env_dev >= 0) { - std::cout << "Using preferred PortAudio device PA_RECOMMENDED_OUTPUT_DEVICE=" << env_dev << std::endl; - preferred_device = env_dev; - } else { - std::cout << "Environment variable PA_RECOMMENDED_OUTPUT_DEVICE not set, using PortAudio defaults." << std::endl; - } - } else { - std::cout << "Environment variable PA_RECOMMENDED_OUTPUT_DEVICE didn't evaluate to a number, using PortAudio defaults." << std::endl; - } - } -#endif + memset(&format, 0, sizeof(format)); + format.bits = 16; + format.channels = 2; + format.rate = AUDIO_FREQUENCY; + format.byte_format = AO_FMT_LITTLE; - outputParameters.device = (preferred_device != -1) ? preferred_device : Pa_GetDefaultOutputDevice(); - if (outputParameters.device == paNoDevice) { - std::cout << "Error: No default output device.\n"; - } + /* -- Open driver -- */ + device = ao_open_live(default_driver, &format, NULL /* no options */); + if (device == NULL) { + fprintf(stderr, "Error opening device.\n"); + return (wxThread::ExitCode) 1; + } - 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; + while (!TestDestroy()) { - stream = NULL; + if (m_pQueue->stackSize()) { - err = Pa_OpenStream(&stream, NULL, &outputParameters, AUDIO_FREQUENCY, paFramesPerBufferUnspecified, paPrimeOutputBuffersUsingStreamCallback|paClipOff, &audioCallback, this); + 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_DATA: - 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; - } + int16_t buf[task.data->data.size()]; - while (!TestDestroy()) { + for (int i = 0; i < task.data->data.size(); i++) { + buf[i] = (int) (task.data->data[i] * 32760.0); + } - if (m_pQueue->stackSize()) { + ao_play(device, (char *) buf, + task.data->data.size() * sizeof(int16_t)); - 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_DATA: - if (!TestDestroy()) { - audio_queue.push(task.data->data); - } - delete task.data; - break; - } - } - } else { - this->Yield(); - this->Sleep(1); - } - } - std::cout << std::endl << "Audio Thread Done." << std::endl << std::endl; + delete task.data; + break; + } + } + } else { + this->Yield(); + this->Sleep(1); + } + } + std::cout << std::endl << "Audio Thread Done." << std::endl << std::endl; - return (wxThread::ExitCode) 0; + return (wxThread::ExitCode) 0; } diff --git a/src/audio/AudioThread.h b/src/audio/AudioThread.h index 0b066ad..c3b08aa 100644 --- a/src/audio/AudioThread.h +++ b/src/audio/AudioThread.h @@ -11,14 +11,8 @@ #include "wx/thread.h" #include "AudioThreadQueue.h" -#include "portaudio.h" -#ifdef WIN32 -#include "pa_stream.h" -#include "pa_debugprint.h" -#endif -static int audioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, void *userData); +#include "ao/ao.h" class AudioThread: public wxThread { public: @@ -33,6 +27,6 @@ protected: AudioThreadQueue* m_pQueue; int m_ID; - PaStreamParameters outputParameters; - PaStream *stream; + ao_device *device; + ao_sample_format format; };