diff --git a/aegisub/configure.in b/aegisub/configure.in index 8855e25b4..52ab0405d 100644 --- a/aegisub/configure.in +++ b/aegisub/configure.in @@ -21,8 +21,7 @@ m4_define([libswscale_required_version], [0.7.1]) # (r18642) m4_define([lua_auto3_required_version], [5.0]) m4_define([lua_auto4_required_version], [5.1]) -m4_define([portaudio_required_version], [1]) -m4_define([portaudio2_required_version], [19]) +m4_define([portaudio_required_version], [19]) m4_define([pulseaudio_required_version], [0.5]) m4_define([fontconfig_required_version], [2.4]) @@ -450,74 +449,18 @@ AM_CONDITIONAL([HAVE_ALSA], [test "$with_alsa" != "no"]) AC_SUBST(ALSA_LDFLAGS) -################### -## PortAudio2 (v19) -################### - -AC_ARG_WITH(portaudio2,[ --without-portaudio2 build without PortAudio v19 audio provider. - (default: auto)], pulseaudio2_disabled="(disabled)") -if test "$with_portaudio2" != "no"; then - PKG_CHECK_MODULES(PORTAUDIO2, portaudio-2.0 >= portaudio2_required_version, [with_portaudio2="yes"], [with_portaudio2="no"]) -fi - -if test "$with_portaudio2" != "no"; then - AC_AGI_COMPILE([PortAudio2], [portaudio2], [$PORTAUDIO2_CFLAGS], [$PORTAUDIO2_LIBS],[ -#include -int main(void) { - PaError err = Pa_Initialize(); - if (err != paNoError) return 1; - return 0; -} ]) -fi - -if test "$agi_cv_with_portaudio2" = "no" && test "$with_portaudio2" = "yes"; then - AC_MSG_WARN([PortAudio2 detected, but it doesn't work...]) - with_portaudio2="no" -fi - -if test "$agi_cv_with_portaudio2" = "yes" && test "$with_portaudio2" = "yes"; then - AC_DEFINE(WITH_PORTAUDIO2, 1, [Enable PortAudio v19 support]) - found_audio_player="yes" -fi - -AM_CONDITIONAL([HAVE_PORTAUDIO2], [test "$with_portaudio2" != "no"]) - - ############ ## PortAudio ############ -AC_ARG_WITH(portaudio,[ --without-portaudio build without PortAudio audio provider. - (default: auto)], portaudio_disabled="(disabled)") - -if test "$with_portaudio2" = "yes"; then - with_portaudio="no" - portaudio_disabled="(disabled by v19)" -fi - -if test -z "$PORTAUDIO_LDFLAGS"; then - PORTAUDIO_LDFLAGS="$LDFLAGS -lportaudio" -fi - -if test -z "$PORTAUDIO_CFLAGS"; then - PORTAUDIO_CFLAGS="$PTHREAD_CFLAGS $PTHREAD_LIBS" -fi - +AC_ARG_WITH(portaudio,[ --without-portaudio build without PortAudio v19 audio provider. + (default: auto)], pulseaudio_disabled="(disabled)") if test "$with_portaudio" != "no"; then - aegisub_save_CPPFLAGS="$CPPFLAGS" - aegisub_save_LDFLAGS="$LDFLAGS" - CPPFLAGS="$PORTAUDIO_CFLAGS" - LDFLAGS="$LDFLAGS $PORTAUDIO_LDFLAGS" - AC_CHECK_LIB([portaudio], [Pa_Initialize], [with_portaudio="yes"], [with_portaudio="no"]) - AC_CHECK_LIB([portaudio], [Pa_GetStreamTime], [ - AC_DEFINE(HAVE_PA_GETSTREAMTIME, 1, [Define to 1 if Pa_GetStreamTime is available in PortAudio]) - ], []) - CPPFLAGS="$aegisub_save_CPPFLAGS" - LDFLAGS="$aegisub_save_LDFLAGS" + PKG_CHECK_MODULES(PORTAUDIO, portaudio-2.0 >= portaudio_required_version, [with_portaudio="yes"], [with_portaudio="no"]) fi if test "$with_portaudio" != "no"; then - AC_AGI_COMPILE([PortAudio], [portaudio], [$PORTAUDIO_CFLAGS], [$PORTAUDIO_LDFLAGS],[ + AC_AGI_COMPILE([PortAudio], [portaudio], [$PORTAUDIO_CFLAGS], [$PORTAUDIO_LIBS],[ #include int main(void) { PaError err = Pa_Initialize(); @@ -531,14 +474,12 @@ if test "$agi_cv_with_portaudio" = "no" && test "$with_portaudio" = "yes"; then with_portaudio="no" fi -if test "$with_portaudio" = "yes" && test "$agi_cv_with_portaudio" = "yes"; then +if test "$agi_cv_with_portaudio" = "yes" && test "$with_portaudio" = "yes"; then + AC_DEFINE(WITH_PORTAUDIO, 1, [Enable PortAudio v19 support]) found_audio_player="yes" - AC_DEFINE(WITH_PORTAUDIO, 1, [Enable PortAudio Audio Provider]) fi AM_CONDITIONAL([HAVE_PORTAUDIO], [test "$with_portaudio" != "no"]) -AC_SUBST(PORTAUDIO_LDFLAGS) -AC_SUBST(PORTAUDIO_CFLAGS) ############# @@ -1420,7 +1361,6 @@ Audio Players ALSA: $with_alsa $alsa_disabled OpenAL: $with_openal $openal_disabled PortAudio: $with_portaudio $portaudio_disabled - PortAudio2 (v19): $with_portaudio2 $portaudio2_disabled PulseAudio: $with_pulseaudio $pulseaudio_disabled A/V Support diff --git a/aegisub/src/Makefile.am b/aegisub/src/Makefile.am index b0a25acfa..983b23a2d 100644 --- a/aegisub/src/Makefile.am +++ b/aegisub/src/Makefile.am @@ -33,7 +33,7 @@ endif if FOUND_AUDIO_PLAYER noinst_LIBRARIES += libaudio_player.a libaudio_player_a_SOURCES = audio_player.cpp -libaudio_player_a_CPPFLAGS = @ALSA_CFLAGS@ @PORTAUDIO_CFLAGS@ @PORTAUDIO2_CFLAGS@ @LIBPULSE_CFLAGS@ @OPENAL_CFLAGS@ +libaudio_player_a_CPPFLAGS = @ALSA_CFLAGS@ @PORTAUDIO_CFLAGS@ @LIBPULSE_CFLAGS@ @OPENAL_CFLAGS@ aegisub_2_1_LDADD += libaudio_player.a endif @@ -48,18 +48,10 @@ if HAVE_PORTAUDIO noinst_LIBRARIES += libaudio_portaudio.a libaudio_portaudio_a_SOURCES = audio_player_portaudio.cpp libaudio_portaudio_a_CPPFLAGS = @PORTAUDIO_CFLAGS@ -aegisub_2_1_LDFLAGS += @PORTAUDIO_LDFLAGS@ +aegisub_2_1_LDFLAGS += @PORTAUDIO_LIBS@ aegisub_2_1_LDADD += libaudio_portaudio.a endif -if HAVE_PORTAUDIO2 -noinst_LIBRARIES += libaudio_portaudio2.a -libaudio_portaudio2_a_SOURCES = audio_player_portaudio2.cpp -libaudio_portaudio2_a_CPPFLAGS = @PORTAUDIO2_CFLAGS@ -aegisub_2_1_LDFLAGS += @PORTAUDIO2_LIBS@ -aegisub_2_1_LDADD += libaudio_portaudio2.a -endif - if HAVE_PULSEAUDIO noinst_LIBRARIES += libaudio_pulseaudio.a libaudio_pulseaudio_a_SOURCES = audio_player_pulse.cpp @@ -193,7 +185,6 @@ EXTRA_aegisub_2_1_SOURCES = \ audio_player_dsound.cpp \ audio_player_dsound2.cpp \ audio_player_portaudio.cpp \ - audio_player_portaudio2.cpp \ audio_player_pulse.cpp \ audio_provider_avs.cpp \ audio_provider_lavc.cpp \ diff --git a/aegisub/src/audio_player.cpp b/aegisub/src/audio_player.cpp index bb84aa747..6f5b34d7d 100644 --- a/aegisub/src/audio_player.cpp +++ b/aegisub/src/audio_player.cpp @@ -54,9 +54,6 @@ #ifdef WITH_PORTAUDIO #include "audio_player_portaudio.h" #endif -#ifdef WITH_PORTAUDIO2 -#include "audio_player_portaudio2.h" -#endif #ifdef WITH_PULSEAUDIO #include "audio_player_pulse.h" #endif @@ -172,9 +169,6 @@ void AudioPlayerFactoryManager::RegisterProviders() { #ifdef WITH_PORTAUDIO RegisterFactory(new PortAudioPlayerFactory(),_T("PortAudio")); #endif -#ifdef WITH_PORTAUDIO2 - RegisterFactory(new PortAudioPlayerFactory(),_T("PortAudio2")); -#endif #ifdef WITH_PULSEAUDIO RegisterFactory(new PulseAudioPlayerFactory(),_T("PulseAudio")); #endif diff --git a/aegisub/src/audio_player_portaudio.cpp b/aegisub/src/audio_player_portaudio.cpp index 81d3f53ee..b46a2464f 100644 --- a/aegisub/src/audio_player_portaudio.cpp +++ b/aegisub/src/audio_player_portaudio.cpp @@ -43,20 +43,11 @@ // Headers #include "audio_player_portaudio.h" #include "audio_provider_manager.h" +#include "options.h" #include "utils.h" -#ifdef HAVE_PA_GETSTREAMTIME -#define Pa_StreamTime Pa_GetStreamTime /* PortAudio v19 */ -#define PaTimestamp PaTime -#endif - - -/////////// -// Library -#if __VISUALC__ >= 1200 -#pragma comment(lib,"portaudio.lib") -#endif - +// Uncomment to enable debug features. +//#define PORTAUDIO_DEBUG ///////////////////// // Reference counter @@ -69,11 +60,13 @@ PortAudioPlayer::PortAudioPlayer() { // Initialize portaudio if (!pa_refcount) { PaError err = Pa_Initialize(); + if (err != paNoError) { static wchar_t errormsg[2048]; swprintf(errormsg, 2048, L"Failed opening PortAudio: %s", Pa_GetErrorText(err)); throw (const wchar_t *)errormsg; } + pa_refcount++; } @@ -92,82 +85,100 @@ PortAudioPlayer::~PortAudioPlayer() { if (!--pa_refcount) Pa_Terminate(); } -////////////////////// -// PortAudio callback -#ifndef HAVE_PA_GETSTREAMTIME -int PortAudioPlayer::paCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData) { -#else -int PortAudioPlayer::paCallback(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timei, - PaStreamCallbackFlags flags, void *userData) { -#endif - // Get provider - PortAudioPlayer *player = (PortAudioPlayer *) userData; - AudioProvider *provider = player->GetProvider(); - int end = 0; - // Calculate how much left - int64_t lenAvailable = player->endPos - player->playPos; - uint64_t avail = 0; - if (lenAvailable > 0) { - avail = lenAvailable; - if (avail > framesPerBuffer) { - lenAvailable = framesPerBuffer; - avail = lenAvailable; +/////////////// +// Open stream +void PortAudioPlayer::OpenStream() { + // Open stream + PaStreamParameters pa_output_p; + + int pa_config_default = Options.AsInt(_T("Audio PortAudio Device")); + PaDeviceIndex pa_device; + + if (pa_config_default < 0) { + pa_device = Pa_GetDefaultOutputDevice(); + wxLogDebug(_T("PortAudioPlayer::OpenStream Using Default Output Device: %d"), pa_device); + } else { + pa_device = pa_config_default; + wxLogDebug(_T("PortAudioPlayer::OpenStream Using Config Device: %d"), pa_device); + } + + pa_output_p.device = pa_device; + pa_output_p.channelCount = provider->GetChannels(); + pa_output_p.sampleFormat = paInt16; + pa_output_p.suggestedLatency = Pa_GetDeviceInfo(pa_device)->defaultLowOutputLatency; + pa_output_p.hostApiSpecificStreamInfo = NULL; + + wxLogDebug(_T("PortAudioPlayer::OpenStream Output channels: %d, Latency: %f Sample Rate: %ld\n"), + pa_output_p.channelCount, pa_output_p.suggestedLatency, pa_output_p.sampleFormat); + + PaError err = Pa_OpenStream(&stream, NULL, &pa_output_p, provider->GetSampleRate(), 256, paPrimeOutputBuffersUsingStreamCallback, paCallback, this); + + if (err != paNoError) { + + const PaHostErrorInfo *pa_err = Pa_GetLastHostErrorInfo(); + if (pa_err->errorCode != 0) { + wxLogDebug(_T("PortAudioPlayer::OpenStream HostError: API: %d, %s (%ld)\n"), pa_err->hostApiType, pa_err->errorText, pa_err->errorCode); } + throw wxString(_T("Failed initializing PortAudio stream with error: ") + wxString(Pa_GetErrorText(err),wxConvLocal)); } - else { - lenAvailable = 0; - avail = 0; +} + + +/////////////// +// Close stream +void PortAudioPlayer::CloseStream() { + try { + Stop(false); + Pa_CloseStream(stream); + } catch (...) {} +} + +// Called when the callback has finished. +void PortAudioPlayer::paStreamFinishedCallback(void *userData) { + PortAudioPlayer *player = (PortAudioPlayer *) userData; + + player->playing = false; + + if (player->displayTimer) { + player->displayTimer->Stop(); } - // Play something - if (lenAvailable > 0) { - provider->GetAudio(outputBuffer,player->playPos,lenAvailable); - } - - // Set volume - short *output = (short*) outputBuffer; - for (unsigned int i=0;iGetVolume()),(1<<15)-1); - - // Fill rest with blank - for (unsigned int i=avail;iplayPos += framesPerBuffer; -#ifndef __APPLE__ - player->realPlayPos = (int64_t)(Pa_StreamTime(player->stream) - player->paStart) + player->startPos; -#else - // AudioDeviceGetCurrentTime(), used by Pa_StreamTime() on OS X, is buggered, so use playPos for now - player->realPlayPos = player->playPos; -#endif - - // Cap to start if lower - return end; + wxLogDebug(_T("PortAudioPlayer::paStreamFinishedCallback Stopping stream.")); } //////// // Play void PortAudioPlayer::Play(int64_t start,int64_t count) { + PaError err; + // Stop if it's already playing wxMutexLocker locker(PAMutex); // Set values endPos = start + count; playPos = start; - realPlayPos = start; startPos = start; // Start playing if (!playing) { - PaError err = Pa_StartStream(stream); + + err = Pa_SetStreamFinishedCallback(stream, paStreamFinishedCallback); + + if (err != paNoError) { + wxLogDebug(_T("PortAudioPlayer::Play Could not set FinishedCallback\n")); + return; + } + + err = Pa_StartStream(stream); + if (err != paNoError) { return; } } playing = true; - paStart = Pa_StreamTime(stream); + paStart = Pa_GetStreamTime(stream); // Update timer if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15); @@ -191,30 +202,82 @@ void PortAudioPlayer::Stop(bool timerToo) { } -/////////////// -// Open stream -void PortAudioPlayer::OpenStream() { - // Open stream - PaError err = Pa_OpenDefaultStream(&stream,0,provider->GetChannels(),paInt16,provider->GetSampleRate(),256, -#ifndef HAVE_PA_GETSTREAMTIME - 16, /* Pa v19 doesn't have a numberOfBuffers parameter */ +////////////////////// +/// PortAudio callback +int PortAudioPlayer::paCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { + + // Get provider + PortAudioPlayer *player = (PortAudioPlayer *) userData; + AudioProvider *provider = player->GetProvider(); + +#ifdef PORTAUDIO_DEBUG + printf("paCallBack: playPos: %lld startPos: %lld paStart: %f Pa_GetStreamTime: %f AdcTime: %f DacTime: %f framesPerBuffer: %lu CPU: %f\n", + player->playPos, player->startPos, player->paStart, Pa_GetStreamTime(player->stream), + timeInfo->inputBufferAdcTime, timeInfo->outputBufferDacTime, framesPerBuffer, Pa_GetStreamCpuLoad(player->stream)); #endif - paCallback,this); - if (err != paNoError) { - throw wxString(_T("Failed initializing PortAudio stream with error: ") + wxString(Pa_GetErrorText(err),wxConvLocal)); + // Calculate how much left + int64_t lenAvailable = (player->endPos - player->playPos) > 0 ? framesPerBuffer : 0; + + + // Play something + if (lenAvailable > 0) { + provider->GetAudioWithVolume(outputBuffer, player->playPos, lenAvailable, player->GetVolume()); + + // Set play position + player->playPos += framesPerBuffer; + + // Continue as normal + return 0; } + + // Abort stream and stop the callback. + return paAbort; +} + + +//////////////////////// +/// Get current stream position. +int64_t PortAudioPlayer::GetCurrentPosition() +{ + + if (!playing) return 0; + + const PaStreamInfo* streamInfo = Pa_GetStreamInfo(stream); + +#ifdef PORTAUDIO_DEBUG + PaTime pa_getstream = Pa_GetStreamTime(stream); + int64_t real = ((pa_getstream - paStart) * streamInfo->sampleRate) + startPos; + printf("GetCurrentPosition: Pa_GetStreamTime: %f startPos: %lld playPos: %lld paStart: %f real: %lld diff: %f\n", + pa_getstream, startPos, playPos, paStart, real, pa_getstream-paStart); + + return real; +#else + return ((Pa_GetStreamTime(stream) - paStart) * streamInfo->sampleRate) + startPos; +#endif + } /////////////// -// Close stream -void PortAudioPlayer::CloseStream() { - try { - Stop(false); - Pa_CloseStream(stream); - } catch (...) {} -} +/// Return a list of available output devices. +/// @param Setting from config file. +wxArrayString PortAudioPlayer::GetOutputDevices(wxString favorite) { + wxArrayString list; + int devices = Pa_GetDeviceCount(); + int i; + if (devices < 0) { + // some error here + } + + for (i=0; iname, wxConvUTF8); + list.Insert(name, i); + } + + return list; +} #endif // WITH_PORTAUDIO diff --git a/aegisub/src/audio_player_portaudio.h b/aegisub/src/audio_player_portaudio.h index 85c3a571b..57fe64bcb 100644 --- a/aegisub/src/audio_player_portaudio.h +++ b/aegisub/src/audio_player_portaudio.h @@ -47,6 +47,7 @@ extern "C" { } + //////////////////// // Portaudio player class PortAudioPlayer : public AudioPlayer { @@ -62,17 +63,19 @@ private: volatile int64_t startPos; volatile int64_t endPos; void *stream; - PaTimestamp paStart; - volatile int64_t realPlayPos; + PaTime paStart; -#ifndef HAVE_PA_GETSTREAMTIME - static int paCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData); -#else - static int paCallback(const void *inputBuffer, void *outputBuffer, + static int paCallback( + const void *inputBuffer, + void *outputBuffer, unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo *timei, - PaStreamCallbackFlags flags, void *userData); -#endif + const PaStreamCallbackTimeInfo* + timeInfo, + PaStreamCallbackFlags + statusFlags, + void *userData); + + static void paStreamFinishedCallback(void *userData); public: PortAudioPlayer(); @@ -87,13 +90,14 @@ public: int64_t GetStartPosition() { return startPos; } int64_t GetEndPosition() { return endPos; } - int64_t GetCurrentPosition() { return realPlayPos; } + int64_t GetCurrentPosition(); void SetEndPosition(int64_t pos) { endPos = pos; } - void SetCurrentPosition(int64_t pos) { playPos = pos; realPlayPos = pos; } + void SetCurrentPosition(int64_t pos) { playPos = pos; } void SetVolume(double vol) { volume = vol; } double GetVolume() { return volume; } + wxArrayString GetOutputDevices(wxString favorite); wxMutex *GetMutex() { return &PAMutex; } }; @@ -105,4 +109,4 @@ public: AudioPlayer *CreatePlayer() { return new PortAudioPlayer(); } }; -#endif +#endif //ifdef WITH_PORTAUDIO diff --git a/aegisub/src/audio_player_portaudio2.cpp b/aegisub/src/audio_player_portaudio2.cpp deleted file mode 100644 index e659ab2c7..000000000 --- a/aegisub/src/audio_player_portaudio2.cpp +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright (c) 2005-2007, Rodrigo Braz Monteiro -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------------- -// -// AEGISUB -// -// Website: http://aegisub.cellosoft.com -// Contact: mailto:zeratul@cellosoft.com -// - - -#include "config.h" - -#ifdef WITH_PORTAUDIO2 - - -/////////// -// Headers -#include "audio_player_portaudio2.h" -#include "audio_provider_manager.h" -#include "options.h" -#include "utils.h" - -// Uncomment to enable debug features. -//#define PORTAUDIO2_DEBUG - -///////////////////// -// Reference counter -int PortAudioPlayer::pa_refcount = 0; - - -/////////////// -// Constructor -PortAudioPlayer::PortAudioPlayer() { - // Initialize portaudio - if (!pa_refcount) { - PaError err = Pa_Initialize(); - - if (err != paNoError) { - static wchar_t errormsg[2048]; - swprintf(errormsg, 2048, L"Failed opening PortAudio: %s", Pa_GetErrorText(err)); - throw (const wchar_t *)errormsg; - } - - pa_refcount++; - } - - // Variables - playing = false; - stopping = false; - volume = 1.0f; - paStart = 0.0; -} - - -////////////// -// Destructor -PortAudioPlayer::~PortAudioPlayer() { - // Deinit portaudio - if (!--pa_refcount) Pa_Terminate(); -} - - -/////////////// -// Open stream -void PortAudioPlayer::OpenStream() { - // Open stream - PaStreamParameters pa_output_p; - - int pa_config_default = Options.AsInt(_T("Audio PortAudio Device")); - PaDeviceIndex pa_device; - - if (pa_config_default < 0) { - pa_device = Pa_GetDefaultOutputDevice(); - wxLogDebug(_T("PortAudioPlayer::OpenStream Using Default Output Device: %d"), pa_device); - } else { - pa_device = pa_config_default; - wxLogDebug(_T("PortAudioPlayer::OpenStream Using Config Device: %d"), pa_device); - } - - pa_output_p.device = pa_device; - pa_output_p.channelCount = provider->GetChannels(); - pa_output_p.sampleFormat = paInt16; - pa_output_p.suggestedLatency = Pa_GetDeviceInfo(pa_device)->defaultLowOutputLatency; - pa_output_p.hostApiSpecificStreamInfo = NULL; - - wxLogDebug(_T("PortAudioPlayer::OpenStream Output channels: %d, Latency: %f Sample Rate: %ld\n"), - pa_output_p.channelCount, pa_output_p.suggestedLatency, pa_output_p.sampleFormat); - - PaError err = Pa_OpenStream(&stream, NULL, &pa_output_p, provider->GetSampleRate(), 256, paPrimeOutputBuffersUsingStreamCallback, paCallback, this); - - if (err != paNoError) { - - const PaHostErrorInfo *pa_err = Pa_GetLastHostErrorInfo(); - if (pa_err->errorCode != 0) { - wxLogDebug(_T("PortAudioPlayer::OpenStream HostError: API: %d, %s (%ld)\n"), pa_err->hostApiType, pa_err->errorText, pa_err->errorCode); - } - throw wxString(_T("Failed initializing PortAudio stream with error: ") + wxString(Pa_GetErrorText(err),wxConvLocal)); - } -} - - -/////////////// -// Close stream -void PortAudioPlayer::CloseStream() { - try { - Stop(false); - Pa_CloseStream(stream); - } catch (...) {} -} - -// Called when the callback has finished. -void PortAudioPlayer::paStreamFinishedCallback(void *userData) { - PortAudioPlayer *player = (PortAudioPlayer *) userData; - - player->playing = false; - - if (player->displayTimer) { - player->displayTimer->Stop(); - } - - wxLogDebug(_T("PortAudioPlayer::paStreamFinishedCallback Stopping stream.")); -} - - -//////// -// Play -void PortAudioPlayer::Play(int64_t start,int64_t count) { - PaError err; - - // Stop if it's already playing - wxMutexLocker locker(PAMutex); - - // Set values - endPos = start + count; - playPos = start; - startPos = start; - - // Start playing - if (!playing) { - - err = Pa_SetStreamFinishedCallback(stream, paStreamFinishedCallback); - - if (err != paNoError) { - wxLogDebug(_T("PortAudioPlayer::Play Could not set FinishedCallback\n")); - return; - } - - err = Pa_StartStream(stream); - - if (err != paNoError) { - return; - } - } - playing = true; - paStart = Pa_GetStreamTime(stream); - - // Update timer - if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15); -} - - -//////// -// Stop -void PortAudioPlayer::Stop(bool timerToo) { - //wxMutexLocker locker(PAMutex); - //softStop = false; - - // Stop stream - playing = false; - Pa_StopStream (stream); - - // Stop timer - if (timerToo && displayTimer) { - displayTimer->Stop(); - } -} - - -////////////////////// -/// PortAudio callback -int PortAudioPlayer::paCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { - - // Get provider - PortAudioPlayer *player = (PortAudioPlayer *) userData; - AudioProvider *provider = player->GetProvider(); - -#ifdef PORTAUDIO2_DEBUG - printf("paCallBack: playPos: %lld startPos: %lld paStart: %f Pa_GetStreamTime: %f AdcTime: %f DacTime: %f framesPerBuffer: %lu CPU: %f\n", - player->playPos, player->startPos, player->paStart, Pa_GetStreamTime(player->stream), - timeInfo->inputBufferAdcTime, timeInfo->outputBufferDacTime, framesPerBuffer, Pa_GetStreamCpuLoad(player->stream)); -#endif - - // Calculate how much left - int64_t lenAvailable = (player->endPos - player->playPos) > 0 ? framesPerBuffer : 0; - - - // Play something - if (lenAvailable > 0) { - provider->GetAudioWithVolume(outputBuffer, player->playPos, lenAvailable, player->GetVolume()); - - // Set play position - player->playPos += framesPerBuffer; - - // Continue as normal - return 0; - } - - // Abort stream and stop the callback. - return paAbort; -} - - -//////////////////////// -/// Get current stream position. -int64_t PortAudioPlayer::GetCurrentPosition() -{ - - if (!playing) return 0; - - const PaStreamInfo* streamInfo = Pa_GetStreamInfo(stream); - -#ifdef PORTAUDIO2_DEBUG - PaTime pa_getstream = Pa_GetStreamTime(stream); - int64_t real = ((pa_getstream - paStart) * streamInfo->sampleRate) + startPos; - printf("GetCurrentPosition: Pa_GetStreamTime: %f startPos: %lld playPos: %lld paStart: %f real: %lld diff: %f\n", - pa_getstream, startPos, playPos, paStart, real, pa_getstream-paStart); - - return real; -#else - return ((Pa_GetStreamTime(stream) - paStart) * streamInfo->sampleRate) + startPos; -#endif - -} - - -/////////////// -/// Return a list of available output devices. -/// @param Setting from config file. -wxArrayString PortAudioPlayer::GetOutputDevices(wxString favorite) { - wxArrayString list; - int devices = Pa_GetDeviceCount(); - int i; - - if (devices < 0) { - // some error here - } - - for (i=0; iname, wxConvUTF8); - list.Insert(name, i); - } - - return list; -} - -#endif // WITH_PORTAUDIO2 diff --git a/aegisub/src/audio_player_portaudio2.h b/aegisub/src/audio_player_portaudio2.h deleted file mode 100644 index 81c85c022..000000000 --- a/aegisub/src/audio_player_portaudio2.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2005-2007, Rodrigo Braz Monteiro -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------------- -// -// AEGISUB -// -// Website: http://aegisub.cellosoft.com -// Contact: mailto:zeratul@cellosoft.com -// - - -#ifdef WITH_PORTAUDIO2 - - -/////////// -// Headers -#include "include/aegisub/audio_player.h" -#include "include/aegisub/audio_provider.h" -#include "utils.h" -extern "C" { -#include -} - - - -//////////////////// -// Portaudio player -class PortAudioPlayer : public AudioPlayer { -private: - static int pa_refcount; - wxMutex PAMutex; - volatile bool stopping; - //bool softStop; - bool playing; - float volume; - - volatile int64_t playPos; - volatile int64_t startPos; - volatile int64_t endPos; - void *stream; - PaTime paStart; - - static int paCallback( - const void *inputBuffer, - void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* - timeInfo, - PaStreamCallbackFlags - statusFlags, - void *userData); - - static void paStreamFinishedCallback(void *userData); - -public: - PortAudioPlayer(); - ~PortAudioPlayer(); - - void OpenStream(); - void CloseStream(); - - void Play(int64_t start,int64_t count); - void Stop(bool timerToo=true); - bool IsPlaying() { return playing; } - - int64_t GetStartPosition() { return startPos; } - int64_t GetEndPosition() { return endPos; } - int64_t GetCurrentPosition(); - void SetEndPosition(int64_t pos) { endPos = pos; } - void SetCurrentPosition(int64_t pos) { playPos = pos; } - - void SetVolume(double vol) { volume = vol; } - double GetVolume() { return volume; } - - wxArrayString GetOutputDevices(wxString favorite); - wxMutex *GetMutex() { return &PAMutex; } -}; - - -/////////// -// Factory -class PortAudioPlayerFactory : public AudioPlayerFactory { -public: - AudioPlayer *CreatePlayer() { return new PortAudioPlayer(); } -}; - -#endif diff --git a/aegisub/src/setup.cpp b/aegisub/src/setup.cpp index 7ea6061b0..8cadd813d 100644 --- a/aegisub/src/setup.cpp +++ b/aegisub/src/setup.cpp @@ -131,7 +131,7 @@ #pragma comment(lib, "ffms2.lib") #endif -#ifdef WITH_PORTAUDIO2 +#ifdef WITH_PORTAUDIO #pragma comment(lib,"portaudio_x86.lib") #endif