CMAudio/src/AudioPlayer.cpp

562 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include<hgl/audio/AudioPlayer.h>
#include<hgl/LogInfo.h>
#include<hgl/PlugIn.h>
#include<hgl/Time.h>
#include<hgl/io/MemoryInputStream.h>
#include"AudioDecode.h"
namespace hgl
{
const os_char *GetAudioDecodeName(const AudioFileType aft);
void AudioPlayer::InitPrivate()
{
if(!alGenSources)
{
LOG_ERROR(OS_TEXT("OpenAL/EE 还未初始化!"));
return;
}
auto_gain.open=false;
audio_ptr=nullptr;
audio_data=nullptr;
audio_data_size=0;
audio_buffer=nullptr;
audio_buffer_size=0;
decode=nullptr;
ps=psNone;
{
hglSetPropertyRead( Index, this,AudioPlayer::GetIndex );
hglSetPropertyRead( Time, this,AudioPlayer::GetTime );
hglSetPropertyRead( State, this,AudioPlayer::GetPlayState );
hglSetPropertyRead( SourceState, this,AudioPlayer::GetSourceState);
hglSetPropertyRead( MinGain, this,AudioPlayer::GetMinGain );
hglSetPropertyRead( MaxGain, this,AudioPlayer::GetMaxGain );
hglSetProperty( Loop, this,AudioPlayer::GetLoop, AudioPlayer::SetLoop );
hglSetProperty( Pitch, this,AudioPlayer::GetPitch, AudioPlayer::SetPitch );
hglSetProperty( Gain, this,AudioPlayer::GetGain, AudioPlayer::SetGain );
hglSetProperty( ConeGain, this,AudioPlayer::GetConeGain, AudioPlayer::SetConeGain );
hglSetProperty( RolloffFactor, this,AudioPlayer::GetRolloffFactor, AudioPlayer::SetRolloffFactor );
}
if(!audiosource.Create())return;
audiosource.Loop=false;
source=audiosource.index;
alGenBuffers(3,buffer);
}
AudioPlayer::AudioPlayer()
{
InitPrivate();
}
AudioPlayer::AudioPlayer(const os_char *filename,AudioFileType aft)
{
InitPrivate();
if(filename)
Load(filename,aft);
}
AudioPlayer::AudioPlayer(InputStream *stream,int size,AudioFileType aft)
{
InitPrivate();
Load(stream,size,aft);
}
// AudioPlayer::AudioPlayer(HAC *hac,const os_char *filename,AudioFileType aft)
// {
// InitPrivate();
//
// Load(hac,filename,aft);
// }
AudioPlayer::~AudioPlayer()
{
if(!audio_data)return;
Clear();
alDeleteBuffers(3,buffer);
SAFE_CLEAR_ARRAY(audio_buffer);
}
bool AudioPlayer::Load(AudioFileType aft)
{
const os_char *plugin_name=GetAudioDecodeName(aft);
if(!plugin_name)return(false);
decode=AudioInterfaceCheck(plugin_name);
if(decode)
{
audio_ptr=decode->Open(audio_data,audio_data_size,&format,&rate,&time);
audio_buffer_size=(AudioTime(format,rate)+9)/10; // 1/10 秒
if(audio_buffer)
delete[] audio_buffer;
audio_buffer=new char[audio_buffer_size];
wait_time=0.1;
if(wait_time>time/3.0f)
wait_time=time/10.0f;
return(true);
}
else return(false);
}
/**
* 从流中加载音频数据,仅支持OGG
* @param stream 要加载数据的流
* @param size 音频数据长度
* @param aft 音频文件类型
* @return 是否加载成功
*/
bool AudioPlayer::Load(InputStream *stream,int size,AudioFileType aft)
{
if(!alGenBuffers)return(false);
if(!stream)return(false);
if(size<=0)return(false);
Clear();
if(aft<=aftNone||aft>=aftEnd)
{
LOG_ERROR(OS_TEXT("未支持的音频文件类型AudioFileType: ")+OSString(aft));
return(false);
}
else
{
audio_data=new ALbyte[size];
stream->Read(audio_data,size);
audio_data_size=size;
return Load(aft);
}
}
/**
* 从文件中加载一段音频数据
* @param filename 音频文件名称
* @param aft 音频文件类型
* @return 是否加载成功
*/
bool AudioPlayer::Load(const os_char *filename,AudioFileType aft)
{
if(!alGenBuffers)return(false);
if(!filename||!(*filename))return(false);
if(aft<=aftNone||aft>=aftEnd)
aft=CheckAudioFileType(filename);
if(aft<=aftNone||aft>=aftEnd)
{
LOG_ERROR(OS_TEXT("未知的音频文件类型AudioFile: ")+OSString(filename));
return(false);
}
OpenFileInputStream fis(filename);
return(Load(fis,fis->Available(),aft));
}
// /**
// * 从文件中加载一段音频数据
// * @param hac HAC包指针
// * @param filename 音频文件名称
// * @param aft 音频文件类型
// * @return 是否加载成功
// */
// bool AudioPlayer::Load(HAC *hac,const os_char *filename,AudioFileType aft)
// {
// if(!alGenBuffers)return(false);
//
// os_char *ext;
// Stream *stream;
// bool result;
//
// ext=strrchr(filename,u'.');
//
// LowerString(ext);
//
// if(aft<=aftNone||aft>=aftEnd)
// {
// if(strcmp(ext,u".ogg")==0)aft=aftOGG;else
// {
// PutError(u"未支持的音频文件类型AudioFileType:%d",aft);
// return(false);
// }
// }
//
// stream=hac->LoadFile(filename);
//
// if(stream)
// {
// result=Load(stream,aft);
//
// delete stream;
//
// return(result);
// }
//
// return(false);
// }
void AudioPlayer::Clear()
{
Stop();
if(decode&&audio_ptr)
decode->Close(audio_ptr);
SAFE_CLEAR_ARRAY(audio_data);
SAFE_CLEAR_ARRAY(audio_buffer);
audio_ptr=nullptr;
time=0;
}
bool AudioPlayer::GetLoop()
{
lock.Lock();
bool rv=loop;
lock.Unlock();
return(rv);
}
void AudioPlayer::SetLoop(bool val)
{
lock.Lock();
loop=val;
lock.Unlock();
}
bool AudioPlayer::ReadData(ALuint n)
{
uint size;
size=decode->Read(audio_ptr,audio_buffer,audio_buffer_size);
if(size)
{
alBufferData(n,format,audio_buffer,size,rate);
if(alLastError())return(false);
return(true);
}
return(false);
}
bool AudioPlayer::Playback()
{
if(!audio_data)return(false);
alSourceStop(source);
ClearBuffer();
decode->Restart(audio_ptr);
int count=0;
audio_buffer_count=0;
if(ReadData(buffer[0]))
{
count++;
if(ReadData(buffer[1])) //以免有些音效太短,在这里直接失败
count++;
if(ReadData(buffer[2])) //以免有些音效太短,在这里直接失败
count++;
alSourceQueueBuffers(source,count,buffer);
alSourcePlay(source);
start_time=GetDoubleTime();
ps=psPlay;
return(true);
}
else
{
ps=psExit;
return(false);
}
}
/**
* 开始播放
* @param _loop 是否循环播放
*/
void AudioPlayer::Play(bool _loop)
{
if(!audio_data)return;
lock.Lock();
loop=_loop;
if(ps==psNone||ps==psPause) //未启动线程
Start();
Playback(); //Execute执行有检测Lock所以不必担心该操作会引起线程冲突
lock.Unlock();
}
/**
* 停止播放
*/
void AudioPlayer::Stop()
{
if(!audio_data)return;
bool thread_is_live=true;
lock.Lock();
if(Thread::IsLive())
ps=psExit;
else
thread_is_live=false;
lock.Unlock();
if(thread_is_live)
Thread::WaitExit();
ps=psNone;
}
/**
* 暂停播放
*/
void AudioPlayer::Pause()
{
if(!audio_data)return;
lock.Lock();
if(ps==psPlay)
ps=psPause;
lock.Unlock();
}
/**
* 继续播放
*/
void AudioPlayer::Resume()
{
if(!audio_data)return;
lock.Lock();
if(ps==psPause)
{
ps=psPlay;
Thread::Start();
}
lock.Unlock();
}
bool AudioPlayer::UpdateBuffer()
{
int processed=0;
bool active=true;
alGetSourcei(source,AL_BUFFERS_PROCESSED,&processed); //取得处理结束的缓冲区数量
if(processed<=0)return(true);
const double cur_time=GetDoubleTime();
if(cur_time-start_time<fade_in_time) //淡入时间
{
audiosource.SetGain(((cur_time-start_time)/fade_in_time)*gain);
}
else
if(cur_time-start_time>time-fade_out_time) //淡出时间
{
audiosource.SetGain(((time-(cur_time-start_time))/fade_out_time)*gain);
}
if(auto_gain.open)
{
if(cur_time>=auto_gain.end.time)
{
auto_gain.open=false;
Gain=auto_gain.end.gain;
if(auto_gain.end.gain<=0)
ps=psExit;
}
else
{
Gain=auto_gain.start.gain+auto_gain.gap*((cur_time-auto_gain.start.time)/auto_gain.time);
}
}
while(processed--)
{
ALuint buffer;
audio_buffer_count+=audio_buffer_size;
alSourceUnqueueBuffers(source,1,&buffer); //解除一个已处理完成的缓冲区
alLastError();
active=ReadData(buffer); //解码数据到这个缓冲区
if(active)
{
alSourceQueueBuffers(source,1,&buffer); //重新将这个缓冲区加入队列
alLastError();
}
else
return(false);
}
return(true);
}
void AudioPlayer::ClearBuffer()
{
int queued;
ALuint buffer;
alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
while(queued--)
alSourceUnqueueBuffers(source, 1, &buffer);
}
bool AudioPlayer::Execute()
{
if(!audio_data)return(false);
while(true)
{
lock.Lock();
if(ps==psPlay) //被要求播放
{
if(!UpdateBuffer())
{
if(loop) //被要求循环播放
{
if(SourceState!=AL_STOPPED) //等它放完
Playback();
}
else
{
//退出
lock.Unlock();
ps=psNone;
return(false);
}
}
else
{
if(SourceState!=AL_PLAYING)
alSourcePlay(source);
}
}
else
if(ps==psPause) //被要求暂停
{
alSourcePause(source);
lock.Unlock();
return(false);
}
else
if(ps==psExit) //被要求暂停或退出
{
alSourceStop(source);
alSourcei(source,AL_BUFFER,0);
ClearBuffer();
lock.Unlock();
return(false);
}
lock.Unlock();
WaitTime(wait_time); //以让线程空出CPU时间片
}
}
double AudioPlayer::GetPlayTime()
{
if(!audio_data)return(0);
uint base=audio_buffer_count;
int off;
lock.Lock();
alGetSourcei(source,AL_BYTE_OFFSET,&off);
lock.Unlock();
return AudioDataTime(base+off,format,rate);
}
/**
* 自动调整增益
*/
void AudioPlayer::AutoGain(float target_gain,double adjust_time)
{
if(!audio_data)return;
lock.Lock();
auto_gain.start.gain=Gain;
auto_gain.start.time=GetDoubleTime();
auto_gain.end.gain=target_gain;
auto_gain.end.time=auto_gain.start.time+adjust_time;
auto_gain.time=adjust_time;
auto_gain.gap=target_gain-auto_gain.start.gain;
auto_gain.open=true;
lock.Unlock();
}
void AudioPlayer::SetFadeTime(double in,double out)
{
fade_in_time=in;
fade_out_time=out;
}
}//namespace hgl