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