Browse code

[NCSF] Implemented the random, variable, and conditional commands. Also fixed loop counter.

Naram Qashat authored on 2014/10/13 18:00:29
Showing 7 changed files
... ...
@@ -52,6 +52,9 @@ v1.9.1 - 2014-10-05 - Fixed volume issues that stemmed from how FeOS Sound
52 52
                     - Added a clone of DeSmuME's Sound View that only shows up
53 53
                       in debug builds, was used to help me identify the above
54 54
                       issue to fix it.
55
+ v1.10 - 2014-10-13 - Implemented the random, variable, and conditional
56
+                      commands.
57
+                    - Fixed loop counter.
55 58
 
56 59
 This is a Winamp plugin to play NCSF files. NCSF is a PSF-style music format that
57 60
 uses SDAT files from Nintendo DS ROMs as it's "program".
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Player structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-05-07
4
+ * Last modification on 2014-10-13
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -16,6 +16,7 @@ Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), m
16 16
 	memset(this->trackIds, 0, sizeof(this->trackIds));
17 17
 	for (size_t i = 0; i < 16; ++i)
18 18
 		this->channels[i].chnId = i;
19
+	memset(this->variables, -1, sizeof(this->variables));
19 20
 }
20 21
 
21 22
 bool Player::Setup(const SSEQ *sseqToPlay)
... ...
@@ -57,6 +58,7 @@ void Player::ClearState()
57 58
 	this->tempoCount = 0;
58 59
 	this->tempoRate = 0x100;
59 60
 	this->masterVol = 0; // this is actually the highest level
61
+	memset(this->variables, -1, sizeof(this->variables));
60 62
 }
61 63
 
62 64
 void Player::FreeTracks()
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Player structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-08
4
+ * Last modification on 2014-10-13
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -26,6 +26,7 @@ struct Player
26 26
 	uint8_t trackIds[FSS_TRACKCOUNT];
27 27
 	Track tracks[FSS_MAXTRACKS];
28 28
 	Channel channels[16];
29
+	int16_t variables[32];
29 30
 
30 31
 	uint32_t sampleRate;
31 32
 	Interpolation interpolation;
... ...
@@ -1,13 +1,15 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-10-05
4
+ * Last modification on 2014-10-13
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
8 8
  * https://github.com/fincs/FSS
9 9
  */
10 10
 
11
+#include <functional>
12
+#include <cstdlib>
11 13
 #include "Track.h"
12 14
 #include "Player.h"
13 15
 #include "common.h"
... ...
@@ -35,9 +37,11 @@ void Track::Zero()
35 37
 	this->ply = nullptr;
36 38
 
37 39
 	this->startPos = this->pos = nullptr;
38
-	memset(this->stack, 0, sizeof(this->stack));
40
+	std::fill_n(&this->stack[0], FSS_TRACKSTACKSIZE, StackValue());
39 41
 	this->stackPos = 0;
40 42
 	memset(this->loopCount, 0, sizeof(this->loopCount));
43
+	this->overriding() = false;
44
+	this->lastComparisonResult = this->processCommand = true;
41 45
 
42 46
 	this->wait = 0;
43 47
 	this->patch = 0;
... ...
@@ -298,11 +302,95 @@ enum SseqCommand
298 302
 	SSEQ_CMD_RANDOM = 0xA0,
299 303
 	SSEQ_CMD_PRINTVAR = 0xD6,
300 304
 	SSEQ_CMD_IF = 0xA2,
