#include #include #include #include #include #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_timetime-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