/*---------------------------------------------------------------------------* Project: NintendoWare File: snd_MmlParser.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. 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. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include #include // NW_PLATFORM_ENDIAN namespace nw { namespace snd { namespace internal { namespace driver { bool MmlParser::mPrintVarEnabledFlag; /*---------------------------------------------------------------------------* Name: Parse Description: シーケンス処理を進めます Arguments: player - プレイヤーポインタ trackNo - トラックナンバ doNoteOn - ノートオンするかどうか Returns: シーケンス継続時には0を、完了時にはー1を返します *---------------------------------------------------------------------------*/ SequenceTrack::ParseResult MmlParser::Parse( MmlSequenceTrack* track, bool doNoteOn ) const { NW_NULL_ASSERT( track ); SequenceSoundPlayer* player = track->GetSequenceSoundPlayer(); NW_NULL_ASSERT( player ); SequenceTrack::ParserTrackParam& trackParam = track->GetParserTrackParam(); SequenceSoundPlayer::ParserPlayerParam& playerParam = player->GetParserPlayerParam(); SeqArgType argType = SEQ_ARG_NONE; SeqArgType argType2 = SEQ_ARG_NONE; bool useArgType = false; bool doExecCommand = true; u32 cmd = ReadByte( &trackParam.currentAddr ); // 接頭バイナリの処理 if ( cmd == MmlCommand::MML_IF ) { cmd = ReadByte( &trackParam.currentAddr ); doExecCommand = trackParam.cmpFlag != 0; } // 第2パラメータ if ( cmd == MmlCommand::MML_TIME ) { cmd = ReadByte( &trackParam.currentAddr ); argType2 = SEQ_ARG_S16; } else if ( cmd == MmlCommand::MML_TIME_RANDOM ) { cmd = ReadByte( &trackParam.currentAddr ); argType2 = SEQ_ARG_RANDOM; } else if ( cmd == MmlCommand::MML_TIME_VARIABLE ) { cmd = ReadByte( &trackParam.currentAddr ); argType2 = SEQ_ARG_VARIABLE; } // パラメータ if ( cmd == MmlCommand::MML_RANDOM ) { cmd = ReadByte( &trackParam.currentAddr ); argType = SEQ_ARG_RANDOM; useArgType = true; } else if ( cmd == MmlCommand::MML_VARIABLE ) { cmd = ReadByte( &trackParam.currentAddr ); argType = SEQ_ARG_VARIABLE; useArgType = true; } if ( ( cmd & 0x80 ) == 0 ) { // ノートコマンド const u8 velocity = ReadByte( &trackParam.currentAddr ); const s32 length = ReadArg( &trackParam.currentAddr, player, track, useArgType ? argType : SEQ_ARG_VMIDI ); int key = static_cast( cmd ) + trackParam.transpose; if ( ! doExecCommand ) return SequenceTrack::PARSE_RESULT_CONTINUE; key = ut::Clamp( key, 0, 127 ); if ( ! trackParam.muteFlag && doNoteOn ) { NoteOnCommandProc( track, key, velocity, length > 0 ? length : -1, trackParam.tieFlag ); } if ( trackParam.noteWaitFlag ) { trackParam.wait = length; if ( length == 0 ) { trackParam.noteFinishWait = true; } } } else { s32 commandArg1 = 0; s32 commandArg2 = 0; switch ( cmd & 0xf0 ) { case 0x80: { switch ( cmd ) { case MmlCommand::MML_WAIT: { // ここで処理する s32 arg = ReadArg( &trackParam.currentAddr, player, track, useArgType ? argType : SEQ_ARG_VMIDI ); if ( doExecCommand ) { trackParam.wait = arg; } break; } case MmlCommand::MML_PRG: { commandArg1 = ReadArg( &trackParam.currentAddr, player, track, useArgType ? argType : SEQ_ARG_VMIDI ); if ( doExecCommand ) { CommandProc( track, cmd, commandArg1, commandArg2 ); } break; } case MmlCommand::MML_OPEN_TRACK: { u8 trackNo = ReadByte( &trackParam.currentAddr ); u32 offset = Read24( &trackParam.currentAddr ); if ( doExecCommand ) { commandArg1 = trackNo; commandArg2 = static_cast( offset ); CommandProc( track, cmd, commandArg1, commandArg2 ); } break; } case MmlCommand::MML_JUMP: { u32 offset = Read24( &trackParam.currentAddr ); if ( doExecCommand ) { commandArg1 = static_cast( offset ); CommandProc( track, cmd, commandArg1, commandArg2 ); } break; } case MmlCommand::MML_CALL: { u32 offset = Read24( &trackParam.currentAddr ); if ( doExecCommand ) { commandArg1 = static_cast( offset ); CommandProc( track, cmd, commandArg1, commandArg2 ); } break; } } break; // case 0x88 - 0x8f } case 0xb0: case 0xc0: case 0xd0: // u8 パラメータ ( 一部 s8 パラメータが混ざってる ) { u8 arg = static_cast( ReadArg( &trackParam.currentAddr, player, track, useArgType ? argType : SEQ_ARG_U8 ) ); if ( argType2 != SEQ_ARG_NONE ) { commandArg2 = ReadArg( &trackParam.currentAddr, player, track, argType2 ); } if ( doExecCommand ) { switch ( cmd ) { case MmlCommand::MML_TRANSPOSE: case MmlCommand::MML_PITCH_BEND: commandArg1 = *reinterpret_cast( &arg ); break; default: commandArg1 = arg; } CommandProc( track, cmd, commandArg1, commandArg2 ); } break; } case 0x90: // 予備 { if ( doExecCommand ) { CommandProc( track, cmd, commandArg1, commandArg2 ); } break; } case 0xe0: // s16 パラメータ { commandArg1 = static_cast( ReadArg( &trackParam.currentAddr, player, track, useArgType ? argType : SEQ_ARG_S16 ) ); if ( doExecCommand ) { CommandProc( track, cmd, commandArg1, commandArg2 ); } break; } case 0xf0: // パラメータ無し or 拡張コマンド { switch ( cmd ) { case MmlCommand::MML_ALLOC_TRACK: (void)Read16( &trackParam.currentAddr ); NW_ASSERTMSG( false, "seq: must use alloctrack in startup code"); break; case MmlCommand::MML_FIN: if ( doExecCommand ) { return SequenceTrack::PARSE_RESULT_FINISH; } break; case MmlCommand::MML_EX_COMMAND: { u32 cmdex = ReadByte( &trackParam.currentAddr ); switch ( cmdex & 0xf0 ) { case 0xe0: // u16 パラメータ { commandArg1 = static_cast( ReadArg( &trackParam.currentAddr, player, track, useArgType ? argType : SEQ_ARG_S16 ) ); if ( doExecCommand ) { CommandProc( track, (cmd << 8) + cmdex, commandArg1, commandArg2 ); } break; } case 0x80: case 0x90: // 2パラメータ { commandArg1 = ReadByte( &trackParam.currentAddr ); commandArg2 = static_cast( ReadArg( &trackParam.currentAddr, player, track, useArgType ? argType : SEQ_ARG_S16 ) ); if ( doExecCommand ) { CommandProc( track, (cmd << 8) + cmdex, commandArg1, commandArg2 ); } break; } } } // case MmlCommand::MML_EX_COMMAND default: { if ( doExecCommand ) { CommandProc( track, cmd, commandArg1, commandArg2 ); } break; } } // case 0xf0 - 0xff break; } // case 0xf0 case 0xa0: // 接頭コマンド { // ここに接頭コマンドがあるのは不正 NW_ASSERTMSG( false, "Invalid seqdata command: %d", cmd ); } } } return SequenceTrack::PARSE_RESULT_CONTINUE; } /*---------------------------------------------------------------------------* Name: CommandProc Description: 一つのMMLコマンドに対する処理を行います。 Arguments: track - トラックポインタ trackParam - パーサパラメータ cmd - コマンド cmdex - 拡張コマンド commandArg1 - コマンドパラメータ1 commandArg2 - コマンドパラメータ2 Returns: なし *---------------------------------------------------------------------------*/ void MmlParser::CommandProc( MmlSequenceTrack* track, u32 command, s32 commandArg1, s32 commandArg2 ) const { NW_NULL_ASSERT( track ); SequenceSoundPlayer* player = track->GetSequenceSoundPlayer(); NW_NULL_ASSERT( player ); SequenceTrack::ParserTrackParam& trackParam = track->GetParserTrackParam(); SequenceSoundPlayer::ParserPlayerParam& playerParam = player->GetParserPlayerParam(); if ( command <= 0xff ) // 1バイトコマンド { switch ( command ) { case MmlCommand::MML_TEMPO: playerParam.tempo = static_cast( ut::Clamp( static_cast( commandArg1 ), TEMPO_MIN, TEMPO_MAX ) ); break; case MmlCommand::MML_TIMEBASE: playerParam.timebase = static_cast( commandArg1 ); break; case MmlCommand::MML_PRG: if ( commandArg1 < 0x10000 ) { trackParam.prgNo = static_cast( commandArg1 ); } else { NW_WARNING( false, "nw::snd::MmlParser: too large prg No. %d", commandArg1 ); } break; case MmlCommand::MML_MUTE: track->SetMute( static_cast( commandArg1 ) ); break; case MmlCommand::MML_VOLUME: trackParam.volume.SetTarget( static_cast( commandArg1 ), static_cast( commandArg2 ) ); break; case MmlCommand::MML_VOLUME2: trackParam.volume2 = static_cast( commandArg1 ); break; case MmlCommand::MML_VELOCITY_RANGE: trackParam.velocityRange = static_cast( commandArg1 ); break; case MmlCommand::MML_MAIN_VOLUME: playerParam.volume = static_cast( commandArg1 ); break; case MmlCommand::MML_TRANSPOSE: trackParam.transpose = static_cast( commandArg1 ); break; case MmlCommand::MML_PITCH_BEND: trackParam.pitchBend.SetTarget( static_cast( commandArg1 ), static_cast( commandArg2 ) ); break; case MmlCommand::MML_BEND_RANGE: trackParam.bendRange = static_cast( commandArg1 ); break; case MmlCommand::MML_PAN: trackParam.pan.SetTarget( static_cast( commandArg1 - PAN_CENTER ), static_cast( commandArg2 ) ); break; case MmlCommand::MML_INIT_PAN: trackParam.initPan = static_cast( commandArg1 - PAN_CENTER ); break; case MmlCommand::MML_SURROUND_PAN: trackParam.surroundPan.SetTarget( static_cast( commandArg1 ), static_cast( commandArg2 ) ); break; case MmlCommand::MML_PRIO: trackParam.priority = static_cast( commandArg1 ); break; case MmlCommand::MML_NOTE_WAIT: trackParam.noteWaitFlag = ( commandArg1 != 0 ); break; case MmlCommand::MML_FRONT_BYPASS: trackParam.frontBypassFlag = ( commandArg1 != 0 ); break; case MmlCommand::MML_PORTA_TIME: trackParam.portaTime = static_cast( commandArg1 ); break; case MmlCommand::MML_MOD_DEPTH: trackParam.lfoParam.depth = static_cast( commandArg1 ) / 128.0f; break; case MmlCommand::MML_MOD_SPEED: trackParam.lfoParam.speed = static_cast( commandArg1 ) * 0.390625f; // 16 で 6.25Hz break; case MmlCommand::MML_MOD_TYPE: trackParam.lfoTarget = static_cast( commandArg1 ); break; case MmlCommand::MML_MOD_RANGE: trackParam.lfoParam.range = static_cast( commandArg1 ); break; case MmlCommand::MML_MOD_DELAY: trackParam.lfoParam.delay = static_cast( commandArg1 * 5 ); // 単位5ms break; case MmlCommand::MML_SWEEP_PITCH: trackParam.sweepPitch = static_cast( commandArg1 ) / 64.0f; break; case MmlCommand::MML_ATTACK: trackParam.attack = static_cast( commandArg1 ); break; case MmlCommand::MML_DECAY: trackParam.decay = static_cast( commandArg1 ); break; case MmlCommand::MML_SUSTAIN: trackParam.sustain = static_cast( commandArg1 ); break; case MmlCommand::MML_RELEASE: trackParam.release = static_cast( commandArg1 ); break; case MmlCommand::MML_ENV_HOLD: trackParam.envHold = static_cast( commandArg1 ); break; case MmlCommand::MML_ENV_RESET: trackParam.attack = SequenceTrack::INVALID_ENVELOPE; trackParam.decay = SequenceTrack::INVALID_ENVELOPE; trackParam.sustain = SequenceTrack::INVALID_ENVELOPE; trackParam.release = SequenceTrack::INVALID_ENVELOPE; trackParam.envHold = SequenceTrack::INVALID_ENVELOPE; break; case MmlCommand::MML_DAMPER: trackParam.damperFlag = ( static_cast( commandArg1 ) >= 64 ); break; case MmlCommand::MML_TIE: trackParam.tieFlag = ( commandArg1 != 0 ); track->ReleaseAllChannel( -1 ); track->FreeAllChannel(); break; case MmlCommand::MML_MONOPHONIC: trackParam.monophonicFlag = ( commandArg1 != 0 ); if ( trackParam.monophonicFlag ) { track->ReleaseAllChannel( -1 ); track->FreeAllChannel(); } break; case MmlCommand::MML_PORTA: trackParam.portaKey = static_cast( commandArg1 + trackParam.transpose ); trackParam.portaFlag = true; break; case MmlCommand::MML_PORTA_SW: trackParam.portaFlag = ( commandArg1 != 0 ); break; case MmlCommand::MML_LPF_CUTOFF: trackParam.lpfFreq = static_cast( commandArg1 - 64 ) / 64.0f; break; case MmlCommand::MML_BIQUAD_TYPE: trackParam.biquadType = static_cast( commandArg1 ); break; case MmlCommand::MML_BIQUAD_VALUE: trackParam.biquadValue = static_cast( commandArg1 ) / 127.0f; break; case MmlCommand::MML_BANK_SELECT: trackParam.bankIndex = static_cast( commandArg1 ); break; case MmlCommand::MML_FXSEND_A: trackParam.fxSend[ AUX_BUS_A ] = static_cast( commandArg1 ); break; case MmlCommand::MML_FXSEND_B: trackParam.fxSend[ AUX_BUS_B ] = static_cast( commandArg1 ); break; #ifdef NW_PLATFORM_RVL case MmlCommand::MML_FXSEND_C: trackParam.fxSend[ AUX_BUS_C ] = static_cast( commandArg1 ); break; #endif case MmlCommand::MML_MAINSEND: trackParam.mainSend = static_cast( commandArg1 ); break; case MmlCommand::MML_PRINTVAR: if ( mPrintVarEnabledFlag ) { const vs16* const varPtr = GetVariablePtr( player, track, commandArg1 ); NN_LOG( "#%08x[%d]: printvar %sVAR_%d(%d) = %d\n", player, track->GetPlayerTrackNo(), ( commandArg1 >= 32 )? "T": ( commandArg1 >= 16 )? "G": "", ( commandArg1 >= 32 )? commandArg1-32: ( commandArg1 >= 16 )? commandArg1-16: commandArg1, commandArg1, *varPtr ); } break; case MmlCommand::MML_OPEN_TRACK: { SequenceTrack* newTrack = player->GetPlayerTrack( commandArg1 ); if ( newTrack == NULL ) { NW_WARNING( false, "nw::snd::MmlParser: opentrack for not allocated track" ); break; } if ( newTrack == track ) { NW_WARNING( false, "nw::snd::MmlParser: opentrack for self track" ); break; } newTrack->Close(); newTrack->SetSeqData( trackParam.baseAddr, commandArg2 ); newTrack->Open(); break; } case MmlCommand::MML_JUMP: trackParam.currentAddr = trackParam.baseAddr + commandArg1; break; case MmlCommand::MML_CALL: { if ( trackParam.callStackDepth >= SequenceTrack::CALL_STACK_DEPTH ) { NW_WARNING( false, "nw::snd::MmlParser: cannot 'call' because already too deep"); break; } SequenceTrack::ParserTrackParam::CallStack* callStack = &trackParam.callStack[ trackParam.callStackDepth ]; callStack->address = trackParam.currentAddr; callStack->loopFlag = false; trackParam.callStackDepth++; trackParam.currentAddr = trackParam.baseAddr + commandArg1; break; } case MmlCommand::MML_RET: { SequenceTrack::ParserTrackParam::CallStack* callStack = NULL; while( trackParam.callStackDepth > 0 ) { trackParam.callStackDepth--; if ( ! trackParam.callStack[ trackParam.callStackDepth ].loopFlag ) { callStack = &trackParam.callStack[ trackParam.callStackDepth ]; break; } } if ( callStack == NULL ) { NW_WARNING( false, "nw::snd::MmlParser: unmatched sequence command 'ret'"); break; } trackParam.currentAddr = callStack->address; break; } case MmlCommand::MML_LOOP_START: { if ( trackParam.callStackDepth >= SequenceTrack::CALL_STACK_DEPTH ) { NW_WARNING( false, "nw::snd::MmlParser: cannot 'loop_start' because already too deep"); break; } SequenceTrack::ParserTrackParam::CallStack* callStack = &trackParam.callStack[ trackParam.callStackDepth ]; callStack->address = trackParam.currentAddr; callStack->loopCount = static_cast( commandArg1 ); callStack->loopFlag = true; trackParam.callStackDepth++; break; } case MmlCommand::MML_LOOP_END: { if ( trackParam.callStackDepth == 0 ) { NW_WARNING( false, "nw::snd::MmlParser: unmatched sequence command 'loop_end'"); break; } SequenceTrack::ParserTrackParam::CallStack* callStack = & trackParam.callStack[ trackParam.callStackDepth - 1 ]; if ( ! callStack->loopFlag ) { NW_WARNING( false, "nw::snd::MmlParser: unmatched sequence command 'loop_end'"); break; } u8 loop_count = callStack->loopCount; if ( loop_count > 0 ) { loop_count--; if ( loop_count == 0 ) { trackParam.callStackDepth--; break; } } callStack->loopCount = loop_count; trackParam.currentAddr = callStack->address; break; } } } else if ( command <= 0xffff ) // 2バイトコマンド { u32 cmd = command >> 8; u32 cmdex = command & 0xff; NW_ASSERT( cmd == MmlCommand::MML_EX_COMMAND ); // ----------------------------------------------------------------- // 拡張コマンド vs16* varPtr = NULL; if ( (( cmdex & 0xf0 ) == 0x80 ) || (( cmdex & 0xf0 ) == 0x90 ) ) { // シーケンス変数コマンドのときはシーケンス変数へのポインタを取得 varPtr = GetVariablePtr( player, track, commandArg1 ); if ( varPtr == NULL ) return; } switch ( cmdex ) { case MmlCommand::MML_SETVAR: *varPtr = static_cast( commandArg2 ); break; case MmlCommand::MML_ADDVAR: *varPtr += static_cast( commandArg2 ); break; case MmlCommand::MML_SUBVAR: *varPtr -= static_cast( commandArg2 ); break; case MmlCommand::MML_MULVAR: *varPtr *= static_cast( commandArg2 ); break; case MmlCommand::MML_DIVVAR: if ( commandArg2 != 0 ) *varPtr /= static_cast( commandArg2 ); break; case MmlCommand::MML_SHIFTVAR: if ( commandArg2 >= 0 ) { *varPtr <<= commandArg2; } else { *varPtr >>= -commandArg2; } break; case MmlCommand::MML_RANDVAR: { bool minus_flag = false; s32 rand; if ( commandArg2 < 0 ) { minus_flag = true; commandArg2 = static_cast( -commandArg2 ); } rand = Util::CalcRandom(); rand *= commandArg2 + 1; rand >>= 16; if ( minus_flag ) rand = -rand; *varPtr = static_cast( rand ); break; } case MmlCommand::MML_ANDVAR: *varPtr &= commandArg2; break; case MmlCommand::MML_ORVAR: *varPtr |= commandArg2; break; case MmlCommand::MML_XORVAR: *varPtr ^= commandArg2; break; case MmlCommand::MML_NOTVAR: *varPtr = static_cast( ~static_cast( commandArg2 ) ); break; case MmlCommand::MML_MODVAR: if ( commandArg2 != 0 ) *varPtr %= commandArg2; break; case MmlCommand::MML_CMP_EQ: trackParam.cmpFlag = ( *varPtr == commandArg2 ) ; break; case MmlCommand::MML_CMP_GE: trackParam.cmpFlag = ( *varPtr >= commandArg2 ) ; break; case MmlCommand::MML_CMP_GT: trackParam.cmpFlag = ( *varPtr > commandArg2 ) ; break; case MmlCommand::MML_CMP_LE: trackParam.cmpFlag = ( *varPtr <= commandArg2 ) ; break; case MmlCommand::MML_CMP_LT: trackParam.cmpFlag = ( *varPtr < commandArg2 ) ; break; case MmlCommand::MML_CMP_NE: trackParam.cmpFlag = ( *varPtr != commandArg2 ) ; break; case MmlCommand::MML_USERPROC: player->CallSequenceUserprocCallback( static_cast( commandArg1 ), // procId track ); break; } // switch ( cmdex ) } } /*---------------------------------------------------------------------------* Name: NoteOnCommandProc Description: ノートオンコマンドを処理します Arguments: track - トラックポインタ trackParam - パーサパラメータ key - キー番号 velocity - ベロシティ length - ノート長 Returns: None. *---------------------------------------------------------------------------*/ void MmlParser::NoteOnCommandProc( MmlSequenceTrack* track, int key, int velocity, s32 length, bool tieFlag ) const { track->NoteOn( key, velocity, length, tieFlag ); } /*---------------------------------------------------------------------------* Name: Read16 Description: シーケンスデータを2バイト読み込みます Arguments: Returns: 読み込んだデータ *---------------------------------------------------------------------------*/ u16 MmlParser::Read16( const u8** ptr ) const { u16 ret = ReadByte( ptr ); ret <<= 8; ret |= ReadByte( ptr ); return ret; } /*---------------------------------------------------------------------------* Name: Read24 Description: シーケンスデータを3バイト読み込みます Arguments: Returns: 読み込んだデータ *---------------------------------------------------------------------------*/ u32 MmlParser::Read24( const u8** ptr ) const { u32 ret = ReadByte( ptr ); ret <<= 8; ret |= ReadByte( ptr ); ret <<= 8; ret |= ReadByte( ptr ); return ret; } /*---------------------------------------------------------------------------* Name: ReadVar Description: 可変長シーケンスデータを読み込みます Arguments: Returns: 読み込んだデータ *---------------------------------------------------------------------------*/ s32 MmlParser::ReadVar( const u8** ptr ) const { s32 ret = 0; u8 b; int i; for( i = 0 ; ; ++i ) { NW_ASSERT( i < 4 ); b = ReadByte( ptr ); ret <<= 7; ret |= b & 0x7f; if ( ! ( b & 0x80 ) ) break; } return ret; } /*---------------------------------------------------------------------------* Name: ReadArg Description: シーケンスコマンド引数を読み込みます Arguments: player - プレイヤーポインタ argType - 引数タイプ Returns: 読み込んだ値 *---------------------------------------------------------------------------*/ s32 MmlParser::ReadArg( const u8** ptr, SequenceSoundPlayer* player, SequenceTrack* track, SeqArgType argType ) const { s32 var = 0; switch ( argType ) { case SEQ_ARG_U8: var = ReadByte( ptr ); break; case SEQ_ARG_S16: var = Read16( ptr ); break; case SEQ_ARG_VMIDI: var = ReadVar( ptr ); break; case SEQ_ARG_VARIABLE: { u8 varNo = ReadByte( ptr ); const vs16* varPtr = GetVariablePtr( player, track, varNo ); if ( varPtr != NULL ) { var = *varPtr; } break; } case SEQ_ARG_RANDOM: { s32 rand; s16 min; s16 max; min = static_cast( Read16( ptr ) ); max = static_cast( Read16( ptr ) ); rand = Util::CalcRandom(); /* 0x0000 - 0xffff */ rand *= ( max - min ) + 1; rand >>= 16; rand += min; var = rand; break; } } return var; } vs16* MmlParser::GetVariablePtr( SequenceSoundPlayer* player, SequenceTrack* track, int varNo ) const { NW_MINMAX_ASSERT( varNo, 0, SequenceSoundPlayer::PLAYER_VARIABLE_NUM + SequenceSoundPlayer::GLOBAL_VARIABLE_NUM + SequenceTrack::TRACK_VARIABLE_NUM ); if ( varNo < SequenceSoundPlayer::PLAYER_VARIABLE_NUM + SequenceSoundPlayer::GLOBAL_VARIABLE_NUM ) { return player->GetVariablePtr( varNo ); } else if ( varNo < SequenceSoundPlayer::PLAYER_VARIABLE_NUM + SequenceSoundPlayer::GLOBAL_VARIABLE_NUM + SequenceTrack::TRACK_VARIABLE_NUM ) { return track->GetVariablePtr( varNo - SequenceSoundPlayer::PLAYER_VARIABLE_NUM - SequenceSoundPlayer::GLOBAL_VARIABLE_NUM ); } else { return NULL; } } /*---------------------------------------------------------------------------* Name: ParseAllocTrack [static] Description: シーケンスデータを解析し、alloctrackコマンドを読みとります。 指定したオフセット位置に alloctrackコマンドがある場合は、 コマンド引数を読み取り、allocTrack引数へ格納し、 読み取り後のオフセット位置を返します。 alloctrackコマンドが無い場合は、 allocTrack引数へ"1"を代入し、オフセット位置をそのまま返します。 Arguments: baseAddress - シーケンスデータの先頭アドレス seqOffset - シーケンスデータの開始オフセット allocTrack - 確保すべきトラックのビットフラグを格納するアドレス Returns: 解析後のシーケンスデータの開始オフセット *---------------------------------------------------------------------------*/ u32 MmlParser::ParseAllocTrack( const void* baseAddress, u32 seqOffset, u32* allocTrack ) { NW_NULL_ASSERT( baseAddress ); NW_NULL_ASSERT( allocTrack ); const u8* ptr = static_cast( ut::AddOffsetToPtr( baseAddress, seqOffset ) ); if ( *ptr != MmlCommand::MML_ALLOC_TRACK ) { *allocTrack = (1 << 0); return seqOffset; } else { ++ptr; u32 tracks = *ptr; tracks <<= 8; ++ptr; tracks |= *ptr; *allocTrack = tracks; return seqOffset + 3; } } } // namespace nw::snd::internal::driver } // namespace nw::snd::internal } // namespace nw::snd } // namespace nw