301
-	SSEQ_CMD_UNSUP1 = 0xA1,
302
-	SSEQ_CMD_UNSUP2_LO = 0xB0,
303
-	SSEQ_CMD_UNSUP2_HI = 0xBD
305
+	SSEQ_CMD_FROMVAR = 0xA1,
306
+	SSEQ_CMD_SETVAR = 0xB0,
307
+	SSEQ_CMD_ADDVAR = 0xB1,
308
+	SSEQ_CMD_SUBVAR = 0xB2,
309
+	SSEQ_CMD_MULVAR = 0xB3,
310
+	SSEQ_CMD_DIVVAR = 0xB4,
311
+	SSEQ_CMD_SHIFTVAR = 0xB5,
312
+	SSEQ_CMD_RANDVAR = 0xB6,
313
+	SSEQ_CMD_CMP_EQ = 0xB8,
314
+	SSEQ_CMD_CMP_GE = 0xB9,
315
+	SSEQ_CMD_CMP_GT = 0xBA,
316
+	SSEQ_CMD_CMP_LE = 0xBB,
317
+	SSEQ_CMD_CMP_LT = 0xBC,
318
+	SSEQ_CMD_CMP_NE = 0xBD,
319
+
320
+	SSEQ_CMD_MUTE = 0xD7 // Unsupported
304 321
 };
305 322
 
323
+static auto varFuncSet = [](int16_t, int16_t value) { return value; };
324
+static auto varFuncAdd = [](int16_t var, int16_t value) -> int16_t { return var + value; };
325
+static auto varFuncSub = [](int16_t var, int16_t value) -> int16_t { return var - value; };
326
+static auto varFuncMul = [](int16_t var, int16_t value) -> int16_t { return var * value; };
327
+static auto varFuncDiv = [](int16_t var, int16_t value) -> int16_t { return var / value; };
328
+static auto varFuncShift = [](int16_t var, int16_t value) -> int16_t
329
+{
330
+	if (value < 0)
331
+		return var >> -value;
332
+	else
333
+		return var << value;
334
+};
335
+static auto varFuncRand = [](int16_t, int16_t value) -> int16_t
336
+{
337
+	if (value < 0)
338
+		return -(std::rand() % (-value + 1));
339
+	else
340
+		return std::rand() % (value + 1);
341
+};
342
+
343
+static inline std::function<int16_t (int16_t, int16_t)> VarFunc(int cmd)
344
+{
345
+	switch (cmd)
346
+	{
347
+		case SSEQ_CMD_SETVAR:
348
+			return varFuncSet;
349
+		case SSEQ_CMD_ADDVAR:
350
+			return varFuncAdd;
351
+		case SSEQ_CMD_SUBVAR:
352
+			return varFuncSub;
353
+		case SSEQ_CMD_MULVAR:
354
+			return varFuncMul;
355
+		case SSEQ_CMD_DIVVAR:
356
+			return varFuncDiv;
357
+		case SSEQ_CMD_SHIFTVAR:
358
+			return varFuncShift;
359
+		case SSEQ_CMD_RANDVAR:
360
+			return varFuncRand;
361
+		default:
362
+			return nullptr;
363
+	}
364
+}
365
+
366
+static auto compareFuncEq = [](int16_t a, int16_t b) { return a == b; };
367
+static auto compareFuncGe = [](int16_t a, int16_t b) { return a >= b; };
368
+static auto compareFuncGt = [](int16_t a, int16_t b) { return a > b; };
369
+static auto compareFuncLe = [](int16_t a, int16_t b) { return a <= b; };
370
+static auto compareFuncLt = [](int16_t a, int16_t b) { return a < b; };
371
+static auto compareFuncNe = [](int16_t a, int16_t b) { return a != b; };
372
+
373
+static inline std::function<bool (int16_t, int16_t)> CompareFunc(int cmd)
374
+{
375
+	switch (cmd)
376
+	{
377
+		case SSEQ_CMD_CMP_EQ:
378
+			return compareFuncEq;
379
+		case SSEQ_CMD_CMP_GE:
380
+			return compareFuncGe;
381
+		case SSEQ_CMD_CMP_GT:
382
+			return compareFuncGt;
383
+		case SSEQ_CMD_CMP_LE:
384
+			return compareFuncLe;
385
+		case SSEQ_CMD_CMP_LT:
386
+			return compareFuncLt;
387
+		case SSEQ_CMD_CMP_NE:
388
+			return compareFuncNe;
389
+		default:
390
+			return nullptr;
391
+	}
392
+}
393
+
306 394
 void Track::Run()
