/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_HioSoundArchive.cpp 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: $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include // #define NW_SND_DEBUG_PRINT_ENABLE namespace nw { namespace snd { HioSoundArchive::HioSoundArchive() : m_IsOpened( false ) { } HioSoundArchive::~HioSoundArchive() { Close(); } bool HioSoundArchive::Open( const char* path ) { { bool result = m_HostFile.Open( path, nn::hio::HostFile::ACCESS_MODE_READ, nn::hio::HostFile::OPEN_DISP_OPEN_EXISTING ).IsSuccess(); if ( result == false ) { NW_WARNING( false, "Cannot open file\n" ); return false; } m_IsOpened = true; } { bool result = LoadFileHeader(); if ( result == false ) { NW_WARNING( false, "Cannot load header\n" ); return false; } } std::size_t len = std::strlen( path ); for ( int i = static_cast( len ) - 1; i >= 0; i-- ) { const char ch = path[i]; if ( ch == '/' || ch == '\\' ) { char dirBuffer[ FILE_PATH_MAX ]; NW_ASSERT( i < FILE_PATH_MAX ); if ( i >= FILE_PATH_MAX ) { return false; } ut::strncpy( dirBuffer, FILE_PATH_MAX, path, static_cast( i ) ); dirBuffer[i] = '\0'; SetExternalFileRoot( dirBuffer ); break; } } return true; } void HioSoundArchive::Close() { if ( m_IsOpened ) { m_HostFile.Close(); m_ArchiveReader.Finalize(); m_IsOpened = false; } Finalize(); } io::FileStream* HioSoundArchive::OpenStream( void* buffer, int size, u32 begin, u32 length ) { if ( m_IsOpened == false ) return NULL; if ( size < sizeof( HioFileStream ) ) return NULL; HioFileStream* stream = new ( buffer ) HioFileStream( &m_HostFile, begin, length ); return stream; } io::FileStream* HioSoundArchive::OpenExtStream( void* buffer, int size, const char* extFilePath, u32 begin, u32 length ) const { if ( m_IsOpened == false ) return NULL; if ( size < sizeof( HioFileStream ) ) return NULL; HioFileStream* stream = new ( buffer ) HioFileStream( extFilePath, begin, length ); return stream; } size_t HioSoundArchive::detail_GetRequiredStreamBufferSize() const { return sizeof( HioFileStream ); } bool HioSoundArchive::LoadFileHeader() { NW_ASSERT( m_IsOpened ); const size_t headerAlignSize = static_cast( ut::RoundUp( sizeof(internal::SoundArchiveFile::FileHeader), 32 ) ); u8 headerArea[ sizeof(internal::SoundArchiveFile::FileHeader) + 32*2 ]; void* alignedBuffer = ut::RoundUp( headerArea, 32 ); s32 readSize = m_HostFile.Read( alignedBuffer, headerAlignSize ); if ( readSize != headerAlignSize ) { NW_WARNING( false, "HioSoundArchive::LoadFileHeader cannot read file.\n" ); return false; } m_ArchiveReader.Initialize( alignedBuffer ); Initialize( &m_ArchiveReader ); return true; } bool HioSoundArchive::LoadHeader( void* buffer, size_t size ) { NW_ASSERT( m_IsOpened ); const s32 infoChunkOffset = m_ArchiveReader.GetInfoBlockOffset(); const u32 infoChunkSize = m_ArchiveReader.GetInfoBlockSize(); if ( size < infoChunkSize ) { NW_WARNING( size >= infoChunkSize, "HioSoundArchive::LoadHeader buffer size is too small.\n" ); return false; } m_HostFile.Seek( infoChunkOffset, nn::hio::HostFile::SEEK_TYPE_SET ); s32 readSize = m_HostFile.Read( buffer, static_cast(infoChunkSize) ); if ( readSize != infoChunkSize ) { NW_WARNING( false, "HioSoundArchive::LoadHeader cannot read file.\n" ); return false; } m_ArchiveReader.SetInfoBlock( buffer ); #ifdef NW_SND_DEBUG_PRINT_ENABLE // デバッグ出力 { // サウンド情報 NN_LOG("### Sound INFO(%d)\n", m_ArchiveReader.GetSoundCount() ); for ( u32 i = 0; i < m_ArchiveReader.GetSoundCount(); i++ ) { // サウンド共通情報 SoundArchive::ItemId soundId = GetSoundIdFromIndex( i ); SoundArchive::SoundType type = m_ArchiveReader.GetSoundType( soundId ); SoundArchive::SoundInfo info; bool ret = m_ArchiveReader.ReadSoundInfo( soundId, &info ); NN_LOG("[%08X]?(%d) fileId(%d) playerId(0x%08X) actorId(%d) type(%d)\n", soundId, ret, info.fileId, info.playerId, info.actorPlayerId, type ); NN_LOG(" *common* volume(%d) panMode(%d) panCurve (%d)\n", info.volume, info.panMode, info.panCurve ); // 3D サウンド情報 { SoundArchive::Sound3DInfo info3d; if ( ReadSound3DInfo( soundId, &info3d ) ) { u32 flag = info3d.flags; NN_LOG(" *3D* ra(%.2f) cv(%d) df(%d) vol(%d) pr(%d) pa(%d) sp(%d) bqf(%d)\n", info3d.decayRatio, info3d.decayCurve, info3d.dopplerFactor, (flag & Sound3DInfo::FLAG_CTRL_VOLUME) > 0, (flag & Sound3DInfo::FLAG_CTRL_PRIORITY) > 0, (flag & Sound3DInfo::FLAG_CTRL_PAN) > 0, (flag & Sound3DInfo::FLAG_CTRL_SPAN) > 0, (flag & Sound3DInfo::FLAG_CTRL_FILTER) > 0 ); } else { NN_LOG(" *3D* data not found\n"); } } // サウンド別個別情報 switch ( type ) { case SoundArchive::SOUND_TYPE_SEQ: { SoundArchive::SequenceSoundInfo seqInfo; bool retDetail = m_ArchiveReader.ReadSequenceSoundInfo( soundId, &seqInfo ); NN_LOG(" *SEQ* ret(%d) ofs(%d) bnk(0x%08X,0x%08X,0x%08X,0x%08X) trk(0x%x) chPrio(%d) rPrioFix(%d)\n", retDetail, seqInfo.startOffset, seqInfo.bankIds[0], seqInfo.bankIds[1], seqInfo.bankIds[2], seqInfo.bankIds[3], seqInfo.allocateTrackFlags, seqInfo.channelPriority, seqInfo.isReleasePriorityFix ); } break; case SoundArchive::SOUND_TYPE_STRM: { SoundArchive::StreamSoundInfo strmInfo; bool retDetail = m_ArchiveReader.ReadStreamSoundInfo( soundId, &strmInfo ); NN_LOG(" *STRM* ret(%d) trk(%d) channel(%d)\n", retDetail, strmInfo.allocTrackCount, strmInfo.allocChannelCount ); } break; case SoundArchive::SOUND_TYPE_WAVE: { SoundArchive::WaveSoundInfo wsdInfo; bool retDetail = m_ArchiveReader.ReadWaveSoundInfo( soundId, &wsdInfo ); NN_LOG(" *WSD* ret(%d) index(%d) trk(0x%x) chPrio(%d) rPrioFix(%d)\n", retDetail, wsdInfo.index, wsdInfo.allocTrackCount, wsdInfo.channelPriority, wsdInfo.isReleasePriorityFix ); } break; case SoundArchive::SOUND_TYPE_INVALID: { NN_LOG("Invalid SoundType (not STRM/WSD/SEQ)\n"); } break; } } // バンク情報 NN_LOG("### BANK Info(%d)\n", m_ArchiveReader.GetBankCount() ); for ( u32 i = 0; i < m_ArchiveReader.GetBankCount(); i++ ) { SoundArchive::ItemId bankId = GetBankIdFromIndex( i ); SoundArchive::BankInfo info; bool ret = m_ArchiveReader.ReadBankInfo( bankId, &info ); NN_LOG("[%08X]?(%d) fileId(%d)\n", bankId, ret, info.fileId ); } // プレイヤー情報 NN_LOG("### PLAYER Info(%d)\n", m_ArchiveReader.GetPlayerCount() ); for ( u32 i = 0; i < m_ArchiveReader.GetPlayerCount(); i++ ) { SoundArchive::ItemId playerId = GetPlayerIdFromIndex( i ); SoundArchive::PlayerInfo info; bool ret = m_ArchiveReader.ReadPlayerInfo( playerId, &info ); NN_LOG("[%08X]?(%d) max(%d) heapSize(%d)\n", playerId, ret, info.playableSoundMax, info.playerHeapSize ); } // サウンドグループ情報 NN_LOG("### SOUND-GROUP Info(%d)\n", m_ArchiveReader.GetSoundGroupCount() ); for ( u32 i = 0; i < m_ArchiveReader.GetSoundGroupCount(); i++ ) { SoundArchive::ItemId soundGroupId = GetSoundGroupIdFromIndex( i ); SoundArchive::SoundGroupInfo info; bool ret = m_ArchiveReader.ReadSoundGroupInfo( soundGroupId, &info ); NN_LOG("[%08X]?(%d) startId(%08X) end(%08X) fileId:count(%d)", soundGroupId, ret, info.startId, info.endId, info.fileIdTable->count ); for ( u32 j = 0; j < info.fileIdTable->count; j++ ) { NN_LOG(" [%08X]", info.fileIdTable->item[j]); } NN_LOG("\n"); } // グループ情報 NN_LOG("### GROUP Info(%d)\n", m_ArchiveReader.GetGroupCount() ); for ( u32 i = 0; i < m_ArchiveReader.GetGroupCount(); i++ ) { SoundArchive::ItemId groupId = GetGroupIdFromIndex( i ); SoundArchive::GroupInfo info; bool ret = m_ArchiveReader.ReadGroupInfo( groupId, &info ); NN_LOG("[%08X]?(%d) fileId(%d)\n", groupId, ret, info.fileId ); } // 波形アーカイブ情報 NN_LOG("### WAVE-ARCHIVE Info(%d)\n", m_ArchiveReader.GetWaveArchiveCount() ); for ( u32 i = 0; i < m_ArchiveReader.GetWaveArchiveCount(); i++ ) { SoundArchive::ItemId warcId = GetWaveArchiveIdFromIndex( i ); SoundArchive::WaveArchiveInfo info; bool ret = m_ArchiveReader.ReadWaveArchiveInfo( warcId, &info ); NN_LOG("[%08X]?(%d) fileId(%d)\n", warcId, ret, info.fileId ); } // ファイル情報 NN_LOG("### FILE Info(%d)\n", m_ArchiveReader.GetFileCount() ); for ( u32 i = 0; i < m_ArchiveReader.GetFileCount(); i++ ) { SoundArchive::FileInfo info; bool ret = m_ArchiveReader.ReadFileInfo( i, &info ); if ( info.externalFilePath != NULL ) { NN_LOG("[%4d]?(%d) fileSize(%8d) ofs(%8d) path(%s)\n", i, ret, info.fileSize, info.offsetFromFileBlockHead, info.externalFilePath ); } else { NN_LOG("[%4d]?(%d) fileSize(%8d) ofs(%8d) path((null))\n", i, ret, info.fileSize, info.offsetFromFileBlockHead ); } } // サウンドアーカイブプレイヤー情報 NN_LOG("### SOUND-ARCHIVE-PLAYER Info\n"); { SoundArchive::SoundArchivePlayerInfo info; bool ret = m_ArchiveReader.ReadSoundArchivePlayerInfo( &info ); NN_LOG("sequenceSoundMax (%2d)\n", info.sequenceSoundMax ); NN_LOG("sequenceTrackMax (%2d)\n", info.sequenceTrackMax ); NN_LOG("streamSoundMax (%2d)\n", info.streamSoundMax ); NN_LOG("streamTrackMax (%2d)\n", info.streamTrackMax ); NN_LOG("streamChannelMax (%2d)\n", info.streamChannelMax ); NN_LOG("waveSoundMax (%2d)\n", info.waveSoundMax ); NN_LOG("waveTrackMax (%2d)\n", info.waveTrackMax ); } } #endif /* NW_SND_DEBUG_PRINT_ENABLE */ return true; } bool HioSoundArchive::LoadLabelStringData( void* buffer, size_t size ) { NW_ASSERT( m_IsOpened ); const s32 stringBlockOffset = m_ArchiveReader.GetStringBlockOffset(); const u32 stringBlockSize = m_ArchiveReader.GetStringBlockSize(); if ( stringBlockOffset == internal::Util::Reference::INVALID_OFFSET ) { // サウンドアーカイブの文字列ブロックが含まれていない return false; } if ( size < stringBlockSize ) { NW_WARNING( size >= stringBlockSize, "HioSoundArchive::LoadLabelStringData buffer size is too small." ); return false; } m_HostFile.Seek( stringBlockOffset, nn::hio::HostFile::SEEK_TYPE_SET ); s32 readSize = m_HostFile.Read( buffer, static_cast(stringBlockSize) ); if ( readSize != stringBlockSize ) { NW_WARNING( false, "HioSoundArchive::LoadLabelStringData cannot read file.\n" ); return false; } m_ArchiveReader.SetStringBlock( buffer ); return true; } HioSoundArchive::HioFileStream::HioFileStream( const char* path, u32 offset, u32 size ) : io::HioFileStream( path, nn::hio::HostFile::ACCESS_MODE_READ, nn::hio::HostFile::OPEN_DISP_OPEN_EXISTING ), m_Offset( static_cast( offset ) ), m_Size( size ) { NW_ASSERT( m_Size <= io::HioFileStream::GetSize() ); if ( size == 0 ) { m_Size = io::HioFileStream::GetSize(); } io::HioFileStream::Seek( m_Offset, io::FILE_STREAM_SEEK_BEGIN ); } HioSoundArchive::HioFileStream::HioFileStream( nn::hio::HostFile* openedFile, u32 offset, u32 size ) : io::HioFileStream( openedFile, nn::hio::HostFile::ACCESS_MODE_READ, false ), m_Offset( static_cast( offset ) ), m_Size( size ) { NW_ASSERT( m_Size <= io::HioFileStream::GetSize() ); if ( size == 0 ) { m_Size = io::HioFileStream::GetSize(); } io::HioFileStream::Seek( m_Offset, io::FILE_STREAM_SEEK_BEGIN ); } s32 HioSoundArchive::HioFileStream::Read( void* buf, u32 length ) { NW_ALIGN32_ASSERT( buf ); NW_ALIGN32_ASSERT( length ); u32 curPos = io::HioFileStream::Tell(); if ( curPos + length > m_Offset + m_Size ) { length = static_cast( ut::RoundUp( m_Offset + m_Size - curPos, 32 ) ); } return io::HioFileStream::Read( buf, length ); } void HioSoundArchive::HioFileStream::Seek( s32 offset, u32 origin ) { switch( origin ) { case io::FILE_STREAM_SEEK_BEGIN: offset += m_Offset; break; case io::FILE_STREAM_SEEK_CURRENT: offset += io::HioFileStream::Tell(); break; case io::FILE_STREAM_SEEK_END: offset = m_Offset + static_cast( m_Size ) - offset; break; default: NW_ASSERTMSG( false, "Unsupported Seek origin" ); return; } if ( offset < m_Offset ) { offset = m_Offset; } else if ( offset > m_Offset + static_cast( m_Size ) ) { offset = m_Offset + static_cast( m_Size ); } io::HioFileStream::Seek( offset, io::FILE_STREAM_SEEK_BEGIN ); } } // namespace nw::snd } // namespace nw