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