1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_HioSoundArchive.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: $
16  *---------------------------------------------------------------------------*/
17 
18 #include "precompiled.h"
19 
20 #include <nw/snd/snd_HioSoundArchive.h>
21 
22 // #define NW_SND_DEBUG_PRINT_ENABLE
23 
24 namespace nw {
25 namespace snd {
26 
HioSoundArchive()27 HioSoundArchive::HioSoundArchive()
28 : m_IsOpened( false )
29 {
30 }
31 
~HioSoundArchive()32 HioSoundArchive::~HioSoundArchive()
33 {
34     Close();
35 }
36 
Open(const char * path)37 bool HioSoundArchive::Open( const char* path )
38 {
39     {
40         bool result = m_HostFile.Open(
41                 path,
42                 nn::hio::HostFile::ACCESS_MODE_READ,
43                 nn::hio::HostFile::OPEN_DISP_OPEN_EXISTING ).IsSuccess();
44         if ( result == false )
45         {
46             NW_WARNING( false, "Cannot open file\n" );
47             return false;
48         }
49         m_IsOpened = true;
50     }
51 
52     {
53         bool result = LoadFileHeader();
54         if ( result == false )
55         {
56             NW_WARNING( false, "Cannot load header\n" );
57             return false;
58         }
59     }
60 
61     std::size_t len = std::strlen( path );
62     for ( int i = static_cast<int>( len ) - 1; i >= 0; i-- )
63     {
64         const char ch = path[i];
65         if ( ch == '/' || ch == '\\' )
66         {
67             char dirBuffer[ FILE_PATH_MAX ];
68             NW_ASSERT( i < FILE_PATH_MAX );
69             if ( i >= FILE_PATH_MAX )
70             {
71                 return false;
72             }
73 
74             ut::strncpy( dirBuffer, FILE_PATH_MAX, path, static_cast<u32>( i ) );
75             dirBuffer[i] = '\0';
76             SetExternalFileRoot( dirBuffer );
77             break;
78         }
79     }
80     return true;
81 }
82 
Close()83 void HioSoundArchive::Close()
84 {
85     if ( m_IsOpened )
86     {
87         m_HostFile.Close();
88         m_ArchiveReader.Finalize();
89         m_IsOpened = false;
90     }
91     Finalize();
92 }
93 
OpenStream(void * buffer,int size,u32 begin,u32 length)94 io::FileStream* HioSoundArchive::OpenStream(
95         void* buffer,
96         int size,
97         u32 begin,
98         u32 length )
99 {
100     if ( m_IsOpened == false ) return NULL;
101     if ( size < sizeof( HioFileStream ) ) return NULL;
102     HioFileStream* stream = new ( buffer ) HioFileStream( &m_HostFile, begin, length );
103     return stream;
104 }
105 
OpenExtStream(void * buffer,int size,const char * extFilePath,u32 begin,u32 length) const106 io::FileStream* HioSoundArchive::OpenExtStream(
107         void* buffer,
108         int size,
109         const char* extFilePath,
110         u32 begin,
111         u32 length ) const
112 {
113     if ( m_IsOpened == false ) return NULL;
114     if ( size < sizeof( HioFileStream ) ) return NULL;
115     HioFileStream* stream = new ( buffer ) HioFileStream( extFilePath, begin, length );
116     return stream;
117 }
118 
detail_GetRequiredStreamBufferSize() const119 size_t HioSoundArchive::detail_GetRequiredStreamBufferSize() const
120 {
121     return sizeof( HioFileStream );
122 }
123 
LoadFileHeader()124 bool HioSoundArchive::LoadFileHeader()
125 {
126     NW_ASSERT( m_IsOpened );
127 
128     const size_t headerAlignSize = static_cast<size_t>(
129             ut::RoundUp( sizeof(internal::SoundArchiveFile::FileHeader), 32 ) );
130     u8 headerArea[ sizeof(internal::SoundArchiveFile::FileHeader) + 32*2 ];
131     void* alignedBuffer = ut::RoundUp( headerArea, 32 );
132 
133     s32 readSize = m_HostFile.Read( alignedBuffer, headerAlignSize );
134     if ( readSize != headerAlignSize )
135     {
136         NW_WARNING( false, "HioSoundArchive::LoadFileHeader cannot read file.\n" );
137         return false;
138     }
139     m_ArchiveReader.Initialize( alignedBuffer );
140     Initialize( &m_ArchiveReader );
141 
142     return true;
143 }
144 
LoadHeader(void * buffer,size_t size)145 bool HioSoundArchive::LoadHeader( void* buffer, size_t size )
146 {
147     NW_ASSERT( m_IsOpened );
148 
149     const s32 infoChunkOffset = m_ArchiveReader.GetInfoBlockOffset();
150     const u32 infoChunkSize = m_ArchiveReader.GetInfoBlockSize();
151 
152     if ( size < infoChunkSize )
153     {
154         NW_WARNING( size >= infoChunkSize,
155                 "HioSoundArchive::LoadHeader buffer size is too small.\n" );
156         return false;
157     }
158 
159     m_HostFile.Seek( infoChunkOffset, nn::hio::HostFile::SEEK_TYPE_SET );
160     s32 readSize = m_HostFile.Read( buffer, static_cast<s32>(infoChunkSize) );
161     if ( readSize != infoChunkSize )
162     {
163         NW_WARNING( false, "HioSoundArchive::LoadHeader cannot read file.\n" );
164         return false;
165     }
166     m_ArchiveReader.SetInfoBlock( buffer );
167 
168 #ifdef NW_SND_DEBUG_PRINT_ENABLE
169     // デバッグ出力
170     {
171         // サウンド情報
172         NN_LOG("### Sound INFO(%d)\n", m_ArchiveReader.GetSoundCount() );
173         for ( u32 i = 0; i < m_ArchiveReader.GetSoundCount(); i++ )
174         {
175             // サウンド共通情報
176             SoundArchive::ItemId soundId = GetSoundIdFromIndex( i );
177             SoundArchive::SoundType type = m_ArchiveReader.GetSoundType( soundId );
178             SoundArchive::SoundInfo info;
179             bool ret = m_ArchiveReader.ReadSoundInfo( soundId, &info );
180             NN_LOG("[%08X]?(%d) fileId(%d) playerId(0x%08X) actorId(%d) type(%d)\n",
181                     soundId, ret, info.fileId, info.playerId, info.actorPlayerId, type );
182             NN_LOG("  *common* volume(%d) panMode(%d) panCurve (%d)\n",
183                     info.volume, info.panMode, info.panCurve );
184 
185             // 3D サウンド情報
186             {
187                 SoundArchive::Sound3DInfo info3d;
188                 if ( ReadSound3DInfo( soundId, &info3d ) )
189                 {
190                     u32 flag = info3d.flags;
191                     NN_LOG("  *3D* ra(%.2f) cv(%d) df(%d) vol(%d) pr(%d) pa(%d) sp(%d) bqf(%d)\n",
192                             info3d.decayRatio, info3d.decayCurve, info3d.dopplerFactor,
193                             (flag & Sound3DInfo::FLAG_CTRL_VOLUME) > 0,
194                             (flag & Sound3DInfo::FLAG_CTRL_PRIORITY) > 0,
195                             (flag & Sound3DInfo::FLAG_CTRL_PAN) > 0,
196                             (flag & Sound3DInfo::FLAG_CTRL_SPAN) > 0,
197                             (flag & Sound3DInfo::FLAG_CTRL_FILTER) > 0 );
198                 }
199                 else
200                 {
201                     NN_LOG("  *3D* data not found\n");
202                 }
203             }
204 
205             // サウンド別個別情報
206             switch ( type )
207             {
208             case SoundArchive::SOUND_TYPE_SEQ:
209             {
210                 SoundArchive::SequenceSoundInfo seqInfo;
211                 bool retDetail = m_ArchiveReader.ReadSequenceSoundInfo( soundId, &seqInfo );
212                 NN_LOG(" *SEQ* ret(%d) ofs(%d) bnk(0x%08X,0x%08X,0x%08X,0x%08X) trk(0x%x) chPrio(%d) rPrioFix(%d)\n",
213                         retDetail,
214                         seqInfo.startOffset,
215                         seqInfo.bankIds[0], seqInfo.bankIds[1],
216                         seqInfo.bankIds[2], seqInfo.bankIds[3],
217                         seqInfo.allocateTrackFlags,
218                         seqInfo.channelPriority, seqInfo.isReleasePriorityFix );
219             }
220             break;
221             case SoundArchive::SOUND_TYPE_STRM:
222             {
223                 SoundArchive::StreamSoundInfo strmInfo;
224                 bool retDetail = m_ArchiveReader.ReadStreamSoundInfo( soundId, &strmInfo );
225                 NN_LOG("  *STRM* ret(%d) trk(%d) channel(%d)\n",
226                         retDetail, strmInfo.allocTrackCount, strmInfo.allocChannelCount );
227             }
228             break;
229             case SoundArchive::SOUND_TYPE_WAVE:
230             {
231                 SoundArchive::WaveSoundInfo wsdInfo;
232                 bool retDetail = m_ArchiveReader.ReadWaveSoundInfo( soundId, &wsdInfo );
233                 NN_LOG("  *WSD* ret(%d) index(%d) trk(0x%x) chPrio(%d) rPrioFix(%d)\n",
234                         retDetail,
235                         wsdInfo.index, wsdInfo.allocTrackCount,
236                         wsdInfo.channelPriority, wsdInfo.isReleasePriorityFix );
237             }
238             break;
239             case SoundArchive::SOUND_TYPE_INVALID:
240             {
241                 NN_LOG("Invalid SoundType (not STRM/WSD/SEQ)\n");
242             }
243             break;
244             }
245         }
246 
247         // バンク情報
248         NN_LOG("### BANK Info(%d)\n", m_ArchiveReader.GetBankCount() );
249         for ( u32 i = 0; i < m_ArchiveReader.GetBankCount(); i++ )
250         {
251             SoundArchive::ItemId bankId = GetBankIdFromIndex( i );
252             SoundArchive::BankInfo info;
253             bool ret = m_ArchiveReader.ReadBankInfo( bankId, &info );
254             NN_LOG("[%08X]?(%d) fileId(%d)\n", bankId, ret, info.fileId );
255         }
256 
257         // プレイヤー情報
258         NN_LOG("### PLAYER Info(%d)\n", m_ArchiveReader.GetPlayerCount() );
259         for ( u32 i = 0; i < m_ArchiveReader.GetPlayerCount(); i++ )
260         {
261             SoundArchive::ItemId playerId = GetPlayerIdFromIndex( i );
262             SoundArchive::PlayerInfo info;
263             bool ret = m_ArchiveReader.ReadPlayerInfo( playerId, &info );
264             NN_LOG("[%08X]?(%d) max(%d) heapSize(%d)\n",
265                     playerId, ret, info.playableSoundMax, info.playerHeapSize );
266         }
267 
268         // サウンドグループ情報
269         NN_LOG("### SOUND-GROUP Info(%d)\n", m_ArchiveReader.GetSoundGroupCount() );
270         for ( u32 i = 0; i < m_ArchiveReader.GetSoundGroupCount(); i++ )
271         {
272             SoundArchive::ItemId soundGroupId = GetSoundGroupIdFromIndex( i );
273             SoundArchive::SoundGroupInfo info;
274             bool ret = m_ArchiveReader.ReadSoundGroupInfo( soundGroupId, &info );
275             NN_LOG("[%08X]?(%d) startId(%08X) end(%08X) fileId:count(%d)",
276                     soundGroupId, ret, info.startId, info.endId, info.fileIdTable->count );
277             for ( u32 j = 0; j < info.fileIdTable->count; j++ )
278             {
279                 NN_LOG(" [%08X]", info.fileIdTable->item[j]);
280             }
281             NN_LOG("\n");
282         }
283 
284         // グループ情報
285         NN_LOG("### GROUP Info(%d)\n", m_ArchiveReader.GetGroupCount() );
286         for ( u32 i = 0; i < m_ArchiveReader.GetGroupCount(); i++ )
287         {
288             SoundArchive::ItemId groupId = GetGroupIdFromIndex( i );
289             SoundArchive::GroupInfo info;
290             bool ret = m_ArchiveReader.ReadGroupInfo( groupId, &info );
291             NN_LOG("[%08X]?(%d) fileId(%d)\n", groupId, ret, info.fileId );
292         }
293 
294         // 波形アーカイブ情報
295         NN_LOG("### WAVE-ARCHIVE Info(%d)\n", m_ArchiveReader.GetWaveArchiveCount() );
296         for ( u32 i = 0; i < m_ArchiveReader.GetWaveArchiveCount(); i++ )
297         {
298             SoundArchive::ItemId warcId = GetWaveArchiveIdFromIndex( i );
299             SoundArchive::WaveArchiveInfo info;
300             bool ret = m_ArchiveReader.ReadWaveArchiveInfo( warcId, &info );
301             NN_LOG("[%08X]?(%d) fileId(%d)\n", warcId, ret, info.fileId );
302         }
303 
304         // ファイル情報
305         NN_LOG("### FILE Info(%d)\n", m_ArchiveReader.GetFileCount() );
306         for ( u32 i = 0; i < m_ArchiveReader.GetFileCount(); i++ )
307         {
308             SoundArchive::FileInfo info;
309             bool ret = m_ArchiveReader.ReadFileInfo( i, &info );
310             if ( info.externalFilePath != NULL )
311             {
312                 NN_LOG("[%4d]?(%d) fileSize(%8d) ofs(%8d) path(%s)\n", i, ret,
313                         info.fileSize, info.offsetFromFileBlockHead, info.externalFilePath );
314             }
315             else
316             {
317                 NN_LOG("[%4d]?(%d) fileSize(%8d) ofs(%8d) path((null))\n", i, ret,
318                         info.fileSize, info.offsetFromFileBlockHead );
319             }
320         }
321 
322         // サウンドアーカイブプレイヤー情報
323         NN_LOG("### SOUND-ARCHIVE-PLAYER Info\n");
324         {
325             SoundArchive::SoundArchivePlayerInfo info;
326             bool ret = m_ArchiveReader.ReadSoundArchivePlayerInfo( &info );
327             NN_LOG("sequenceSoundMax (%2d)\n", info.sequenceSoundMax );
328             NN_LOG("sequenceTrackMax (%2d)\n", info.sequenceTrackMax );
329             NN_LOG("streamSoundMax   (%2d)\n", info.streamSoundMax );
330             NN_LOG("streamTrackMax   (%2d)\n", info.streamTrackMax );
331             NN_LOG("streamChannelMax (%2d)\n", info.streamChannelMax );
332             NN_LOG("waveSoundMax     (%2d)\n", info.waveSoundMax );
333             NN_LOG("waveTrackMax     (%2d)\n", info.waveTrackMax );
334         }
335     }
336 #endif /* NW_SND_DEBUG_PRINT_ENABLE */
337 
338     return true;
339 }
340 
LoadLabelStringData(void * buffer,size_t size)341 bool HioSoundArchive::LoadLabelStringData( void* buffer, size_t size )
342 {
343     NW_ASSERT( m_IsOpened );
344     const s32 stringBlockOffset = m_ArchiveReader.GetStringBlockOffset();
345     const u32 stringBlockSize = m_ArchiveReader.GetStringBlockSize();
346 
347     if ( stringBlockOffset == internal::Util::Reference::INVALID_OFFSET )
348     {
349         // サウンドアーカイブの文字列ブロックが含まれていない
350         return false;
351     }
352 
353     if ( size < stringBlockSize )
354     {
355         NW_WARNING(
356             size >= stringBlockSize,
357             "HioSoundArchive::LoadLabelStringData buffer size is too small."
358         );
359         return false;
360     }
361 
362     m_HostFile.Seek( stringBlockOffset, nn::hio::HostFile::SEEK_TYPE_SET );
363     s32 readSize = m_HostFile.Read( buffer, static_cast<s32>(stringBlockSize) );
364     if ( readSize != stringBlockSize )
365     {
366         NW_WARNING(
367             false,
368             "HioSoundArchive::LoadLabelStringData cannot read file.\n"
369         );
370         return false;
371     }
372 
373     m_ArchiveReader.SetStringBlock( buffer );
374 
375     return true;
376 }
377 
HioFileStream(const char * path,u32 offset,u32 size)378 HioSoundArchive::HioFileStream::HioFileStream( const char* path, u32 offset, u32 size )
379 : io::HioFileStream(
380         path, nn::hio::HostFile::ACCESS_MODE_READ, nn::hio::HostFile::OPEN_DISP_OPEN_EXISTING ),
381   m_Offset( static_cast<s32>( offset ) ),
382   m_Size( size )
383 {
384     NW_ASSERT( m_Size <= io::HioFileStream::GetSize() );
385     if ( size == 0 )
386     {
387         m_Size = io::HioFileStream::GetSize();
388     }
389     io::HioFileStream::Seek( m_Offset, io::FILE_STREAM_SEEK_BEGIN );
390 }
391 
HioFileStream(nn::hio::HostFile * openedFile,u32 offset,u32 size)392 HioSoundArchive::HioFileStream::HioFileStream(
393         nn::hio::HostFile* openedFile, u32 offset, u32 size )
394 : io::HioFileStream( openedFile, nn::hio::HostFile::ACCESS_MODE_READ, false ),
395   m_Offset( static_cast<s32>( offset ) ),
396   m_Size( size )
397 {
398     NW_ASSERT( m_Size <= io::HioFileStream::GetSize() );
399     if ( size == 0 )
400     {
401         m_Size = io::HioFileStream::GetSize();
402     }
403     io::HioFileStream::Seek( m_Offset, io::FILE_STREAM_SEEK_BEGIN );
404 }
405 
Read(void * buf,u32 length)406 s32 HioSoundArchive::HioFileStream::Read( void* buf, u32 length )
407 {
408     NW_ALIGN32_ASSERT( buf );
409     NW_ALIGN32_ASSERT( length );
410 
411     u32 curPos = io::HioFileStream::Tell();
412     if ( curPos + length > m_Offset + m_Size ) {
413         length = static_cast<u32>( ut::RoundUp( m_Offset + m_Size - curPos, 32 ) );
414     }
415     return io::HioFileStream::Read( buf, length );
416 }
417 
Seek(s32 offset,u32 origin)418 void HioSoundArchive::HioFileStream::Seek( s32 offset, u32 origin )
419 {
420     switch( origin ) {
421     case io::FILE_STREAM_SEEK_BEGIN:
422         offset += m_Offset;
423         break;
424     case io::FILE_STREAM_SEEK_CURRENT:
425         offset += io::HioFileStream::Tell();
426         break;
427     case io::FILE_STREAM_SEEK_END:
428         offset = m_Offset + static_cast<s32>( m_Size ) - offset;
429         break;
430     default:
431         NW_ASSERTMSG( false, "Unsupported Seek origin" );
432         return;
433     }
434 
435     if ( offset < m_Offset )
436     {
437         offset = m_Offset;
438     }
439     else if ( offset > m_Offset + static_cast<s32>( m_Size ) )
440     {
441         offset = m_Offset + static_cast<s32>( m_Size );
442     }
443 
444     io::HioFileStream::Seek( offset, io::FILE_STREAM_SEEK_BEGIN );
445 }
446 
447 
448 } // namespace nw::snd
449 } // namespace nw
450 
451