/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_SoundArchivePlayer.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. 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. $Revision: 27590 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace nw { namespace snd { /*---------------------------------------------------------------------------* Name: SoundArchivePlayer Description: コンストラクタ Arguments: 無し Returns: 無し *---------------------------------------------------------------------------*/ SoundArchivePlayer::SoundArchivePlayer() : m_pSoundArchive( NULL ), m_SequenceCallback( *this ), m_WaveSoundCallback( *this ), m_SequenceUserprocCallback( NULL ), m_pSequenceUserprocCallbackArg( NULL ), m_SoundPlayerCount( 0 ), m_pSoundPlayers( NULL ), m_MmlSequenceTrackAllocator( &m_MmlParser ), m_pSetupBufferAddress( NULL ), m_SetupBufferSize( 0 ) { } /*---------------------------------------------------------------------------* Name: SoundArchivePlayer Description: デストラクタ Arguments: 無し Returns: 無し *---------------------------------------------------------------------------*/ SoundArchivePlayer::~SoundArchivePlayer() { } /*---------------------------------------------------------------------------* Name: IsAvailable Description: サウンドアーカイブプレイヤーが利用可能かどうかを調べる Arguments: 無し Returns: 利用可能かどうかを返す *---------------------------------------------------------------------------*/ bool SoundArchivePlayer::IsAvailable() const { if ( m_pSoundArchive == NULL ) return false; if ( ! m_pSoundArchive->IsAvailable() ) return false; return true; } /*---------------------------------------------------------------------------* Name: Initialize Description: サウンドアーカイブ中のプレイヤー情報にしたがって プレイヤーをセットアップする Arguments: arc - サウンドアーカイブ buffer - セットアップに使用するメモリ size - メモリサイズ aramBuffer - セットアップに使用するAメモリ aramSize - メモリサイズ Returns: セットアップに成功したらtrue *---------------------------------------------------------------------------*/ bool SoundArchivePlayer::Initialize( const SoundArchive* arc, const SoundDataManager* manager, void* buffer, u32 size, void* strmBuffer, u32 strmBufferSize ) { // サウンドシステムの初期化が必要 NW_ASSERT( SoundSystem::IsInitialized() ); if ( ! SoundSystem::IsInitialized() ) { return false; } NW_NULL_ASSERT( arc ); NW_NULL_ASSERT( manager ); NW_NULL_ASSERT( buffer ); NW_ALIGN32_ASSERT( buffer ); if ( strmBufferSize > 0 ) { NW_NULL_ASSERT( strmBuffer ); NW_ALIGN32_ASSERT( strmBuffer ); if ( ! internal::Util::IsDeviceMemory( reinterpret_cast(strmBuffer), strmBufferSize ) ) { NW_ASSERTMSG( false, "strmBuffer, strmBuffer + strmBufferSize is not Device Memory."); return false; } } NW_ASSERT( strmBufferSize >= GetRequiredStreamBufferSize( arc ) ); if ( ! SetupMram( arc, buffer, size ) ) { return false; } if ( ! SetupStreamBuffer( arc, strmBuffer, strmBufferSize ) ) { return false; } m_pSequenceTrackAllocator = &m_MmlSequenceTrackAllocator; m_pSoundDataManager = manager; return true; } /*---------------------------------------------------------------------------* Name: Finalize Description: サウンドアーカイブプレイヤーの機能を停止させる Arguments: 無し Returns: 無し *---------------------------------------------------------------------------*/ void SoundArchivePlayer::Finalize() { // 参照の破棄 m_pSoundArchive = NULL; m_pSequenceTrackAllocator = NULL; // 全サウンドの停止 for ( SoundArchive::ItemId playerId = 0; playerId < m_SoundPlayerCount ; ++playerId ) { m_pSoundPlayers[ playerId ].StopAllSound(0); } // 停止完了待ち internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance(); u32 tag = cmdmgr.FlushCommand( true ); cmdmgr.WaitCommandReply( tag ); // インスタンスの破棄 m_SoundPlayerCount = 0; m_pSoundPlayers = NULL; m_StreamBufferPool.Finalize(); if ( m_pSetupBufferAddress != NULL ) { m_SequenceSoundInstanceManager.Destroy( m_pSetupBufferAddress, m_SetupBufferSize ); m_MmlSequenceTrackAllocator.Destroy( m_pSetupBufferAddress, m_SetupBufferSize ); m_WaveSoundInstanceManager.Destroy( m_pSetupBufferAddress, m_SetupBufferSize ); m_StreamSoundInstanceManager.Destroy( m_pSetupBufferAddress, m_SetupBufferSize ); m_pSetupBufferAddress = NULL; m_SetupBufferSize = 0; } } /*---------------------------------------------------------------------------* Name: GetRequiredMemSize Description: サウンドアーカイブプレイヤーで使用するメモリサイズを取得する Arguments: arc - サウンドアーカイブ Returns: 無し *---------------------------------------------------------------------------*/ size_t SoundArchivePlayer::GetRequiredMemSize( const SoundArchive* arc ) { NW_NULL_ASSERT( arc ); size_t size = 0; // SoundPlayer { u32 playerCount = arc->GetPlayerCount(); size += ut::RoundUp( playerCount * sizeof( SoundPlayer ), 4 ); for ( u32 playerIndex = 0; playerIndex < playerCount; ++playerIndex ) { SoundArchive::PlayerInfo playerInfo; if ( ! arc->ReadPlayerInfo( internal::Util::GetMaskedItemId( playerIndex, internal::ItemType_Player ), &playerInfo ) ) { continue; } if ( playerInfo.playerHeapSize > 0 ) { for ( int i = 0; i < playerInfo.playableSoundMax ; i++ ) { size += ut::RoundUp( sizeof(internal::PlayerHeap), 4 ); size = ut::RoundUp( size, 32 ); size += ut::RoundUp( playerInfo.playerHeapSize, 4 ); } } } } SoundArchive::SoundArchivePlayerInfo soundArchivePlayerInfo; if ( arc->ReadSoundArchivePlayerInfo( &soundArchivePlayerInfo ) ) { // SequenceSound size += ut::RoundUp( m_SequenceSoundInstanceManager.GetRequiredMemSize(soundArchivePlayerInfo.sequenceSoundMax), 4 ); // WaveSound size += ut::RoundUp( m_WaveSoundInstanceManager.GetRequiredMemSize(soundArchivePlayerInfo.waveSoundMax), 4 ); // StreamSound size += ut::RoundUp( m_StreamSoundInstanceManager.GetRequiredMemSize(soundArchivePlayerInfo.streamSoundMax), 4 ); // SequenceTrack size += ut::RoundUp( soundArchivePlayerInfo.sequenceTrackMax * sizeof( internal::driver::MmlSequenceTrack ), 4 ); } return size; } /*---------------------------------------------------------------------------* Name: GetRequiredStreamBufferSize Description: サウンドアーカイブプレイヤーで使用するAメモリサイズを取得する Arguments: arc - サウンドアーカイブ Returns: 無し *---------------------------------------------------------------------------*/ size_t SoundArchivePlayer::GetRequiredStreamBufferSize( const nw::snd::SoundArchive* arc ) { NW_NULL_ASSERT( arc ); int strmChannelCount = 0; SoundArchive::SoundArchivePlayerInfo soundArchivePlayerInfo; if ( arc->ReadSoundArchivePlayerInfo( &soundArchivePlayerInfo ) ) { strmChannelCount = soundArchivePlayerInfo.streamChannelMax; } size_t memSize = static_cast( internal::driver::StreamSoundPlayer::DATA_BLOCK_SIZE_MAX * DEFAULT_STREAM_BLOCK_COUNT * strmChannelCount ); return memSize; } /*---------------------------------------------------------------------------* Name: SetupMram Description: サウンドアーカイブ中のプレイヤー情報にしたがって プレイヤーをセットアップする Arguments: arc - サウンドアーカイブ buffer - セットアップに使用するメモリ size - メモリサイズ Returns: セットアップに成功したらtrue *---------------------------------------------------------------------------*/ bool SoundArchivePlayer::SetupMram( const SoundArchive* arc, void* buffer, unsigned long size ) { NW_ASSERT( size >= GetRequiredMemSize( arc ) ); void* endp = static_cast(buffer) + size; void* buf = buffer; if ( ! SetupSoundPlayer( arc, &buf, endp ) ) { return false; } SoundArchive::SoundArchivePlayerInfo soundArchivePlayerInfo; if ( arc->ReadSoundArchivePlayerInfo( &soundArchivePlayerInfo ) ) { if ( ! SetupSequenceSound( arc, soundArchivePlayerInfo.sequenceSoundMax, &buf, endp ) ) { return false; } if ( ! SetupWaveSound( arc, soundArchivePlayerInfo.waveSoundMax, &buf, endp ) ) { return false; } if ( ! SetupStreamSound( arc, soundArchivePlayerInfo.streamSoundMax, &buf, endp ) ) { return false; } if ( ! SetupSequenceTrack( arc, soundArchivePlayerInfo.sequenceTrackMax, &buf, endp ) ) { return false; } } NW_ASSERT( static_cast(buf) - static_cast(buffer) == static_cast( GetRequiredMemSize( arc ) ) ); m_pSoundArchive = arc; m_pSetupBufferAddress = buffer; m_SetupBufferSize = size; return true; } /*---------------------------------------------------------------------------* Name: CreatePlayerHeap Description: プレイヤーヒープの作成 Arguments: heap - サウンドヒープ size - プレイヤーヒープサイズ Returns: 作成したプレイヤーヒープへのポインタ *---------------------------------------------------------------------------*/ internal::PlayerHeap* SoundArchivePlayer::CreatePlayerHeap( void** buffer, void* endp, size_t heapSize ) { // プレイヤーヒープ構造体初期化 void* ep = ut::RoundUp( ut::AddOffsetToPtr( *buffer, sizeof(internal::PlayerHeap) ), 4 ); if ( ut::ComparePtr( ep, endp ) > 0 ) { return NULL; } void* buf = *buffer; *buffer = ep; internal::PlayerHeap* playerHeap = new ( buf ) internal::PlayerHeap(); // プレイヤーヒープ構築 *buffer = ut::RoundUp( *buffer, 32 ); ep = ut::RoundUp( ut::AddOffsetToPtr( *buffer, heapSize ), 4 ); if ( ut::ComparePtr( ep, endp ) > 0 ) { return NULL; } buf = *buffer; *buffer = ep; bool result = playerHeap->Create( buf, heapSize ); if ( ! result ) { return NULL; } return playerHeap; } bool SoundArchivePlayer::SetupSoundPlayer( const SoundArchive* arc, void** buffer, void* endp ) { u32 playerCount = arc->GetPlayerCount(); size_t requireSize = playerCount * sizeof( SoundPlayer ); void* ep = ut::RoundUp( ut::AddOffsetToPtr( *buffer, requireSize ), 4 ); if ( ut::ComparePtr( ep, endp ) > 0 ) { return false; } void* buf = *buffer; *buffer = ep; // buf 上に SoundPlayer インスタンスを playerCount 個並べる m_pSoundPlayers = reinterpret_cast( buf ); m_SoundPlayerCount = playerCount; u8* ptr = static_cast( buf ); for ( u32 playerIndex = 0; playerIndex < playerCount; ++playerIndex, ptr += sizeof( SoundPlayer ) ) { SoundPlayer* player = new ( ptr ) SoundPlayer(); SoundArchive::PlayerInfo playerInfo; if ( ! arc->ReadPlayerInfo( internal::Util::GetMaskedItemId( playerIndex, internal::ItemType_Player ), &playerInfo ) ) { continue; } player->SetPlayableSoundCount( playerInfo.playableSoundMax ); // プレイヤーヒープのセットアップ if ( playerInfo.playerHeapSize > 0 ) { for ( int i = 0; i < playerInfo.playableSoundMax ; i++ ) { internal::PlayerHeap* playerHeap = CreatePlayerHeap( buffer, endp, playerInfo.playerHeapSize ); NW_WARNING( playerHeap != NULL, "failed to create player heap. ( player id = %d )", playerIndex ); if ( playerHeap == NULL ) { return false; } player->detail_AppendPlayerHeap( playerHeap ); } // プレイヤーヒープを使用する場合、 // 用意されたプレイヤーヒープ数を超える同時再生数は指定できない player->detail_SetPlayableSoundLimit( playerInfo.playableSoundMax ); } } return true; } /*---------------------------------------------------------------------------* Name: SetupSequenceSound Description: シーケンスサウンドのセットアップ Arguments: numSounds - 確保するシーケンスサウンドの数 heap - サウンドヒープ Returns: 成功したかどうか *---------------------------------------------------------------------------*/ bool SoundArchivePlayer::SetupSequenceSound( const SoundArchive* /*arc*/, int numSounds, void** buffer, void* endp ) { size_t requireSize = m_SequenceSoundInstanceManager.GetRequiredMemSize(numSounds); void* ep = ut::RoundUp( ut::AddOffsetToPtr( *buffer, requireSize ), 4 ); if ( ut::ComparePtr( ep, endp ) > 0 ) { return false; } unsigned long createNum = m_SequenceSoundInstanceManager.Create( *buffer, requireSize ); NW_ASSERT( createNum == numSounds ); *buffer = ep; return true; } /*---------------------------------------------------------------------------* Name: SetupWaveSound Description: ウェーブサウンドのセットアップ Arguments: numSounds - 確保するウェーブサウンドの数 heap - サウンドヒープ Returns: 成功したかどうか *---------------------------------------------------------------------------*/ bool SoundArchivePlayer::SetupWaveSound( const SoundArchive* /*arc*/, int numSounds, void** buffer, void* endp ) { size_t requireSize = m_WaveSoundInstanceManager.GetRequiredMemSize(numSounds); void* ep = ut::RoundUp( ut::AddOffsetToPtr( *buffer, requireSize ), 4 ); if ( ut::ComparePtr( ep, endp ) > 0 ) { return false; } unsigned long createNum = m_WaveSoundInstanceManager.Create( *buffer, requireSize ); NW_ASSERT( createNum == numSounds ); *buffer = ep; return true; } /*---------------------------------------------------------------------------* Name: SetupStreamSound Description: ストリームサウンドのセットアップ Arguments: numSounds - 確保するストリームサウンドの数 heap - サウンドヒープ Returns: 成功したかどうか *---------------------------------------------------------------------------*/ bool SoundArchivePlayer::SetupStreamSound( const SoundArchive* /*arc*/, int numSounds, void** buffer, void* endp ) { size_t requireSize = m_StreamSoundInstanceManager.GetRequiredMemSize(numSounds); void* ep = ut::RoundUp( ut::AddOffsetToPtr( *buffer, requireSize ), 4 ); if ( ut::ComparePtr( ep, endp ) > 0 ) { return false; } unsigned long createNum = m_StreamSoundInstanceManager.Create( *buffer, requireSize ); NW_ASSERT( createNum == numSounds ); *buffer = ep; return true; } /*---------------------------------------------------------------------------* Name: SetupSequenceTrack Description: シーケンスサウンドのセットアップ Arguments: numSounds - 確保するシーケンスサウンドの数 heap - サウンドヒープ Returns: 成功したかどうか *---------------------------------------------------------------------------*/ bool SoundArchivePlayer::SetupSequenceTrack( const SoundArchive* /*arc*/, int numTracks, void** buffer, void* endp ) { unsigned long requireSize = numTracks * sizeof( internal::driver::MmlSequenceTrack ); void* ep = ut::RoundUp( ut::AddOffsetToPtr( *buffer, requireSize ), 4 ); if ( ut::ComparePtr( ep, endp ) > 0 ) { return false; } unsigned long createNum = m_MmlSequenceTrackAllocator.Create( *buffer, requireSize ); NW_ASSERT( createNum == numTracks ); *buffer = ep; return true; } /*---------------------------------------------------------------------------* Name: SetupStreamBuffer Description: ストリームチャンネルのセットアップ Arguments: heap - サウンドヒープ Returns: 成功したかどうか *---------------------------------------------------------------------------*/ bool SoundArchivePlayer::SetupStreamBuffer( const SoundArchive* arc, void* buffer, unsigned long size ) { if ( size < GetRequiredStreamBufferSize( arc ) ) return false; int strmChannelCount = 0; SoundArchive::SoundArchivePlayerInfo soundArchivePlayerInfo; if ( arc->ReadSoundArchivePlayerInfo( &soundArchivePlayerInfo ) ) { strmChannelCount = soundArchivePlayerInfo.streamChannelMax; } m_StreamBufferPool.Initialize( buffer, size, strmChannelCount ); return true; } /*---------------------------------------------------------------------------* Name: Update Description: プレイヤーのフレーム処理を更新する Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void SoundArchivePlayer::Update() { for ( u32 playerIndex = 0; playerIndex < m_SoundPlayerCount; ++playerIndex ) { GetSoundPlayer( internal::Util::GetMaskedItemId( playerIndex, internal::ItemType_Player ) ).Update(); } m_SequenceSoundInstanceManager.SortPriorityList(); m_WaveSoundInstanceManager.SortPriorityList(); m_StreamSoundInstanceManager.SortPriorityList(); internal::DriverCommandManager& cmdmgr = internal::DriverCommandManager::GetInstance(); cmdmgr.RecvCommandReply(); cmdmgr.FlushCommand( false ); } const SoundArchive& SoundArchivePlayer::GetSoundArchive() const { NW_ASSERTMSG( m_pSoundArchive != NULL, "Setup is not completed." ); return *m_pSoundArchive; } SoundPlayer& SoundArchivePlayer::GetSoundPlayer( SoundArchive::ItemId playerId ) { u32 itemIndex = internal::Util::GetItemIndex( playerId ); NW_MINMAXLT_ASSERT( itemIndex, 0, m_SoundPlayerCount ); return m_pSoundPlayers[ itemIndex ]; } SoundPlayer& SoundArchivePlayer::GetSoundPlayer( const char* pStr ) { NW_NULL_ASSERT( m_pSoundArchive ); SoundArchive::ItemId playerId = m_pSoundArchive->GetItemId( pStr ); NW_ASSERT( playerId != SoundArchive::INVALID_ID ); return GetSoundPlayer( playerId ); } /*---------------------------------------------------------------------------* Name: AllocSound Description: サウンドを取得する Arguments: manager - サウンドインスタンスマネージャ soundId - サウンドID priority - プレイヤープライオリティ ambientPriority - アンビエントプライオリティ ambientArgInfo - アンビエント情報 Returns: サウンドへのポインタ。取得できなかったらNULL *---------------------------------------------------------------------------*/ template< typename Sound, typename Player > Sound* SoundArchivePlayer::AllocSound( internal::SoundInstanceManager< Sound,Player >* manager, SoundArchive::ItemId soundId, int priority, int ambientPriority, internal::BasicSound::AmbientInfo* ambientArgInfo ) { NW_NULL_ASSERT( manager ); // サウンドの確保 Sound* sound = manager->Alloc( priority, ambientPriority ); if ( sound == NULL ) return NULL; // ID設定 sound->SetId( soundId ); // アンビエント設定 if ( ambientArgInfo != NULL ) { sound->SetAmbientInfo( *ambientArgInfo ); } return sound; } const void* SoundArchivePlayer::detail_GetFileAddress( SoundArchive::FileId fileId ) const { if ( m_pSoundDataManager == NULL ) return NULL; return m_pSoundDataManager->detail_GetFileAddress( fileId ); } SoundStartable::StartResult SoundArchivePlayer::detail_SetupSound( SoundHandle* handle, u32 soundId, bool holdFlag, const StartInfo* startInfo ) { return detail_SetupSoundImpl( handle, soundId, NULL, NULL, holdFlag, startInfo ); } /*---------------------------------------------------------------------------* Name: detail_SetupSoundImpl Description: 再生の実装関数 Arguments: handle - サウンドハンドル soundId - サウンドID ambientArgInfo - 外部パラメータ actor - サウンドアクター holdFlag - ホールドサウンドフラグ Returns: 結果コード *---------------------------------------------------------------------------*/ SoundStartable::StartResult SoundArchivePlayer::detail_SetupSoundImpl( SoundHandle* handle, u32 soundId, internal::BasicSound::AmbientInfo* ambientArgInfo, SoundActor* actor, bool holdFlag, const StartInfo* startInfo ) { NW_NULL_ASSERT( handle ); if ( ! IsAvailable() ) { SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_AVAILABLE ); return result; } // サウンドハンドルを古いサウンドから切断 if ( handle->IsAttachedSound() ) { handle->DetachSound(); } // サウンドアーカイブからサウンド情報の取得 SoundArchive::SoundInfo soundInfo; if ( ! m_pSoundArchive->ReadSoundInfo( soundId, &soundInfo ) ) { SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_INVALID_SOUNDID ); return result; } // StartInfoの処理 SoundStartable::StartInfo::StartOffsetType startOffsetType = SoundStartable::StartInfo::START_OFFSET_TYPE_MILLISEC; int startOffset = 0; int playerPriority = soundInfo.playerPriority; SoundArchive::ItemId playerId = soundInfo.playerId; int actorPlayerId = soundInfo.actorPlayerId; const SoundStartable::StartInfo::SeqSoundInfo* seqInfo = NULL; if ( startInfo != NULL ) { if ( startInfo->enableFlag & StartInfo::ENABLE_START_OFFSET ) { startOffsetType = startInfo->startOffsetType; startOffset = startInfo->startOffset; } if ( startInfo->enableFlag & StartInfo::ENABLE_PLAYER_PRIORITY ) { playerPriority = startInfo->playerPriority; } if ( startInfo->enableFlag & StartInfo::ENABLE_PLAYER_ID ) { playerId = startInfo->playerId; } if ( startInfo->enableFlag & StartInfo::ENABLE_ACTOR_PLAYER_ID ) { actorPlayerId = startInfo->actorPlayerId; } if ( startInfo->enableFlag & StartInfo::ENABLE_SEQ_SOUND_INFO ) { seqInfo = &startInfo->seqSoundInfo; } } // プライオリティの計算 int priority = playerPriority; if ( holdFlag ) --priority; // HoldSoundで再生するときは同プライオリティで先着優先 int ambientPriority = 0; if ( ambientArgInfo != NULL ) { ambientPriority = internal::BasicSound::GetAmbientPriority( *ambientArgInfo, soundId ); } int allocPriority = priority + ambientPriority; allocPriority = ut::Clamp( allocPriority, internal::BasicSound::PRIORITY_MIN, internal::BasicSound::PRIORITY_MAX ); // ExternalSoundPlayer internal::ExternalSoundPlayer* extPlayer = NULL; if ( actor != NULL ) { extPlayer = actor->detail_GetActorPlayer( actorPlayerId ); if ( extPlayer == NULL ) { NW_WARNING( false, "actorPlayerId(%d) is out of range. (0-%d)", actorPlayerId, SoundActor::ACTOR_PLAYER_COUNT-1 ); return StartResult::START_ERR_INVALID_PARAMETER; } } // プレイヤーの空きをチェック SoundPlayer& player = GetSoundPlayer( playerId ); if ( ! player.detail_CanPlaySound( allocPriority ) ) { return StartResult::START_ERR_LOW_PRIORITY; } if ( ( extPlayer != NULL ) && ( ! extPlayer->detail_CanPlaySound( allocPriority ) ) ) { return StartResult::START_ERR_LOW_PRIORITY; } // サウンドのアロケート internal::BasicSound* sound = NULL; internal::SequenceSound* seqSound = NULL; internal::StreamSound* strmSound = NULL; internal::WaveSound* waveSound = NULL; switch ( m_pSoundArchive->GetSoundType( soundId ) ) { case SoundArchive::SOUND_TYPE_SEQ: seqSound = AllocSound( &m_SequenceSoundInstanceManager, soundId, priority, ambientPriority, ambientArgInfo ); if ( seqSound == NULL ) { NW_WARNING( ! internal::Debug_GetWarningFlag( DEBUG_WARNING_NOT_ENOUGH_SEQSOUND ), "Failed to start sound (id:%d) for not enough SequenceSound instance.", soundId ); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_ENOUGH_INSTANCE ); return result; } sound = seqSound; break; case SoundArchive::SOUND_TYPE_STRM: strmSound = AllocSound( &m_StreamSoundInstanceManager, soundId, priority, ambientPriority, ambientArgInfo ); if ( strmSound == NULL ) { NW_WARNING( ! internal::Debug_GetWarningFlag( DEBUG_WARNING_NOT_ENOUGH_STRMSOUND ), "Failed to start sound (id:%d) for not enough StreamSound instance.", soundId ); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_ENOUGH_INSTANCE ); return result; } sound = strmSound; break; case SoundArchive::SOUND_TYPE_WAVE: waveSound = AllocSound( &m_WaveSoundInstanceManager, soundId, priority, ambientPriority, ambientArgInfo ); if ( waveSound == NULL ) { NW_WARNING( ! internal::Debug_GetWarningFlag( DEBUG_WARNING_NOT_ENOUGH_WAVESOUND ), "Failed to start sound (id:%d) for not enough WaveSound instance.", soundId ); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_ENOUGH_INSTANCE ); return result; } sound = waveSound; break; default: { SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_INVALID_SOUNDID ); return result; } } // サウンドプレイヤーに登録 if ( ! player.detail_AppendSound( sound ) ) { sound->Finalize(); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_UNKNOWN ); return result; } // フロントバイパス設定 sound->SetFrontBypass( soundInfo.isFrontBypass ); // サウンドのプリペア switch ( m_pSoundArchive->GetSoundType( soundId ) ) { case SoundArchive::SOUND_TYPE_SEQ: { NW_NULL_ASSERT( seqSound ); // プレイヤーヒープの確保 (void)player.detail_AllocPlayerHeap( seqSound ); // シーケンスサウンド情報の取得 SoundArchive::SequenceSoundInfo info; if ( ! m_pSoundArchive->ReadSequenceSoundInfo( soundId, &info ) ) { seqSound->Finalize(); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_INVALID_SOUNDID ); return result; } // バンクの上書き (必要であれば) if ( seqInfo != NULL ) { for ( int i = 0; i < SoundArchive::SEQ_BANK_MAX; i++ ) { SoundArchive::ItemId bankId = seqInfo->bankIds[ i ]; if ( bankId != SoundArchive::INVALID_ID ) { info.bankIds[ i ] = seqInfo->bankIds[ i ]; } } } // シーケンスサウンドの準備 StartResult result = PrepareSeqImpl( seqSound, &soundInfo, &info, startOffsetType, startOffset, seqInfo ); if ( ! result.IsSuccess() ) { seqSound->Finalize(); return result; } break; } case SoundArchive::SOUND_TYPE_STRM: { NW_NULL_ASSERT( strmSound ); // ストリームサウンド情報の取得 SoundArchive::StreamSoundInfo info; if ( ! m_pSoundArchive->detail_ReadStreamSoundInfo( soundId, &info ) ) { strmSound->Finalize(); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_INVALID_SOUNDID ); return result; } // ストリームサウンドの準備 StartResult result = PrepareStreamImpl( strmSound, &soundInfo, &info, startOffsetType, startOffset ); if ( ! result.IsSuccess() ) { strmSound->Finalize(); return result; } break; } case SoundArchive::SOUND_TYPE_WAVE: { NW_NULL_ASSERT( waveSound ); // ウェーブサウンド情報の取得 SoundArchive::WaveSoundInfo info; if ( ! m_pSoundArchive->detail_ReadWaveSoundInfo( soundId, &info ) ) { waveSound->Finalize(); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_INVALID_SOUNDID ); return result; } // ウェーブサウンドの準備 StartResult result = PrepareWaveSoundImpl( waveSound, &soundInfo, &info, startOffsetType, startOffset ); if ( ! result.IsSuccess() ) { waveSound->Finalize(); return result; } break; } default: NW_ASSERT( false ); sound->Finalize(); { return StartResult::START_ERR_INVALID_SOUNDID; } } // 外部プレイヤーに登録 if ( extPlayer != NULL ) { if ( ! extPlayer->AppendSound( sound ) ) { sound->Finalize(); return StartResult::START_ERR_UNKNOWN; } } // アクターに登録 if ( actor != NULL ) { sound->AttachSoundActor( actor ); } // プライオリティの再設定 if ( holdFlag ) { sound->SetPlayerPriority( playerPriority ); } // サウンドハンドルを確保したサウンドと接続 handle->detail_AttachSound( sound ); SoundStartable::StartResult result( SoundStartable::StartResult::START_SUCCESS ); return result; } /*---------------------------------------------------------------------------* Name: PrepareSeqImpl Description: シーケンスを再生 Arguments: playerId - プレイヤー番号 playerPrio - プレイヤープライオリティ info - シーケンス情報構造体のポインタ seqId - シーケンス番号 Returns: 成功したかどうか *---------------------------------------------------------------------------*/ SoundStartable::StartResult SoundArchivePlayer::PrepareSeqImpl( internal::SequenceSound* sound, const SoundArchive::SoundInfo* commonInfo, const SoundArchive::SequenceSoundInfo* info, SoundStartable::StartInfo::StartOffsetType startOffsetType, int startOffset, const StartInfo::SeqSoundInfo* externalSeqInfo ) { NW_NULL_ASSERT( info ); const internal::SequenceSoundFile* seqFile = NULL; io::FileStream* fileStream = NULL; u32 seqOffset = 0; u32 allocTrack = info->allocateTrackFlags; if ( externalSeqInfo != NULL ) { if ( externalSeqInfo->seqDataAddress != NULL ) { seqFile = reinterpret_cast( externalSeqInfo->seqDataAddress ); seqOffset = 0; internal::SequenceSoundFileReader seqFileReader( seqFile ); if ( externalSeqInfo->startLocationLabel != NULL ) { bool result = seqFileReader.GetOffsetByLabel( externalSeqInfo->startLocationLabel, &seqOffset ); if ( ! result ) { SoundStartable::StartResult startResult( SoundStartable::StartResult::START_ERR_INVALID_SEQ_START_LOCATION_LABEL); return startResult; } } seqOffset = internal::driver::MmlParser::ParseAllocTrack( seqFileReader.GetSequenceData(), seqOffset, &allocTrack ); } } // 外部データが指定されていなかったら // サウンドアーカイブ中のシーケンスデータを使用する if ( seqFile == NULL ) { seqFile = reinterpret_cast ( m_pSoundDataManager->detail_GetFileAddress( commonInfo->fileId ) ); seqOffset = info->startOffset; if ( externalSeqInfo != NULL && externalSeqInfo->startLocationLabel != NULL ) { // TODO: seqFile がロードされていなかったらどうなる? 090730 internal::SequenceSoundFileReader seqFileReader( seqFile ); bool result = seqFileReader.GetOffsetByLabel( externalSeqInfo->startLocationLabel, &seqOffset ); if ( ! result ) { SoundStartable::StartResult startResult( SoundStartable::StartResult::START_ERR_INVALID_SEQ_START_LOCATION_LABEL ); return startResult; } } } // データがロードされていないのでプレイヤーヒープにロードできるかを確認する if ( seqFile == NULL ) { // プレイヤーヒープがあるか internal::PlayerHeap* pPlayerHeap = sound->GetPlayerHeap(); if ( pPlayerHeap == NULL ) { SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_SEQ_LOADED ); return result; } void* fileStreamBuffer = sound->GetFileStreamBuffer(); NW_NULL_ASSERT( fileStreamBuffer ); size_t fileStreamBufferSize = sound->GetFileStreamBufferSize(); fileStream = const_cast(m_pSoundArchive)->detail_OpenFileStream( commonInfo->fileId, fileStreamBuffer, fileStreamBufferSize ); if ( fileStream == NULL ) { SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_CANNOT_OPEN_FILE ); return result; } // プレイヤーヒープにデータをロードできるかどうか if ( pPlayerHeap->GetFreeSize() < fileStream->GetSize() ) { fileStream->Close(); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_ENOUGH_PLAYER_HEAP ); return result; } } SoundArchive::ItemId bankIds[ SoundArchive::SEQ_BANK_MAX ]; const void* bankFiles[ SoundArchive::SEQ_BANK_MAX ] = { NULL }; if ( externalSeqInfo != NULL ) { for ( int i = 0; i < SoundArchive::SEQ_BANK_MAX; i++ ) { bankIds[ i ] = externalSeqInfo->bankIds[ i ]; } } else { for ( int i = 0; i < SoundArchive::SEQ_BANK_MAX; i++ ) { bankIds[ i ] = info->bankIds[ i ]; } } // バンクがロード済みか? for ( int i = 0; i < SoundArchive::SEQ_BANK_MAX; i++ ) { if ( bankIds[ i ] != SoundArchive::INVALID_ID ) { SoundArchive::BankInfo bankInfo; bool isReadBank = GetSoundArchive().ReadBankInfo( bankIds[ i ], &bankInfo ); NW_ASSERTMSG( isReadBank, "invalid bank id(%d)", bankIds[ i ] ); const void* bankFile = m_pSoundDataManager->detail_GetFileAddress( bankInfo.fileId ); bankFiles[ i ] = bankFile; if ( bankFile == NULL ) { // return START_ERR_NOT_BANK_LOADED; // TODO: 失敗とすべきか? // 失敗とできるなら、スタート時のバンク切替で // アドレスをセットできる。 SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_BANK_LOADED ); return result; } // 波形アーカイブがロード済みか? (MEMO: 不要かも) { // TODO: bankFile を解析する } } } // プレイヤーのセットアップ #if 0 internal::driver::SequenceSoundPlayer::SetupResult result = sound->Initialize( m_pSequenceTrackAllocator, allocTrack, &m_SequenceCallback, bankFiles ); while ( result != internal::driver::SequenceSoundPlayer::SETUP_SUCCESS ) { if ( result == internal::driver::SequenceSoundPlayer::SETUP_ERR_CANNOT_ALLOCATE_TRACK ) { // トラックが足りない if ( m_SequenceSoundInstanceManager.GetActiveCount() == 1 ) { // ほかにサウンドを再生していないのにトラックが足りない if ( fileStream != NULL ) { fileStream->Close(); } NW_WARNING( ! internal::Debug_GetWarningFlag( DEBUG_WARNING_NOT_ENOUGH_SEQTRACK ), "Failed to start sound (id:%d) for not enough SequenceTrack instance.", sound->GetId() ); SoundStartable::StartResult startResult( SoundStartable::StartResult::START_ERR_NOT_ENOUGH_INSTANCE ); return startResult; } internal::SequenceSound* lowest = m_SequenceSoundInstanceManager.GetLowestPrioritySound(); if ( sound == lowest ) { // 自分が一番プライオリティが低い if ( fileStream != NULL ) { fileStream->Close(); } NW_WARNING( ! internal::Debug_GetWarningFlag( DEBUG_WARNING_NOT_ENOUGH_SEQTRACK ), "Failed to start sound (id:%d) for not enough SequenceTrack instance.", sound->GetId() ); SoundStartable::StartResult startResult( SoundStartable::StartResult::START_ERR_NOT_ENOUGH_INSTANCE ); return startResult; } // もう一度 Setup NW_WARNING( ! internal::Debug_GetWarningFlag( DEBUG_WARNING_NOT_ENOUGH_SEQTRACK ), "Sound (id:%d) is stopped for not enough SequenceTrack instance.", lowest->GetId() ); lowest->Stop( 0 ); result = sound->Initialize( m_pSequenceTrackAllocator, allocTrack, &m_SequenceCallback, bankFiles ); } else { SoundStartable::StartResult startResult( SoundStartable::StartResult::START_ERR_UNKNOWN ); return startResult; } } #else // トラックが足りない時のケア無し sound->Setup( m_pSequenceTrackAllocator, allocTrack, &m_SequenceCallback, bankFiles, SoundArchive::SEQ_BANK_MAX ); #endif // パラメータ設定 UpdateCommonSoundParam( sound, commonInfo ); sound->SetChannelPriority( info->channelPriority ); sound->SetReleasePriorityFix( info->isReleasePriorityFix ); sound->SetSequenceUserprocCallback( m_SequenceUserprocCallback, m_pSequenceUserprocCallbackArg ); internal::driver::SequenceSoundPlayer::OffsetType seqOffsetType; switch ( startOffsetType ) { case SoundStartable::StartInfo::START_OFFSET_TYPE_MILLISEC: seqOffsetType = internal::driver::SequenceSoundPlayer::OFFSET_TYPE_MILLISEC; break; case SoundStartable::StartInfo::START_OFFSET_TYPE_TICK: seqOffsetType = internal::driver::SequenceSoundPlayer::OFFSET_TYPE_TICK; break; case SoundStartable::StartInfo::START_OFFSET_TYPE_SAMPLE: seqOffsetType = internal::driver::SequenceSoundPlayer::OFFSET_TYPE_TICK; startOffset = 0; break; default: seqOffsetType = internal::driver::SequenceSoundPlayer::OFFSET_TYPE_TICK; startOffset = 0; break; } if ( seqFile != NULL ) { // ロード済みのシーケンスデータを使ってプリペア internal::SequenceSoundFileReader seqFileReader( seqFile ); sound->Prepare( seqFileReader.GetSequenceData(), static_cast( seqOffset ), seqOffsetType, startOffset ); } else { // プレイヤーヒープにデータをロードしてプリペア sound->Prepare( fileStream, static_cast( seqOffset ), seqOffsetType, startOffset ); } SoundStartable::StartResult startResult( SoundStartable::StartResult::START_SUCCESS ); return startResult; } /*---------------------------------------------------------------------------* Name: PrepareStreamImpl Description: ストリームを再生 Arguments: playerId - プレイヤー番号 playerPrio - プレイヤープライオリティ info - ストリームの情報 strmId - ストリーム番号 Returns: 成功したかどうか *---------------------------------------------------------------------------*/ SoundStartable::StartResult SoundArchivePlayer::PrepareStreamImpl( internal::StreamSound* sound, const SoundArchive::SoundInfo* commonInfo, const SoundArchive::StreamSoundInfo* info, SoundStartable::StartInfo::StartOffsetType startOffsetType, int startOffset ) { // プレイヤーのセットアップ #if 0 internal::driver::StreamSoundPlayer::SetupResult setupResult = sound->Initialize( &m_StreamBufferPool, info->allocChannelCount, info->allocTrackCount ); while ( setupResult != internal::driver::StreamSoundPlayer::SETUP_SUCCESS ) { if ( setupResult == internal::driver::StreamSoundPlayer::SETUP_ERR_CANNOT_ALLOCATE_BUFFER ) { // バッファが足りない if ( m_StreamSoundInstanceManager.GetActiveCount() == 1 ) { // ほかにサウンドを再生していないのにバッファが足りない NW_WARNING( ! internal::Debug_GetWarningFlag( DEBUG_WARNING_NOT_ENOUGH_SEQTRACK ), "Failed to start sound (id:%d) for not enough StrmChannel instance.", sound->GetId() ); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_ENOUGH_INSTANCE ); return result; } internal::StreamSound* lowest = m_StreamSoundInstanceManager.GetLowestPrioritySound(); if ( sound == lowest ) { // 自分が一番プライオリティが低い NW_WARNING( ! internal::Debug_GetWarningFlag( DEBUG_WARNING_NOT_ENOUGH_SEQTRACK ), "Failed to start sound (id:%d) for not enough StrmChannel instance.", sound->GetId() ); SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_ENOUGH_INSTANCE ); return result; } // もう一度 Initialize NW_WARNING( ! internal::Debug_GetWarningFlag( DEBUG_WARNING_NOT_ENOUGH_STRMCHANNEL ), "Sound (id:%d) is stopped for not enough StrmChannel instance.", lowest->GetId() ); lowest->Stop( 0 ); setupResult = sound->Initialize( &m_StreamBufferPool, info->allocChannelCount, info->allocTrackCount ); } else { SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_UNKNOWN ); return result; } } #else // 再生失敗時のケア無し sound->Setup( &m_StreamBufferPool, info->allocChannelCount, info->allocTrackCount ); #endif // プリペア internal::driver::StreamSoundPlayer::StartOffsetType strmStartOffsetType; switch ( startOffsetType ) { case SoundStartable::StartInfo::START_OFFSET_TYPE_MILLISEC: strmStartOffsetType = internal::driver::StreamSoundPlayer::START_OFFSET_TYPE_MILLISEC; break; case SoundStartable::StartInfo::START_OFFSET_TYPE_TICK: strmStartOffsetType = internal::driver::StreamSoundPlayer::START_OFFSET_TYPE_SAMPLE; startOffset = 0; break; case SoundStartable::StartInfo::START_OFFSET_TYPE_SAMPLE: strmStartOffsetType = internal::driver::StreamSoundPlayer::START_OFFSET_TYPE_SAMPLE; break; default: strmStartOffsetType = internal::driver::StreamSoundPlayer::START_OFFSET_TYPE_SAMPLE; startOffset = 0; break; } void* fileStreamBuffer = sound->GetFileStreamBuffer(); NW_NULL_ASSERT( fileStreamBuffer ); long fileStreamBufferSize = sound->GetFileStreamBufferSize(); io::FileStream* fileStream = const_cast(m_pSoundArchive)->detail_OpenFileStream( commonInfo->fileId, fileStreamBuffer, fileStreamBufferSize ); if ( fileStream == NULL ) { SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_CANNOT_OPEN_FILE ); return result; } sound->Prepare( strmStartOffsetType, startOffset, fileStream ); // パラメータ設定 UpdateCommonSoundParam( sound, commonInfo ); SoundStartable::StartResult startResult( SoundStartable::StartResult::START_SUCCESS ); return startResult; } /*---------------------------------------------------------------------------* Name: PrepareWaveSoundImpl Description: ウェーブサウンドを再生 Arguments: playerId - プレイヤー番号 bankId - バンク番号 playerPrio - プレイヤープライオリティ info - シーケンス情報構造体のポインタ seqId - シーケンス番号 Returns: 成功したかどうか *---------------------------------------------------------------------------*/ SoundStartable::StartResult SoundArchivePlayer::PrepareWaveSoundImpl( internal::WaveSound* sound, const SoundArchive::SoundInfo* commonInfo, const SoundArchive::WaveSoundInfo* info, SoundStartable::StartInfo::StartOffsetType startOffsetType, int startOffset ) { NW_NULL_ASSERT( info ); // データの取得 const void* wsdData = m_pSoundDataManager->detail_GetFileAddress( commonInfo->fileId ); if ( wsdData == NULL ) { // return START_ERR_NOT_DATA_LOADED; // return START_ERR_NOT_WSD_LOADED; SoundStartable::StartResult result( SoundStartable::StartResult::START_ERR_NOT_WSD_LOADED ); return result; } internal::driver::WaveSoundPlayer::StartOffsetType wsdStartOffsetType; switch ( startOffsetType ) { case SoundStartable::StartInfo::START_OFFSET_TYPE_MILLISEC: wsdStartOffsetType = internal::driver::WaveSoundPlayer::START_OFFSET_TYPE_MILLISEC; break; case SoundStartable::StartInfo::START_OFFSET_TYPE_TICK: wsdStartOffsetType = internal::driver::WaveSoundPlayer::START_OFFSET_TYPE_SAMPLE; startOffset = 0; break; case SoundStartable::StartInfo::START_OFFSET_TYPE_SAMPLE: wsdStartOffsetType = internal::driver::WaveSoundPlayer::START_OFFSET_TYPE_SAMPLE; break; default: wsdStartOffsetType = internal::driver::WaveSoundPlayer::START_OFFSET_TYPE_SAMPLE; startOffset = 0; break; } // プリペア sound->Prepare( wsdData, info->index, wsdStartOffsetType, startOffset, &m_WaveSoundCallback, commonInfo->fileId ); // パラメータ設定 UpdateCommonSoundParam( sound, commonInfo ); sound->SetChannelPriority( info->channelPriority ); sound->SetReleasePriorityFix( info->isReleasePriorityFix ); SoundStartable::StartResult startResult( SoundStartable::StartResult::START_SUCCESS ); return startResult; } /*---------------------------------------------------------------------------* Name: UpdateCommonSoundParam Description: サウンド共通パラメータの更新 Arguments: sound - 更新対象のサウンド commonInfo - サウンド共通パラメータ Returns: None. *---------------------------------------------------------------------------*/ void SoundArchivePlayer::UpdateCommonSoundParam( internal::BasicSound* sound, const SoundArchive::SoundInfo* commonInfo ) { NW_NULL_ASSERT(sound); NW_NULL_ASSERT(commonInfo); sound->SetInitialVolume( static_cast( commonInfo->volume ) / 127.0f ); sound->SetPanMode( commonInfo->panMode ); sound->SetPanCurve( commonInfo->panCurve ); } /*---------------------------------------------------------------------------* Name: SetSequenceUserprocCallback Description: シーケンスコマンド'userproc'で呼び出されるコールバックを登録する Arguments: callback - コールバック arg - コールバック引数 Returns: *---------------------------------------------------------------------------*/ void SoundArchivePlayer::SetSequenceUserprocCallback( SequenceUserprocCallback callback, void* callbackArg ) { m_SequenceUserprocCallback = callback; m_pSequenceUserprocCallbackArg = callbackArg; } /*---------------------------------------------------------------------------* Name: NoteOn Description: シーケンスサウンドのノートオン処理 Arguments: Returns: None. *---------------------------------------------------------------------------*/ internal::driver::Channel* SoundArchivePlayer::SequenceNoteOnCallback::NoteOn( internal::driver::SequenceSoundPlayer* seqPlayer, u8 bankIndex, const internal::driver::NoteOnInfo& noteOnInfo ) { if ( ! m_pSoundArchivePlayer.IsAvailable() ) return NULL; const SoundArchive& sndArc = m_pSoundArchivePlayer.GetSoundArchive(); // 当該ノートに該当する波形アーカイブ ID・波形アーカイブ内インデックス取得 const void* bankFile = seqPlayer->GetBankFile( bankIndex ); internal::driver::Bank bank; internal::driver::Channel* channel = bank.NoteOn( bankFile, noteOnInfo, sndArc, m_pSoundArchivePlayer ); internal::driver::SoundThread::GetInstance().IncrNoteOnCount(); return channel; } /* ======================================================================== SoundArchivePlayer::WaveSoundCallback class ======================================================================== */ /*---------------------------------------------------------------------------* Name: GetWaveSoundData Description: ウェーブサウンドの波形取得処理 Arguments: Returns: None. *---------------------------------------------------------------------------*/ bool SoundArchivePlayer::WaveSoundCallback::GetWaveSoundData( internal::WaveSoundInfo* info, internal::WaveSoundNoteInfo* noteInfo, internal::WaveInfo* waveInfo, const void* waveSoundData, // メモリに展開されたウェーブサウンドセットファイル int index, // ウェーブサウンドセットファイル内でのインデックス int noteIndex, // 現状ではつねにゼロ u32 // userData // SoundArchivePlayer::PrepareWaveSoundImpl にて fileId が入るが、 // CTR では不要 ) const { // const u32 fileID = userData; if ( ! m_pSoundArchivePlayer.IsAvailable() ) { return false; } // ウェーブサウンド情報および、ノート情報を取得 { internal::WaveSoundFileReader reader( waveSoundData ); if ( ! reader.ReadWaveSoundInfo( info, index ) ) { return false; } if ( ! reader.ReadNoteInfo( noteInfo, index, noteIndex ) ) { return false; } } // 波形アーカイブ取得 const SoundArchive& sndArc = m_pSoundArchivePlayer.GetSoundArchive(); #if 0 // 不要? (Util::GetWaveFile で波形アーカイブのロード確認をしているので) { SoundArchive::WaveArchiveInfo warcInfo; if ( ! sndArc.ReadWaveArchiveInfo( noteInfo->waveArchiveId, &warcInfo ) ) { return false; } const void* warcFile = m_pSoundArchivePlayer.detail_GetFileAddress( warcInfo.fileId ); NW_WARNING( warcFile, "WSD failed - warc(%d) is not loaded", noteInfo->waveArchiveId ); if ( warcFile == NULL ) { return false; } } #endif // 波形ファイル取得 const void* waveFile = internal::Util::GetWaveFile( noteInfo->waveArchiveId, noteInfo->waveIndex, sndArc, m_pSoundArchivePlayer ); if ( waveFile == NULL ) { return false; } // 波形ファイル情報取得 { internal::WaveFileReader reader( waveFile ); if ( ! reader.ReadWaveInfo( waveInfo ) ) { return false; } } return true; } } // namespace nw::snd } // namespace nw