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