/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_WaveFileReader.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: 23499 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include namespace nw { namespace snd { namespace internal { namespace { const u32 SIGNATURE_INFO_BLOCK = NW_UT_MAKE_SIGWORD( 'I', 'N', 'F', 'O' ); const u32 SIGNATURE_DATA_BLOCK = NW_UT_MAKE_SIGWORD( 'D', 'A', 'T', 'A' ); const u32 SUPPORTED_FILE_VERSION = 0x02000000; // ライブラリがサポートする最低バージョン const u32 CURRENT_FILE_VERSION = 0x02010000; // ライブラリがサポートする最新バージョン bool IsValidFileHeader( const void* waveFile ) { const ut::BinaryFileHeader& header = *reinterpret_cast( waveFile ); // シグニチャ確認 NW_ASSERTMSG( header.signature == WaveFileReader::SIGNATURE_FILE, "invalid file signature." ); if ( header.signature != WaveFileReader::SIGNATURE_FILE ) { return false; } // バージョン確認 NW_ASSERTMSG( header.version >= SUPPORTED_FILE_VERSION, "wave file is not supported version.\n" "please reconvert file using new version tools.\n" "(SUPPORTED_FILE_VERSION:0x%08x >= your version:0x%08x)\n", SUPPORTED_FILE_VERSION, header.version ); if ( header.version < SUPPORTED_FILE_VERSION ) { return false; } NW_ASSERTMSG( header.version <= CURRENT_FILE_VERSION, "wave file is not supported version.\n" "please reconvert file using new version tools.\n" "(CURRENT_FILE_VERSION:0x%08x <= your version:0x%08x)\n", CURRENT_FILE_VERSION, header.version ); if ( header.version > CURRENT_FILE_VERSION ) { return false; } return true; } } // anonymous namespace SampleFormat WaveFileReader::GetSampleFormat( u8 format ) { switch ( format ) { case WaveFile::PCM8: return SAMPLE_FORMAT_PCM_S8; case WaveFile::PCM16: return SAMPLE_FORMAT_PCM_S16; case WaveFile::DSP_ADPCM: return SAMPLE_FORMAT_DSP_ADPCM; default: NW_ASSERTMSG( false, "Unknown wave data format(%d)", format ); return SAMPLE_FORMAT_DSP_ADPCM; } } WaveFileReader::WaveFileReader( const void* waveFile ) : m_pInfoBlockBody( NULL ) { if ( ! IsValidFileHeader( waveFile ) ) return; const WaveFile::FileHeader* header = reinterpret_cast(waveFile); const WaveFile::InfoBlock* infoBlock = header->GetInfoBlock(); const WaveFile::DataBlock* dataBlock = header->GetDataBlock(); if ( infoBlock == NULL ) return; if ( dataBlock == NULL ) return; NW_ASSERT( infoBlock->header.kind == SIGNATURE_INFO_BLOCK ); NW_ASSERT( dataBlock->header.kind == SIGNATURE_DATA_BLOCK ); m_pInfoBlockBody = &infoBlock->body; m_pDataBlockBody = &dataBlock->byte; } // MEMO: 本当に必要?! // WaveFileReader::WaveFileReader( const WaveFile::InfoBlockBody* infoBlockBody ) // : m_pInfoBlockBody( infoBlockBody ) // { // } bool WaveFileReader::ReadWaveInfo( WaveInfo* info, const void* waveDataOffsetOrigin ) const { NW_ASSERT( m_pInfoBlockBody ); const SampleFormat format = GetSampleFormat( m_pInfoBlockBody->encoding ); info->sampleFormat = format; info->channelCount = m_pInfoBlockBody->GetChannelCount(); info->sampleRate = m_pInfoBlockBody->sampleRate; info->loopFlag = ( m_pInfoBlockBody->isLoop == 1 ); info->loopStartFrame = m_pInfoBlockBody->loopStartFrame; info->loopEndFrame = m_pInfoBlockBody->loopEndFrame; for ( s32 i = 0; i < m_pInfoBlockBody->GetChannelCount(); i++ ) { if ( i >= WAVE_CHANNEL_MAX ) continue; WaveInfo::ChannelParam& channelParam = info->channelParam[ i ]; const WaveFile::ChannelInfo& channelInfo = m_pInfoBlockBody->GetChannelInfo( i ); // if ( channelInfo.offsetToAdpcmInfo != 0 ) if ( channelInfo.referToAdpcmInfo.offset != 0 ) { const WaveFile::DspAdpcmInfo& adpcmInfo = channelInfo.GetDspAdpcmInfo(); channelParam.adpcmParam = adpcmInfo.adpcmParam; channelParam.adpcmLoopParam = adpcmInfo.adpcmLoopParam; } channelParam.dataAddress = GetWaveDataAddress( &channelInfo, waveDataOffsetOrigin ); } return true; } const void* WaveFileReader::GetWaveDataAddress( const WaveFile::ChannelInfo* info, const void* waveDataOffsetOrigin ) const { NW_NULL_ASSERT( m_pInfoBlockBody ); NW_NULL_ASSERT( info ); NW_UNUSED_VARIABLE( waveDataOffsetOrigin ); #if 0 const void* waveDataAddress = NULL; // dataLocationがデータブロックの先頭を指しているか(WaveFileの場合) // 波形データの先頭を指しているか(BankFile中のWaveInfoの場合) bool offsetIsDataBlock = ( waveDataOffsetOrigin == NULL ); if ( waveDataOffsetOrigin == NULL ) { waveDataOffsetOrigin = m_pInfoBlockBody; } // MEMO: バンクの波形差し替えで WAVE_DATA_LOCATION_ADDRESS を使っていた?模様。 // 今回、バンクの波形差し替えは、インストの warcID と waveIndex を // 差し替えられるようにして、対応する。 switch( m_pInfoBlockBody->dataLocationType ) { case WaveFile::WAVE_DATA_LOCATION_OFFSET: waveDataAddress = ut::AddOffsetToPtr( waveDataOffsetOrigin, m_pInfoBlockBody->dataLocation ); if ( offsetIsDataBlock ) { waveDataAddress = ut::AddOffsetToPtr( waveDataAddress, 8 ); } break; case WaveFile::WAVE_DATA_LOCATION_ADDRESS: waveDataAddress = reinterpret_cast( m_pInfoBlockBody->dataLocation ); break; default: return NULL; } waveDataAddress = ut::AddOffsetToPtr( waveDataAddress, waveChannelInfo->channelDataOffset ); return waveDataAddress; #endif return info->GetSamplesAddress( m_pDataBlockBody ); } } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw