Improve audio open error reporting and remove a pile of unused stuff in AudioPlayer
Originally committed to SVN as r6223.
This commit is contained in:
parent
a927672c27
commit
df9c6b627f
26 changed files with 226 additions and 303 deletions
|
@ -292,18 +292,14 @@ void AudioController::OpenAudio(const wxString &url)
|
||||||
/*
|
/*
|
||||||
* Assume it's not a URI but instead a filename in the platform's native format.
|
* Assume it's not a URI but instead a filename in the platform's native format.
|
||||||
*/
|
*/
|
||||||
wxFileName fn(url);
|
try {
|
||||||
if (!fn.FileExists())
|
provider = AudioProviderFactory::GetProvider(url);
|
||||||
{
|
StandardPaths::SetPathValue("?audio", wxFileName(url).GetPath());
|
||||||
config::mru->Remove("Audio", STD_STR(url));
|
}
|
||||||
agi::FileNotFoundError fnf(STD_STR(url));
|
catch (...) {
|
||||||
throw agi::AudioOpenError(
|
config::mru->Remove("Audio", STD_STR(url));
|
||||||
"Failed opening audio file (parsing as plain filename)",
|
throw;
|
||||||
&fnf);
|
|
||||||
}
|
}
|
||||||
provider = AudioProviderFactory::GetProvider(url);
|
|
||||||
|
|
||||||
StandardPaths::SetPathValue("?audio", fn.GetPath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
|
@ -445,6 +445,27 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace agi {
|
namespace agi {
|
||||||
DEFINE_BASE_EXCEPTION(AudioControllerError, Exception)
|
/// Base class for all audio-related errors
|
||||||
DEFINE_SIMPLE_EXCEPTION(AudioOpenError, AudioControllerError, "audio_controller/open_failed")
|
DEFINE_BASE_EXCEPTION(AudioError, Exception)
|
||||||
|
|
||||||
|
/// Opening the audio failed for any reason
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(AudioOpenError, AudioError, "audio/open")
|
||||||
|
|
||||||
|
/// There are no audio providers available to open audio files
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(NoAudioProvidersError, AudioOpenError, "audio/open/no_providers")
|
||||||
|
|
||||||
|
/// The file exists, but no providers could find any audio tracks in it
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(AudioDataNotFoundError, AudioOpenError, "audio/open/no_tracks")
|
||||||
|
|
||||||
|
/// There are audio tracks, but no provider could actually read them
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(AudioProviderOpenError, AudioOpenError, "audio/open/provider")
|
||||||
|
|
||||||
|
/// The audio cache failed to initialize
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(AudioCacheOpenError, AudioOpenError, "audio/open/cache")
|
||||||
|
|
||||||
|
/// There are no audio players available
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(NoAudioPlayersError, AudioOpenError, "audio/open/no_players")
|
||||||
|
|
||||||
|
/// The audio player failed to initialize
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(AudioPlayerOpenError, AudioOpenError, "audio/open/player")
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@
|
||||||
#ifdef WITH_LIBPULSE
|
#ifdef WITH_LIBPULSE
|
||||||
#include "audio_player_pulse.h"
|
#include "audio_player_pulse.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
@ -70,38 +72,20 @@ AudioPlayer::~AudioPlayer() {
|
||||||
CloseStream();
|
CloseStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Ask to stop later
|
|
||||||
void AudioPlayer::RequestStop() {
|
|
||||||
wxCommandEvent event(wxEVT_STOP_AUDIO, 1000);
|
|
||||||
event.SetEventObject(this);
|
|
||||||
AddPendingEvent(event); // thread safe
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_EVENT_TYPE(wxEVT_STOP_AUDIO)
|
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(AudioPlayer, wxEvtHandler)
|
|
||||||
EVT_COMMAND (1000, wxEVT_STOP_AUDIO, AudioPlayer::OnStopAudio)
|
|
||||||
END_EVENT_TABLE()
|
|
||||||
|
|
||||||
void AudioPlayer::OnStopAudio(wxCommandEvent &) {
|
|
||||||
Stop(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioPlayer* AudioPlayerFactory::GetAudioPlayer() {
|
AudioPlayer* AudioPlayerFactory::GetAudioPlayer() {
|
||||||
std::vector<std::string> list = GetClasses(OPT_GET("Audio/Player")->GetString());
|
std::vector<std::string> list = GetClasses(OPT_GET("Audio/Player")->GetString());
|
||||||
if (list.empty()) throw "No audio players are available.";
|
if (list.empty()) throw agi::NoAudioPlayersError("No audio players are available.", 0);
|
||||||
|
|
||||||
wxString error;
|
std::string error;
|
||||||
for (unsigned int i=0;i<list.size();i++) {
|
for (size_t i = 0; i < list.size(); ++i) {
|
||||||
try {
|
try {
|
||||||
AudioPlayer *player = Create(list[i]);
|
return Create(list[i]);
|
||||||
if (player) return player;
|
}
|
||||||
|
catch (agi::AudioPlayerOpenError const& err) {
|
||||||
|
error += list[i] + " factory: " + err.GetChainedMessage() + "\n";
|
||||||
}
|
}
|
||||||
catch (wxString err) { error += list[i] + " factory: " + err + "\n"; }
|
|
||||||
catch (const wxChar *err) { error += list[i] + " factory: " + wxString(err) + "\n"; }
|
|
||||||
catch (...) { error += list[i] + " factory: Unknown error\n"; }
|
|
||||||
}
|
}
|
||||||
throw error;
|
throw agi::AudioPlayerOpenError(error, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioPlayerFactory::RegisterProviders() {
|
void AudioPlayerFactory::RegisterProviders() {
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_player_alsa.h"
|
#include "audio_player_alsa.h"
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
@ -365,7 +367,7 @@ void AlsaPlayer::OpenStream()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw 1; // FIXME
|
throw agi::AudioPlayerOpenError("AlsaPlayer: Creating the playback thread failed", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,4 +71,3 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_player_dsound.h"
|
#include "audio_player_dsound.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -75,7 +76,7 @@ void DirectSoundPlayer::OpenStream() {
|
||||||
// Initialize the DirectSound object
|
// Initialize the DirectSound object
|
||||||
HRESULT res;
|
HRESULT res;
|
||||||
res = DirectSoundCreate8(&DSDEVID_DefaultPlayback,&directSound,NULL); // TODO: support selecting audio device
|
res = DirectSoundCreate8(&DSDEVID_DefaultPlayback,&directSound,NULL); // TODO: support selecting audio device
|
||||||
if (FAILED(res)) throw "Failed initializing DirectSound";
|
if (FAILED(res)) throw agi::AudioPlayerOpenError("Failed initializing DirectSound", 0);
|
||||||
|
|
||||||
// Set DirectSound parameters
|
// Set DirectSound parameters
|
||||||
directSound->SetCooperativeLevel((HWND)wxGetApp().frame->GetHandle(),DSSCL_PRIORITY);
|
directSound->SetCooperativeLevel((HWND)wxGetApp().frame->GetHandle(),DSSCL_PRIORITY);
|
||||||
|
@ -106,11 +107,11 @@ void DirectSoundPlayer::OpenStream() {
|
||||||
// Create the buffer
|
// Create the buffer
|
||||||
IDirectSoundBuffer *buf;
|
IDirectSoundBuffer *buf;
|
||||||
res = directSound->CreateSoundBuffer(&desc,&buf,NULL);
|
res = directSound->CreateSoundBuffer(&desc,&buf,NULL);
|
||||||
if (res != DS_OK) throw "Failed creating DirectSound buffer";
|
if (res != DS_OK) throw agi::AudioPlayerOpenError("Failed creating DirectSound buffer", 0);
|
||||||
|
|
||||||
// Copy interface to buffer
|
// Copy interface to buffer
|
||||||
res = buf->QueryInterface(IID_IDirectSoundBuffer8,(LPVOID*) &buffer);
|
res = buf->QueryInterface(IID_IDirectSoundBuffer8,(LPVOID*) &buffer);
|
||||||
if (res != S_OK) throw "Failed casting interface to IDirectSoundBuffer8";
|
if (res != S_OK) throw agi::AudioPlayerOpenError("Failed casting interface to IDirectSoundBuffer8", 0);
|
||||||
|
|
||||||
// Set data
|
// Set data
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
|
|
||||||
#include "audio_player_dsound2.h"
|
#include "audio_player_dsound2.h"
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -669,7 +670,7 @@ DirectSoundPlayer2Thread::DirectSoundPlayer2Thread(AudioProvider *provider, int
|
||||||
thread_handle.handle = (HANDLE)_beginthreadex(0, 0, ThreadProc, this, 0, 0);
|
thread_handle.handle = (HANDLE)_beginthreadex(0, 0, ThreadProc, this, 0, 0);
|
||||||
|
|
||||||
if (!thread_handle)
|
if (!thread_handle)
|
||||||
throw "Failed creating playback thread in DirectSoundPlayer2. This is bad.";
|
throw agi::AudioPlayerOpenError("Failed creating playback thread in DirectSoundPlayer2. This is bad.", 0);
|
||||||
|
|
||||||
HANDLE running_or_error[] = { thread_running, error_happened };
|
HANDLE running_or_error[] = { thread_running, error_happened };
|
||||||
switch (WaitForMultipleObjects(2, running_or_error, FALSE, INFINITE))
|
switch (WaitForMultipleObjects(2, running_or_error, FALSE, INFINITE))
|
||||||
|
@ -680,10 +681,10 @@ DirectSoundPlayer2Thread::DirectSoundPlayer2Thread(AudioProvider *provider, int
|
||||||
|
|
||||||
case WAIT_OBJECT_0 + 1:
|
case WAIT_OBJECT_0 + 1:
|
||||||
// error happened, we fail
|
// error happened, we fail
|
||||||
throw error_message;
|
throw agi::AudioPlayerOpenError(error_message, 0);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw "Failed wait for thread start or thread error in DirectSoundPlayer2. This is bad.";
|
throw agi::AudioPlayerOpenError("Failed wait for thread start or thread error in DirectSoundPlayer2. This is bad.", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,7 +715,7 @@ void DirectSoundPlayer2Thread::Play(int64_t start, int64_t count)
|
||||||
case WAIT_OBJECT_0+1: // Error
|
case WAIT_OBJECT_0+1: // Error
|
||||||
throw error_message;
|
throw error_message;
|
||||||
default:
|
default:
|
||||||
throw "Unexpected result from WaitForMultipleObjects in DirectSoundPlayer2Thread::Play";
|
throw agi::InternalError("Unexpected result from WaitForMultipleObjects in DirectSoundPlayer2Thread::Play", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
#include "audio_player_openal.h"
|
#include "audio_player_openal.h"
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
// Auto-link to OpenAL lib for MSVC
|
// Auto-link to OpenAL lib for MSVC
|
||||||
|
@ -49,6 +50,8 @@
|
||||||
#pragma comment(lib, "openal32.lib")
|
#pragma comment(lib, "openal32.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(OpenALException, agi::AudioPlayerOpenError, "audio/open/player/openal")
|
||||||
|
|
||||||
OpenALPlayer::OpenALPlayer()
|
OpenALPlayer::OpenALPlayer()
|
||||||
: open(false)
|
: open(false)
|
||||||
, playing(false)
|
, playing(false)
|
||||||
|
@ -76,25 +79,25 @@ void OpenALPlayer::OpenStream()
|
||||||
try {
|
try {
|
||||||
// Open device
|
// Open device
|
||||||
device = alcOpenDevice(0);
|
device = alcOpenDevice(0);
|
||||||
if (!device) throw OpenALException("Failed opening default OpenAL device");
|
if (!device) throw OpenALException("Failed opening default OpenAL device", 0);
|
||||||
|
|
||||||
// Create context
|
// Create context
|
||||||
context = alcCreateContext(device, 0);
|
context = alcCreateContext(device, 0);
|
||||||
if (!context) throw OpenALException("Failed creating OpenAL context");
|
if (!context) throw OpenALException("Failed creating OpenAL context", 0);
|
||||||
if (!alcMakeContextCurrent(context)) throw OpenALException("Failed selecting OpenAL context");
|
if (!alcMakeContextCurrent(context)) throw OpenALException("Failed selecting OpenAL context", 0);
|
||||||
|
|
||||||
// Clear error code
|
// Clear error code
|
||||||
alGetError();
|
alGetError();
|
||||||
|
|
||||||
// Generate buffers
|
// Generate buffers
|
||||||
alGenBuffers(num_buffers, buffers);
|
alGenBuffers(num_buffers, buffers);
|
||||||
if (alGetError() != AL_NO_ERROR) throw OpenALException("Error generating OpenAL buffers");
|
if (alGetError() != AL_NO_ERROR) throw OpenALException("Error generating OpenAL buffers", 0);
|
||||||
|
|
||||||
// Generate source
|
// Generate source
|
||||||
alGenSources(1, &source);
|
alGenSources(1, &source);
|
||||||
if (alGetError() != AL_NO_ERROR) {
|
if (alGetError() != AL_NO_ERROR) {
|
||||||
alDeleteBuffers(num_buffers, buffers);
|
alDeleteBuffers(num_buffers, buffers);
|
||||||
throw OpenALException("Error generating OpenAL source");
|
throw OpenALException("Error generating OpenAL source", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
|
|
@ -53,10 +53,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <libaegisub/exception.h>
|
|
||||||
|
|
||||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(OpenALException, agi::Exception, "audio/player/openal/generic")
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class OpenALPlayer
|
/// @class OpenALPlayer
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
|
|
|
@ -43,11 +43,16 @@
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_player_oss.h"
|
#include "audio_player_oss.h"
|
||||||
#include "frame_main.h"
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
#include "include/aegisub/audio_provider.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(OSSError, agi::AudioPlayerOpenError, "audio/player/open/oss")
|
||||||
|
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
///
|
///
|
||||||
OSSPlayer::OSSPlayer()
|
OSSPlayer::OSSPlayer()
|
||||||
|
@ -81,7 +86,7 @@ void OSSPlayer::OpenStream()
|
||||||
wxString device = lagi_wxString(OPT_GET("Audio/OSS/Device")->GetString());
|
wxString device = lagi_wxString(OPT_GET("Audio/OSS/Device")->GetString());
|
||||||
dspdev = ::open(device.mb_str(wxConvUTF8), O_WRONLY, 0);
|
dspdev = ::open(device.mb_str(wxConvUTF8), O_WRONLY, 0);
|
||||||
if (dspdev < 0) {
|
if (dspdev < 0) {
|
||||||
throw OSSError("OSS player: opening device failed");
|
throw OSSError("OSS player: opening device failed", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a reasonable buffer policy for low latency (OSS4)
|
// Use a reasonable buffer policy for low latency (OSS4)
|
||||||
|
@ -93,7 +98,7 @@ void OSSPlayer::OpenStream()
|
||||||
// Set number of channels
|
// Set number of channels
|
||||||
int channels = provider->GetChannels();
|
int channels = provider->GetChannels();
|
||||||
if (ioctl(dspdev, SNDCTL_DSP_CHANNELS, &channels) < 0) {
|
if (ioctl(dspdev, SNDCTL_DSP_CHANNELS, &channels) < 0) {
|
||||||
throw OSSError("OSS player: setting channels failed");
|
throw OSSError("OSS player: setting channels failed", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sample format
|
// Set sample format
|
||||||
|
@ -106,17 +111,17 @@ void OSSPlayer::OpenStream()
|
||||||
sample_format = AFMT_S16_LE;
|
sample_format = AFMT_S16_LE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw OSSError("OSS player: can only handle 8 and 16 bit sound");
|
throw OSSError("OSS player: can only handle 8 and 16 bit sound", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(dspdev, SNDCTL_DSP_SETFMT, &sample_format) < 0) {
|
if (ioctl(dspdev, SNDCTL_DSP_SETFMT, &sample_format) < 0) {
|
||||||
throw OSSError("OSS player: setting sample format failed");
|
throw OSSError("OSS player: setting sample format failed", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sample rate
|
// Set sample rate
|
||||||
rate = provider->GetSampleRate();
|
rate = provider->GetSampleRate();
|
||||||
if (ioctl(dspdev, SNDCTL_DSP_SPEED, &rate) < 0) {
|
if (ioctl(dspdev, SNDCTL_DSP_SPEED, &rate) < 0) {
|
||||||
throw OSSError("OSS player: setting samplerate failed");
|
throw OSSError("OSS player: setting samplerate failed", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now ready
|
// Now ready
|
||||||
|
|
|
@ -49,12 +49,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "include/aegisub/audio_player.h"
|
#include "include/aegisub/audio_player.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
|
||||||
|
|
||||||
#include <libaegisub/exception.h>
|
|
||||||
|
|
||||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(OSSError, agi::Exception, "audio/player/oss")
|
|
||||||
|
|
||||||
|
class AudioProvider;
|
||||||
class OSSPlayer;
|
class OSSPlayer;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
|
|
|
@ -42,11 +42,15 @@
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_player_portaudio.h"
|
#include "audio_player_portaudio.h"
|
||||||
#include "charset_conv.h"
|
|
||||||
|
#include "audio_controller.h"
|
||||||
|
#include "compat.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(PortAudioError, agi::AudioPlayerOpenError, "audio/player/open/portaudio")
|
||||||
|
|
||||||
// Uncomment to enable extremely spammy debug logging
|
// Uncomment to enable extremely spammy debug logging
|
||||||
//#define PORTAUDIO_DEBUG
|
//#define PORTAUDIO_DEBUG
|
||||||
|
|
||||||
|
@ -54,7 +58,7 @@ PortAudioPlayer::PortAudioPlayer() {
|
||||||
PaError err = Pa_Initialize();
|
PaError err = Pa_Initialize();
|
||||||
|
|
||||||
if (err != paNoError)
|
if (err != paNoError)
|
||||||
throw PortAudioError(std::string("Failed opening PortAudio:") + Pa_GetErrorText(err));
|
throw PortAudioError(std::string("Failed opening PortAudio:") + Pa_GetErrorText(err), 0);
|
||||||
|
|
||||||
volume = 1.0f;
|
volume = 1.0f;
|
||||||
pa_start = 0.0;
|
pa_start = 0.0;
|
||||||
|
@ -109,7 +113,7 @@ void PortAudioPlayer::OpenStream() {
|
||||||
const PaHostErrorInfo *pa_err = Pa_GetLastHostErrorInfo();
|
const PaHostErrorInfo *pa_err = Pa_GetLastHostErrorInfo();
|
||||||
LOG_D_IF(pa_err->errorCode != 0, "audio/player/portaudio") << "HostError: API: " << pa_err->hostApiType << ", " << pa_err->errorText << ", " << pa_err->errorCode;
|
LOG_D_IF(pa_err->errorCode != 0, "audio/player/portaudio") << "HostError: API: " << pa_err->hostApiType << ", " << pa_err->errorText << ", " << pa_err->errorCode;
|
||||||
LOG_D("audio/player/portaudio") << "Failed initializing PortAudio stream with error: " << Pa_GetErrorText(err);
|
LOG_D("audio/player/portaudio") << "Failed initializing PortAudio stream with error: " << Pa_GetErrorText(err);
|
||||||
throw PortAudioError("Failed initializing PortAudio stream with error: " + std::string(Pa_GetErrorText(err)));
|
throw PortAudioError("Failed initializing PortAudio stream with error: " + std::string(Pa_GetErrorText(err)), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,15 +37,15 @@
|
||||||
#ifdef WITH_PORTAUDIO
|
#ifdef WITH_PORTAUDIO
|
||||||
|
|
||||||
#include "include/aegisub/audio_player.h"
|
#include "include/aegisub/audio_player.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
|
||||||
|
|
||||||
#include <libaegisub/exception.h>
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <portaudio.h>
|
#include <portaudio.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(PortAudioError, agi::Exception, "audio/player/portaudio")
|
#ifndef AGI_PRE
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#endif
|
||||||
|
|
||||||
/// @class PortAudioPlayer
|
/// @class PortAudioPlayer
|
||||||
/// @brief PortAudio Player
|
/// @brief PortAudio Player
|
||||||
|
|
|
@ -43,11 +43,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "audio_player_pulse.h"
|
#include "audio_player_pulse.h"
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
|
#include "include/aegisub/audio_provider.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
/// @brief Constructor
|
|
||||||
///
|
|
||||||
PulseAudioPlayer::PulseAudioPlayer()
|
PulseAudioPlayer::PulseAudioPlayer()
|
||||||
: context_notify(0, 1)
|
: context_notify(0, 1)
|
||||||
, context_success(0, 1)
|
, context_success(0, 1)
|
||||||
|
@ -60,32 +60,20 @@ PulseAudioPlayer::PulseAudioPlayer()
|
||||||
is_playing = false;
|
is_playing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Destructor
|
|
||||||
///
|
|
||||||
PulseAudioPlayer::~PulseAudioPlayer()
|
PulseAudioPlayer::~PulseAudioPlayer()
|
||||||
{
|
{
|
||||||
if (open) CloseStream();
|
CloseStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Open stream
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::OpenStream()
|
void PulseAudioPlayer::OpenStream()
|
||||||
{
|
{
|
||||||
//printf("Opening PulseAudio stream\n");
|
|
||||||
if (open) CloseStream();
|
if (open) CloseStream();
|
||||||
|
|
||||||
// Get provider
|
|
||||||
AudioProvider *provider = GetProvider();
|
|
||||||
|
|
||||||
// Initialise a mainloop
|
// Initialise a mainloop
|
||||||
//printf("Initialising threaded main loop\n");
|
//printf("Initialising threaded main loop\n");
|
||||||
mainloop = pa_threaded_mainloop_new();
|
mainloop = pa_threaded_mainloop_new();
|
||||||
if (!mainloop) {
|
if (!mainloop) {
|
||||||
throw "Failed to initialise PulseAudio threaded mainloop object";
|
throw agi::AudioPlayerOpenError("Failed to initialise PulseAudio threaded mainloop object", 0);
|
||||||
}
|
}
|
||||||
//printf("Starting main loop\n");
|
//printf("Starting main loop\n");
|
||||||
pa_threaded_mainloop_start(mainloop);
|
pa_threaded_mainloop_start(mainloop);
|
||||||
|
@ -95,7 +83,7 @@ void PulseAudioPlayer::OpenStream()
|
||||||
context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Aegisub");
|
context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Aegisub");
|
||||||
if (!context) {
|
if (!context) {
|
||||||
pa_threaded_mainloop_free(mainloop);
|
pa_threaded_mainloop_free(mainloop);
|
||||||
throw "Failed to create PulseAudio context";
|
throw agi::AudioPlayerOpenError("Failed to create PulseAudio context", 0);
|
||||||
}
|
}
|
||||||
pa_context_set_state_callback(context, (pa_context_notify_cb_t)pa_context_notify, this);
|
pa_context_set_state_callback(context, (pa_context_notify_cb_t)pa_context_notify, this);
|
||||||
|
|
||||||
|
@ -113,9 +101,7 @@ void PulseAudioPlayer::OpenStream()
|
||||||
pa_context_unref(context);
|
pa_context_unref(context);
|
||||||
pa_threaded_mainloop_stop(mainloop);
|
pa_threaded_mainloop_stop(mainloop);
|
||||||
pa_threaded_mainloop_free(mainloop);
|
pa_threaded_mainloop_free(mainloop);
|
||||||
wxString s(pa_strerror(paerror), wxConvUTF8);
|
throw agi::AudioPlayerOpenError(std::string("PulseAudio reported error: ") + pa_strerror(paerror), 0);
|
||||||
s.Prepend("PulseAudio reported error: ");
|
|
||||||
throw s.c_str();
|
|
||||||
}
|
}
|
||||||
// otherwise loop once more
|
// otherwise loop once more
|
||||||
}
|
}
|
||||||
|
@ -137,7 +123,7 @@ void PulseAudioPlayer::OpenStream()
|
||||||
pa_context_unref(context);
|
pa_context_unref(context);
|
||||||
pa_threaded_mainloop_stop(mainloop);
|
pa_threaded_mainloop_stop(mainloop);
|
||||||
pa_threaded_mainloop_free(mainloop);
|
pa_threaded_mainloop_free(mainloop);
|
||||||
throw "PulseAudio could not create stream";
|
throw agi::AudioPlayerOpenError("PulseAudio could not create stream", 0);
|
||||||
}
|
}
|
||||||
pa_stream_set_state_callback(stream, (pa_stream_notify_cb_t)pa_stream_notify, this);
|
pa_stream_set_state_callback(stream, (pa_stream_notify_cb_t)pa_stream_notify, this);
|
||||||
pa_stream_set_write_callback(stream, (pa_stream_request_cb_t)pa_stream_write, this);
|
pa_stream_set_write_callback(stream, (pa_stream_request_cb_t)pa_stream_write, this);
|
||||||
|
@ -147,9 +133,7 @@ void PulseAudioPlayer::OpenStream()
|
||||||
paerror = pa_stream_connect_playback(stream, NULL, NULL, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_NOT_MONOTONOUS|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL);
|
paerror = pa_stream_connect_playback(stream, NULL, NULL, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_NOT_MONOTONOUS|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL);
|
||||||
if (paerror) {
|
if (paerror) {
|
||||||
printf("PulseAudio reported error: %s (%d)\n", pa_strerror(paerror), paerror);
|
printf("PulseAudio reported error: %s (%d)\n", pa_strerror(paerror), paerror);
|
||||||
wxString s(pa_strerror(paerror), wxConvUTF8);
|
throw agi::AudioPlayerOpenError(std::string("PulseAudio reported error: ") + pa_strerror(paerror), 0);
|
||||||
s.Prepend("PulseAudio reported error: ");
|
|
||||||
throw s.c_str();
|
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
stream_notify.Wait();
|
stream_notify.Wait();
|
||||||
|
@ -158,7 +142,7 @@ void PulseAudioPlayer::OpenStream()
|
||||||
} else if (sstate == PA_STREAM_FAILED) {
|
} else if (sstate == PA_STREAM_FAILED) {
|
||||||
paerror = pa_context_errno(context);
|
paerror = pa_context_errno(context);
|
||||||
printf("PulseAudio player: Stream connection failed: %s (%d)\n", pa_strerror(paerror), paerror);
|
printf("PulseAudio player: Stream connection failed: %s (%d)\n", pa_strerror(paerror), paerror);
|
||||||
throw "PulseAudio player: Something went wrong connecting the stream";
|
throw agi::AudioPlayerOpenError("PulseAudio player: Something went wrong connecting the stream", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//printf("Connected playback stream, now playing\n\n");
|
//printf("Connected playback stream, now playing\n\n");
|
||||||
|
@ -168,11 +152,6 @@ void PulseAudioPlayer::OpenStream()
|
||||||
open = true;
|
open = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Close stream
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::CloseStream()
|
void PulseAudioPlayer::CloseStream()
|
||||||
{
|
{
|
||||||
if (!open) return;
|
if (!open) return;
|
||||||
|
@ -192,12 +171,6 @@ void PulseAudioPlayer::CloseStream()
|
||||||
open = false;
|
open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Play
|
|
||||||
/// @param start
|
|
||||||
/// @param count
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::Play(int64_t start,int64_t count)
|
void PulseAudioPlayer::Play(int64_t start,int64_t count)
|
||||||
{
|
{
|
||||||
//printf("Starting PulseAudio playback\n");
|
//printf("Starting PulseAudio playback\n");
|
||||||
|
@ -249,12 +222,6 @@ void PulseAudioPlayer::Play(int64_t start,int64_t count)
|
||||||
if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15);
|
if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Stop
|
|
||||||
/// @param timerToo
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::Stop(bool timerToo)
|
void PulseAudioPlayer::Stop(bool timerToo)
|
||||||
{
|
{
|
||||||
if (!is_playing) return;
|
if (!is_playing) return;
|
||||||
|
@ -286,61 +253,31 @@ void PulseAudioPlayer::Stop(bool timerToo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
bool PulseAudioPlayer::IsPlaying()
|
bool PulseAudioPlayer::IsPlaying()
|
||||||
{
|
{
|
||||||
return is_playing;
|
return is_playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Set end
|
|
||||||
/// @param pos
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::SetEndPosition(int64_t pos)
|
void PulseAudioPlayer::SetEndPosition(int64_t pos)
|
||||||
{
|
{
|
||||||
end_frame = pos;
|
end_frame = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Set current position
|
|
||||||
/// @param pos
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::SetCurrentPosition(int64_t pos)
|
void PulseAudioPlayer::SetCurrentPosition(int64_t pos)
|
||||||
{
|
{
|
||||||
cur_frame = pos;
|
cur_frame = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
int64_t PulseAudioPlayer::GetStartPosition()
|
int64_t PulseAudioPlayer::GetStartPosition()
|
||||||
{
|
{
|
||||||
return start_frame;
|
return start_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
int64_t PulseAudioPlayer::GetEndPosition()
|
int64_t PulseAudioPlayer::GetEndPosition()
|
||||||
{
|
{
|
||||||
return end_frame;
|
return end_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Get current position
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
int64_t PulseAudioPlayer::GetCurrentPosition()
|
int64_t PulseAudioPlayer::GetCurrentPosition()
|
||||||
{
|
{
|
||||||
if (!is_playing) return 0;
|
if (!is_playing) return 0;
|
||||||
|
@ -356,52 +293,28 @@ int64_t PulseAudioPlayer::GetCurrentPosition()
|
||||||
return start_frame + playtime * provider->GetSampleRate() / (1000*1000);
|
return start_frame + playtime * provider->GetSampleRate() / (1000*1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Called by PA to notify about contetxt operation completion
|
/// @brief Called by PA to notify about contetxt operation completion
|
||||||
/// @param c
|
|
||||||
/// @param success
|
|
||||||
/// @param thread
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::pa_context_success(pa_context *c, int success, PulseAudioPlayer *thread)
|
void PulseAudioPlayer::pa_context_success(pa_context *c, int success, PulseAudioPlayer *thread)
|
||||||
{
|
{
|
||||||
thread->context_success_val = success;
|
thread->context_success_val = success;
|
||||||
thread->context_success.Post();
|
thread->context_success.Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Called by PA to notify about other context-related stuff
|
/// @brief Called by PA to notify about other context-related stuff
|
||||||
/// @param c
|
|
||||||
/// @param thread
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::pa_context_notify(pa_context *c, PulseAudioPlayer *thread)
|
void PulseAudioPlayer::pa_context_notify(pa_context *c, PulseAudioPlayer *thread)
|
||||||
{
|
{
|
||||||
thread->cstate = pa_context_get_state(thread->context);
|
thread->cstate = pa_context_get_state(thread->context);
|
||||||
thread->context_notify.Post();
|
thread->context_notify.Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Called by PA when an operation completes
|
/// @brief Called by PA when an operation completes
|
||||||
/// @param p
|
|
||||||
/// @param success
|
|
||||||
/// @param thread
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::pa_stream_success(pa_stream *p, int success, PulseAudioPlayer *thread)
|
void PulseAudioPlayer::pa_stream_success(pa_stream *p, int success, PulseAudioPlayer *thread)
|
||||||
{
|
{
|
||||||
thread->stream_success_val = success;
|
thread->stream_success_val = success;
|
||||||
thread->stream_success.Post();
|
thread->stream_success.Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Called by PA to request more data (and other things?)
|
/// @brief Called by PA to request more data (and other things?)
|
||||||
/// @param p
|
|
||||||
/// @param length
|
|
||||||
/// @param thread
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::pa_stream_write(pa_stream *p, size_t length, PulseAudioPlayer *thread)
|
void PulseAudioPlayer::pa_stream_write(pa_stream *p, size_t length, PulseAudioPlayer *thread)
|
||||||
{
|
{
|
||||||
if (!thread->is_playing) return;
|
if (!thread->is_playing) return;
|
||||||
|
@ -434,12 +347,7 @@ void PulseAudioPlayer::pa_stream_write(pa_stream *p, size_t length, PulseAudioPl
|
||||||
thread->cur_frame += frames;
|
thread->cur_frame += frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Called by PA to notify about other stuff
|
/// @brief Called by PA to notify about other stuff
|
||||||
/// @param p
|
|
||||||
/// @param thread
|
|
||||||
///
|
|
||||||
void PulseAudioPlayer::pa_stream_notify(pa_stream *p, PulseAudioPlayer *thread)
|
void PulseAudioPlayer::pa_stream_notify(pa_stream *p, PulseAudioPlayer *thread)
|
||||||
{
|
{
|
||||||
thread->sstate = pa_stream_get_state(thread->stream);
|
thread->sstate = pa_stream_get_state(thread->stream);
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
#include <pulse/pulseaudio.h>
|
#include <pulse/pulseaudio.h>
|
||||||
|
|
||||||
#include "include/aegisub/audio_player.h"
|
#include "include/aegisub/audio_player.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
|
||||||
|
|
||||||
class PulseAudioPlayer;
|
class PulseAudioPlayer;
|
||||||
|
|
||||||
|
@ -141,16 +140,7 @@ public:
|
||||||
void SetEndPosition(int64_t pos);
|
void SetEndPosition(int64_t pos);
|
||||||
void SetCurrentPosition(int64_t pos);
|
void SetCurrentPosition(int64_t pos);
|
||||||
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @param vol
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void SetVolume(double vol) { volume = vol; }
|
void SetVolume(double vol) { volume = vol; }
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
double GetVolume() { return volume; }
|
double GetVolume() { return volume; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include <wx/thread.h>
|
#include <wx/thread.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#ifdef WITH_AVISYNTH
|
#ifdef WITH_AVISYNTH
|
||||||
#include "audio_provider_avs.h"
|
#include "audio_provider_avs.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -56,13 +57,6 @@
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
/// @brief Get audio with volume
|
|
||||||
/// @param buf
|
|
||||||
/// @param start
|
|
||||||
/// @param count
|
|
||||||
/// @param volume
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const {
|
void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const {
|
||||||
try {
|
try {
|
||||||
GetAudio(buf,start,count);
|
GetAudio(buf,start,count);
|
||||||
|
@ -92,8 +86,9 @@ void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count,
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioProvider *AudioProviderFactory::GetProvider(wxString const& filename, int cache) {
|
AudioProvider *AudioProviderFactory::GetProvider(wxString const& filename, int cache) {
|
||||||
AudioProvider *provider = NULL;
|
AudioProvider *provider = 0;
|
||||||
bool found = false;
|
bool found_file = false;
|
||||||
|
bool found_audio = false;
|
||||||
std::string msg;
|
std::string msg;
|
||||||
|
|
||||||
if (!OPT_GET("Provider/Audio/PCM/Disable")->GetBool()) {
|
if (!OPT_GET("Provider/Audio/PCM/Disable")->GetBool()) {
|
||||||
|
@ -104,16 +99,16 @@ AudioProvider *AudioProviderFactory::GetProvider(wxString const& filename, int c
|
||||||
catch (agi::FileNotFoundError const& err) {
|
catch (agi::FileNotFoundError const& err) {
|
||||||
msg = "PCM audio provider: " + err.GetMessage() + " not found.\n";
|
msg = "PCM audio provider: " + err.GetMessage() + " not found.\n";
|
||||||
}
|
}
|
||||||
catch (AudioOpenError const& err) {
|
catch (agi::AudioOpenError const& err) {
|
||||||
found = true;
|
found_file = true;
|
||||||
msg += err.GetMessage() + "\n";
|
msg += err.GetChainedMessage() + "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
std::vector<std::string> list = GetClasses(OPT_GET("Audio/Provider")->GetString());
|
std::vector<std::string> list = GetClasses(OPT_GET("Audio/Provider")->GetString());
|
||||||
if (list.empty()) throw AudioOpenError("No audio providers are available.");
|
if (list.empty()) throw agi::NoAudioProvidersError("No audio providers are available.", 0);
|
||||||
|
|
||||||
for (unsigned int i=0;i<list.size();i++) {
|
for (size_t i = 0; i < list.size() ; ++i) {
|
||||||
try {
|
try {
|
||||||
provider = Create(list[i], filename);
|
provider = Create(list[i], filename);
|
||||||
if (provider) break;
|
if (provider) break;
|
||||||
|
@ -121,20 +116,25 @@ AudioProvider *AudioProviderFactory::GetProvider(wxString const& filename, int c
|
||||||
catch (agi::FileNotFoundError const& err) {
|
catch (agi::FileNotFoundError const& err) {
|
||||||
msg += list[i] + ": " + err.GetMessage() + " not found.\n";
|
msg += list[i] + ": " + err.GetMessage() + " not found.\n";
|
||||||
}
|
}
|
||||||
catch (AudioOpenError const& err) {
|
catch (agi::AudioDataNotFoundError const& err) {
|
||||||
found = true;
|
found_file = true;
|
||||||
msg += list[i] + ": " + err.GetMessage() + "\n";
|
msg += list[i] + ": " + err.GetChainedMessage() + "\n";
|
||||||
|
}
|
||||||
|
catch (agi::AudioOpenError const& err) {
|
||||||
|
found_audio = true;
|
||||||
|
found_file = true;
|
||||||
|
msg += list[i] + ": " + err.GetChainedMessage() + "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
if (found) {
|
if (found_audio)
|
||||||
throw AudioOpenError(msg);
|
throw agi::AudioProviderOpenError(msg, 0);
|
||||||
}
|
if (found_file)
|
||||||
else {
|
throw agi::AudioDataNotFoundError(msg, 0);
|
||||||
throw agi::FileNotFoundError(STD_STR(filename));
|
throw agi::FileNotFoundError(STD_STR(filename));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsCache = provider->NeedsCache();
|
bool needsCache = provider->NeedsCache();
|
||||||
|
|
||||||
// Give it a converter if needed
|
// Give it a converter if needed
|
||||||
|
@ -155,7 +155,7 @@ AudioProvider *AudioProviderFactory::GetProvider(wxString const& filename, int c
|
||||||
// Convert to HD
|
// Convert to HD
|
||||||
if (cache == 2) return new HDAudioProvider(provider, &progress);
|
if (cache == 2) return new HDAudioProvider(provider, &progress);
|
||||||
|
|
||||||
throw AudioOpenError("Unknown caching method");
|
throw agi::AudioCacheOpenError("Unknown caching method", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Register all providers
|
/// @brief Register all providers
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "audio_provider_avs.h"
|
#include "audio_provider_avs.h"
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "charset_conv.h"
|
#include "charset_conv.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -55,45 +57,53 @@
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
/// @param _filename
|
/// @param _filename
|
||||||
///
|
///
|
||||||
AvisynthAudioProvider::AvisynthAudioProvider(wxString filename) try : filename(filename) {
|
AvisynthAudioProvider::AvisynthAudioProvider(wxString filename)
|
||||||
AVSValue script;
|
: filename(filename)
|
||||||
wxMutexLocker lock(AviSynthMutex);
|
{
|
||||||
|
try {
|
||||||
|
AVSValue script;
|
||||||
|
wxMutexLocker lock(AviSynthMutex);
|
||||||
|
|
||||||
wxFileName fn(filename);
|
wxFileName fn(filename);
|
||||||
if (!fn.FileExists())
|
if (!fn.FileExists())
|
||||||
throw agi::FileNotFoundError(STD_STR(filename));
|
throw agi::FileNotFoundError(STD_STR(filename));
|
||||||
|
|
||||||
// Include
|
// Include
|
||||||
if (filename.EndsWith(".avs")) {
|
if (filename.EndsWith(".avs")) {
|
||||||
char *fname = env->SaveString(fn.GetShortPath().mb_str(csConvLocal));
|
char *fname = env->SaveString(fn.GetShortPath().mb_str(csConvLocal));
|
||||||
script = env->Invoke("Import", fname);
|
script = env->Invoke("Import", fname);
|
||||||
}
|
|
||||||
|
|
||||||
// Use DirectShowSource
|
|
||||||
else {
|
|
||||||
const char * argnames[3] = { 0, "video", "audio" };
|
|
||||||
AVSValue args[3] = { env->SaveString(fn.GetShortPath().mb_str(csConvLocal)), false, true };
|
|
||||||
|
|
||||||
// Load DirectShowSource.dll from app dir if it exists
|
|
||||||
wxFileName dsspath(StandardPaths::DecodePath("?data/DirectShowSource.dll"));
|
|
||||||
if (dsspath.FileExists()) {
|
|
||||||
env->Invoke("LoadPlugin",env->SaveString(dsspath.GetShortPath().mb_str(csConvLocal)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load audio with DSS if it exists
|
// Use DirectShowSource
|
||||||
if (env->FunctionExists("DirectShowSource")) {
|
|
||||||
script = env->Invoke("DirectShowSource", AVSValue(args,3),argnames);
|
|
||||||
}
|
|
||||||
// Otherwise fail
|
|
||||||
else {
|
else {
|
||||||
throw AudioOpenError("No suitable audio source filter found. Try placing DirectShowSource.dll in the Aegisub application directory.");
|
const char * argnames[3] = { 0, "video", "audio" };
|
||||||
}
|
AVSValue args[3] = { env->SaveString(fn.GetShortPath().mb_str(csConvLocal)), false, true };
|
||||||
}
|
|
||||||
|
|
||||||
LoadFromClip(script);
|
// Load DirectShowSource.dll from app dir if it exists
|
||||||
}
|
wxFileName dsspath(StandardPaths::DecodePath("?data/DirectShowSource.dll"));
|
||||||
catch (AvisynthError &err) {
|
if (dsspath.FileExists()) {
|
||||||
throw AudioOpenError("Avisynth error: " + std::string(err.msg));
|
env->Invoke("LoadPlugin",env->SaveString(dsspath.GetShortPath().mb_str(csConvLocal)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load audio with DSS if it exists
|
||||||
|
if (env->FunctionExists("DirectShowSource")) {
|
||||||
|
script = env->Invoke("DirectShowSource", AVSValue(args,3),argnames);
|
||||||
|
}
|
||||||
|
// Otherwise fail
|
||||||
|
else {
|
||||||
|
throw agi::AudioProviderOpenError("No suitable audio source filter found. Try placing DirectShowSource.dll in the Aegisub application directory.", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadFromClip(script);
|
||||||
|
}
|
||||||
|
catch (AvisynthError &err) {
|
||||||
|
std::string errmsg(err.msg);
|
||||||
|
if (errmsg.find("filter graph manager won't talk to me") != errmsg.npos)
|
||||||
|
throw agi::AudioDataNotFoundError("Avisynth error: " + errmsg, 0);
|
||||||
|
else
|
||||||
|
throw agi::AudioProviderOpenError("Avisynth error: " + errmsg, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Read from environment
|
/// @brief Read from environment
|
||||||
|
@ -104,7 +114,7 @@ void AvisynthAudioProvider::LoadFromClip(AVSValue _clip) {
|
||||||
|
|
||||||
// Check if it has audio
|
// Check if it has audio
|
||||||
VideoInfo vi = _clip.AsClip()->GetVideoInfo();
|
VideoInfo vi = _clip.AsClip()->GetVideoInfo();
|
||||||
if (!vi.HasAudio()) throw AudioOpenError("No audio found.");
|
if (!vi.HasAudio()) throw agi::AudioDataNotFoundError("No audio found.", 0);
|
||||||
|
|
||||||
// Convert to one channel
|
// Convert to one channel
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "audio_provider_convert.h"
|
#include "audio_provider_convert.h"
|
||||||
|
|
||||||
#include "aegisub_endian.h"
|
#include "aegisub_endian.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
|
||||||
#include <libaegisub/scoped_ptr.h>
|
#include <libaegisub/scoped_ptr.h>
|
||||||
|
@ -54,7 +55,7 @@ class BitdepthConvertAudioProvider : public AudioProviderConverter {
|
||||||
public:
|
public:
|
||||||
BitdepthConvertAudioProvider(AudioProvider *src) : AudioProviderConverter(src) {
|
BitdepthConvertAudioProvider(AudioProvider *src) : AudioProviderConverter(src) {
|
||||||
if (bytes_per_sample > 8)
|
if (bytes_per_sample > 8)
|
||||||
throw AudioOpenError("Audio format converter: audio with bitdepths greater than 64 bits/sample is currently unsupported");
|
throw agi::AudioProviderOpenError("Audio format converter: audio with bitdepths greater than 64 bits/sample is currently unsupported", 0);
|
||||||
|
|
||||||
src_is_native_endian = src->AreSamplesNativeEndian();
|
src_is_native_endian = src->AreSamplesNativeEndian();
|
||||||
src_bytes_per_sample = bytes_per_sample;
|
src_bytes_per_sample = bytes_per_sample;
|
||||||
|
|
|
@ -47,10 +47,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "audio_provider_ffmpegsource.h"
|
#include "audio_provider_ffmpegsource.h"
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
/// @param filename
|
/// @param filename
|
||||||
///
|
///
|
||||||
|
@ -64,7 +65,7 @@ FFmpegSourceAudioProvider::FFmpegSourceAudioProvider(wxString filename)
|
||||||
if (SUCCEEDED(res))
|
if (SUCCEEDED(res))
|
||||||
COMInited = true;
|
COMInited = true;
|
||||||
else if (res != RPC_E_CHANGED_MODE)
|
else if (res != RPC_E_CHANGED_MODE)
|
||||||
throw AudioOpenError("COM initialization failure");
|
throw agi::AudioProviderOpenError("COM initialization failure", 0);
|
||||||
#endif
|
#endif
|
||||||
// initialize ffmpegsource
|
// initialize ffmpegsource
|
||||||
// FIXME: CPU detection?
|
// FIXME: CPU detection?
|
||||||
|
@ -101,7 +102,7 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
||||||
|
|
||||||
std::map<int,wxString> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_AUDIO);
|
std::map<int,wxString> TrackList = GetTracksOfType(Indexer, FFMS_TYPE_AUDIO);
|
||||||
if (TrackList.size() <= 0)
|
if (TrackList.size() <= 0)
|
||||||
throw AudioOpenError("no audio tracks found");
|
throw agi::AudioDataNotFoundError("no audio tracks found", 0);
|
||||||
|
|
||||||
// initialize the track number to an invalid value so we can detect later on
|
// initialize the track number to an invalid value so we can detect later on
|
||||||
// whether the user actually had to choose a track or not
|
// whether the user actually had to choose a track or not
|
||||||
|
@ -110,7 +111,7 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
||||||
TrackNumber = AskForTrackSelection(TrackList, FFMS_TYPE_AUDIO);
|
TrackNumber = AskForTrackSelection(TrackList, FFMS_TYPE_AUDIO);
|
||||||
// if it's still -1 here, user pressed cancel
|
// if it's still -1 here, user pressed cancel
|
||||||
if (TrackNumber == -1)
|
if (TrackNumber == -1)
|
||||||
throw agi::UserCancelException("audio loading cancelled by user");
|
throw agi::UserCancelException("audio loading canceled by user");
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate a name for the cache file
|
// generate a name for the cache file
|
||||||
|
@ -137,7 +138,7 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
||||||
if (TrackNumber < 0) {
|
if (TrackNumber < 0) {
|
||||||
FFMS_DestroyIndex(Index);
|
FFMS_DestroyIndex(Index);
|
||||||
Index = NULL;
|
Index = NULL;
|
||||||
throw AudioOpenError(std::string("Couldn't find any audio tracks: ") + ErrInfo.Buffer);
|
throw agi::AudioDataNotFoundError(std::string("Couldn't find any audio tracks: ") + ErrInfo.Buffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// index is valid and track number is now set,
|
// index is valid and track number is now set,
|
||||||
|
@ -166,7 +167,7 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
||||||
Index = DoIndexing(Indexer, CacheName, TrackMask, GetErrorHandlingMode());
|
Index = DoIndexing(Indexer, CacheName, TrackMask, GetErrorHandlingMode());
|
||||||
}
|
}
|
||||||
catch (wxString const& err) {
|
catch (wxString const& err) {
|
||||||
throw AudioOpenError(STD_STR(err));
|
throw agi::AudioProviderOpenError(STD_STR(err), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if tracknumber still isn't set we need to set it now
|
// if tracknumber still isn't set we need to set it now
|
||||||
|
@ -187,7 +188,7 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
||||||
FFMS_DestroyIndex(Index);
|
FFMS_DestroyIndex(Index);
|
||||||
Index = NULL;
|
Index = NULL;
|
||||||
if (!AudioSource) {
|
if (!AudioSource) {
|
||||||
throw AudioOpenError(std::string("Failed to open audio track: %s") + ErrInfo.Buffer);
|
throw agi::AudioProviderOpenError(std::string("Failed to open audio track: %s") + ErrInfo.Buffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const FFMS_AudioProperties AudioInfo = *FFMS_GetAudioProperties(AudioSource);
|
const FFMS_AudioProperties AudioInfo = *FFMS_GetAudioProperties(AudioSource);
|
||||||
|
@ -196,7 +197,7 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
||||||
sample_rate = AudioInfo.SampleRate;
|
sample_rate = AudioInfo.SampleRate;
|
||||||
num_samples = AudioInfo.NumSamples;
|
num_samples = AudioInfo.NumSamples;
|
||||||
if (channels <= 0 || sample_rate <= 0 || num_samples <= 0)
|
if (channels <= 0 || sample_rate <= 0 || num_samples <= 0)
|
||||||
throw AudioOpenError("sanity check failed, consult your local psychiatrist");
|
throw agi::AudioProviderOpenError("sanity check failed, consult your local psychiatrist", 0);
|
||||||
|
|
||||||
// FIXME: use the actual sample format too?
|
// FIXME: use the actual sample format too?
|
||||||
// why not just bits_per_sample/8? maybe there's some oddball format with half bytes out there somewhere...
|
// why not just bits_per_sample/8? maybe there's some oddball format with half bytes out there somewhere...
|
||||||
|
@ -206,7 +207,7 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
||||||
case 24: bytes_per_sample = 3; break;
|
case 24: bytes_per_sample = 3; break;
|
||||||
case 32: bytes_per_sample = 4; break;
|
case 32: bytes_per_sample = 4; break;
|
||||||
default:
|
default:
|
||||||
throw AudioOpenError("unknown or unsupported sample format");
|
throw agi::AudioProviderOpenError("unknown or unsupported sample format", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
|
|
||||||
#include "audio_provider_hd.h"
|
#include "audio_provider_hd.h"
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_provider_pcm.h"
|
#include "audio_provider_pcm.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -103,7 +104,7 @@ HDAudioProvider::HDAudioProvider(AudioProvider *src, agi::BackgroundRunner *br)
|
||||||
wxDiskspaceSize_t freespace;
|
wxDiskspaceSize_t freespace;
|
||||||
if (wxGetDiskSpace(cache_dir(), 0, &freespace)) {
|
if (wxGetDiskSpace(cache_dir(), 0, &freespace)) {
|
||||||
if (num_samples * channels * bytes_per_sample > freespace)
|
if (num_samples * channels * bytes_per_sample > freespace)
|
||||||
throw AudioOpenError("Not enough free disk space in " + STD_STR(cache_dir()) + " to cache the audio");
|
throw agi::AudioCacheOpenError("Not enough free disk space in " + STD_STR(cache_dir()) + " to cache the audio", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes_per_sample = source->GetBytesPerSample();
|
bytes_per_sample = source->GetBytesPerSample();
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "aegisub_endian.h"
|
#include "aegisub_endian.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_provider_pcm.h"
|
#include "audio_provider_pcm.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
@ -81,7 +82,7 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
|
||||||
LARGE_INTEGER li_file_size = {0};
|
LARGE_INTEGER li_file_size = {0};
|
||||||
if (!GetFileSizeEx(file_handle, &li_file_size)) {
|
if (!GetFileSizeEx(file_handle, &li_file_size)) {
|
||||||
CloseHandle(file_handle);
|
CloseHandle(file_handle);
|
||||||
throw AudioOpenError("Failed getting file size");
|
throw agi::AudioProviderOpenError("Failed getting file size", 0);
|
||||||
}
|
}
|
||||||
file_size = li_file_size.QuadPart;
|
file_size = li_file_size.QuadPart;
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
|
||||||
|
|
||||||
if (file_mapping == 0) {
|
if (file_mapping == 0) {
|
||||||
CloseHandle(file_handle);
|
CloseHandle(file_handle);
|
||||||
throw AudioOpenError("Failed creating file mapping");
|
throw agi::AudioProviderOpenError("Failed creating file mapping", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
current_mapping = 0;
|
current_mapping = 0;
|
||||||
|
@ -111,7 +112,7 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
|
||||||
memset(&filestats, 0, sizeof(filestats));
|
memset(&filestats, 0, sizeof(filestats));
|
||||||
if (fstat(file_handle, &filestats)) {
|
if (fstat(file_handle, &filestats)) {
|
||||||
close(file_handle);
|
close(file_handle);
|
||||||
throw AudioOpenError("Could not stat file to get size");
|
throw agi::AudioProviderOpenError("Could not stat file to get size", 0);
|
||||||
}
|
}
|
||||||
file_size = filestats.st_size;
|
file_size = filestats.st_size;
|
||||||
|
|
||||||
|
@ -331,9 +332,9 @@ public:
|
||||||
|
|
||||||
// Check magic values
|
// Check magic values
|
||||||
if (!CheckFourcc(header.ch.type, "RIFF"))
|
if (!CheckFourcc(header.ch.type, "RIFF"))
|
||||||
throw AudioOpenError("File is not a RIFF file");
|
throw agi::AudioDataNotFoundError("File is not a RIFF file", 0);
|
||||||
if (!CheckFourcc(header.format, "WAVE"))
|
if (!CheckFourcc(header.format, "WAVE"))
|
||||||
throw AudioOpenError("File is not a RIFF WAV file");
|
throw agi::AudioDataNotFoundError("File is not a RIFF WAV file", 0);
|
||||||
|
|
||||||
// Count how much more data we can have in the entire file
|
// Count how much more data we can have in the entire file
|
||||||
// The first 4 bytes are already eaten by the header.format field
|
// The first 4 bytes are already eaten by the header.format field
|
||||||
|
@ -356,13 +357,13 @@ public:
|
||||||
filepos += sizeof(ch);
|
filepos += sizeof(ch);
|
||||||
|
|
||||||
if (CheckFourcc(ch.type, "fmt ")) {
|
if (CheckFourcc(ch.type, "fmt ")) {
|
||||||
if (got_fmt_header) throw AudioOpenError("Invalid file, multiple 'fmt ' chunks");
|
if (got_fmt_header) throw agi::AudioProviderOpenError("Invalid file, multiple 'fmt ' chunks", 0);
|
||||||
got_fmt_header = true;
|
got_fmt_header = true;
|
||||||
|
|
||||||
fmtChunk &fmt = *(fmtChunk*)EnsureRangeAccessible(filepos, sizeof(fmtChunk));
|
fmtChunk &fmt = *(fmtChunk*)EnsureRangeAccessible(filepos, sizeof(fmtChunk));
|
||||||
|
|
||||||
if (Endian::LittleToMachine(fmt.compression) != 1)
|
if (Endian::LittleToMachine(fmt.compression) != 1)
|
||||||
throw AudioOpenError("Can't use file, not PCM encoding");
|
throw agi::AudioProviderOpenError("Can't use file, not PCM encoding", 0);
|
||||||
|
|
||||||
// Set stuff inherited from the AudioProvider class
|
// Set stuff inherited from the AudioProvider class
|
||||||
sample_rate = Endian::LittleToMachine(fmt.samplerate);
|
sample_rate = Endian::LittleToMachine(fmt.samplerate);
|
||||||
|
@ -374,7 +375,7 @@ public:
|
||||||
// This won't pick up 'data' chunks inside 'wavl' chunks
|
// This won't pick up 'data' chunks inside 'wavl' chunks
|
||||||
// since the 'wavl' chunks wrap those.
|
// since the 'wavl' chunks wrap those.
|
||||||
|
|
||||||
if (!got_fmt_header) throw AudioOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.");
|
if (!got_fmt_header) throw agi::AudioProviderOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.", 0);
|
||||||
|
|
||||||
int64_t samples = Endian::LittleToMachine(ch.size) / bytes_per_sample;
|
int64_t samples = Endian::LittleToMachine(ch.size) / bytes_per_sample;
|
||||||
int64_t frames = samples / channels;
|
int64_t frames = samples / channels;
|
||||||
|
@ -518,7 +519,7 @@ public:
|
||||||
int64_t smallest_possible_file = sizeof(RiffChunk) + sizeof(FormatChunk) + sizeof(DataChunk);
|
int64_t smallest_possible_file = sizeof(RiffChunk) + sizeof(FormatChunk) + sizeof(DataChunk);
|
||||||
|
|
||||||
if (file_size < smallest_possible_file)
|
if (file_size < smallest_possible_file)
|
||||||
throw AudioOpenError("File is too small to be a Wave64 file");
|
throw agi::AudioDataNotFoundError("File is too small to be a Wave64 file", 0);
|
||||||
|
|
||||||
// Read header
|
// Read header
|
||||||
// This should throw an exception if the mapping fails
|
// This should throw an exception if the mapping fails
|
||||||
|
@ -528,9 +529,9 @@ public:
|
||||||
|
|
||||||
// Check magic values
|
// Check magic values
|
||||||
if (!CheckGuid(header.riff_guid, w64GuidRIFF))
|
if (!CheckGuid(header.riff_guid, w64GuidRIFF))
|
||||||
throw AudioOpenError("File is not a Wave64 RIFF file");
|
throw agi::AudioDataNotFoundError("File is not a Wave64 RIFF file", 0);
|
||||||
if (!CheckGuid(header.format_guid, w64GuidWAVE))
|
if (!CheckGuid(header.format_guid, w64GuidWAVE))
|
||||||
throw AudioOpenError("File is not a Wave64 WAVE file");
|
throw agi::AudioDataNotFoundError("File is not a Wave64 WAVE file", 0);
|
||||||
|
|
||||||
// Count how much more data we can have in the entire file
|
// Count how much more data we can have in the entire file
|
||||||
uint64_t data_left = Endian::LittleToMachine(header.file_size) - sizeof(RiffChunk);
|
uint64_t data_left = Endian::LittleToMachine(header.file_size) - sizeof(RiffChunk);
|
||||||
|
@ -550,15 +551,15 @@ public:
|
||||||
|
|
||||||
if (CheckGuid(chunk_guid, w64Guidfmt)) {
|
if (CheckGuid(chunk_guid, w64Guidfmt)) {
|
||||||
if (got_fmt_header)
|
if (got_fmt_header)
|
||||||
throw AudioOpenError("Bad file, found more than one 'fmt' chunk");
|
throw agi::AudioProviderOpenError("Bad file, found more than one 'fmt' chunk", 0);
|
||||||
|
|
||||||
FormatChunk &fmt = *(FormatChunk*)EnsureRangeAccessible(filepos, sizeof(FormatChunk));
|
FormatChunk &fmt = *(FormatChunk*)EnsureRangeAccessible(filepos, sizeof(FormatChunk));
|
||||||
got_fmt_header = true;
|
got_fmt_header = true;
|
||||||
|
|
||||||
if (Endian::LittleToMachine(fmt.format.wFormatTag) == 3)
|
if (Endian::LittleToMachine(fmt.format.wFormatTag) == 3)
|
||||||
throw AudioOpenError("File is IEEE 32 bit float format which isn't supported. Bug the developers if this matters.");
|
throw agi::AudioProviderOpenError("File is IEEE 32 bit float format which isn't supported. Bug the developers if this matters.", 0);
|
||||||
if (Endian::LittleToMachine(fmt.format.wFormatTag) != 1)
|
if (Endian::LittleToMachine(fmt.format.wFormatTag) != 1)
|
||||||
throw AudioOpenError("Can't use file, not PCM encoding");
|
throw agi::AudioProviderOpenError("Can't use file, not PCM encoding", 0);
|
||||||
|
|
||||||
// Set stuff inherited from the AudioProvider class
|
// Set stuff inherited from the AudioProvider class
|
||||||
sample_rate = Endian::LittleToMachine(fmt.format.nSamplesPerSec);
|
sample_rate = Endian::LittleToMachine(fmt.format.nSamplesPerSec);
|
||||||
|
@ -567,7 +568,7 @@ public:
|
||||||
}
|
}
|
||||||
else if (CheckGuid(chunk_guid, w64Guiddata)) {
|
else if (CheckGuid(chunk_guid, w64Guiddata)) {
|
||||||
if (!got_fmt_header)
|
if (!got_fmt_header)
|
||||||
throw AudioOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.");
|
throw agi::AudioProviderOpenError("Found 'data' chunk before 'fmt ' chunk, file is invalid.", 0);
|
||||||
|
|
||||||
int64_t samples = chunk_size / bytes_per_sample;
|
int64_t samples = chunk_size / bytes_per_sample;
|
||||||
int64_t frames = samples / channels;
|
int64_t frames = samples / channels;
|
||||||
|
@ -601,23 +602,35 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @param filename
|
|
||||||
///
|
|
||||||
AudioProvider *CreatePCMAudioProvider(const wxString &filename)
|
AudioProvider *CreatePCMAudioProvider(const wxString &filename)
|
||||||
{
|
{
|
||||||
|
bool wrong_file_type = true;
|
||||||
std::string msg;
|
std::string msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new RiffWavPCMAudioProvider(filename);
|
return new RiffWavPCMAudioProvider(filename);
|
||||||
}
|
}
|
||||||
catch (AudioOpenError const& err) {
|
catch (agi::AudioDataNotFoundError const& err) {
|
||||||
msg = "RIFF PCM WAV audio provider: " + err.GetMessage();
|
msg = "RIFF PCM WAV audio provider: " + err.GetMessage();
|
||||||
}
|
}
|
||||||
|
catch (agi::AudioProviderOpenError const& err) {
|
||||||
|
wrong_file_type = false;
|
||||||
|
msg = "RIFF PCM WAV audio provider: " + err.GetMessage();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new Wave64AudioProvider(filename);
|
return new Wave64AudioProvider(filename);
|
||||||
}
|
}
|
||||||
catch (AudioOpenError const& err) {
|
catch (agi::AudioDataNotFoundError const& err) {
|
||||||
msg += "\nWave64 audio provider: " + err.GetMessage();
|
msg += "\nWave64 audio provider: " + err.GetMessage();
|
||||||
throw AudioOpenError(msg);
|
|
||||||
}
|
}
|
||||||
|
catch (agi::AudioProviderOpenError const& err) {
|
||||||
|
wrong_file_type = false;
|
||||||
|
msg += "\nWave64 audio provider: " + err.GetMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wrong_file_type)
|
||||||
|
throw agi::AudioDataNotFoundError(msg, 0);
|
||||||
|
else
|
||||||
|
throw agi::AudioProviderOpenError(msg, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
#include "audio_provider_ram.h"
|
#include "audio_provider_ram.h"
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
@ -67,7 +68,7 @@ RAMAudioProvider::RAMAudioProvider(AudioProvider *src, agi::BackgroundRunner *br
|
||||||
}
|
}
|
||||||
catch (std::bad_alloc const&) {
|
catch (std::bad_alloc const&) {
|
||||||
Clear();
|
Clear();
|
||||||
throw AudioOpenError("Couldn't open audio, not enough ram available.");
|
throw agi::AudioCacheOpenError("Couldn't open audio, not enough ram available.", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy parameters
|
// Copy parameters
|
||||||
|
|
|
@ -72,8 +72,6 @@ namespace agi { struct Context; }
|
||||||
namespace cmd { class Command; }
|
namespace cmd { class Command; }
|
||||||
|
|
||||||
|
|
||||||
DECLARE_EVENT_TYPE(wxEVT_AUTOMATION_SCRIPT_COMPLETED, -1)
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
namespace Automation4 {
|
namespace Automation4 {
|
||||||
DEFINE_BASE_EXCEPTION_NOINNER(AutomationError, agi::Exception)
|
DEFINE_BASE_EXCEPTION_NOINNER(AutomationError, agi::Exception)
|
||||||
|
|
|
@ -119,7 +119,12 @@ struct audio_open_blank : public Command {
|
||||||
STR_HELP("Open a 150 minutes blank audio clip, for debugging.")
|
STR_HELP("Open a 150 minutes blank audio clip, for debugging.")
|
||||||
|
|
||||||
void operator()(agi::Context *c) {
|
void operator()(agi::Context *c) {
|
||||||
c->audioController->OpenAudio("dummy-audio:silence?sr=44100&bd=16&ch=1&ln=396900000");
|
try {
|
||||||
|
c->audioController->OpenAudio("dummy-audio:silence?sr=44100&bd=16&ch=1&ln=396900000");
|
||||||
|
}
|
||||||
|
catch (agi::Exception const& e) {
|
||||||
|
wxMessageBox(lagi_wxString(e.GetChainedMessage()), "Error loading file", wxICON_ERROR | wxOK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -132,7 +137,12 @@ struct audio_open_noise : public Command {
|
||||||
STR_HELP("Open a 150 minutes noise-filled audio clip, for debugging.")
|
STR_HELP("Open a 150 minutes noise-filled audio clip, for debugging.")
|
||||||
|
|
||||||
void operator()(agi::Context *c) {
|
void operator()(agi::Context *c) {
|
||||||
c->audioController->OpenAudio("dummy-audio:noise?sr=44100&bd=16&ch=1&ln=396900000");
|
try {
|
||||||
|
c->audioController->OpenAudio("dummy-audio:noise?sr=44100&bd=16&ch=1&ln=396900000");
|
||||||
|
}
|
||||||
|
catch (agi::Exception const& e) {
|
||||||
|
wxMessageBox(lagi_wxString(e.GetChainedMessage()), "Error loading file", wxICON_ERROR | wxOK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -153,6 +163,7 @@ struct audio_open_video : public Command {
|
||||||
try {
|
try {
|
||||||
c->audioController->OpenAudio(c->videoController->GetVideoName());
|
c->audioController->OpenAudio(c->videoController->GetVideoName());
|
||||||
}
|
}
|
||||||
|
catch (agi::UserCancelException const&) { }
|
||||||
catch (agi::Exception const& e) {
|
catch (agi::Exception const& e) {
|
||||||
wxMessageBox(lagi_wxString(e.GetChainedMessage()), "Error loading file", wxICON_ERROR | wxOK);
|
wxMessageBox(lagi_wxString(e.GetChainedMessage()), "Error loading file", wxICON_ERROR | wxOK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,9 +50,7 @@ class AudioProvider;
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class AudioPlayer : public wxEvtHandler {
|
class AudioPlayer {
|
||||||
void OnStopAudio(wxCommandEvent &event);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// DOCME
|
/// DOCME
|
||||||
AudioProvider *provider;
|
AudioProvider *provider;
|
||||||
|
@ -64,18 +62,11 @@ public:
|
||||||
AudioPlayer();
|
AudioPlayer();
|
||||||
virtual ~AudioPlayer();
|
virtual ~AudioPlayer();
|
||||||
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
///
|
|
||||||
virtual void OpenStream() {}
|
virtual void OpenStream() {}
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
///
|
|
||||||
virtual void CloseStream() {}
|
virtual void CloseStream() {}
|
||||||
|
|
||||||
virtual void Play(int64_t start,int64_t count)=0; // Play sample range
|
virtual void Play(int64_t start,int64_t count)=0; // Play sample range
|
||||||
virtual void Stop(bool timerToo=true)=0; // Stop playing
|
virtual void Stop(bool timerToo=true)=0; // Stop playing
|
||||||
virtual void RequestStop(); // Request it to stop playing in a thread-safe way
|
|
||||||
virtual bool IsPlaying()=0;
|
virtual bool IsPlaying()=0;
|
||||||
|
|
||||||
virtual void SetVolume(double volume)=0;
|
virtual void SetVolume(double volume)=0;
|
||||||
|
@ -87,14 +78,8 @@ public:
|
||||||
virtual void SetEndPosition(int64_t pos)=0;
|
virtual void SetEndPosition(int64_t pos)=0;
|
||||||
virtual void SetCurrentPosition(int64_t pos)=0;
|
virtual void SetCurrentPosition(int64_t pos)=0;
|
||||||
|
|
||||||
virtual wxMutex *GetMutex() { return NULL; }
|
|
||||||
|
|
||||||
virtual void SetProvider(AudioProvider *new_provider) { provider = new_provider; }
|
virtual void SetProvider(AudioProvider *new_provider) { provider = new_provider; }
|
||||||
AudioProvider *GetProvider() const { return provider; }
|
AudioProvider *GetProvider() const { return provider; }
|
||||||
|
|
||||||
void SetDisplayTimer(wxTimer *timer) { displayTimer = timer; }
|
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioPlayerFactory : public Factory0<AudioPlayer> {
|
class AudioPlayerFactory : public Factory0<AudioPlayer> {
|
||||||
|
@ -104,5 +89,3 @@ public:
|
||||||
static void RegisterProviders();
|
static void RegisterProviders();
|
||||||
static AudioPlayer *GetAudioPlayer();
|
static AudioPlayer *GetAudioPlayer();
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_EVENT_TYPE(wxEVT_STOP_AUDIO, -1)
|
|
||||||
|
|
|
@ -98,7 +98,5 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_BASE_EXCEPTION_NOINNER(AudioProviderError, agi::Exception)
|
DEFINE_BASE_EXCEPTION_NOINNER(AudioProviderError, agi::Exception)
|
||||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(AudioOpenError, AudioProviderError, "audio/open/failed")
|
|
||||||
|
|
||||||
/// Error of some sort occurred while decoding a frame
|
/// Error of some sort occurred while decoding a frame
|
||||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(AudioDecodeError, AudioProviderError, "audio/error")
|
DEFINE_SIMPLE_EXCEPTION_NOINNER(AudioDecodeError, AudioProviderError, "audio/error")
|
||||||
|
|
Loading…
Reference in a new issue