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