307 395
 {
308 396
 	// Indicate "heartbeat" for this track
... ...
@@ -323,21 +411,40 @@ void Track::Run()
323 411
 
324 412
 	while (!this->wait)
325 413
 	{
326
-		int cmd = read8(pData);
414
+		int cmd;
415
+		if (this->overriding())
416
+			cmd = this->overriding.cmd;
417
+		else
418
+			cmd = read8(pData);
327 419
 		if (cmd < 0x80)
328 420
 		{
329 421
 			// Note on
330 422
 			int key = cmd + this->transpose;
331
-			int vel = read8(pData);
332
-			int len = readvl(pData);
333
-			if (this->state[TS_NOTEWAIT])
334
-				this->wait = len;
335
-			if (this->state[TS_TIEBIT])
336
-				this->NoteOnTie(key, vel);
423
+			int vel;
424
+			int len;
425
+			if (this->overriding())
426
+			{
427
+				vel = this->overriding.extraValue;
428
+				len = this->overriding.value;
429
+			}
337 430
 			else
338
-				this->NoteOn(key, vel, len);
431
+			{
432
+				vel = read8(pData);
433
+				len = readvl(pData);
434
+			}
435
+			if (this->processCommand)
436
+			{
437
+				if (this->state[TS_NOTEWAIT])
438
+					this->wait = len;
439
+				if (this->state[TS_TIEBIT])
440
+					this->NoteOnTie(key, vel);
441
+				else
442
+					this->NoteOn(key, vel, len);
443
+			}
339 444
 		}
340 445
 		else
446
+		{
447
+			int value;
341 448
 			switch (cmd)
342 449
 			{
343 450
 				//-----------------------------------------------------------------
... ...
@@ -345,86 +452,156 @@ void Track::Run()
345 452
 				//-----------------------------------------------------------------
346 453
 
347 454
 				case SSEQ_CMD_REST:
348
-					this->wait = readvl(pData);
455
+					if (this->overriding())
456
+						value = this->overriding.value;
457
+					else
458
+						value = readvl(pData);
459
+					if (this->processCommand)
460
+						this->wait = value;
349 461
 					break;
350 462
 
351 463
 				case SSEQ_CMD_PATCH:
352
-					this->patch = readvl(pData);
464
+					if (this->overriding())
465
+						value = this->overriding.value;
466
+					else
467
+						value = readvl(pData);
468
+					if (this->processCommand)
469
+						this->patch = value;
353 470
 					break;
354 471
 
355 472
 				case SSEQ_CMD_GOTO:
356
-					*pData = &this->ply->sseq->data[read24(pData)];
473
+					value = read24(pData);
474
+					if (this->processCommand)
475
+						*pData = &this->ply->sseq->data[value];
357 476
 					break;
358 477
 
359 478
 				case SSEQ_CMD_CALL:
360
-				{
361
-					const uint8_t *dest = &this->ply->sseq->data[read24(pData)];
362
-					this->stack[this->stackPos++] = *pData;
363
-					*pData = dest;
479
+					value = read24(pData);
480
+					if (this->processCommand && this->stackPos < FSS_TRACKSTACKSIZE)
481
+					{
482
+						const uint8_t *dest = &this->ply->sseq->data[value];
483
+						this->stack[this->stackPos++] = StackValue(STACKTYPE_CALL, *pData);
484
+						*pData = dest;
485
+					}
364 486
 					break;
365
-				}
366 487
 
367 488
 				case SSEQ_CMD_RET:
368
-					*pData = this->stack[--this->stackPos];
489
+					if (this->processCommand && this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_CALL)
490
+						*pData = this->stack[--this->stackPos].dest;
369 491
 					break;
370 492
 
371 493
 				case SSEQ_CMD_PAN:
372
-					this->pan = read8(pData) - 64;
373
-					this->updateFlags.set(TUF_PAN);
494
+					if (this->overriding())
495
+						value = this->overriding.value;
496
+					else
497
+						value = read8(pData);
498
+					if (this->processCommand)
499
+					{
500
+						this->pan = value - 64;
501
+						this->updateFlags.set(TUF_PAN);
502
+					}
374 503
 					break;
375 504
 
376 505
 				case SSEQ_CMD_VOL:
377
-					this->vol = read8(pData);
378
-					this->updateFlags.set(TUF_VOL);
506
+					if (this->overriding())
507
+						value = this->overriding.value;
508
+					else
509
+						value = read8(pData);
510
+					if (this->processCommand)
511
+					{
512
+						this->vol = value;
513
+						this->updateFlags.set(TUF_VOL);
514
+					}
379 515
 					break;
380 516
 
381 517
 				case SSEQ_CMD_MASTERVOL:
382
-					this->ply->masterVol = Cnv_Sust(read8(pData));
383
-					for (uint8_t i = 0; i < this->ply->nTracks; ++i)
384
-						this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
518
+					if (this->overriding())
519
+						value = this->overriding.value;
520
+					else
521
+						value = read8(pData);
522
+					if (this->processCommand)
523
+					{
524
+						this->ply->masterVol = Cnv_Sust(value);
525
+						for (uint8_t i = 0; i < this->ply->nTracks; ++i)
526
+							this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
527
+					}
385 528
 					break;
386 529
 
387 530
 				case SSEQ_CMD_PRIO:
388
-					this->prio = this->ply->prio + read8(pData);
531
+					value = read8(pData);
532
+					if (this->processCommand)
533
+						this->prio = this->ply->prio + value;
389 534
 					// Update here?
390 535
 					break;
391 536
 
392 537
 				case SSEQ_CMD_NOTEWAIT:
393
-					this->state.set(TS_NOTEWAIT, !!read8(pData));
538
+					value = read8(pData);
539
+					if (this->processCommand)
540
+						this->state.set(TS_NOTEWAIT, !!value);
394 541
 					break;
395 542
 
396 543
 				case SSEQ_CMD_TIE:
397
-					this->state.set(TS_TIEBIT, !!read8(pData));
398
-					this->ReleaseAllNotes();
544
+					value = read8(pData);
545
+					if (this->processCommand)
546
+					{
547
+						this->state.set(TS_TIEBIT, !!value);
548
+						this->ReleaseAllNotes();
549
+					}
399 550
 					break;
400 551
 
401 552
 				case SSEQ_CMD_EXPR:
402
-					this->expr = read8(pData);
403
-					this->updateFlags.set(TUF_VOL);
553
+					if (this->overriding())
554
+						value = this->overriding.value;
555
+					else
556
+						value = read8(pData);
557
+					if (this->processCommand)
558
+					{
559
+						this->expr = value;
560
+						this->updateFlags.set(TUF_VOL);
561
+					}
404 562
 					break;
405 563
 
406 564
 				case SSEQ_CMD_TEMPO:
407
-					this->ply->tempo = read16(pData);
565
+					value = read16(pData);
566
+					if (this->processCommand)
567
+						this->ply->tempo = value;
408 568
 					break;
409 569
 
410 570
 				case SSEQ_CMD_END:
411
-					this->state.set(TS_END);
412
-					return;
571
+					if (this->processCommand)
572
+					{
573
+						this->state.set(TS_END);
574
+						return;
575
+					}
576
+					break;
413 577
 
414 578
 				case SSEQ_CMD_LOOPSTART:
415
-					this->loopCount[this->stackPos] = read8(pData);
416
-					this->stack[this->stackPos++] = *pData;
579
+					if (this->overriding())
580
+						value = this->overriding.value;
581
+					else
582
+						value = read8(pData);
583
+					if (this->processCommand && this->stackPos < FSS_TRACKSTACKSIZE)
584
+					{
585
+						this->loopCount[this->stackPos] = value;
586
+						this->stack[this->stackPos++] = StackValue(STACKTYPE_LOOP, *pData);
587
+					}
417 588
 					break;
418 589
 
419 590
 				case SSEQ_CMD_LOOPEND:
420
-					if (this->stackPos)
591
+					if (this->processCommand && this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_LOOP)
421 592
 					{
422
-						const uint8_t *rPos = this->stack[this->stackPos - 1];
593
+						const uint8_t *rPos = this->stack[this->stackPos - 1].dest;
423 594
 						uint8_t &nR = this->loopCount[this->stackPos - 1];
424 595
 						uint8_t prevR = nR;
425
-						if (prevR && !--nR)
426
-							--this->stackPos;
427
-						*pData = rPos;
596
+						if (!prevR)
597
+							*pData = rPos;
598
+						else
599
+						{
600
+							if (--nR)
601
+								*pData = rPos;
602
+							else
603
+								--this->stackPos;
604
+						}
428 605
 					}
429 606
 					break;
430 607
 
... ...
@@ -433,17 +610,33 @@ void Track::Run()
433 610
 				//-----------------------------------------------------------------
434 611
 
435 612
 				case SSEQ_CMD_TRANSPOSE:
436
-					this->transpose = read8(pData);
613
+					if (this->overriding())
614
+						value = this->overriding.value;
615
+					else
616
+						value = read8(pData);
617
+					if (this->processCommand)
618
+						this->transpose = value;
437 619
 					break;
438 620
 
439 621
 				case SSEQ_CMD_PITCHBEND:
440
-					this->pitchBend = read8(pData);
441
-					this->updateFlags.set(TUF_TIMER);
622
+					if (this->overriding())
623
+						value = this->overriding.value;
624
+					else
625
+						value = read8(pData);
626
+					if (this->processCommand)
627
+					{
628
+						this->pitchBend = value;
629
+						this->updateFlags.set(TUF_TIMER);
630
+					}
442 631
 					break;
443 632
 
444 633
 				case SSEQ_CMD_PITCHBENDRANGE:
445
-					this->pitchBendRange = read8(pData);
446
-					this->updateFlags.set(TUF_TIMER);
634
+					value = read8(pData);
635
+					if (this->processCommand)
636
+					{
637
+						this->pitchBendRange = value;
638
+						this->updateFlags.set(TUF_TIMER);
639
+					}
447 640
 					break;
448 641
 
449 642
 				//-----------------------------------------------------------------
... ...
@@ -451,19 +644,39 @@ void Track::Run()
451 644
 				//-----------------------------------------------------------------
452 645
 
453 646
 				case SSEQ_CMD_ATTACK:
454
-					this->a = read8(pData);
647
+					if (this->overriding())
648
+						value = this->overriding.value;
649
+					else
650
+						value = read8(pData);
651
+					if (this->processCommand)
652
+						this->a = value;
455 653
 					break;
456 654
 
457 655
 				case SSEQ_CMD_DECAY:
458
-					this->d = read8(pData);
656
+					if (this->overriding())
657
+						value = this->overriding.value;
658
+					else
659
+						value = read8(pData);
660
+					if (this->processCommand)
661
+						this->d = value;
459 662
 					break;
460 663
 
461 664
 				case SSEQ_CMD_SUSTAIN:
462
-					this->s = read8(pData);
665
+					if (this->overriding())
666
+						value = this->overriding.value;
667
+					else
668
+						value = read8(pData);
669
+					if (this->processCommand)
670
+						this->s = value;
463 671
 					break;
464 672
 
465 673
 				case SSEQ_CMD_RELEASE:
466
-					this->r = read8(pData);
674
+					if (this->overriding())
675
+						value = this->overriding.value;
676
+					else
677
+						value = read8(pData);
678
+					if (this->processCommand)
679
+						this->r = value;
467 680
 					break;
468 681
 
469 682
 				//-----------------------------------------------------------------
... ...
@@ -471,23 +684,41 @@ void Track::Run()
471 684
 				//-----------------------------------------------------------------
472 685
 
473 686
 				case SSEQ_CMD_PORTAKEY:
474
-					this->portaKey = read8(pData) + this->transpose;
475
-					this->state.set(TS_PORTABIT);
476
-					// Update here?
687
+					value = read8(pData);
688
+					if (this->processCommand)
689
+					{
690
+						this->portaKey = value + this->transpose;
691
+						this->state.set(TS_PORTABIT);
692
+						// Update here?
693
+					}
477 694
 					break;
478 695
 
479 696
 				case SSEQ_CMD_PORTAFLAG:
480
-					this->state.set(TS_PORTABIT, !!read8(pData));
481
-					// Update here?
697
+					value = read8(pData);
698
+					if (this->processCommand)
699
+					{
700
+						this->state.set(TS_PORTABIT, !!value);
701
+						// Update here?
702
+					}
482 703
 					break;
483 704
 
484 705
 				case SSEQ_CMD_PORTATIME:
485
-					this->portaTime = read8(pData);
706
+					if (this->overriding())
707
+						value = this->overriding.value;
708
+					else
709
+						value = read8(pData);
710
+					if (this->processCommand)
711
+						this->portaTime = value;
486 712
 					// Update here?
487 713
 					break;
488 714
 
489 715
 				case SSEQ_CMD_SWEEPPITCH:
490
-					this->sweepPitch = read16(pData);
716
+					if (this->overriding())
717
+						value = this->overriding.value;
718
+					else
719
+						value = read16(pData);
720
+					if (this->processCommand)
721
+						this->sweepPitch = value;
491 722
 					// Update here?
492 723
 					break;
493 724
 
... ...
@@ -496,57 +727,158 @@ void Track::Run()
496 727
 				//-----------------------------------------------------------------
497 728
 
498 729
 				case SSEQ_CMD_MODDEPTH:
499
-					this->modDepth = read8(pData);
500
-					this->updateFlags.set(TUF_MOD);
730
+					if (this->overriding())
731
+						value = this->overriding.value;
732
+					else
733
+						value = read8(pData);
734
+					if (this->processCommand)
735
+					{
736
+						this->modDepth = value;
737
+						this->updateFlags.set(TUF_MOD);
738
+					}
501 739
 					break;
502 740
 
503 741
 				case SSEQ_CMD_MODSPEED:
504
-					this->modSpeed = read8(pData);
505
-					this->updateFlags.set(TUF_MOD);
742
+					if (this->overriding())
743
+						value = this->overriding.value;
744
+					else
745
+						value = read8(pData);
746
+					if (this->processCommand)
747
+					{
748
+						this->modSpeed = value;
749
+						this->updateFlags.set(TUF_MOD);
750
+					}
506 751
 					break;
507 752
 
508 753
 				case SSEQ_CMD_MODTYPE:
509
-					this->modType = read8(pData);
510
-					this->updateFlags.set(TUF_MOD);
754
+					value = read8(pData);
755
+					if (this->processCommand)
756
+					{
757
+						this->modType = value;
758
+						this->updateFlags.set(TUF_MOD);
759
+					}
511 760
 					break;
512 761
 
513 762
 				case SSEQ_CMD_MODRANGE:
514
-					this->modRange = read8(pData);
515
-					this->updateFlags.set(TUF_MOD);
763
+					value = read8(pData);
764
+					if (this->processCommand)
765
+					{
766
+						this->modRange = value;
767
+						this->updateFlags.set(TUF_MOD);
768
+					}
516 769
 					break;
517 770
 
518 771
 				case SSEQ_CMD_MODDELAY:
519
-					this->modDelay = read16(pData);
520
-					this->updateFlags.set(TUF_MOD);
772
+					if (this->overriding())
773
+						value = this->overriding.value;
774
+					else
775
+						value = read16(pData);
776
+					if (this->processCommand)
777
+					{
778
+						this->modDelay = value;
779
+						this->updateFlags.set(TUF_MOD);
780
+					}
521 781
 					break;
522 782
 
523 783
 				//-----------------------------------------------------------------
524
-				// Variable-related commands
784
+				// Randomness-related commands
525 785
 				//-----------------------------------------------------------------
526 786
 
527
-				case SSEQ_CMD_RANDOM: // TODO
528
-					*pData += 5;
787
+				case SSEQ_CMD_RANDOM:
788
+				{
789
+					if (this->processCommand)
790
+						this->overriding() = true;
791
+					this->overriding.cmd = read8(pData);
792
+					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
793
+						this->overriding.extraValue = read8(pData);
794
+					int16_t minVal = read16(pData);
795
+					int16_t maxVal = read16(pData);
796
+					this->overriding.value = (std::rand() % (maxVal - minVal + 1)) + minVal;
529 797
 					break;
798
+				}
530 799
 
531
-				case SSEQ_CMD_PRINTVAR: // TODO
532
-					*pData += 1;
800
+				//-----------------------------------------------------------------
801
+				// Variable-related commands
802
+				//-----------------------------------------------------------------
803
+
804
+				case SSEQ_CMD_FROMVAR:
805
+					if (this->processCommand)
806
+						this->overriding() = true;
807
+					this->overriding.cmd = read8(pData);
808
+					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
809
+						this->overriding.extraValue = read8(pData);
810
+					this->overriding.value = this->ply->variables[read8(pData)];
811
+					break;
812
+
813
+				case SSEQ_CMD_SETVAR:
814
+				case SSEQ_CMD_ADDVAR:
815
+				case SSEQ_CMD_SUBVAR:
816
+				case SSEQ_CMD_MULVAR:
817
+				case SSEQ_CMD_DIVVAR:
818
+				case SSEQ_CMD_SHIFTVAR:
819
+				case SSEQ_CMD_RANDVAR:
820
+				{
821
+					int8_t varNo;
822
+					if (this->overriding())
823
+					{
824
+						varNo = this->overriding.extraValue;
825
+						value = this->overriding.value;
826
+					}
827
+					else
828
+					{
829
+						varNo = read8(pData);
830
+						value = read16(pData);
831
+					}
832
+					if (cmd == SSEQ_CMD_DIVVAR && !value) // Division by 0, skip it to prevent crashing
833
+						break;
834
+					if (this->processCommand)
835
+						this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], value);
533 836
 					break;
837
+				}
534 838
 
535
-				case SSEQ_CMD_UNSUP1: // TODO
839
+				//-----------------------------------------------------------------
840
+				// Conditional-related commands
841
+				//-----------------------------------------------------------------
842
+
843
+				case SSEQ_CMD_CMP_EQ:
844
+				case SSEQ_CMD_CMP_GE:
845
+				case SSEQ_CMD_CMP_GT:
846
+				case SSEQ_CMD_CMP_LE:
847
+				case SSEQ_CMD_CMP_LT:
848
+				case SSEQ_CMD_CMP_NE:
536 849
 				{
537
-					int t = read8(pData);
538
-					if (t >= SSEQ_CMD_UNSUP2_LO && t <= SSEQ_CMD_UNSUP2_HI)
539
-						*pData += 1;
540
-					*pData += 1;
850
+					int8_t varNo;
851
+					if (this->overriding())
852
+					{
853
+						varNo = this->overriding.extraValue;
854
+						value = this->overriding.value;
855
+					}
856
+					else
857
+					{
858
+						varNo = read8(pData);
859
+						value = read16(pData);
860
+					}
861
+					if (this->processCommand)
862
+						this->lastComparisonResult = CompareFunc(cmd)(this->ply->variables[varNo], value);
541 863
 					break;
542 864
 				}
543 865
 
544
-				case SSEQ_CMD_IF: // TODO
866
+				case SSEQ_CMD_IF:
867
+					this->processCommand = this->lastComparisonResult;
868
+					break;
869
+
870
+				case SSEQ_CMD_PRINTVAR:
871
+					++*pData;
545 872
 					break;
546 873
 
547
-				default:
548
-					if (cmd >= SSEQ_CMD_UNSUP2_LO && cmd <= SSEQ_CMD_UNSUP2_HI) // TODO
549
-						*pData += 3;
874
+				case SSEQ_CMD_MUTE: // UNSUPPORTED
875
+					++*pData;
550 876
 			}
877
+		}
878
+
879
+		if (cmd != SSEQ_CMD_RANDOM && cmd != SSEQ_CMD_FROMVAR)
880
+			this->overriding() = false;
881
+		if (cmd != SSEQ_CMD_IF)
882
+			this->processCommand = true;
551 883
 	}
