PageRenderTime 135ms CodeModel.GetById 12ms app.highlight 111ms RepoModel.GetById 3ms app.codeStats 1ms

/engines/scumm/player_nes.cpp

http://github.com/scummvm/scummvm
C++ | 1067 lines | 842 code | 197 blank | 28 comment | 118 complexity | 48b5e1dbb2b6483dd8fdd107e684105c MD5 | raw file
   1/* ScummVM - Graphic Adventure Engine
   2 *
   3 * ScummVM is the legal property of its developers, whose names
   4 * are too numerous to list here. Please refer to the COPYRIGHT
   5 * file distributed with this source distribution.
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * as published by the Free Software Foundation; either version 2
  10 * of the License, or (at your option) any later version.
  11
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16
  17 * You should have received a copy of the GNU General Public License
  18 * aint32 with this program; if not, write to the Free Software
  19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20 *
  21 */
  22
  23#ifndef DISABLE_NES_APU
  24
  25#include "engines/engine.h"
  26#include "scumm/player_nes.h"
  27#include "scumm/scumm.h"
  28#include "audio/mixer.h"
  29
  30namespace Scumm {
  31
  32static const byte channelMask[4] = {1, 2, 4, 8};
  33
  34static const uint16 freqTable[64] = {
  35	0x07F0, 0x077E, 0x0712, 0x06AE, 0x064E, 0x05F3, 0x059E, 0x054D,
  36	0x0501, 0x04B9, 0x0475, 0x0435, 0x03F8, 0x03BF, 0x0389, 0x0357,
  37	0x0327, 0x02F9, 0x02CF, 0x02A6, 0x0280, 0x025C, 0x023A, 0x021A,
  38	0x01FC, 0x01DF, 0x01C4, 0x01AB, 0x0193, 0x017C, 0x0167, 0x0152,
  39	0x013F, 0x012D, 0x011C, 0x010C, 0x00FD, 0x00EE, 0x00E1, 0x00D4,
  40	0x00C8, 0x00BD, 0x00B2, 0x00A8, 0x009F, 0x0096, 0x008D, 0x0085,
  41	0x007E, 0x0076, 0x0070, 0x0069, 0x0063, 0x005E, 0x0058, 0x0053,
  42	0x004F, 0x004A, 0x0046, 0x0042, 0x003E, 0x003A, 0x0037, 0x0034
  43};
  44
  45static const byte instChannel[16] = {
  46	0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 1, 3, 3, 3
  47};
  48static const byte startCmd[16] = {
  49	0x05, 0x03, 0x06, 0x08, 0x0B, 0x01, 0x01, 0x1A,
  50	0x16, 0x06, 0x04, 0x17, 0x02, 0x10, 0x0E, 0x0D
  51};
  52static const byte releaseCmd[16] = {
  53	0x0F, 0x00, 0x00, 0x09, 0x00, 0x14, 0x15, 0x00,
  54	0x00, 0x00, 0x1B, 0x1B, 0x0F, 0x0F, 0x0F, 0x0F
  55};
  56static const byte nextCmd[28] =	{
  57	0xFF, 0xFF, 0xFF, 0xFF, 0x17, 0xFF, 0x07, 0xFF,
  58	0xFF, 0x0A, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00,
  59	0x11, 0x12, 0x11, 0x03, 0xFF, 0xFF, 0x18, 0x00,
  60	0x19, 0x00, 0x00, 0x00
  61};
  62static const byte nextDelay[28] = {
  63	0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
  64	0x00, 0x05, 0x08, 0x03, 0x00, 0x00, 0x00, 0x00,
  65	0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00,
  66	0x03, 0x00, 0x00, 0x00
  67};
  68
  69namespace APUe {
  70
  71static const byte LengthCounts[32] = {
  72	0x0A,0xFE,
  73	0x14,0x02,
  74	0x28,0x04,
  75	0x50,0x06,
  76	0xA0,0x08,
  77	0x3C,0x0A,
  78	0x0E,0x0C,
  79	0x1A,0x0E,
  80
  81	0x0C,0x10,
  82	0x18,0x12,
  83	0x30,0x14,
  84	0x60,0x16,
  85	0xC0,0x18,
  86	0x48,0x1A,
  87	0x10,0x1C,
  88	0x20,0x1E
  89};
  90
  91class SoundGen {
  92protected:
  93	byte wavehold;
  94	uint32 freq;	// short
  95	uint32 CurD;
  96
  97public:
  98	byte Timer;
  99	int32 Pos;
 100	uint32 Cycles;	// short
 101
 102	inline byte GetTimer() const { return Timer; }
 103};
 104
 105class Square : public SoundGen {
 106protected:
 107	byte volume, envelope, duty, swpspeed, swpdir, swpstep, swpenab;
 108	byte Vol;
 109	byte EnvCtr, Envelope, BendCtr;
 110	bool Enabled, ValidFreq, Active;
 111	bool EnvClk, SwpClk;
 112
 113	void CheckActive();
 114
 115public:
 116	void Reset();
 117	void Write(int Reg, byte Val);
 118	void Run();
 119	void QuarterFrame();
 120	void HalfFrame();
 121};
 122
 123static const int8 Duties[4][8] = {
 124	{-4,+4,-4,-4,-4,-4,-4,-4},
 125	{-4,+4,+4,-4,-4,-4,-4,-4},
 126	{-4,+4,+4,+4,+4,-4,-4,-4},
 127	{+4,-4,-4,+4,+4,+4,+4,+4}
 128};
 129
 130void Square::Reset() {
 131	memset(this, 0, sizeof(*this));
 132	Cycles = 1;
 133	EnvCtr = 1;
 134	BendCtr = 1;
 135}
 136
 137void Square::CheckActive() {
 138	ValidFreq = (freq >= 0x8) && ((swpdir) || !((freq + (freq >> swpstep)) & 0x800));
 139	Active = Timer && ValidFreq;
 140	Pos = Active ? (Duties[duty][CurD] * Vol) : 0;
 141}
 142
 143void Square::Write(int Reg, byte Val) {
 144	switch (Reg) {
 145	case 0:
 146		volume = Val & 0xF;
 147		envelope = Val & 0x10;
 148		wavehold = Val & 0x20;
 149		duty = (Val >> 6) & 0x3;
 150		Vol = envelope ? volume : Envelope;
 151		break;
 152
 153	case 1:
 154		swpstep = Val & 0x07;
 155		swpdir = Val & 0x08;
 156		swpspeed = (Val >> 4) & 0x7;
 157		swpenab = Val & 0x80;
 158		SwpClk = true;
 159		break;
 160
 161	case 2:
 162		freq &= 0x700;
 163		freq |= Val;
 164		break;
 165
 166	case 3:
 167		freq &= 0xFF;
 168		freq |= (Val & 0x7) << 8;
 169
 170		if (Enabled)
 171			Timer = LengthCounts[(Val >> 3) & 0x1F];
 172
 173		CurD = 0;
 174		EnvClk = true;
 175		break;
 176
 177	case 4:
 178		Enabled = (Val != 0);
 179		if (!Enabled)
 180			Timer = 0;
 181		break;
 182	}
 183	CheckActive();
 184}
 185
 186void Square::Run() {
 187	Cycles = (freq + 1) << 1;
 188	CurD = (CurD + 1) & 0x7;
 189
 190	if (Active)
 191		Pos = Duties[duty][CurD] * Vol;
 192}
 193
 194void Square::QuarterFrame() {
 195	if (EnvClk) {
 196		EnvClk = false;
 197		Envelope = 0xF;
 198		EnvCtr = volume + 1;
 199	} else if (!--EnvCtr) {
 200		EnvCtr = volume + 1;
 201
 202		if (Envelope)
 203			Envelope--;
 204		else
 205			Envelope = wavehold ? 0xF : 0x0;
 206	}
 207
 208	Vol = envelope ? volume : Envelope;
 209	CheckActive();
 210}
 211
 212void Square::HalfFrame() {
 213	if (!--BendCtr) {
 214		BendCtr = swpspeed + 1;
 215
 216		if (swpenab && swpstep && ValidFreq) {
 217			int sweep = freq >> swpstep;
 218			// FIXME: Is -sweep or ~sweep correct???
 219			freq += swpdir ? -sweep : sweep;
 220		}
 221	}
 222
 223	if (SwpClk) {
 224		SwpClk = false;
 225		BendCtr = swpspeed + 1;
 226	}
 227
 228	if (Timer && !wavehold)
 229		Timer--;
 230
 231	CheckActive();
 232}
 233
 234
 235class Triangle : public SoundGen {
 236protected:
 237	byte linear;
 238	byte LinCtr;
 239	bool Enabled, Active;
 240	bool LinClk;
 241
 242	void CheckActive();
 243
 244public:
 245	void Reset();
 246	void Write(int Reg, byte Val);
 247	void Run();
 248	void QuarterFrame();
 249	void HalfFrame();
 250};
 251
 252static const int8 TriDuty[32] = {
 253	-8,-7,-6,-5,-4,-3,-2,-1,
 254	+0,+1,+2,+3,+4,+5,+6,+7,
 255	+7,+6,+5,+4,+3,+2,+1,+0,
 256	-1,-2,-3,-4,-5,-6,-7,-8
 257};
 258
 259void Triangle::Reset() {
 260	memset(this, 0, sizeof(*this));
 261	Cycles = 1;
 262}
 263
 264void Triangle::CheckActive() {
 265	Active = Timer && LinCtr;
 266
 267	if (freq < 4)
 268		Pos = 0;	// beyond hearing range
 269	else
 270		Pos = TriDuty[CurD] * 8;
 271}
 272
 273void Triangle::Write(int Reg, byte Val) {
 274	switch (Reg) {
 275	case 0:
 276		linear = Val & 0x7F;
 277		wavehold = (Val >> 7) & 0x1;
 278		break;
 279
 280	case 2:
 281		freq &= 0x700;
 282		freq |= Val;
 283		break;
 284
 285	case 3:
 286		freq &= 0xFF;
 287		freq |= (Val & 0x7) << 8;
 288
 289		if (Enabled)
 290			Timer = LengthCounts[(Val >> 3) & 0x1F];
 291
 292		LinClk = true;
 293		break;
 294
 295	case 4:
 296		Enabled = (Val != 0);
 297		if (!Enabled)
 298			Timer = 0;
 299		break;
 300	}
 301	CheckActive();
 302}
 303
 304void Triangle::Run() {
 305	Cycles = freq + 1;
 306
 307	if (Active) {
 308		CurD++;
 309		CurD &= 0x1F;
 310
 311		if (freq < 4)
 312			Pos = 0;	// beyond hearing range
 313		else
 314			Pos = TriDuty[CurD] * 8;
 315	}
 316}
 317
 318void Triangle::QuarterFrame() {
 319	if (LinClk)
 320		LinCtr = linear;
 321	else if (LinCtr)
 322		LinCtr--;
 323
 324	if (!wavehold)
 325		LinClk = false;
 326
 327	CheckActive();
 328}
 329
 330void Triangle::HalfFrame() {
 331	if (Timer && !wavehold)
 332		Timer--;
 333
 334	CheckActive();
 335}
 336
 337class Noise : public SoundGen {
 338protected:
 339	byte volume, envelope, datatype;
 340	byte Vol;
 341	byte EnvCtr, Envelope;
 342	bool Enabled;
 343	bool EnvClk;
 344
 345	void CheckActive();
 346
 347public:
 348	void Reset();
 349	void Write(int Reg, byte Val);
 350	void Run();
 351	void QuarterFrame();
 352	void HalfFrame();
 353};
 354
 355static const uint32 NoiseFreq[16] = {
 356	0x004,0x008,0x010,0x020,0x040,0x060,0x080,0x0A0,
 357	0x0CA,0x0FE,0x17C,0x1FC,0x2FA,0x3F8,0x7F2,0xFE4
 358};
 359
 360void Noise::Reset() {
 361	memset(this, 0, sizeof(*this));
 362	CurD = 1;
 363	Cycles = 1;
 364	EnvCtr = 1;
 365
 366}
 367
 368void Noise::Write(int Reg, byte Val) {
 369	switch (Reg) {
 370	case 0:
 371		volume = Val & 0x0F;
 372		envelope = Val & 0x10;
 373		wavehold = Val & 0x20;
 374		Vol = envelope ? volume : Envelope;
 375
 376		if (Timer)
 377			Pos = ((CurD & 0x4000) ? -2 : 2) * Vol;
 378		break;
 379
 380	case 2:
 381		freq = Val & 0xF;
 382		datatype = Val & 0x80;
 383		break;
 384
 385	case 3:
 386		if (Enabled)
 387			Timer = LengthCounts[(Val >> 3) & 0x1F];
 388
 389		EnvClk = true;
 390		break;
 391
 392	case 4:
 393		Enabled = (Val != 0);
 394		if (!Enabled)
 395			Timer = 0;
 396		break;
 397	}
 398}
 399
 400void Noise::Run() {
 401	Cycles = NoiseFreq[freq];	/* no + 1 here */
 402
 403	if (datatype)
 404		CurD = (CurD << 1) | (((CurD >> 14) ^ (CurD >> 8)) & 0x1);
 405	else
 406		CurD = (CurD << 1) | (((CurD >> 14) ^ (CurD >> 13)) & 0x1);
 407
 408	if (Timer)
 409		Pos = ((CurD & 0x4000) ? -2 : 2) * Vol;
 410}
 411
 412void Noise::QuarterFrame() {
 413	if (EnvClk) {
 414		EnvClk = false;
 415		Envelope = 0xF;
 416		EnvCtr = volume + 1;
 417	} else if (!--EnvCtr) {
 418		EnvCtr = volume + 1;
 419
 420		if (Envelope)
 421			Envelope--;
 422		else
 423			Envelope = wavehold ? 0xF : 0x0;
 424	}
 425
 426	Vol = envelope ? volume : Envelope;
 427
 428	if (Timer)
 429		Pos = ((CurD & 0x4000) ? -2 : 2) * Vol;
 430}
 431
 432void Noise::HalfFrame() {
 433	if (Timer && !wavehold)
 434		Timer--;
 435}
 436
 437class APU {
 438protected:
 439	int	BufPos;
 440	int	SampleRate;
 441
 442	Square _square0;
 443	Square _square1;
 444	Triangle _triangle;
 445	Noise _noise;
 446
 447	struct {
 448		uint32 Cycles;
 449		int Num;
 450	} Frame;
 451
 452public:
 453	APU(int rate) : SampleRate(rate) {
 454		Reset();
 455	}
 456
 457	void WriteReg(int Addr, byte Val);
 458	byte Read4015();
 459	void Reset ();
 460	int16 GetSample();
 461};
 462
 463void APU::WriteReg(int Addr, byte Val) {
 464	switch (Addr) {
 465	case 0x000:	_square0.Write(0,Val);	break;
 466	case 0x001:	_square0.Write(1,Val);	break;
 467	case 0x002:	_square0.Write(2,Val);	break;
 468	case 0x003:	_square0.Write(3,Val);	break;
 469	case 0x004:	_square1.Write(0,Val);	break;
 470	case 0x005:	_square1.Write(1,Val);	break;
 471	case 0x006:	_square1.Write(2,Val);	break;
 472	case 0x007:	_square1.Write(3,Val);	break;
 473	case 0x008:	_triangle.Write(0,Val);	break;
 474	case 0x009:	_triangle.Write(1,Val);	break;
 475	case 0x00A:	_triangle.Write(2,Val);	break;
 476	case 0x00B:	_triangle.Write(3,Val);	break;
 477	case 0x00C:	_noise.Write(0,Val);	break;
 478	case 0x00D:	_noise.Write(1,Val);	break;
 479	case 0x00E:	_noise.Write(2,Val);	break;
 480	case 0x00F:	_noise.Write(3,Val);	break;
 481	case 0x015:	_square0.Write(4,Val & 0x1);
 482				_square1.Write(4,Val & 0x2);
 483				_triangle.Write(4,Val & 0x4);
 484				_noise.Write(4,Val & 0x8);
 485		break;
 486	}
 487}
 488
 489byte APU::Read4015() {
 490	byte result =
 491		(( _square0.GetTimer()) ? 0x01 : 0) |
 492		(( _square1.GetTimer()) ? 0x02 : 0) |
 493		((_triangle.GetTimer()) ? 0x04 : 0) |
 494		((   _noise.GetTimer()) ? 0x08 : 0);
 495	return result;
 496}
 497
 498void APU::Reset () {
 499	BufPos = 0;
 500
 501	_square0.Reset();
 502	_square1.Reset();
 503	_triangle.Reset();
 504	_noise.Reset();
 505
 506	Frame.Num = 0;
 507	Frame.Cycles = 1;
 508}
 509
 510template<class T>
 511int step(T &obj, int sampcycles, uint frame_Cycles, int frame_Num) {
 512	int samppos = 0;
 513	while (sampcycles) {
 514		// Compute the maximal amount we can step ahead before triggering
 515		// an action (i.e. compute the minimum of sampcycles, frame_Cycles
 516		// and obj.Cycles).
 517		uint max_step = sampcycles;
 518		if (max_step > frame_Cycles)
 519			max_step = frame_Cycles;
 520		if (max_step > obj.Cycles)
 521			max_step = obj.Cycles;
 522
 523		// During all but the last of these steps, we just add the value of obj.Pos
 524		// to samppos -- so we can to that all at once with a simple multiplication:
 525		samppos += obj.Pos * (max_step - 1);
 526
 527		// Now step ahead...
 528		sampcycles -= max_step;
 529		frame_Cycles -= max_step;
 530		obj.Cycles -= max_step;
 531
 532		if (!frame_Cycles) {
 533			frame_Cycles = 7457;
 534
 535			if (frame_Num < 4) {
 536				obj.QuarterFrame();
 537
 538				if (frame_Num & 1)
 539					frame_Cycles++;
 540				else
 541					obj.HalfFrame();
 542
 543				frame_Num++;
 544			} else
 545				frame_Num = 0;
 546		}
 547
 548		if (!obj.Cycles)
 549			obj.Run();
 550
 551		samppos += obj.Pos;
 552	}
 553
 554	return samppos;
 555}
 556
 557int16 APU::GetSample() {
 558	int samppos = 0;
 559
 560	const int sampcycles = 1+(1789773-BufPos-1)/SampleRate;
 561	BufPos = BufPos + sampcycles * SampleRate - 1789773;
 562
 563	samppos += step( _square0, sampcycles, Frame.Cycles, Frame.Num);
 564	samppos += step( _square1, sampcycles, Frame.Cycles, Frame.Num);
 565	samppos += step(_triangle, sampcycles, Frame.Cycles, Frame.Num);
 566	samppos += step(   _noise, sampcycles, Frame.Cycles, Frame.Num);
 567
 568	uint tmp = sampcycles;
 569	while (tmp >= Frame.Cycles) {
 570		tmp -= Frame.Cycles;
 571		Frame.Cycles = 7457;
 572
 573		if (Frame.Num < 4) {
 574			if (Frame.Num & 1)
 575				Frame.Cycles++;
 576			Frame.Num++;
 577		} else
 578			Frame.Num = 0;
 579	}
 580
 581	Frame.Cycles -= tmp;
 582
 583	return (samppos << 6) / sampcycles;
 584}
 585
 586} // End of namespace APUe
 587
 588Player_NES::Player_NES(ScummEngine *scumm, Audio::Mixer *mixer) {
 589	int i;
 590	_vm = scumm;
 591	_mixer = mixer;
 592	_sampleRate = _mixer->getOutputRate();
 593	_apu = new APUe::APU(_sampleRate);
 594
 595	_samples_per_frame = _sampleRate / 60;
 596	_current_sample = 0;
 597
 598	for (i = 0; i < NUMSLOTS; i++) {
 599		_slot[i].id = -1;
 600		_slot[i].framesleft = 0;
 601		_slot[i].type = 0;
 602		_slot[i].offset = 0;
 603		_slot[i].data = NULL;
 604	}
 605
 606	for (i = 0; i < NUMCHANS; i++) {
 607		_mchan[i].command = 0;
 608		_mchan[i].framedelay = 0;
 609		_mchan[i].pitch = 0;
 610		_mchan[i].volume = 0;
 611		_mchan[i].voldelta = 0;
 612		_mchan[i].envflags = 0;
 613		_mchan[i].cmdlock = 0;
 614	}
 615	isSFXplaying = wasSFXplaying = false;
 616
 617	auxData1 = auxData2 = NULL;
 618	numNotes = 0;
 619
 620	APU_writeControl(0);
 621
 622	_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
 623}
 624
 625Player_NES::~Player_NES() {
 626	_mixer->stopHandle(_soundHandle);
 627	delete _apu;
 628}
 629
 630void Player_NES::setMusicVolume (int vol) {
 631	_maxvol = vol;
 632}
 633
 634int Player_NES::readBuffer(int16 *buffer, const int numSamples) {
 635	for (int n = 0; n < numSamples; n++) {
 636		buffer[n] = _apu->GetSample() * _maxvol / 255;
 637		_current_sample++;
 638
 639		if (_current_sample == _samples_per_frame) {
 640			_current_sample = 0;
 641			sound_play();
 642		}
 643	}
 644	return numSamples;
 645}
 646void Player_NES::stopAllSounds() {
 647	for (int i = 0; i < NUMSLOTS; i++) {
 648		_slot[i].framesleft = 0;
 649		_slot[i].type = 0;
 650		_slot[i].id = -1;
 651	}
 652
 653	isSFXplaying = 0;
 654	checkSilenceChannels(0);
 655}
 656
 657void Player_NES::stopSound(int nr) {
 658	if (nr == -1)
 659		return;
 660
 661	for (int i = 0; i < NUMSLOTS; i++) {
 662		if (_slot[i].id != nr)
 663			continue;
 664
 665		isSFXplaying = 0;
 666		_slot[i].framesleft = 0;
 667		_slot[i].type = 0;
 668		_slot[i].id = -1;
 669		checkSilenceChannels(i);
 670	}
 671}
 672
 673void Player_NES::startSound(int nr) {
 674	byte *data = _vm->getResourceAddress(rtSound, nr) + 2;
 675	assert(data);
 676
 677	int soundType = data[1];
 678	int chan = data[0];
 679
 680	if (chan == 4) {
 681		if (_slot[2].framesleft)
 682			return;
 683		chan = 0;
 684	}
 685
 686	if (soundType < _slot[chan].type)
 687		return;
 688
 689	_slot[chan].type = soundType;
 690	_slot[chan].id = nr;
 691	_slot[chan].data = data;
 692	_slot[chan].offset = 2;
 693	_slot[chan].framesleft = 1;
 694	checkSilenceChannels(chan);
 695	if (chan == 2) {
 696		numNotes = _slot[chan].data[2];
 697		auxData1 = _slot[chan].data + 3;
 698		auxData2 = auxData1 + numNotes;
 699		_slot[chan].data = auxData2 + numNotes;
 700		_slot[chan].offset = 0;
 701
 702		for (int i = 0; i < NUMCHANS; i++)
 703			_mchan[i].cmdlock = 0;
 704	}
 705}
 706
 707void Player_NES::checkSilenceChannels(int chan) {
 708	for (chan--; chan >= 0; chan--) {
 709		if (_slot[chan].framesleft)
 710			return;
 711	}
 712	APU_writeControl(0);
 713}
 714
 715void Player_NES::sound_play() {
 716	if (_slot[0].framesleft)
 717		playSFX(0);
 718	else if (_slot[1].framesleft)
 719		playSFX(1);
 720
 721	playMusic();
 722}
 723
 724void Player_NES::playSFX (int nr) {
 725	if (--_slot[nr].framesleft)
 726		return;
 727
 728	while (1) {
 729		int a = _slot[nr].data[_slot[nr].offset++];
 730		if (a < 16) {
 731			a >>= 2;
 732			APU_writeControl(APU_readStatus() | channelMask[a]);
 733			isSFXplaying = true;
 734			APU_writeChannel(a, 0, _slot[nr].data[_slot[nr].offset++]);
 735			APU_writeChannel(a, 1, _slot[nr].data[_slot[nr].offset++]);
 736			APU_writeChannel(a, 2, _slot[nr].data[_slot[nr].offset++]);
 737			APU_writeChannel(a, 3, _slot[nr].data[_slot[nr].offset++]);
 738		} else if (a == 0xFE) {
 739			_slot[nr].offset = 2;
 740		} else if (a == 0xFF) {
 741			_slot[nr].id = -1;
 742			_slot[nr].type = 0;
 743			isSFXplaying = false;
 744			APU_writeControl(0);
 745
 746			if (!nr && _slot[1].framesleft) {
 747				_slot[1].framesleft = 1;
 748				isSFXplaying = true;
 749			}
 750			return;
 751		} else {
 752			_slot[nr].framesleft = _slot[nr].data[_slot[nr].offset++];
 753			return;
 754		}
 755	}
 756}
 757
 758void Player_NES::playMusic() {
 759	if (!_slot[2].framesleft)
 760		return;
 761
 762	if (wasSFXplaying && !isSFXplaying)
 763		for (int x = 1; x >= 0; x--)
 764			if (_mchan[x].cmdlock) {
 765				_mchan[x].command = _mchan[x].cmdlock;
 766				_mchan[x].framedelay = 1;
 767			}
 768
 769	wasSFXplaying = isSFXplaying;
 770	if (!--_slot[2].framesleft) {
 771top:
 772		int b = _slot[2].data[_slot[2].offset++];
 773		if (b == 0xFF) {
 774			_slot[2].id = -1;
 775			_slot[2].type = 0;
 776			b = 0;
 777		} else if (b == 0xFE) {
 778			_slot[2].offset = 0;
 779			goto top;
 780		} else {
 781			if (b < numNotes) {
 782				int inst = auxData1[b];
 783				int ch = instChannel[inst];
 784				_mchan[ch].pitch = auxData2[b];
 785				_mchan[ch].cmdlock = startCmd[inst];
 786				_mchan[ch].command = startCmd[inst];
 787				_mchan[ch].framedelay = 1;
 788				goto top;
 789			}
 790			b -= numNotes;
 791			if (b < 16) {
 792				int inst = b;
 793				int ch = instChannel[inst];
 794				_mchan[ch].cmdlock = 0;
 795				_mchan[ch].command = releaseCmd[inst];
 796				_mchan[ch].framedelay = 1;
 797				goto top;
 798			}
 799			b -= 16;
 800		}
 801		_slot[2].framesleft = b;
 802	}
 803
 804	for (int x = NUMCHANS - 1; x >= 0; x--) {
 805		if (_slot[0].framesleft || _slot[1].framesleft) {
 806			_mchan[x].volume = 0;
 807			_mchan[x].framedelay = 0;
 808			continue;
 809		}
 810
 811		if (_mchan[x].framedelay && !--_mchan[x].framedelay) {
 812			switch (_mchan[x].command) {
 813			case 0x00:
 814			case 0x13:
 815				_mchan[x].voldelta = -10;
 816				break;
 817
 818			case 0x01:
 819			case 0x03:
 820			case 0x08:
 821			case 0x16:
 822				_mchan[x].envflags = 0x30;
 823				_mchan[x].volume = 0x6F;
 824				_mchan[x].voldelta = 0;
 825
 826				APU_writeChannel(x, 0, 0x00);
 827				APU_writeChannel(x, 1, 0x7F);
 828				APU_writeControl(APU_readStatus() | channelMask[x]);
 829				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF);
 830				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8);
 831
 832				chainCommand(x);
 833				break;
 834
 835			case 0x02:
 836				_mchan[x].envflags = 0xB0;
 837				_mchan[x].volume = 0x6F;
 838				_mchan[x].voldelta = 0;
 839
 840				APU_writeChannel(x, 0, 0x00);
 841				APU_writeChannel(x, 1, 0x84);
 842				APU_writeControl(APU_readStatus() | channelMask[x]);
 843				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF);
 844				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8);
 845
 846				chainCommand(x);
 847				break;
 848
 849			case 0x04:
 850				_mchan[x].envflags = 0x80;
 851				_mchan[x].volume = 0x6F;
 852				_mchan[x].voldelta = 0;
 853
 854				APU_writeChannel(x, 0, 0x00);
 855				APU_writeChannel(x, 1, 0x7F);
 856				APU_writeControl(APU_readStatus() | channelMask[x]);
 857				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF);
 858				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8);
 859
 860				chainCommand(x);
 861				break;
 862
 863			case 0x05:
 864				_mchan[x].envflags = 0xF0;
 865				_mchan[x].volume = 0x6F;
 866				_mchan[x].voldelta = -15;
 867
 868				APU_writeChannel(x, 1, 0x7F);
 869				APU_writeControl(APU_readStatus() | channelMask[x]);
 870				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF);
 871				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8);
 872
 873				chainCommand(x);
 874				break;
 875
 876			case 0x06:
 877				_mchan[x].pitch += 0x18;
 878				_mchan[x].envflags = 0x80;
 879				_mchan[x].volume = 0x6F;
 880				_mchan[x].voldelta = 0;
 881
 882				APU_writeChannel(x, 0, 0x00);
 883				APU_writeChannel(x, 1, 0x7F);
 884				APU_writeControl(APU_readStatus() | channelMask[x]);
 885				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF);
 886				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8);
 887
 888				chainCommand(x);
 889				break;
 890
 891			case 0x07:
 892				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch - 0x0C] & 0xFF);
 893				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch - 0x0C] >> 8);
 894
 895				chainCommand(x);
 896				break;
 897
 898			case 0x09:
 899				_mchan[x].voldelta = -2;
 900
 901				APU_writeChannel(x, 1, 0x7F);
 902				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF);
 903				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8);
 904
 905				chainCommand(x);
 906				break;
 907
 908			case 0x0A:
 909				APU_writeChannel(x, 1, 0x86);
 910				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF);
 911				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8);
 912
 913				chainCommand(x);
 914				break;
 915
 916			case 0x0B:	case 0x1A:
 917				_mchan[x].envflags = 0x70;
 918				_mchan[x].volume = 0x6F;
 919				_mchan[x].voldelta = 0;
 920
 921				APU_writeChannel(x, 0, 0x00);
 922				APU_writeChannel(x, 1, 0x7F);
 923				APU_writeControl(APU_readStatus() | channelMask[x]);
 924				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF);
 925				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8);
 926
 927				chainCommand(x);
 928				break;
 929
 930			case 0x0C:
 931				_mchan[x].envflags = 0xB0;
 932
 933				chainCommand(x);
 934				break;
 935
 936			case 0x0D:
 937				_mchan[x].envflags = 0x30;
 938				_mchan[x].volume = 0x5F;
 939				_mchan[x].voldelta = -22;
 940
 941				APU_writeChannel(x, 0, 0x00);
 942				APU_writeControl(APU_readStatus() | channelMask[x]);
 943				APU_writeChannel(x, 2, _mchan[x].pitch & 0xF);
 944				APU_writeChannel(x, 3, 0xFF);
 945
 946				chainCommand(x);
 947				break;
 948
 949			case 0x0E:
 950			case 0x10:
 951				_mchan[x].envflags = 0x30;
 952				_mchan[x].volume = 0x5F;
 953				_mchan[x].voldelta = -6;
 954
 955				APU_writeChannel(x, 0, 0x00);
 956				APU_writeControl(APU_readStatus() | channelMask[x]);
 957				APU_writeChannel(x, 2, _mchan[x].pitch & 0xF);
 958				APU_writeChannel(x, 3, 0xFF);
 959
 960				chainCommand(x);
 961				break;
 962
 963			case 0x0F:
 964				chainCommand(x);
 965				break;
 966
 967			case 0x11:
 968				APU_writeChannel(x, 2, _mchan[x].pitch & 0xF);
 969				APU_writeChannel(x, 3, 0xFF);
 970
 971				chainCommand(x);
 972				break;
 973
 974			case 0x12:
 975				APU_writeChannel(x, 2, (_mchan[x].pitch + 3) & 0xF);
 976				APU_writeChannel(x, 3, 0xFF);
 977
 978				chainCommand(x);
 979				break;
 980
 981			case 0x14:
 982				_mchan[x].voldelta = -12;
 983
 984				APU_writeChannel(x, 1, 0x8C);
 985
 986				chainCommand(x);
 987				break;
 988
 989			case 0x15:
 990				_mchan[x].voldelta = -12;
 991
 992				APU_writeChannel(x, 1, 0x84);
 993
 994				chainCommand(x);
 995				break;
 996
 997			case 0x17:
 998				_mchan[x].pitch += 0x0C;
 999				_mchan[x].envflags = 0x80;
1000				_mchan[x].volume = 0x6F;
1001				_mchan[x].voldelta = 0;
1002
1003				APU_writeChannel(x, 0, 0x00);
1004				APU_writeChannel(x, 1, 0x7F);
1005				APU_writeControl(APU_readStatus() | channelMask[x]);
1006				APU_writeChannel(x, 2, freqTable[_mchan[x].pitch] & 0xFF);
1007				APU_writeChannel(x, 3, freqTable[_mchan[x].pitch] >> 8);
1008
1009				chainCommand(x);
1010				break;
1011
1012			case 0x18:
1013				_mchan[x].envflags = 0x70;
1014
1015				chainCommand(x);
1016				break;
1017
1018			case 0x19:
1019				_mchan[x].envflags = 0xB0;
1020
1021				chainCommand(x);
1022				break;
1023
1024			case 0x1B:
1025				_mchan[x].envflags = 0x00;
1026				_mchan[x].voldelta = -10;
1027				break;
1028			}
1029		}
1030
1031		_mchan[x].volume += _mchan[x].voldelta;
1032
1033		if (_mchan[x].volume < 0)
1034			_mchan[x].volume = 0;
1035		if (_mchan[x].volume > MAXVOLUME)
1036			_mchan[x].volume = MAXVOLUME;
1037
1038		APU_writeChannel(x, 0, (_mchan[x].volume >> 3) | _mchan[x].envflags);
1039	}
1040}
1041
1042void Player_NES::chainCommand(int c) {
1043	int i = _mchan[c].command;
1044	_mchan[c].command = nextCmd[i];
1045	_mchan[c].framedelay = nextDelay[i];
1046}
1047
1048int Player_NES::getSoundStatus(int nr) const {
1049	for (int i = 0; i < NUMSLOTS; i++)
1050		if (_slot[i].id == nr)
1051			return 1;
1052	return 0;
1053}
1054
1055void Player_NES::APU_writeChannel(int chan, int offset, byte value) {
1056	_apu->WriteReg(0x000 + 4 * chan + offset, value);
1057}
1058void Player_NES::APU_writeControl(byte value) {
1059	_apu->WriteReg(0x015, value);
1060}
1061byte Player_NES::APU_readStatus() {
1062	return _apu->Read4015();
1063}
1064
1065} // End of namespace Scumm
1066
1067#endif // DISABLE_NES_APU