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: 26005 $
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::__anondfd3d91f0111::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::__anondfd3d91f0111::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::__anondfd3d91f0111::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::__anondfd3d91f0111::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