552 884
 }
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-08
4
+ * Last modification on 2014-10-13
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -15,6 +15,33 @@
15 15
 
16 16
 struct Player;
17 17
 
18
+enum StackType
19
+{
20
+	STACKTYPE_CALL,
21
+	STACKTYPE_LOOP
22
+};
23
+
24
+struct StackValue
25
+{
26
+	StackType type;
27
+	const uint8_t *dest;
28
+
29
+	StackValue() : type(STACKTYPE_CALL), dest(nullptr) { }
30
+	StackValue(StackType newType, const uint8_t *newDest) : type(newType), dest(newDest) { }
31
+};
32
+
33
+struct Override
34
+{
35
+	bool overriding;
36
+	int cmd;
37
+	int value;
38
+	int extraValue;
39
+
40
+	Override() : overriding(false) { }
41
+	bool operator()() const { return this->overriding; }
42
+	bool &operator()() { return this->overriding; }
43
+};
44
+
18 45
 struct Track
19 46
 {
20 47
 	int8_t trackId;
... ...
@@ -25,9 +52,12 @@ struct Track
25 52
 
26 53
 	const uint8_t *startPos;
27 54
 	const uint8_t *pos;
28
-	const uint8_t *stack[FSS_TRACKSTACKSIZE];
55
+	StackValue stack[FSS_TRACKSTACKSIZE];
29 56
 	uint8_t stackPos;
30 57
 	uint8_t loopCount[FSS_TRACKSTACKSIZE];
58
+	Override overriding;
59
+	bool lastComparisonResult;
60
+	bool processCommand;
31 61
 
32 62
 	int wait;
33 63
 	uint16_t patch;
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - NCSF configuration
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-10-05
4
+ * Last modification on 2014-10-13
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -21,7 +21,7 @@ enum
21 21
 
22 22
 unsigned XSFConfig::initSampleRate = 44100;
23 23
 std::string XSFConfig::commonName = "NCSF Decoder";
24
-std::string XSFConfig::versionNumber = "1.9.1";
24
+std::string XSFConfig::versionNumber = "1.10";
25 25
 unsigned XSFConfig_NCSF::initInterpolation = 4;
26 26
 std::string XSFConfig_NCSF::initMutes = "0000000000000000";
27 27
 
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - NCSF Player
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-10-05
4
+ * Last modification on 2014-10-13
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  *
... ...
@@ -10,6 +10,8 @@
10 10
  */
11 11
 
12 12
 #include <memory>
13
+#include <cstdlib>
14
+#include <ctime>
13 15
 #include <zlib.h>
14 16
 #include "convert.h"
15 17
 #include "XSFPlayer_NCSF.h"
... ...
@@ -165,6 +167,8 @@ bool XSFPlayer_NCSF::Load()
165 167
 	soundViewThreadHandle = CreateThread(nullptr, 0, soundViewThread, this, 0, nullptr);
166 168
 #endif
167 169
 
170
+	std::srand(static_cast<unsigned>(std::time(nullptr)));
171
+
168 172
 	PseudoFile file;
169 173
 	file.data = &this->sdatData;
170 174
 	this->sdat.reset(new SDAT(file, this->sseq));