/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_BankFile.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 26005 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include namespace nw { namespace snd { namespace internal { namespace { const u8 DEFAULT_ORIGINAL_KEY = 60; // cn4 const u8 DEFAULT_VOLUME = 127; const u8 DEFAULT_PAN = 64; // 中央 const s8 DEFAULT_SURROUND_PAN = 0; // 中央 const f32 DEFAULT_PITCH = 1.0f; const bool DEFAULT_IGNORE_NOTE_OFF = false; const u8 DEFAULT_KEY_GROUP = 0; const u8 DEFAULT_INTERPOLATION_TYPE = 0; // 0: 4点補間, 1: 線形補間, 2: 補間なし const AdshrCurve DEFAULT_ADSHR_CURVE( 127, // u8 attack 127, // u8 decay 127, // u8 sustain 127, // u8 hold 127 // u8 release ); enum VelocityRegionBitFlag { VELOCITY_REGION_KEY = 0x00, VELOCITY_REGION_VOLUME, VELOCITY_REGION_PAN, VELOCITY_REGION_PITCH, VELOCITY_REGION_INSTRUMENT_NOTE_PARAM, VELOCITY_REGION_SENDS = 0x08, // 欠番(予約) VELOCITY_REGION_ENVELOPE, VELOCITY_REGION_RANDOMIZER, // 未実装 VELOCITY_REGION_LFO, // 未実装 VELOCITY_REGION_BASIC_PARAM_FLAG = ( 1 << VELOCITY_REGION_KEY ) | ( 1 << VELOCITY_REGION_VOLUME ) | ( 1 << VELOCITY_REGION_PAN ) | ( 1 << VELOCITY_REGION_PITCH ) | ( 1 << VELOCITY_REGION_INSTRUMENT_NOTE_PARAM ) | ( 1 << VELOCITY_REGION_ENVELOPE ) // ベロシティリージョンの基本パラメータ // (NW4C-1.2.0 現在、このパラメータが必ず入っている) }; struct DirectChunk { Util::Reference toRegion; const void* GetRegion() const { return ut::AddOffsetToPtr( this, toRegion.offset ); } }; struct RangeChunk { // データ Util::Table borderTable; // borderTable の最終 item のうしろに 4 バイト境界に、 // RegionTable が配置されている。 // (この RegionTable は Util::Table と異なり、count を持たない) // アクセサ const Util::Reference& GetRegionTableAddress( int index ) const { return *reinterpret_cast( ut::AddOffsetToPtr( this, sizeof(borderTable.count) + ut::RoundUp( borderTable.count, 4 ) + sizeof(Util::Reference) * index ) ); } const void* GetRegion( u32 index ) const { NW_ASSERT( index <= 127 ); bool isFoundRangeChunkIndex = false; u32 regionTableIndex = 0; for ( u32 i = 0; i < borderTable.count; i++ ) { if ( index <= borderTable.item[i] ) { regionTableIndex = i; isFoundRangeChunkIndex = true; break; } } if ( isFoundRangeChunkIndex == false ) { return NULL; } const Util::Reference& ref = GetRegionTableAddress( regionTableIndex ); return ut::AddOffsetToPtr( this, ref.offset ); } }; struct IndexChunk { // データ u8 min; u8 max; u8 reserved[2]; Util::Reference toRegion[1]; // アクセサ const void* GetRegion( u32 index ) const { NW_WARNING( index >= min, "out of region value[%d] < min[%d]\n", index, min ); NW_WARNING( index <= max, "out of region value[%d] > max[%d]\n", index, max ); if ( index < min ) { return NULL; } else if ( index > max ) { return NULL; } return ut::AddOffsetToPtr( this, toRegion[index-min].offset ); } }; enum RegionType { REGION_TYPE_DIRECT, // リージョンの要素は 1 個だけ REGION_TYPE_RANGE, // リージョンの要素は 10 個まで REGION_TYPE_INDEX, // リージョンの要素は 127 個 REGION_TYPE_UNKNOWN }; RegionType GetRegionType( u16 typeId ) { switch ( typeId ) { case ElementType_BankFile_DirectReferenceTable: return REGION_TYPE_DIRECT; case ElementType_BankFile_RangeReferenceTable: return REGION_TYPE_RANGE; case ElementType_BankFile_IndexReferenceTable: return REGION_TYPE_INDEX; default: return REGION_TYPE_UNKNOWN; } } inline const void* GetDirectChunk( const void* regionChunk ) { const DirectChunk& directChunk = *reinterpret_cast( regionChunk ); return directChunk.GetRegion(); } inline const void* GetRangeChunk( const void* regionChunk, u32 index ) { const RangeChunk& rangeChunk = *reinterpret_cast( regionChunk ); return rangeChunk.GetRegion( index ); } inline const void* GetIndexChunk( const void* regionChunk, u32 index ) { const IndexChunk& indexChunk = *reinterpret_cast( regionChunk ); return indexChunk.GetRegion( index ); } const void* GetRegion( const void* startPtr, u16 typeId, u32 offset, u32 index ) { NW_NULL_ASSERT( startPtr ); const void* regionChunk = ut::AddOffsetToPtr( startPtr, offset ); const void* region = NULL; switch ( GetRegionType( typeId ) ) { case REGION_TYPE_DIRECT: region = GetDirectChunk( regionChunk ); break; case REGION_TYPE_RANGE: region = GetRangeChunk( regionChunk, index ); break; case REGION_TYPE_INDEX: region = GetIndexChunk( regionChunk, index ); break; case REGION_TYPE_UNKNOWN: default: region = NULL; } return region; } } // anonymous namespace // // BankFile::FileHeader // const BankFile::InfoBlock* BankFile::FileHeader::GetInfoBlock() const { return reinterpret_cast( GetBlock( ElementType_BankFile_InfoBlock ) ); } // // BankFile::InfoBlockBody // const Util::WaveIdTable& BankFile::InfoBlockBody::GetWaveIdTable() const { return *reinterpret_cast( ut::AddOffsetToPtr( this, toWaveIdTable.offset ) ); } const Util::ReferenceTable& BankFile::InfoBlockBody::GetInstrumentReferenceTable() const { return *reinterpret_cast( ut::AddOffsetToPtr( this, toInstrumentReferenceTable.offset ) ); } const BankFile::Instrument* BankFile::InfoBlockBody::GetInstrument( int programNo ) const { NW_ASSERT( programNo < GetInstrumentCount() ); const Util::ReferenceTable& table = GetInstrumentReferenceTable(); const Util::Reference& ref = table.item[ programNo ]; switch ( ref.typeId ) { case ElementType_BankFile_InstrumentInfo: break; case ElementType_BankFile_NullInfo: return NULL; default: NW_ASSERTMSG( 0, "cannot support Bank::InstRef::TypeId" ); return NULL; } return reinterpret_cast( table.GetReferedItem( programNo ) ); } const BankFile::KeyRegion* BankFile::Instrument::GetKeyRegion( u32 key ) const { // toKeyRegionChunk の typeId によって、 // offset 先にあるオブジェクトの型が DirectChunk, // RangeChunk, IndexChunk のいずれかになる return reinterpret_cast( GetRegion( this, toKeyRegionChunk.typeId, toKeyRegionChunk.offset, key ) ); } const BankFile::VelocityRegion* BankFile::KeyRegion::GetVelocityRegion( u32 velocity ) const { // Instrument::GetKeyRegion と同様の構成になっている return reinterpret_cast( GetRegion( this, toVelocityRegionChunk.typeId, toVelocityRegionChunk.offset, velocity ) ); } // // BankFile::VelocityRegion // u8 BankFile::VelocityRegion::GetOriginalKey() const { u32 value; bool result = optionParameter.GetValue( &value, VELOCITY_REGION_KEY ); if ( result == false ) return DEFAULT_ORIGINAL_KEY; return Util::DevideBy8bit( value, 0 ); } u8 BankFile::VelocityRegion::GetVolume() const { u32 value; bool result = optionParameter.GetValue( &value, VELOCITY_REGION_VOLUME ); if ( result == false ) return DEFAULT_VOLUME; return Util::DevideBy8bit( value, 0 ); } u8 BankFile::VelocityRegion::GetPan() const { u32 value; bool result = optionParameter.GetValue( &value, VELOCITY_REGION_PAN ); if ( result == false ) return DEFAULT_PAN; return Util::DevideBy8bit( value, 0 ); } #ifdef NW_PLATFORM_RVL u8 BankFile::VelocityRegion::GetSurroundPan() const { u32 value; bool result = optionParameter.GetValue( &value, VELOCITY_REGION_PAN ); if ( result == false ) return DEFAULT_SURROUND_PAN; return Util::DevideBy8bit( value, 1 ); } #endif /* NW_PLATFORM_RVL */ f32 BankFile::VelocityRegion::GetPitch() const { f32 value; bool result = optionParameter.GetValueF32( &value, VELOCITY_REGION_PITCH ); if ( result == false ) return DEFAULT_PITCH; return value; } bool BankFile::VelocityRegion::IsIgnoreNoteOff() const { u32 value; bool result = optionParameter.GetValue( &value, VELOCITY_REGION_INSTRUMENT_NOTE_PARAM ); if ( result == false ) return DEFAULT_IGNORE_NOTE_OFF; return Util::DevideBy8bit( value, 0 ) > 0; } u8 BankFile::VelocityRegion::GetKeyGroup() const { u32 value; bool result = optionParameter.GetValue( &value, VELOCITY_REGION_INSTRUMENT_NOTE_PARAM ); if ( result == false ) return DEFAULT_KEY_GROUP; return Util::DevideBy8bit( value, 1 ); } u8 BankFile::VelocityRegion::GetInterpolationType() const { u32 value; bool result = optionParameter.GetValue( &value, VELOCITY_REGION_INSTRUMENT_NOTE_PARAM ); if ( result == false ) return DEFAULT_INTERPOLATION_TYPE; return Util::DevideBy8bit( value, 2 ); } const AdshrCurve& BankFile::VelocityRegion::GetAdshrCurve() const { u32 offsetToReference; bool result = optionParameter.GetValue( &offsetToReference, VELOCITY_REGION_ENVELOPE ); if ( result == false ) return DEFAULT_ADSHR_CURVE; const Util::Reference& ref = *reinterpret_cast( ut::AddOffsetToPtr( this, offsetToReference ) ); return *reinterpret_cast( ut::AddOffsetToPtr( &ref, ref.offset ) ); } const BankFile::RegionParameter* BankFile::VelocityRegion::GetRegionParameter() const { if ( optionParameter.bitFlag != VELOCITY_REGION_BASIC_PARAM_FLAG ) { return NULL; } return reinterpret_cast( ut::AddOffsetToPtr( this, sizeof(VelocityRegion) ) ); } } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw