1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: snd_BankFile.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: 31311 $
16 *---------------------------------------------------------------------------*/
17
18 #include "precompiled.h"
19
20 #include <nw/types.h>
21 #include <nw/snd/snd_BankFile.h>
22 #include <nw/snd/snd_ElementType.h>
23 #include <nw/snd/snd_CurveAdshr.h>
24 #include <nw/ut/ut_Inlines.h>
25
26 namespace nw {
27 namespace snd {
28 namespace internal {
29
30 namespace
31 {
32
33 const u8 DEFAULT_ORIGINAL_KEY = 60; // cn4
34 const u8 DEFAULT_VOLUME = 127;
35 const u8 DEFAULT_PAN = 64; // 中央
36 const s8 DEFAULT_SURROUND_PAN = 0; // 中央
37 const f32 DEFAULT_PITCH = 1.0f;
38 const bool DEFAULT_IGNORE_NOTE_OFF = false;
39 const u8 DEFAULT_KEY_GROUP = 0;
40 const u8 DEFAULT_INTERPOLATION_TYPE = 0; // 0: 4点補間, 1: 線形補間, 2: 補間なし
41 const AdshrCurve DEFAULT_ADSHR_CURVE(
42 127, // u8 attack
43 127, // u8 decay
44 127, // u8 sustain
45 127, // u8 hold
46 127 // u8 release
47 );
48
49 enum VelocityRegionBitFlag
50 {
51 VELOCITY_REGION_KEY = 0x00,
52 VELOCITY_REGION_VOLUME,
53 VELOCITY_REGION_PAN,
54 VELOCITY_REGION_PITCH,
55 VELOCITY_REGION_INSTRUMENT_NOTE_PARAM,
56 VELOCITY_REGION_SENDS = 0x08, // 欠番(予約)
57 VELOCITY_REGION_ENVELOPE,
58 VELOCITY_REGION_RANDOMIZER, // 未実装
59 VELOCITY_REGION_LFO, // 未実装
60 VELOCITY_REGION_BASIC_PARAM_FLAG =
61 ( 1 << VELOCITY_REGION_KEY )
62 | ( 1 << VELOCITY_REGION_VOLUME )
63 | ( 1 << VELOCITY_REGION_PAN )
64 | ( 1 << VELOCITY_REGION_PITCH )
65 | ( 1 << VELOCITY_REGION_INSTRUMENT_NOTE_PARAM )
66 | ( 1 << VELOCITY_REGION_ENVELOPE ) // ベロシティリージョンの基本パラメータ
67 // (NW4C-1.2.0 現在、このパラメータが必ず入っている)
68 };
69
70
71
72 struct DirectChunk
73 {
74 Util::Reference toRegion;
GetRegionnw::snd::internal::__anon25887d2c0111::DirectChunk75 const void* GetRegion() const
76 {
77 return ut::AddOffsetToPtr( this, toRegion.offset );
78 }
79 };
80
81 struct RangeChunk
82 {
83 // データ
84 Util::Table<u8> borderTable;
85 // borderTable の最終 item のうしろに 4 バイト境界に、
86 // RegionTable が配置されている。
87 // (この RegionTable は Util::Table と異なり、count を持たない)
88
89 // アクセサ
GetRegionTableAddressnw::snd::internal::__anon25887d2c0111::RangeChunk90 const Util::Reference& GetRegionTableAddress( int index ) const
91 {
92 return *reinterpret_cast<const Util::Reference*>(
93 ut::AddOffsetToPtr( this,
94 sizeof(borderTable.count) + ut::RoundUp( borderTable.count, 4 )
95 + sizeof(Util::Reference) * index ) );
96 }
GetRegionnw::snd::internal::__anon25887d2c0111::RangeChunk97 const void* GetRegion( u32 index ) const
98 {
99 NW_ASSERT( index <= 127 );
100
101 bool isFoundRangeChunkIndex = false;
102 u32 regionTableIndex = 0;
103 for ( u32 i = 0; i < borderTable.count; i++ )
104 {
105 if ( index <= borderTable.item[i] )
106 {
107 regionTableIndex = i;
108 isFoundRangeChunkIndex = true;
109 break;
110 }
111 }
112 if ( isFoundRangeChunkIndex == false )
113 {
114 return NULL;
115 }
116 const Util::Reference& ref = GetRegionTableAddress( regionTableIndex );
117 return ut::AddOffsetToPtr( this, ref.offset );
118 }
119 };
120
121 struct IndexChunk
122 {
123 // データ
124 u8 min;
125 u8 max;
126 u8 reserved[2];
127 Util::Reference toRegion[1];
128
129 // アクセサ
GetRegionnw::snd::internal::__anon25887d2c0111::IndexChunk130 const void* GetRegion( u32 index ) const
131 {
132 NW_WARNING( index >= min, "out of region value[%d] < min[%d]\n", index, min );
133 NW_WARNING( index <= max, "out of region value[%d] > max[%d]\n", index, max );
134 if ( index < min )
135 {
136 return NULL;
137 }
138 else if ( index > max )
139 {
140 return NULL;
141 }
142 return ut::AddOffsetToPtr( this, toRegion[index-min].offset );
143 }
144 };
145
146 enum RegionType
147 {
148 REGION_TYPE_DIRECT, // リージョンの要素は 1 個だけ
149 REGION_TYPE_RANGE, // リージョンの要素は 10 個まで
150 REGION_TYPE_INDEX, // リージョンの要素は 127 個
151 REGION_TYPE_UNKNOWN
152 };
153
GetRegionType(u16 typeId)154 RegionType GetRegionType( u16 typeId )
155 {
156 switch ( typeId )
157 {
158 case ElementType_BankFile_DirectReferenceTable:
159 return REGION_TYPE_DIRECT;
160 case ElementType_BankFile_RangeReferenceTable:
161 return REGION_TYPE_RANGE;
162 case ElementType_BankFile_IndexReferenceTable:
163 return REGION_TYPE_INDEX;
164 default:
165 return REGION_TYPE_UNKNOWN;
166 }
167 }
168
GetDirectChunk(const void * regionChunk)169 inline const void* GetDirectChunk( const void* regionChunk )
170 {
171 const DirectChunk& directChunk =
172 *reinterpret_cast<const DirectChunk*>( regionChunk );
173 return directChunk.GetRegion();
174 }
175
GetRangeChunk(const void * regionChunk,u32 index)176 inline const void* GetRangeChunk( const void* regionChunk, u32 index )
177 {
178 const RangeChunk& rangeChunk =
179 *reinterpret_cast<const RangeChunk*>( regionChunk );
180 return rangeChunk.GetRegion( index );
181 }
182
GetIndexChunk(const void * regionChunk,u32 index)183 inline const void* GetIndexChunk( const void* regionChunk, u32 index )
184 {
185 const IndexChunk& indexChunk =
186 *reinterpret_cast<const IndexChunk*>( regionChunk );
187 return indexChunk.GetRegion( index );
188 }
189
GetRegion(const void * startPtr,u16 typeId,u32 offset,u32 index)190 const void* GetRegion( const void* startPtr, u16 typeId, u32 offset, u32 index )
191 {
192 NW_NULL_ASSERT( startPtr );
193
194 const void* regionChunk = ut::AddOffsetToPtr( startPtr, offset );
195 const void* region = NULL;
196
197 switch ( GetRegionType( typeId ) )
198 {
199 case REGION_TYPE_DIRECT:
200 region = GetDirectChunk( regionChunk );
201 break;
202 case REGION_TYPE_RANGE:
203 region = GetRangeChunk( regionChunk, index );
204 break;
205 case REGION_TYPE_INDEX:
206 region = GetIndexChunk( regionChunk, index );
207 break;
208 case REGION_TYPE_UNKNOWN:
209 default:
210 region = NULL;
211 }
212 return region;
213 }
214
215 } // anonymous namespace
216
217
218 //
219 // BankFile::FileHeader
220 //
GetInfoBlock() const221 const BankFile::InfoBlock* BankFile::FileHeader::GetInfoBlock() const
222 {
223 return reinterpret_cast<const InfoBlock*>( GetBlock( ElementType_BankFile_InfoBlock ) );
224 }
225
226
227 //
228 // BankFile::InfoBlockBody
229 //
230 const Util::WaveIdTable&
GetWaveIdTable() const231 BankFile::InfoBlockBody::GetWaveIdTable() const
232 {
233 return *reinterpret_cast<const Util::WaveIdTable*>(
234 ut::AddOffsetToPtr( this, toWaveIdTable.offset ) );
235 }
236
237 const Util::ReferenceTable&
GetInstrumentReferenceTable() const238 BankFile::InfoBlockBody::GetInstrumentReferenceTable() const
239 {
240 return *reinterpret_cast<const Util::ReferenceTable*>(
241 ut::AddOffsetToPtr( this, toInstrumentReferenceTable.offset ) );
242 }
243
244 const BankFile::Instrument*
GetInstrument(int programNo) const245 BankFile::InfoBlockBody::GetInstrument( int programNo ) const
246 {
247 NW_ASSERT( programNo < GetInstrumentCount() );
248 const Util::ReferenceTable& table = GetInstrumentReferenceTable();
249 const Util::Reference& ref = table.item[ programNo ];
250
251 switch ( ref.typeId )
252 {
253 case ElementType_BankFile_InstrumentInfo:
254 break;
255 case ElementType_BankFile_NullInfo:
256 return NULL;
257 default:
258 NW_ASSERTMSG( 0, "cannot support Bank::InstRef::TypeId" );
259 return NULL;
260 }
261
262 return reinterpret_cast<const BankFile::Instrument*>(
263 table.GetReferedItem( programNo ) );
264 }
265
266 const BankFile::KeyRegion*
GetKeyRegion(u32 key) const267 BankFile::Instrument::GetKeyRegion( u32 key ) const
268 {
269 // toKeyRegionChunk の typeId によって、
270 // offset 先にあるオブジェクトの型が DirectChunk,
271 // RangeChunk, IndexChunk のいずれかになる
272 return reinterpret_cast<const BankFile::KeyRegion*>(
273 GetRegion(
274 this,
275 toKeyRegionChunk.typeId,
276 toKeyRegionChunk.offset,
277 key )
278 );
279 }
280
281 const BankFile::VelocityRegion*
GetVelocityRegion(u32 velocity) const282 BankFile::KeyRegion::GetVelocityRegion( u32 velocity ) const
283 {
284 // Instrument::GetKeyRegion と同様の構成になっている
285 return reinterpret_cast<const BankFile::VelocityRegion*>(
286 GetRegion(
287 this,
288 toVelocityRegionChunk.typeId,
289 toVelocityRegionChunk.offset,
290 velocity )
291 );
292 }
293
294
295 //
296 // BankFile::VelocityRegion
297 //
GetOriginalKey() const298 u8 BankFile::VelocityRegion::GetOriginalKey() const
299 {
300 u32 value;
301 bool result = optionParameter.GetValue( &value, VELOCITY_REGION_KEY );
302 if ( result == false ) return DEFAULT_ORIGINAL_KEY;
303 return Util::DevideBy8bit( value, 0 );
304 }
305
GetVolume() const306 u8 BankFile::VelocityRegion::GetVolume() const
307 {
308 u32 value;
309 bool result = optionParameter.GetValue( &value, VELOCITY_REGION_VOLUME );
310 if ( result == false ) return DEFAULT_VOLUME;
311 return Util::DevideBy8bit( value, 0 );
312 }
313
GetPan() const314 u8 BankFile::VelocityRegion::GetPan() const
315 {
316 u32 value;
317 bool result = optionParameter.GetValue( &value, VELOCITY_REGION_PAN );
318 if ( result == false ) return DEFAULT_PAN;
319 return Util::DevideBy8bit( value, 0 );
320 }
321
322 #ifdef NW_PLATFORM_RVL
GetSurroundPan() const323 u8 BankFile::VelocityRegion::GetSurroundPan() const
324 {
325 u32 value;
326 bool result = optionParameter.GetValue( &value, VELOCITY_REGION_PAN );
327 if ( result == false ) return DEFAULT_SURROUND_PAN;
328 return Util::DevideBy8bit( value, 1 );
329 }
330 #endif /* NW_PLATFORM_RVL */
331
GetPitch() const332 f32 BankFile::VelocityRegion::GetPitch() const
333 {
334 f32 value;
335 bool result = optionParameter.GetValueF32( &value, VELOCITY_REGION_PITCH );
336 if ( result == false ) return DEFAULT_PITCH;
337 return value;
338 }
339
IsIgnoreNoteOff() const340 bool BankFile::VelocityRegion::IsIgnoreNoteOff() const
341 {
342 u32 value;
343 bool result = optionParameter.GetValue( &value, VELOCITY_REGION_INSTRUMENT_NOTE_PARAM );
344 if ( result == false ) return DEFAULT_IGNORE_NOTE_OFF;
345 return Util::DevideBy8bit( value, 0 ) > 0;
346 }
347
GetKeyGroup() const348 u8 BankFile::VelocityRegion::GetKeyGroup() const
349 {
350 u32 value;
351 bool result = optionParameter.GetValue( &value, VELOCITY_REGION_INSTRUMENT_NOTE_PARAM );
352 if ( result == false ) return DEFAULT_KEY_GROUP;
353 return Util::DevideBy8bit( value, 1 );
354 }
355
GetInterpolationType() const356 u8 BankFile::VelocityRegion::GetInterpolationType() const
357 {
358 u32 value;
359 bool result = optionParameter.GetValue( &value, VELOCITY_REGION_INSTRUMENT_NOTE_PARAM );
360 if ( result == false ) return DEFAULT_INTERPOLATION_TYPE;
361 return Util::DevideBy8bit( value, 2 );
362 }
363
GetAdshrCurve() const364 const AdshrCurve& BankFile::VelocityRegion::GetAdshrCurve() const
365 {
366 u32 offsetToReference;
367 bool result = optionParameter.GetValue( &offsetToReference, VELOCITY_REGION_ENVELOPE );
368 if ( result == false ) return DEFAULT_ADSHR_CURVE;
369 const Util::Reference& ref = *reinterpret_cast<const Util::Reference*>(
370 ut::AddOffsetToPtr( this, offsetToReference ) );
371 return *reinterpret_cast<const AdshrCurve*>(
372 ut::AddOffsetToPtr( &ref, ref.offset ) );
373 }
374
GetRegionParameter() const375 const BankFile::RegionParameter* BankFile::VelocityRegion::GetRegionParameter() const
376 {
377 if ( optionParameter.bitFlag != VELOCITY_REGION_BASIC_PARAM_FLAG )
378 {
379 return NULL;
380 }
381
382 return reinterpret_cast<const RegionParameter*>(
383 ut::AddOffsetToPtr( this, sizeof(VelocityRegion) ) );
384 }
385
386
387
388 } // namespace nw::snd::internal
389 } // namespace nw::snd
390 } // namespace nw
391
392