1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     snd_MmlParser.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/snd/snd_MmlParser.h>
21 #include <nw/snd/snd_MmlCommand.h>
22 #include <nw/snd/snd_MmlSequenceTrack.h>
23 #include <nw/snd/snd_SequenceSoundPlayer.h>
24 #include <nw/snd/snd_Util.h>
25 #include <nw/config/platform.h> // NW_PLATFORM_ENDIAN
26 
27 namespace nw {
28 namespace snd {
29 namespace internal {
30 namespace driver {
31 
32 bool MmlParser::mPrintVarEnabledFlag;
33 
34 /*---------------------------------------------------------------------------*
35   Name:         Parse
36 
37   Description:  シーケンス処理を進めます
38 
39   Arguments:    player - プレイヤーポインタ
40                 trackNo - トラックナンバ
41                 doNoteOn - ノートオンするかどうか
42 
43   Returns:      シーケンス継続時には0を、完了時にはー1を返します
44  *---------------------------------------------------------------------------*/
Parse(MmlSequenceTrack * track,bool doNoteOn) const45 SequenceTrack::ParseResult MmlParser::Parse(
46     MmlSequenceTrack* track,
47     bool doNoteOn
48 ) const
49 {
50     NW_NULL_ASSERT( track );
51     SequenceSoundPlayer* player = track->GetSequenceSoundPlayer();
52     NW_NULL_ASSERT( player );
53     SequenceTrack::ParserTrackParam& trackParam = track->GetParserTrackParam();
54     SequenceSoundPlayer::ParserPlayerParam& playerParam = player->GetParserPlayerParam();
55 
56     SeqArgType argType = SEQ_ARG_NONE;
57     SeqArgType argType2 = SEQ_ARG_NONE;
58     bool useArgType = false;
59     bool doExecCommand = true;
60 
61     u32 cmd = ReadByte( &trackParam.currentAddr );
62 
63     // 接頭バイナリの処理
64     if ( cmd == MmlCommand::MML_IF )
65     {
66         cmd = ReadByte( &trackParam.currentAddr );
67         doExecCommand = trackParam.cmpFlag != 0;
68     }
69 
70     // 第2パラメータ
71     if ( cmd == MmlCommand::MML_TIME )
72     {
73         cmd = ReadByte( &trackParam.currentAddr );
74         argType2 = SEQ_ARG_S16;
75     }
76     else if ( cmd == MmlCommand::MML_TIME_RANDOM )
77     {
78         cmd = ReadByte( &trackParam.currentAddr );
79         argType2 = SEQ_ARG_RANDOM;
80     }
81     else if ( cmd == MmlCommand::MML_TIME_VARIABLE )
82     {
83         cmd = ReadByte( &trackParam.currentAddr );
84         argType2 = SEQ_ARG_VARIABLE;
85     }
86 
87     // パラメータ
88     if ( cmd == MmlCommand::MML_RANDOM )
89     {
90         cmd = ReadByte( &trackParam.currentAddr );
91         argType = SEQ_ARG_RANDOM;
92         useArgType = true;
93     }
94     else if ( cmd == MmlCommand::MML_VARIABLE )
95     {
96         cmd = ReadByte( &trackParam.currentAddr );
97         argType = SEQ_ARG_VARIABLE;
98         useArgType = true;
99     }
100 
101     if ( ( cmd & 0x80 ) == 0 )
102     {
103         // ノートコマンド
104         const u8 velocity = ReadByte( &trackParam.currentAddr );
105         const s32 length = ReadArg(
106             &trackParam.currentAddr,
107             player,
108             track,
109             useArgType ? argType : SEQ_ARG_VMIDI
110         );
111         int key = static_cast<int>( cmd ) + trackParam.transpose;
112         if ( ! doExecCommand ) return SequenceTrack::PARSE_RESULT_CONTINUE;
113 
114         key = ut::Clamp( key, 0, 127 );
115 
116         if ( ! trackParam.muteFlag && doNoteOn )
117         {
118             NoteOnCommandProc(
119                 track,
120                 key,
121                 velocity,
122                 length > 0 ? length : -1,
123                 trackParam.tieFlag
124             );
125         }
126 
127         if ( trackParam.noteWaitFlag ) {
128             trackParam.wait = length;
129             if ( length == 0 ) {
130                 trackParam.noteFinishWait = true;
131             }
132         }
133     }
134     else
135     {
136         s32 commandArg1 = 0;
137         s32 commandArg2 = 0;
138 
139         switch ( cmd & 0xf0 )
140         {
141         case 0x80:
142         {
143             switch ( cmd )
144             {
145             case MmlCommand::MML_WAIT:
146             {
147                 // ここで処理する
148                 s32 arg = ReadArg(
149                     &trackParam.currentAddr,
150                     player,
151                     track,
152                     useArgType ? argType : SEQ_ARG_VMIDI
153                 );
154                 if ( doExecCommand )
155                 {
156                     trackParam.wait = arg;
157                 }
158                 break;
159             }
160             case MmlCommand::MML_PRG:
161             {
162                 commandArg1 = ReadArg(
163                     &trackParam.currentAddr,
164                     player,
165                     track,
166                     useArgType ? argType : SEQ_ARG_VMIDI
167                 );
168                 if ( doExecCommand )
169                 {
170                     CommandProc(
171                         track,
172                         cmd,
173                         commandArg1,
174                         commandArg2
175                     );
176                 }
177                 break;
178             }
179             case MmlCommand::MML_OPEN_TRACK:
180             {
181                 u8 trackNo = ReadByte( &trackParam.currentAddr );
182                 u32 offset = Read24( &trackParam.currentAddr );
183                 if ( doExecCommand )
184                 {
185                     commandArg1 = trackNo;
186                     commandArg2 = static_cast<signed long>( offset );
187                     CommandProc(
188                         track,
189                         cmd,
190                         commandArg1,
191                         commandArg2
192                     );
193                 }
194                 break;
195             }
196             case MmlCommand::MML_JUMP:
197             {
198                 u32 offset = Read24( &trackParam.currentAddr );
199                 if ( doExecCommand )
200                 {
201                     commandArg1 = static_cast<signed long>( offset );
202                     CommandProc(
203                         track,
204                         cmd,
205                         commandArg1,
206                         commandArg2
207                     );
208                 }
209                 break;
210             }
211             case MmlCommand::MML_CALL:
212             {
213                 u32 offset = Read24( &trackParam.currentAddr );
214                 if ( doExecCommand )
215                 {
216                     commandArg1 = static_cast<signed long>( offset );
217                     CommandProc(
218                         track,
219                         cmd,
220                         commandArg1,
221                         commandArg2
222                     );
223                 }
224                 break;
225             }
226             }
227             break; // case 0x88 - 0x8f
228         }
229 
230         case 0xb0: case 0xc0: case 0xd0: // u8 パラメータ ( 一部 s8 パラメータが混ざってる )
231         {
232             u8 arg = static_cast<u8>( ReadArg(
233                 &trackParam.currentAddr,
234                 player,
235                 track,
236                 useArgType ? argType : SEQ_ARG_U8
237             ) );
238 
239             if ( argType2 != SEQ_ARG_NONE )
240             {
241                 commandArg2 = ReadArg(
242                     &trackParam.currentAddr,
243                     player,
244                     track,
245                     argType2
246                 );
247             }
248 
249             if ( doExecCommand )
250             {
251                 switch ( cmd )
252                 {
253                 case MmlCommand::MML_TRANSPOSE:
254                 case MmlCommand::MML_PITCH_BEND:
255                     commandArg1 = *reinterpret_cast<s8*>( &arg );
256                     break;
257                 default:
258                     commandArg1 = arg;
259                 }
260 
261                 CommandProc(
262                     track,
263                     cmd,
264                     commandArg1,
265                     commandArg2
266                 );
267             }
268             break;
269         }
270 
271         case 0x90: // 予備
272         {
273             if ( doExecCommand )
274             {
275                 CommandProc(
276                     track,
277                     cmd,
278                     commandArg1,
279                     commandArg2
280                 );
281             }
282             break;
283         }
284 
285         case 0xe0: // s16 パラメータ
286         {
287             commandArg1 = static_cast<s16>( ReadArg(
288                 &trackParam.currentAddr,
289                 player,
290                 track,
291                 useArgType ? argType : SEQ_ARG_S16
292             ) );
293 
294             if ( doExecCommand )
295             {
296                 CommandProc(
297                     track,
298                     cmd,
299                     commandArg1,
300                     commandArg2
301                 );
302             }
303             break;
304         }
305 
306         case 0xf0: // パラメータ無し or 拡張コマンド
307         {
308 
309             switch ( cmd )
310             {
311             case MmlCommand::MML_ALLOC_TRACK:
312                 (void)Read16( &trackParam.currentAddr );
313                 NW_ASSERTMSG( false, "seq: must use alloctrack in startup code");
314                 break;
315 
316             case MmlCommand::MML_FIN:
317                 if ( doExecCommand )
318                 {
319                     return SequenceTrack::PARSE_RESULT_FINISH;
320                 }
321                 break;
322 
323             case MmlCommand::MML_EX_COMMAND:
324             {
325                 u32 cmdex = ReadByte( &trackParam.currentAddr );
326 
327                 switch ( cmdex & 0xf0 )
328                 {
329 
330                 case 0xe0: // u16 パラメータ
331                 {
332                     commandArg1 = static_cast<u16>( ReadArg(
333                         &trackParam.currentAddr,
334                         player,
335                         track,
336                         useArgType ? argType : SEQ_ARG_S16
337                     ) );
338                     if ( doExecCommand )
339                     {
340                         CommandProc(
341                             track,
342                             (cmd << 8) + cmdex,
343                             commandArg1,
344                             commandArg2
345                         );
346                     }
347                     break;
348                 }
349 
350                 case 0x80: case 0x90: // 2パラメータ
351                 {
352                     commandArg1 = ReadByte( &trackParam.currentAddr );
353                     commandArg2 = static_cast<s16>( ReadArg(
354                         &trackParam.currentAddr,
355                         player,
356                         track,
357                         useArgType ? argType : SEQ_ARG_S16
358                     ) );
359                     if ( doExecCommand )
360                     {
361                         CommandProc(
362                             track,
363                             (cmd << 8) + cmdex,
364                             commandArg1,
365                             commandArg2
366                         );
367                     }
368                     break;
369                 }
370                 }
371             } // case MmlCommand::MML_EX_COMMAND
372 
373             default:
374             {
375                 if ( doExecCommand )
376                 {
377                     CommandProc(
378                         track,
379                         cmd,
380                         commandArg1,
381                         commandArg2
382                     );
383                 }
384                 break;
385             }
386             } // case 0xf0 - 0xff
387             break;
388         } // case 0xf0
389 
390         case 0xa0: // 接頭コマンド
391         {
392             // ここに接頭コマンドがあるのは不正
393             NW_ASSERTMSG( false, "Invalid seqdata command: %d", cmd );
394         }
395         }
396     }
397 
398     return SequenceTrack::PARSE_RESULT_CONTINUE;
399 }
400 
401 /*---------------------------------------------------------------------------*
402   Name:         CommandProc
403 
404   Description:  一つのMMLコマンドに対する処理を行います。
405 
406   Arguments:    track - トラックポインタ
407                 trackParam - パーサパラメータ
408                 cmd     - コマンド
409                 cmdex   - 拡張コマンド
410                 commandArg1  - コマンドパラメータ1
411                 commandArg2  - コマンドパラメータ2
412 
413   Returns:      なし
414  *---------------------------------------------------------------------------*/
CommandProc(MmlSequenceTrack * track,u32 command,s32 commandArg1,s32 commandArg2) const415 void MmlParser::CommandProc(
416     MmlSequenceTrack* track,
417     u32 command,
418     s32 commandArg1,
419     s32 commandArg2
420 ) const
421 {
422     NW_NULL_ASSERT( track );
423     SequenceSoundPlayer* player = track->GetSequenceSoundPlayer();
424     NW_NULL_ASSERT( player );
425     SequenceTrack::ParserTrackParam& trackParam = track->GetParserTrackParam();
426     SequenceSoundPlayer::ParserPlayerParam& playerParam = player->GetParserPlayerParam();
427 
428     if ( command <= 0xff ) // 1バイトコマンド
429     {
430         switch ( command )
431         {
432 
433         case MmlCommand::MML_TEMPO:
434             playerParam.tempo = static_cast<u16>(
435                 ut::Clamp( static_cast<int>( commandArg1 ), TEMPO_MIN, TEMPO_MAX )
436             );
437             break;
438 
439         case MmlCommand::MML_TIMEBASE:
440             playerParam.timebase = static_cast<u8>( commandArg1 );
441             break;
442 
443         case MmlCommand::MML_PRG:
444             if ( commandArg1 < 0x10000 )
445             {
446                 trackParam.prgNo = static_cast<u16>( commandArg1 );
447             }
448             else
449             {
450                 NW_WARNING( false, "nw::snd::MmlParser: too large prg No. %d", commandArg1 );
451             }
452             break;
453 
454         case MmlCommand::MML_MUTE:
455             track->SetMute( static_cast<SeqMute>( commandArg1 ) );
456             break;
457 
458         case MmlCommand::MML_VOLUME:
459             trackParam.volume.SetTarget(
460                 static_cast<u8>( commandArg1 ),
461                 static_cast<s16>( commandArg2 )
462             );
463             break;
464 
465         case MmlCommand::MML_VOLUME2:
466             trackParam.volume2 = static_cast<u8>( commandArg1 );
467             break;
468 
469         case MmlCommand::MML_VELOCITY_RANGE:
470             trackParam.velocityRange = static_cast<u8>( commandArg1 );
471             break;
472 
473         case MmlCommand::MML_MAIN_VOLUME:
474             playerParam.volume = static_cast<u8>( commandArg1 );
475             break;
476 
477         case MmlCommand::MML_TRANSPOSE:
478             trackParam.transpose = static_cast<s8>( commandArg1 );
479             break;
480 
481         case MmlCommand::MML_PITCH_BEND:
482             trackParam.pitchBend.SetTarget(
483                 static_cast<s8>( commandArg1 ),
484                 static_cast<s16>( commandArg2 )
485             );
486             break;
487 
488         case MmlCommand::MML_BEND_RANGE:
489             trackParam.bendRange = static_cast<u8>( commandArg1 );
490             break;
491 
492         case MmlCommand::MML_PAN:
493             trackParam.pan.SetTarget(
494                 static_cast<s8>( commandArg1 - PAN_CENTER ),
495                 static_cast<s16>( commandArg2 )
496             );
497             break;
498 
499         case MmlCommand::MML_INIT_PAN:
500             trackParam.initPan = static_cast<s8>( commandArg1 - PAN_CENTER );
501             break;
502 
503         case MmlCommand::MML_SURROUND_PAN:
504             trackParam.surroundPan.SetTarget(
505                 static_cast<s8>( commandArg1 ),
506                 static_cast<s16>( commandArg2 )
507             );
508             break;
509 
510         case MmlCommand::MML_PRIO:
511             trackParam.priority = static_cast<u8>( commandArg1 );
512             break;
513 
514         case MmlCommand::MML_NOTE_WAIT:
515             trackParam.noteWaitFlag = ( commandArg1 != 0 );
516             break;
517 
518         case MmlCommand::MML_FRONT_BYPASS:
519             trackParam.frontBypassFlag = ( commandArg1 != 0 );
520             break;
521 
522         case MmlCommand::MML_PORTA_TIME:
523             trackParam.portaTime = static_cast<u8>( commandArg1 );
524             break;
525 
526         case MmlCommand::MML_MOD_DEPTH:
527             trackParam.lfoParam.depth = static_cast<u8>( commandArg1 ) / 128.0f;
528             break;
529 
530         case MmlCommand::MML_MOD_SPEED:
531             trackParam.lfoParam.speed = static_cast<u8>( commandArg1 ) * 0.390625f; // 16 で 6.25Hz
532             break;
533 
534         case MmlCommand::MML_MOD_TYPE:
535             trackParam.lfoTarget = static_cast<u8>( commandArg1 );
536             break;
537 
538         case MmlCommand::MML_MOD_RANGE:
539             trackParam.lfoParam.range = static_cast<u8>( commandArg1 );
540             break;
541 
542         case MmlCommand::MML_MOD_DELAY:
543             trackParam.lfoParam.delay = static_cast<u32>( commandArg1 * 5 ); // 単位5ms
544             break;
545 
546         case MmlCommand::MML_SWEEP_PITCH:
547             trackParam.sweepPitch = static_cast<f32>( commandArg1 ) / 64.0f;
548             break;
549 
550         case MmlCommand::MML_ATTACK:
551             trackParam.attack = static_cast<u8>( commandArg1 );
552             break;
553 
554         case MmlCommand::MML_DECAY:
555             trackParam.decay = static_cast<u8>( commandArg1 );
556             break;
557 
558         case MmlCommand::MML_SUSTAIN:
559             trackParam.sustain = static_cast<u8>( commandArg1 );
560             break;
561 
562         case MmlCommand::MML_RELEASE:
563             trackParam.release = static_cast<u8>( commandArg1 );
564             break;
565 
566         case MmlCommand::MML_ENV_HOLD:
567             trackParam.envHold = static_cast<u8>( commandArg1 );
568             break;
569 
570         case MmlCommand::MML_ENV_RESET:
571             trackParam.attack = SequenceTrack::INVALID_ENVELOPE;
572             trackParam.decay = SequenceTrack::INVALID_ENVELOPE;
573             trackParam.sustain = SequenceTrack::INVALID_ENVELOPE;
574             trackParam.release = SequenceTrack::INVALID_ENVELOPE;
575             trackParam.envHold = SequenceTrack::INVALID_ENVELOPE;
576             break;
577 
578         case MmlCommand::MML_DAMPER:
579             trackParam.damperFlag = ( static_cast<u8>( commandArg1 ) >= 64 );
580             break;
581 
582         case MmlCommand::MML_TIE:
583             trackParam.tieFlag = ( commandArg1 != 0 );
584             track->ReleaseAllChannel( -1 );
585             track->FreeAllChannel();
586             break;
587 
588         case MmlCommand::MML_MONOPHONIC:
589             trackParam.monophonicFlag = ( commandArg1 != 0 );
590             if ( trackParam.monophonicFlag )
591             {
592                 track->ReleaseAllChannel( -1 );
593                 track->FreeAllChannel();
594             }
595             break;
596 
597         case MmlCommand::MML_PORTA:
598             trackParam.portaKey = static_cast<u8>( commandArg1 + trackParam.transpose );
599             trackParam.portaFlag = true;
600             break;
601 
602         case MmlCommand::MML_PORTA_SW:
603             trackParam.portaFlag = ( commandArg1 != 0 );
604             break;
605 
606         case MmlCommand::MML_LPF_CUTOFF:
607             trackParam.lpfFreq = static_cast<f32>( commandArg1 - 64 ) / 64.0f;
608             break;
609 
610         case MmlCommand::MML_BIQUAD_TYPE:
611             trackParam.biquadType = static_cast<u8>( commandArg1 );
612             break;
613 
614         case MmlCommand::MML_BIQUAD_VALUE:
615             trackParam.biquadValue = static_cast<f32>( commandArg1 ) / 127.0f;
616             break;
617 
618         case MmlCommand::MML_BANK_SELECT:
619             trackParam.bankIndex = static_cast<u8>( commandArg1 );
620             break;
621 
622         case MmlCommand::MML_FXSEND_A:
623             trackParam.fxSend[ AUX_BUS_A ] = static_cast<u8>( commandArg1 );
624             break;
625 
626         case MmlCommand::MML_FXSEND_B:
627             trackParam.fxSend[ AUX_BUS_B ] = static_cast<u8>( commandArg1 );
628             break;
629 
630 #ifdef NW_PLATFORM_RVL
631         case MmlCommand::MML_FXSEND_C:
632             trackParam.fxSend[ AUX_BUS_C ] = static_cast<u8>( commandArg1 );
633             break;
634 #endif
635 
636         case MmlCommand::MML_MAINSEND:
637             trackParam.mainSend = static_cast<u8>( commandArg1 );
638             break;
639 
640         case MmlCommand::MML_PRINTVAR:
641             if ( mPrintVarEnabledFlag ) {
642                 const vs16* const varPtr = GetVariablePtr( player, track, commandArg1 );
643                 NN_LOG( "#%08x[%d]: printvar %sVAR_%d(%d) = %d\n",
644                     player,
645                     track->GetPlayerTrackNo(),
646                     ( commandArg1 >= 32 )? "T": ( commandArg1 >= 16 )? "G": "",
647                     ( commandArg1 >= 32 )? commandArg1-32: ( commandArg1 >= 16 )? commandArg1-16: commandArg1,
648                     commandArg1,
649                     *varPtr );
650             }
651             break;
652 
653         case MmlCommand::MML_OPEN_TRACK:
654         {
655             SequenceTrack* newTrack = player->GetPlayerTrack( commandArg1 );
656             if ( newTrack == NULL )
657             {
658                 NW_WARNING( false, "nw::snd::MmlParser: opentrack for not allocated track" );
659                 break;
660             }
661             if ( newTrack == track )
662             {
663                 NW_WARNING( false, "nw::snd::MmlParser: opentrack for self track" );
664                 break;
665             }
666             newTrack->Close();
667             newTrack->SetSeqData( trackParam.baseAddr, commandArg2 );
668             newTrack->Open();
669             break;
670         }
671 
672         case MmlCommand::MML_JUMP:
673             trackParam.currentAddr = trackParam.baseAddr + commandArg1;
674             break;
675 
676         case MmlCommand::MML_CALL:
677         {
678             if ( trackParam.callStackDepth >= SequenceTrack::CALL_STACK_DEPTH ) {
679                 NW_WARNING( false, "nw::snd::MmlParser: cannot 'call' because already too deep");
680                 break;
681             }
682 
683             SequenceTrack::ParserTrackParam::CallStack* callStack = &trackParam.callStack[ trackParam.callStackDepth ];
684             callStack->address = trackParam.currentAddr;
685             callStack->loopFlag = false;
686             trackParam.callStackDepth++;
687             trackParam.currentAddr = trackParam.baseAddr + commandArg1;
688             break;
689         }
690 
691         case MmlCommand::MML_RET:
692         {
693             SequenceTrack::ParserTrackParam::CallStack* callStack = NULL;
694             while( trackParam.callStackDepth > 0 ) {
695                 trackParam.callStackDepth--;
696                 if ( ! trackParam.callStack[ trackParam.callStackDepth ].loopFlag ) {
697                     callStack = &trackParam.callStack[ trackParam.callStackDepth ];
698                     break;
699                 }
700             }
701             if ( callStack == NULL ) {
702                 NW_WARNING( false, "nw::snd::MmlParser: unmatched sequence command 'ret'");
703                 break;
704             }
705             trackParam.currentAddr = callStack->address;
706             break;
707         }
708 
709         case MmlCommand::MML_LOOP_START:
710         {
711             if ( trackParam.callStackDepth >= SequenceTrack::CALL_STACK_DEPTH ) {
712                 NW_WARNING( false, "nw::snd::MmlParser: cannot 'loop_start' because already too deep");
713                 break;
714             }
715 
716             SequenceTrack::ParserTrackParam::CallStack* callStack = &trackParam.callStack[ trackParam.callStackDepth ];
717             callStack->address = trackParam.currentAddr;
718             callStack->loopCount = static_cast<u8>( commandArg1 );
719             callStack->loopFlag = true;
720             trackParam.callStackDepth++;
721             break;
722         }
723 
724         case MmlCommand::MML_LOOP_END:
725         {
726             if ( trackParam.callStackDepth == 0 ) {
727                 NW_WARNING( false, "nw::snd::MmlParser: unmatched sequence command 'loop_end'");
728                 break;
729             }
730 
731             SequenceTrack::ParserTrackParam::CallStack* callStack = & trackParam.callStack[ trackParam.callStackDepth - 1 ];
732             if ( ! callStack->loopFlag ) {
733                 NW_WARNING( false, "nw::snd::MmlParser: unmatched sequence command 'loop_end'");
734                 break;
735             }
736 
737             u8 loop_count = callStack->loopCount;
738             if ( loop_count > 0 ) {
739                 loop_count--;
740                 if ( loop_count == 0 ) {
741                     trackParam.callStackDepth--;
742                     break;
743                 }
744             }
745 
746             callStack->loopCount = loop_count;
747             trackParam.currentAddr = callStack->address;
748             break;
749         }
750         }
751     }
752     else if ( command <= 0xffff ) // 2バイトコマンド
753     {
754         u32 cmd = command >> 8;
755         u32 cmdex = command & 0xff;
756         NW_ASSERT( cmd == MmlCommand::MML_EX_COMMAND );
757 
758         // -----------------------------------------------------------------
759         // 拡張コマンド
760 
761         vs16* varPtr = NULL;
762         if ( (( cmdex & 0xf0 ) == 0x80 ) ||
763              (( cmdex & 0xf0 ) == 0x90 )
764            )
765         {
766             // シーケンス変数コマンドのときはシーケンス変数へのポインタを取得
767             varPtr = GetVariablePtr( player, track, commandArg1 );
768             if ( varPtr == NULL ) return;
769         }
770 
771         switch ( cmdex )
772         {
773         case MmlCommand::MML_SETVAR:
774             *varPtr = static_cast<s16>( commandArg2 );
775             break;
776 
777         case MmlCommand::MML_ADDVAR:
778             *varPtr += static_cast<s16>( commandArg2 );
779             break;
780 
781         case MmlCommand::MML_SUBVAR:
782             *varPtr -= static_cast<s16>( commandArg2 );
783             break;
784 
785         case MmlCommand::MML_MULVAR:
786             *varPtr *= static_cast<s16>( commandArg2 );
787             break;
788 
789         case MmlCommand::MML_DIVVAR:
790             if ( commandArg2 != 0 ) *varPtr /= static_cast<s16>( commandArg2 );
791             break;
792 
793         case MmlCommand::MML_SHIFTVAR:
794             if ( commandArg2 >= 0 )
795             {
796                 *varPtr <<= commandArg2;
797             }
798             else
799             {
800                 *varPtr >>= -commandArg2;
801             }
802             break;
803 
804         case MmlCommand::MML_RANDVAR:
805         {
806             bool minus_flag = false;
807             s32 rand;
808 
809             if ( commandArg2 < 0 ) {
810                 minus_flag = true;
811                 commandArg2 = static_cast<s16>( -commandArg2 );
812             }
813 
814             rand = Util::CalcRandom();
815             rand *= commandArg2 + 1;
816             rand >>= 16;
817             if ( minus_flag ) rand = -rand;
818             *varPtr = static_cast<s16>( rand );
819             break;
820 
821         }
822 
823         case MmlCommand::MML_ANDVAR:
824             *varPtr &= commandArg2;
825             break;
826 
827         case MmlCommand::MML_ORVAR:
828             *varPtr |= commandArg2;
829             break;
830 
831         case MmlCommand::MML_XORVAR:
832             *varPtr ^= commandArg2;
833             break;
834 
835         case MmlCommand::MML_NOTVAR:
836             *varPtr = static_cast<s16>( ~static_cast<u16>( commandArg2 ) );
837             break;
838 
839         case MmlCommand::MML_MODVAR:
840             if ( commandArg2 != 0 ) *varPtr %= commandArg2;
841             break;
842 
843         case MmlCommand::MML_CMP_EQ:
844             trackParam.cmpFlag = ( *varPtr == commandArg2 ) ;
845             break;
846 
847         case MmlCommand::MML_CMP_GE:
848             trackParam.cmpFlag = ( *varPtr >= commandArg2 ) ;
849             break;
850 
851         case MmlCommand::MML_CMP_GT:
852             trackParam.cmpFlag = ( *varPtr > commandArg2 ) ;
853             break;
854 
855         case MmlCommand::MML_CMP_LE:
856             trackParam.cmpFlag = ( *varPtr <= commandArg2 ) ;
857             break;
858 
859         case MmlCommand::MML_CMP_LT:
860             trackParam.cmpFlag = ( *varPtr < commandArg2 ) ;
861             break;
862 
863         case MmlCommand::MML_CMP_NE:
864             trackParam.cmpFlag = ( *varPtr != commandArg2 ) ;
865             break;
866 
867         case MmlCommand::MML_USERPROC:
868             player->CallSequenceUserprocCallback(
869                 static_cast<u16>( commandArg1 ), // procId
870                 track
871             );
872             break;
873 
874         } // switch ( cmdex )
875     }
876 }
877 
878 /*---------------------------------------------------------------------------*
879   Name:         NoteOnCommandProc
880 
881   Description:  ノートオンコマンドを処理します
882 
883   Arguments:    track - トラックポインタ
884                 trackParam - パーサパラメータ
885                 key      - キー番号
886                 velocity - ベロシティ
887                 length   - ノート長
888 
889   Returns:      None.
890  *---------------------------------------------------------------------------*/
NoteOnCommandProc(MmlSequenceTrack * track,int key,int velocity,s32 length,bool tieFlag) const891 void MmlParser::NoteOnCommandProc(
892     MmlSequenceTrack* track,
893     int key,
894     int velocity,
895     s32 length,
896     bool tieFlag
897 ) const
898 {
899     track->NoteOn( key, velocity, length, tieFlag );
900 }
901 
902 /*---------------------------------------------------------------------------*
903   Name:         Read16
904 
905   Description:  シーケンスデータを2バイト読み込みます
906 
907   Arguments:
908 
909   Returns:      読み込んだデータ
910  *---------------------------------------------------------------------------*/
Read16(const u8 ** ptr) const911 u16 MmlParser::Read16( const u8** ptr ) const
912 {
913     u16 ret = ReadByte( ptr );
914     ret <<= 8;
915     ret |= ReadByte( ptr );
916     return ret;
917 }
918 
919 /*---------------------------------------------------------------------------*
920   Name:         Read24
921 
922   Description:  シーケンスデータを3バイト読み込みます
923 
924   Arguments:
925 
926   Returns:      読み込んだデータ
927  *---------------------------------------------------------------------------*/
Read24(const u8 ** ptr) const928 u32 MmlParser::Read24( const u8** ptr ) const
929 {
930     u32 ret = ReadByte( ptr );
931     ret <<= 8;
932     ret |= ReadByte( ptr );
933     ret <<= 8;
934     ret |= ReadByte( ptr );
935     return ret;
936 }
937 
938 /*---------------------------------------------------------------------------*
939   Name:         ReadVar
940 
941   Description:  可変長シーケンスデータを読み込みます
942 
943   Arguments:
944 
945   Returns:      読み込んだデータ
946  *---------------------------------------------------------------------------*/
ReadVar(const u8 ** ptr) const947 s32 MmlParser::ReadVar( const u8** ptr ) const
948 {
949     s32 ret = 0;
950     u8 b;
951     int i;
952 
953     for( i = 0 ; ; ++i ) {
954         NW_ASSERT( i < 4 );
955         b = ReadByte( ptr );
956         ret <<= 7;
957         ret |= b & 0x7f;
958         if ( ! ( b & 0x80 ) ) break;
959     }
960 
961     return ret;
962 }
963 
964 /*---------------------------------------------------------------------------*
965   Name:         ReadArg
966 
967   Description:  シーケンスコマンド引数を読み込みます
968 
969   Arguments:    player - プレイヤーポインタ
970                 argType - 引数タイプ
971 
972   Returns:      読み込んだ値
973  *---------------------------------------------------------------------------*/
ReadArg(const u8 ** ptr,SequenceSoundPlayer * player,SequenceTrack * track,SeqArgType argType) const974 s32 MmlParser::ReadArg( const u8** ptr, SequenceSoundPlayer* player, SequenceTrack* track, SeqArgType argType ) const
975 {
976     s32 var = 0;
977 
978     switch ( argType ) {
979 
980     case SEQ_ARG_U8:
981         var = ReadByte( ptr );
982         break;
983 
984     case SEQ_ARG_S16:
985         var = Read16( ptr );
986         break;
987 
988     case SEQ_ARG_VMIDI:
989         var = ReadVar( ptr );
990         break;
991 
992     case SEQ_ARG_VARIABLE: {
993         u8 varNo = ReadByte( ptr );
994         const vs16* varPtr = GetVariablePtr( player, track, varNo );
995         if ( varPtr != NULL ) {
996             var = *varPtr;
997         }
998         break;
999     }
1000 
1001     case SEQ_ARG_RANDOM: {
1002         s32 rand;
1003         s16 min;
1004         s16 max;
1005 
1006         min = static_cast<s16>( Read16( ptr ) );
1007         max = static_cast<s16>( Read16( ptr ) );
1008 
1009         rand = Util::CalcRandom();  /* 0x0000 - 0xffff */
1010         rand *= ( max - min ) + 1;
1011         rand >>= 16;
1012         rand += min;
1013         var = rand;
1014         break;
1015     }
1016 
1017     }
1018 
1019     return var;
1020 }
1021 
GetVariablePtr(SequenceSoundPlayer * player,SequenceTrack * track,int varNo) const1022 vs16* MmlParser::GetVariablePtr( SequenceSoundPlayer* player, SequenceTrack* track, int varNo ) const
1023 {
1024     NW_MINMAX_ASSERT(
1025         varNo,
1026         0,
1027         SequenceSoundPlayer::PLAYER_VARIABLE_NUM + SequenceSoundPlayer::GLOBAL_VARIABLE_NUM + SequenceTrack::TRACK_VARIABLE_NUM
1028     );
1029 
1030     if ( varNo < SequenceSoundPlayer::PLAYER_VARIABLE_NUM
1031                + SequenceSoundPlayer::GLOBAL_VARIABLE_NUM )
1032     {
1033         return player->GetVariablePtr( varNo );
1034     }
1035     else if ( varNo < SequenceSoundPlayer::PLAYER_VARIABLE_NUM
1036                     + SequenceSoundPlayer::GLOBAL_VARIABLE_NUM
1037                     + SequenceTrack::TRACK_VARIABLE_NUM )
1038     {
1039         return track->GetVariablePtr( varNo - SequenceSoundPlayer::PLAYER_VARIABLE_NUM - SequenceSoundPlayer::GLOBAL_VARIABLE_NUM );
1040     }
1041     else
1042     {
1043         return NULL;
1044     }
1045 }
1046 
1047 /*---------------------------------------------------------------------------*
1048   Name:         ParseAllocTrack [static]
1049 
1050   Description:  シーケンスデータを解析し、alloctrackコマンドを読みとります。
1051                 指定したオフセット位置に alloctrackコマンドがある場合は、
1052                 コマンド引数を読み取り、allocTrack引数へ格納し、
1053                 読み取り後のオフセット位置を返します。
1054                 alloctrackコマンドが無い場合は、
1055                 allocTrack引数へ"1"を代入し、オフセット位置をそのまま返します。
1056 
1057   Arguments:    baseAddress - シーケンスデータの先頭アドレス
1058                 seqOffset - シーケンスデータの開始オフセット
1059                 allocTrack - 確保すべきトラックのビットフラグを格納するアドレス
1060 
1061   Returns:      解析後のシーケンスデータの開始オフセット
1062   *---------------------------------------------------------------------------*/
ParseAllocTrack(const void * baseAddress,u32 seqOffset,u32 * allocTrack)1063 u32 MmlParser::ParseAllocTrack( const void* baseAddress, u32 seqOffset, u32* allocTrack )
1064 {
1065     NW_NULL_ASSERT( baseAddress );
1066     NW_NULL_ASSERT( allocTrack );
1067 
1068     const u8* ptr = static_cast<const u8*>( ut::AddOffsetToPtr( baseAddress, seqOffset ) );
1069     if ( *ptr != MmlCommand::MML_ALLOC_TRACK ) {
1070         *allocTrack = (1 << 0);
1071         return seqOffset;
1072     }
1073     else {
1074         ++ptr;
1075         u32 tracks = *ptr;
1076         tracks <<= 8;
1077         ++ptr;
1078         tracks |= *ptr;
1079         *allocTrack = tracks;
1080         return seqOffset + 3;
1081     }
1082 }
1083 
1084 } // namespace nw::snd::internal::driver
1085 } // namespace nw::snd::internal
1086 } // namespace nw::snd
1087 } // namespace nw
1088 
1089