/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_StreamSoundPlayer.h Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ /** * :include nw/snd/snd_StreamSoundPlayer.h * * @file snd_StreamSoundPlayer.h */ #ifndef NW_SND_STREAM_SOUND_PLAYER_H_ #define NW_SND_STREAM_SOUND_PLAYER_H_ #include #include #include #include #include #include #include #include namespace nw { namespace snd { //--------------------------------------------------------------------------- //! @brief ストリームデータのパラメータセットです。 //! //! この情報は @ref StreamSoundHandle::ReadStreamDataInfo から取得できます。 //! //! @see StreamSoundHandle::ReadStreamDataInfo //! //! @date 2010/03/12 誤植修正 (StearmSoundHandle → StreamSoundHandle) //! @date 2010/01/22 初版 //--------------------------------------------------------------------------- struct StreamDataInfo { //--------------------------------------------------------------------------- //! @brief ストリームデータがループするなら true、 //! 終端で終了するなら false となります。 //--------------------------------------------------------------------------- bool loopFlag; //--------------------------------------------------------------------------- //! @brief ストリームデータのサンプリングレートです。 //--------------------------------------------------------------------------- int sampleRate; //--------------------------------------------------------------------------- //! @brief ストリームデータがループする時のループ開始位置を、 //! ストリームの先頭からのサンプル数で表します。 //--------------------------------------------------------------------------- u32 loopStart; //--------------------------------------------------------------------------- //! @brief ストリームデータがループする時のループ終了位置を、 //! ストリームの先頭からのサンプル数で表します。 //! ループしない時は、データの終端をサンプル数で表します。 //! (再生される最後のサンプルの次のサンプルを指します) //--------------------------------------------------------------------------- u32 loopEnd; }; namespace internal { namespace driver { class StreamBufferPool; class StreamSoundPlayer : public BasicSoundPlayer, public SoundThread::PlayerCallback { /* ------------------------------------------------------------------------ constant definition ------------------------------------------------------------------------ */ public: // 再生できる最大ブロックサイズ static const u32 DATA_BLOCK_SIZE_MAX = 8 * 1024; static const u32 STRM_TRACK_NUM = 4; enum SetupResult { SETUP_SUCCESS = 0, SETUP_ERR_CANNOT_ALLOCATE_BUFFER, SETUP_ERR_UNKNOWN }; enum StartOffsetType { START_OFFSET_TYPE_SAMPLE, START_OFFSET_TYPE_MILLISEC }; /* ------------------------------------------------------------------------ class member ------------------------------------------------------------------------ */ StreamSoundPlayer(); virtual ~StreamSoundPlayer(); virtual void Initialize(); SetupResult Setup( StreamBufferPool* pBufferPool, u32 allocChannelCount, u16 allocTrackFlag ); virtual void Finalize(); bool Prepare( io::FileStream* pFileStream, StartOffsetType startOffsetType, int startOffset ); virtual void Start(); virtual void Stop(); virtual void Pause( bool flag ); bool IsSuspendByLoadingDelay() const { return m_LoadWaitFlag; } bool IsPrepared() const { return m_IsPrepared; } //------------------------------------------------------------------ // プレイヤーパラメータ //------------------------------------------------------------------ // トラックパラメータ void SetTrackVolume( u32 trackBitFlag, float volume ); void SetTrackPan( u32 trackBitFlag, float pan ); void SetTrackSurroundPan( u32 trackBitFlag, float span ); //------------------------------------------------------------------ // 情報取得 bool ReadStreamDataInfo( StreamDataInfo* info ) const; long GetPlayLoopCount() const { return m_ActiveFlag ? m_LoopCounter : -1; } long GetPlaySamplePosition() const; float GetFilledBufferPercentage() const; //------------------------------------------------------------------ StreamTrack* GetPlayerTrack( int trackNo ); const StreamTrack* GetPlayerTrack( int trackNo ) const; bool LoadHeader( const StreamSoundFile::StreamSoundInfo& streamInfo, const StreamSoundFileReader::TrackInfo trackInfos[], const DspAdpcmParam dspAdpcmParam[], const DspAdpcmLoopParam dspAdpcmLoopParam[], u32 dataBlockOffset, u32 trackCount, u32 channelCount ); bool LoadStreamData( int bufferBlockIndex, int dataBlockIndex, u32 blockSamples, bool isDataLoopBlock, bool lastBlockFlag ); //------------------------------------------------------------------ protected: virtual void OnUpdateFrameSoundThread() { Update(); } virtual void OnUpdateVoiceSoundThread() { UpdateBuffer(); } virtual void OnShutdownSoundThread() { Stop(); } //------------------------------------------------------------------ private: static const u32 STRM_CHANNEL_NUM = 8; static const u32 STRM_CHANNEL_NUM_PER_TRACK = 2; static const u32 BUFFER_BLOCK_COUNT_MAX = 32; // 扱えるバッファブロックの最大数 static const u32 LOAD_BUFFER_CHANNEL_NUM = 2; // 同時にロードを行うチャンネルの数 static const u32 LOAD_BUFFER_SIZE = DATA_BLOCK_SIZE_MAX * LOAD_BUFFER_CHANNEL_NUM; /* ------------------------------------------------------------------------ StreamHeaderLoadTask class ------------------------------------------------------------------------ */ class StreamHeaderLoadTask : public Task { public: StreamHeaderLoadTask(); virtual void Execute(); public: StreamSoundPlayer* m_PlayerHandle; io::FileStream* m_pFileStream; StreamSoundPlayer::StartOffsetType m_StartOffsetType; s32 m_StartOffset; private: bool LoadHeader(); }; friend class StreamHeaderLoadTask; /* ------------------------------------------------------------------------ StreamDataLoadTask class ------------------------------------------------------------------------ */ class StreamDataLoadTask : public Task { public: StreamDataLoadTask(); virtual void Execute(); public: StreamSoundPlayer* m_PlayerHandle; io::FileStream* m_pFileStream; void* m_BufferAddress[ STRM_CHANNEL_NUM ]; u32 m_ChannelCount; s32 m_Offset; size_t m_BlockBytes; s32 m_BufferBlockIndex; u32 m_BlockSamples; u32 m_DataBlockSize; u32 m_LoadingDataBlockIndex; bool m_IsDataLoopBlock; bool m_LastBlockFlag; ut::LinkListNode m_Link; private: bool LoadStreamData(); }; friend class StreamDataLoadTask; typedef ut::LinkList StreamDataLoadTaskList; bool SetupPlayer(); void Update(); void UpdateTask(); void UpdateBuffer(); void UpdateVoiceParams( StreamTrack* track ); bool AllocVoices(); void FreeVoices(); bool AllocStreamBuffers(); void FreeStreamBuffers(); void UpdatePlayingBlockIndex(); void UpdateLoadingBlockIndex(); void UpdatePauseStatus(); #ifdef NW_PLATFORM_CTRWIN void UpdateLoopAddress( unsigned long loopStartSamples, unsigned long loopEndSamples ); void UpdateDataLoopAddress( s32 endBufferBlockIndex ); void SetLoopEndToZeroBuffer( int endBufferBlockIndex ); #endif void SetAdpcmLoopContext( int channelNum, u16 predScale[] ); void* GetBuffer( int channelNum ); void SetTaskErrorFlag() { m_IsTaskError = true; } bool CheckDiskDriveError() const; int CalcLoadingBufferBlockCount() const; bool CalcStartOffset( s32* pStartBlockIndex, u32* pStartBlockOffset, s32* pLoopCount ); static void VoiceCallbackFunc( Voice* voice, Voice::VoiceCallbackStatus status, void* arg ); StreamChannel* GetTrackChannel( const StreamTrack& track, int channelIndex ); s32 CalcLoadOffset() const; bool IsDspAdpcm() const; StreamSoundFile::StreamSoundInfo m_StreamInfo; bool m_IsInitialized; // Initialize が呼ばれた bool m_IsPrepared; // 準備完了フラグ bool m_IsTaskError; // タスク実行中、エラー発生 bool m_IsLoadingDelay; // ロード遅延メッセージ bool m_PauseStatus; bool m_LoadWaitFlag; // バッファが溜まるまで、一時停止解除を遅延させる bool m_IsNoRealtimeLoad; // ストリームデータがバッファサイズより小さい時のモード bool m_SkipUpdateAdpcmLoop; bool m_ValidAdpcmLoop; bool m_PlayFinishFlag; bool m_LoadFinishFlag; s32 m_LoopCounter; int m_PrepareCounter; int m_ChangeNumBlocks; int m_DataBlockSize; u32 m_BufferBlockCount; int m_BufferBlockCountBase; // NOTE: StreamBufferPool からロード用のバッファが与えられるが、 // これを、bcstm 内の 1 ブロック (現在は 8KB で固定) に分割して利用する。 // 以下に出てくる「ブロック」とは、この 8KB で区切られたメモリ領域を指す。 int m_LoadingBufferBlockCount; // ロード用バッファ中のブロック数 int m_LoadingBufferBlockIndex; // ロード用バッファのうち、ロード中のブロックの通し番号 int m_LoadingDataBlockIndex; // 全データのうち、現在ロード中のブロックの通し番号 int m_PlayingBufferBlockCount; // 再生用ロード用バッファ中のブロック数 // NW4R の実装では、m_LoadingBufferBlockCount // と異なることがあった int m_PlayingBufferBlockIndex; // ロード用バッファ中のうち、再生中のブロックの通し番号 int m_PlayingDataBlockIndex; // 全データのうち、現在再生中のブロックの通し番号 int m_LoopStartBlockIndex; int m_LastBlockIndex; u32 m_DataOffsetFromFileHead; // ストリームファイル先頭を起点とした、 // サンプル実データまでのオフセット volatile int m_LoadWaitCount; StartOffsetType m_StartOffsetType; int m_StartOffset; StreamHeaderLoadTask m_StreamHeaderLoadTask; StreamDataLoadTaskList m_StreamDataLoadTaskList; InstancePool m_StreamDataLoadTaskPool; StreamDataLoadTask m_StreamDataLoadTaskArea[BUFFER_BLOCK_COUNT_MAX]; StreamBufferPool* m_pBufferPool; io::FileStream* m_pFileStream; s32 m_TrackCount; s32 m_ChannelCount; StreamChannel m_Channels[ STRM_CHANNEL_NUM ]; StreamTrack m_Tracks[ STRM_TRACK_NUM ]; static u8 s_LoadBuffer[ LOAD_BUFFER_SIZE ]; }; } // namespace nw::snd::internal::driver } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw #endif /* NW_SND_STREAM_SOUND_PLAYER_H_ */