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