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