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