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