forked from mia/Aegisub
Further abstraction of audio classes
Originally committed to SVN as r168.
This commit is contained in:
parent
68431d0c1a
commit
4698ec6f6b
9 changed files with 334 additions and 178 deletions
|
@ -283,7 +283,7 @@ void AudioBox::OnVerticalZoom(wxScrollEvent &event) {
|
|||
float value = pow(float(pos)/50.0f,3);
|
||||
audioDisplay->SetScale(value);
|
||||
if (VerticalLink->GetValue()) {
|
||||
audioDisplay->provider->volume = value;
|
||||
audioDisplay->provider->SetVolume(value);
|
||||
VolumeBar->SetValue(pos);
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ void AudioBox::OnVolume(wxScrollEvent &event) {
|
|||
int pos = event.GetPosition();
|
||||
if (pos < 1) pos = 1;
|
||||
if (pos > 100) pos = 100;
|
||||
audioDisplay->provider->volume = pow(float(pos)/50.0f,3);
|
||||
audioDisplay->provider->SetVolume(pow(float(pos)/50.0f,3));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,7 +309,7 @@ void AudioBox::OnVerticalLink(wxCommandEvent &event) {
|
|||
if (pos > 100) pos = 100;
|
||||
float value = pow(float(pos)/50.0f,3);
|
||||
if (VerticalLink->GetValue()) {
|
||||
audioDisplay->provider->volume = value;
|
||||
audioDisplay->provider->SetVolume(value);
|
||||
VolumeBar->SetValue(pos);
|
||||
}
|
||||
VolumeBar->Enable(!VerticalLink->GetValue());
|
||||
|
|
|
@ -1121,7 +1121,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) {
|
|||
}
|
||||
|
||||
// Cursor drawing
|
||||
if (!provider->playing) {
|
||||
if (!provider->IsPlaying()) {
|
||||
// Draw bg
|
||||
wxClientDC dc(this);
|
||||
dc.BeginDrawing();
|
||||
|
@ -1206,7 +1206,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) {
|
|||
if (event.ButtonDown(wxMOUSE_BTN_RIGHT)) {
|
||||
curEndMS = GetMSAtX(x);
|
||||
mod = true;
|
||||
provider->endPos = GetSampleAtX(x);
|
||||
provider->SetEndPosition(GetSampleAtX(x));
|
||||
}
|
||||
|
||||
// Modified, commit changes
|
||||
|
@ -1381,7 +1381,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) {
|
|||
|
||||
// Update stuff
|
||||
if (updated) {
|
||||
provider->endPos = GetSampleAtX(selEnd);
|
||||
provider->SetEndPosition(GetSampleAtX(selEnd));
|
||||
wxCursor cursor(wxCURSOR_SIZEWE);
|
||||
SetCursor(cursor);
|
||||
UpdateImage(true);
|
||||
|
@ -1449,8 +1449,12 @@ void AudioDisplay::OnSize(wxSizeEvent &event) {
|
|||
// Timer event
|
||||
void AudioDisplay::OnUpdateTimer(wxTimerEvent &event) {
|
||||
// Get lock and check if it's OK
|
||||
wxMutexLocker locker(provider->PAMutex);
|
||||
if (!locker.IsOk() || !provider->playing) return;
|
||||
if (provider->GetMutex()) {
|
||||
wxMutexLocker locker(*provider->GetMutex());
|
||||
if (!locker.IsOk()) return;
|
||||
}
|
||||
|
||||
if (!provider->IsPlaying()) return;
|
||||
|
||||
// Get DCs
|
||||
//wxMutexGuiEnter();
|
||||
|
@ -1464,13 +1468,13 @@ void AudioDisplay::OnUpdateTimer(wxTimerEvent &event) {
|
|||
|
||||
// Draw cursor
|
||||
int curpos = -1;
|
||||
if (provider->playing) {
|
||||
if (provider->realPlayPos > provider->startPos && provider->realPlayPos < provider->endPos) {
|
||||
if (provider->IsPlaying()) {
|
||||
if (provider->GetCurrentPosition() > provider->GetStartPosition() && provider->GetCurrentPosition() < provider->GetEndPosition()) {
|
||||
dc.SetPen(wxPen(Options.AsColour(_T("Audio Play cursor"))));
|
||||
curpos = GetXAtSample(provider->realPlayPos);
|
||||
curpos = GetXAtSample(provider->GetCurrentPosition());
|
||||
dc.DrawLine(curpos,0,curpos,h);
|
||||
}
|
||||
else if (provider->realPlayPos > provider->endPos + 8192) {
|
||||
else if (provider->GetCurrentPosition() > provider->GetEndPosition() + 8192) {
|
||||
provider->Stop();
|
||||
}
|
||||
}
|
||||
|
@ -1516,7 +1520,7 @@ void AudioDisplay::OnKeyDown(wxKeyEvent &event) {
|
|||
|
||||
// Play
|
||||
if (Hotkeys.IsPressed(_T("Audio Play")) || Hotkeys.IsPressed(_T("Audio Play Alt"))) {
|
||||
if (provider->playing) Stop();
|
||||
if (provider->IsPlaying()) Stop();
|
||||
else {
|
||||
int start=0,end=0;
|
||||
GetTimesSelection(start,end);
|
||||
|
|
|
@ -45,12 +45,16 @@
|
|||
// Constructor
|
||||
AudioPlayer::AudioPlayer() {
|
||||
provider = NULL;
|
||||
displayTimer = NULL;
|
||||
}
|
||||
|
||||
|
||||
//////////////
|
||||
// Destructor
|
||||
AudioPlayer::~AudioPlayer() {
|
||||
if (displayTimer) {
|
||||
displayTimer->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -61,6 +65,27 @@ void AudioPlayer::SetProvider(AudioProvider *_provider) {
|
|||
}
|
||||
|
||||
|
||||
////////////////
|
||||
// Get provider
|
||||
AudioProvider *AudioPlayer::GetProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
|
||||
/////////////
|
||||
// Get mutex
|
||||
wxMutex *AudioPlayer::GetMutex() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/////////////
|
||||
// Set timer
|
||||
void AudioPlayer::SetDisplayTimer(wxTimer *timer) {
|
||||
displayTimer = timer;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////
|
||||
// Ask to stop later
|
||||
void AudioPlayer::RequestStop() {
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
//////////////
|
||||
// Prototypes
|
||||
class AudioProvider;
|
||||
class wxTimer;
|
||||
class wxMutex;
|
||||
|
||||
|
||||
///////////////////////////
|
||||
|
@ -55,6 +57,7 @@ private:
|
|||
|
||||
protected:
|
||||
AudioProvider *provider;
|
||||
wxTimer *displayTimer;
|
||||
|
||||
public:
|
||||
AudioPlayer();
|
||||
|
@ -63,17 +66,23 @@ public:
|
|||
virtual void Play(__int64 start,__int64 count)=0; // Play sample range
|
||||
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 void SetVolume(double volume)=0;
|
||||
virtual double GetVolume()=0;
|
||||
|
||||
void SetProvider(AudioProvider *provider);
|
||||
AudioProvider *GetProvider();
|
||||
|
||||
virtual __int64 GetStartPosition()=0;
|
||||
virtual __int64 GetEndPosition()=0;
|
||||
virtual __int64 GetCurrentPosition()=0;
|
||||
virtual void SetEndPosition(__int64 pos)=0;
|
||||
virtual void SetCurrentPosition(__int64 pos)=0;
|
||||
|
||||
void SetDisplayTimer(wxTimer *timer);
|
||||
virtual wxMutex *GetMutex();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
|
|
186
core/audio_player_portaudio.cpp
Normal file
186
core/audio_player_portaudio.cpp
Normal file
|
@ -0,0 +1,186 @@
|
|||
// Copyright (c) 2005, 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
|
||||
//
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "audio_player_portaudio.h"
|
||||
#include "audio_provider.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
/////////////////////
|
||||
// Reference counter
|
||||
int PortAudioPlayer::pa_refcount = 0;
|
||||
|
||||
|
||||
///////////////
|
||||
// Constructor
|
||||
PortAudioPlayer::PortAudioPlayer() {
|
||||
// Initialize portaudio
|
||||
if (!pa_refcount) {
|
||||
PaError err = Pa_Initialize();
|
||||
if (err != paNoError)
|
||||
throw wxString::Format(_T("Failed opening PortAudio with error: %s"), wxString(Pa_GetErrorText(err),wxConvLocal));
|
||||
pa_refcount++;
|
||||
}
|
||||
|
||||
// Variables
|
||||
playing = false;
|
||||
stopping = false;
|
||||
volume = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
//////////////
|
||||
// Destructor
|
||||
PortAudioPlayer::~PortAudioPlayer() {
|
||||
// Deinit portaudio
|
||||
if (!--pa_refcount) Pa_Terminate();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////
|
||||
// PortAudio callback
|
||||
int PortAudioPlayer::paCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData) {
|
||||
// Get provider
|
||||
PortAudioPlayer *player = (PortAudioPlayer *) userData;
|
||||
AudioProvider *provider = player->GetProvider();
|
||||
int end = 0;
|
||||
|
||||
// Calculate how much left
|
||||
__int64 lenAvailable = player->endPos - player->playPos;
|
||||
unsigned __int64 avail = 0;
|
||||
if (lenAvailable > 0) {
|
||||
avail = lenAvailable;
|
||||
if (avail > framesPerBuffer) {
|
||||
lenAvailable = framesPerBuffer;
|
||||
avail = lenAvailable;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lenAvailable = 0;
|
||||
avail = 0;
|
||||
}
|
||||
|
||||
// Play something
|
||||
if (lenAvailable > 0) {
|
||||
provider->GetAudio(outputBuffer,player->playPos,lenAvailable);
|
||||
}
|
||||
|
||||
// Pad end with blank
|
||||
if (avail < (unsigned __int64) framesPerBuffer) {
|
||||
//provider->softStop = true;
|
||||
}
|
||||
|
||||
// Set volume
|
||||
short *output = (short*) outputBuffer;
|
||||
for (unsigned int i=0;i<avail;i++) output[i] = MID(-(1<<15),int(output[i] * player->GetVolume()),(1<<15)-1);
|
||||
|
||||
// Fill rest with blank
|
||||
for (unsigned int i=avail;i<framesPerBuffer;i++) output[i]=0;
|
||||
|
||||
// Set play position (and real one)
|
||||
player->playPos += framesPerBuffer;
|
||||
player->realPlayPos = player->playPos - (outTime - Pa_StreamTime(player->stream));
|
||||
|
||||
// Cap to start if lower
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
////////
|
||||
// Play
|
||||
void PortAudioPlayer::Play(__int64 start,__int64 count) {
|
||||
// Stop if it's already playing
|
||||
wxMutexLocker locker(PAMutex);
|
||||
|
||||
// Set values
|
||||
endPos = start + count;
|
||||
realPlayPos = start;
|
||||
playPos = start;
|
||||
startPos = start;
|
||||
startMS = startPos * 1000 / provider->GetSampleRate();
|
||||
|
||||
// Start playing
|
||||
if (!playing) {
|
||||
PaError err = Pa_StartStream(stream);
|
||||
if (err != paNoError) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
playing = true;
|
||||
|
||||
// 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);
|
||||
realPlayPos = 0;
|
||||
|
||||
// Stop timer
|
||||
if (timerToo && displayTimer) {
|
||||
displayTimer->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
// Open stream
|
||||
void PortAudioPlayer::OpenStream() {
|
||||
// Open stream
|
||||
PaError err = Pa_OpenDefaultStream(&stream,0,provider->GetChannels(),paInt16,provider->GetSampleRate(),256,16,paCallback,this);
|
||||
if (err != paNoError)
|
||||
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 (...) {}
|
||||
}
|
90
core/audio_player_portaudio.h
Normal file
90
core/audio_player_portaudio.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2005, 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
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "audio_player.h"
|
||||
extern "C" {
|
||||
#include <portaudio.h>
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// Portaudio player
|
||||
class PortAudioPlayer : public AudioPlayer {
|
||||
private:
|
||||
static int pa_refcount;
|
||||
wxMutex PAMutex;
|
||||
volatile bool stopping;
|
||||
//bool softStop;
|
||||
bool playing;
|
||||
float volume;
|
||||
|
||||
volatile __int64 playPos;
|
||||
volatile __int64 startPos;
|
||||
volatile __int64 endPos;
|
||||
volatile __int64 realPlayPos;
|
||||
volatile __int64 startMS;
|
||||
void *stream;
|
||||
|
||||
static int PortAudioPlayer::paCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData);
|
||||
|
||||
protected:
|
||||
void OpenStream();
|
||||
void CloseStream();
|
||||
|
||||
public:
|
||||
PortAudioPlayer();
|
||||
~PortAudioPlayer();
|
||||
|
||||
void Play(__int64 start,__int64 count);
|
||||
void Stop(bool timerToo=true);
|
||||
bool IsPlaying() { return playing; }
|
||||
|
||||
__int64 GetStartPosition() { return startPos; }
|
||||
__int64 GetEndPosition() { return endPos; }
|
||||
__int64 GetCurrentPosition() { return realPlayPos; }
|
||||
void SetEndPosition(__int64 pos) { endPos = pos; }
|
||||
void SetCurrentPosition(__int64 pos) { playPos = pos; realPlayPos = pos; }
|
||||
|
||||
void SetVolume(double vol) { volume = vol; }
|
||||
double GetVolume() { return volume; }
|
||||
|
||||
wxMutex *GetMutex() { return &PAMutex; }
|
||||
};
|
|
@ -48,42 +48,28 @@
|
|||
#include "main.h"
|
||||
#include "dialog_progress.h"
|
||||
|
||||
extern "C" {
|
||||
#include <portaudio.h>
|
||||
}
|
||||
|
||||
int AudioProvider::pa_refcount = 0;
|
||||
|
||||
#define CacheBits ((22))
|
||||
#define CacheBlockSize ((1 << CacheBits))
|
||||
|
||||
//////////////
|
||||
// Constructor
|
||||
AudioProvider::AudioProvider(wxString _filename, AudioDisplay *_display) {
|
||||
SetProvider(this);
|
||||
SetDisplayTimer(&_display->UpdateTimer);
|
||||
type = AUDIO_PROVIDER_NONE;
|
||||
playing = false;
|
||||
stopping = false;
|
||||
blockcache = NULL;
|
||||
blockcount = 0;
|
||||
raw = NULL;
|
||||
display = _display;
|
||||
blockcount = 0;
|
||||
volume = 1.0f;
|
||||
|
||||
filename = _filename;
|
||||
|
||||
// Initialize portaudio
|
||||
if (!pa_refcount) {
|
||||
PaError err = Pa_Initialize();
|
||||
if (err != paNoError)
|
||||
throw wxString::Format(_T("Failed opening PortAudio with error: %s"), wxString(Pa_GetErrorText(err),wxConvLocal));
|
||||
pa_refcount++;
|
||||
}
|
||||
|
||||
try {
|
||||
OpenAVSAudio();
|
||||
OpenStream();
|
||||
} catch (...) {
|
||||
}
|
||||
catch (...) {
|
||||
Unload();
|
||||
throw;
|
||||
}
|
||||
|
@ -120,9 +106,6 @@ void AudioProvider::Unload() {
|
|||
|
||||
// Clear buffers
|
||||
delete raw;
|
||||
|
||||
if (!--pa_refcount)
|
||||
Pa_Terminate();
|
||||
}
|
||||
|
||||
|
||||
|
@ -469,115 +452,3 @@ wxString AudioProvider::DiskCacheName() {
|
|||
return DiskCachePath() + _T("audio.tmp");
|
||||
}
|
||||
|
||||
|
||||
//////////////////////
|
||||
// PortAudio callback
|
||||
int paCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData) {
|
||||
// Get provider
|
||||
AudioProvider *provider = (AudioProvider *) userData;
|
||||
int end = 0;
|
||||
|
||||
// Calculate how much left
|
||||
__int64 lenAvailable = provider->endPos - provider->playPos;
|
||||
unsigned __int64 avail = 0;
|
||||
if (lenAvailable > 0) {
|
||||
avail = lenAvailable;
|
||||
if (avail > framesPerBuffer) {
|
||||
lenAvailable = framesPerBuffer;
|
||||
avail = lenAvailable;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lenAvailable = 0;
|
||||
avail = 0;
|
||||
}
|
||||
|
||||
// Play something
|
||||
if (lenAvailable > 0) {
|
||||
provider->GetAudio(outputBuffer,provider->playPos,lenAvailable);
|
||||
}
|
||||
|
||||
// Pad end with blank
|
||||
if (avail < (unsigned __int64) framesPerBuffer) {
|
||||
provider->softStop = true;
|
||||
}
|
||||
|
||||
// Set volume
|
||||
short *output = (short*) outputBuffer;
|
||||
for (unsigned int i=0;i<avail;i++) output[i] = MID(-(1<<15),int(output[i] * provider->volume),(1<<15)-1);
|
||||
|
||||
// Fill rest with blank
|
||||
for (unsigned int i=avail;i<framesPerBuffer;i++) output[i]=0;
|
||||
|
||||
// Set play position (and real one)
|
||||
provider->playPos += framesPerBuffer;
|
||||
provider->realPlayPos = provider->playPos - (outTime - Pa_StreamTime(provider->stream));
|
||||
|
||||
// Cap to start if lower
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
////////
|
||||
// Play
|
||||
void AudioProvider::Play(__int64 start,__int64 count) {
|
||||
// Stop if it's already playing
|
||||
wxMutexLocker locker(PAMutex);
|
||||
|
||||
// Set values
|
||||
endPos = start + count;
|
||||
realPlayPos = start;
|
||||
playPos = start;
|
||||
startPos = start;
|
||||
startMS = startPos * 1000 / GetSampleRate();
|
||||
|
||||
// Start playing
|
||||
if (!playing) {
|
||||
PaError err = Pa_StartStream(stream);
|
||||
if (err != paNoError) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
playing = true;
|
||||
|
||||
if (!display->UpdateTimer.IsRunning()) display->UpdateTimer.Start(15);
|
||||
}
|
||||
|
||||
|
||||
////////
|
||||
// Stop
|
||||
void AudioProvider::Stop(bool timerToo) {
|
||||
//wxMutexLocker locker(PAMutex);
|
||||
softStop = false;
|
||||
|
||||
// Stop stream
|
||||
playing = false;
|
||||
Pa_StopStream (stream);
|
||||
realPlayPos = 0;
|
||||
|
||||
// Stop timer
|
||||
if (timerToo) {
|
||||
display->UpdateTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
// Open stream
|
||||
void AudioProvider::OpenStream() {
|
||||
// Open stream
|
||||
PaError err = Pa_OpenDefaultStream(&stream,0,GetChannels(),paInt16,GetSampleRate(),256,16,paCallback,this);
|
||||
if (err != paNoError)
|
||||
throw wxString(_T("Failed initializing PortAudio stream with error: ") + wxString(Pa_GetErrorText(err),wxConvLocal));
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
// Close stream
|
||||
void AudioProvider::CloseStream() {
|
||||
try {
|
||||
Stop(false);
|
||||
Pa_CloseStream(stream);
|
||||
} catch (...) {}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
#include <fstream>
|
||||
#include <time.h>
|
||||
#include "avisynth_wrap.h"
|
||||
#include "audio_player.h"
|
||||
#include "audio_player_portaudio.h"
|
||||
|
||||
|
||||
//////////////
|
||||
|
@ -63,10 +63,8 @@ enum AudioProviderType {
|
|||
|
||||
////////////////////////
|
||||
// Audio provider class
|
||||
class AudioProvider : public AviSynthWrapper, public AudioPlayer {
|
||||
class AudioProvider : public AviSynthWrapper, public PortAudioPlayer {
|
||||
private:
|
||||
static int pa_refcount;
|
||||
|
||||
wxMutex diskmutex;
|
||||
|
||||
AudioProviderType type;
|
||||
|
@ -88,8 +86,6 @@ private:
|
|||
int sample_rate;
|
||||
int bytes_per_sample;
|
||||
|
||||
void OpenStream();
|
||||
void CloseStream();
|
||||
void ConvertToRAMCache(PClip &tempclip);
|
||||
void ConvertToDiskCache(PClip &tempclip);
|
||||
void LoadFromClip(AVSValue clip);
|
||||
|
@ -100,19 +96,6 @@ private:
|
|||
void Unload();
|
||||
|
||||
public:
|
||||
wxMutex PAMutex;
|
||||
volatile bool stopping;
|
||||
bool softStop;
|
||||
bool playing;
|
||||
float volume;
|
||||
|
||||
volatile __int64 playPos;
|
||||
volatile __int64 startPos;
|
||||
volatile __int64 endPos;
|
||||
volatile __int64 realPlayPos;
|
||||
volatile __int64 startMS;
|
||||
void *stream;
|
||||
|
||||
AudioProvider(wxString _filename, AudioDisplay *_display);
|
||||
~AudioProvider();
|
||||
|
||||
|
@ -124,15 +107,4 @@ public:
|
|||
int GetChannels();
|
||||
__int64 GetNumSamples();
|
||||
int GetSampleRate();
|
||||
|
||||
void Play(__int64 start,__int64 count);
|
||||
void Stop(bool timerToo=true);
|
||||
|
||||
__int64 GetEndPosition() { return endPos; }
|
||||
__int64 GetCurrentPosition() { return realPlayPos; }
|
||||
void SetEndPosition(__int64 pos) { endPos = pos; }
|
||||
void SetCurrentPosition(__int64 pos) { playPos = pos; realPlayPos = pos; }
|
||||
|
||||
void SetVolume(double vol) { volume = vol; }
|
||||
double GetVolume() { return volume; }
|
||||
};
|
||||
|
|
|
@ -887,8 +887,7 @@ void VideoDisplay::OnPlayTimer(wxTimerEvent &event) {
|
|||
// Sync audio
|
||||
if (nextFrame % 25 == 0) {
|
||||
__int64 audPos = audio->GetSampleAtMS(VFR_Output.GetTimeAtFrame(nextFrame));
|
||||
audio->provider->playPos = audPos;
|
||||
audio->provider->realPlayPos = audPos;
|
||||
audio->provider->SetCurrentPosition(audPos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue