PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

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