pcm.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * Emulation routines for the RF5C164 PCM chip
  3. * (C) notaz, 2007, 2013
  4. *
  5. * This work is licensed under the terms of MAME license.
  6. * See COPYING file in the top-level directory.
  7. */
  8. #include "../pico_int.h"
  9. #define PCM_STEP_SHIFT 11
  10. void pcd_pcm_write(unsigned int a, unsigned int d)
  11. {
  12. unsigned int cycles = SekCyclesDoneS68k();
  13. if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384)
  14. pcd_pcm_sync(cycles);
  15. if (a < 7)
  16. {
  17. Pico_mcd->pcm.ch[Pico_mcd->pcm.cur_ch].regs[a] = d;
  18. }
  19. else if (a == 7) // control register
  20. {
  21. if (d & 0x40)
  22. Pico_mcd->pcm.cur_ch = d & 7;
  23. else
  24. Pico_mcd->pcm.bank = d & 0xf;
  25. Pico_mcd->pcm.control = d;
  26. elprintf(EL_CD, "pcm control %02x", Pico_mcd->pcm.control);
  27. }
  28. else if (a == 8)
  29. {
  30. Pico_mcd->pcm.enabled = ~d;
  31. }
  32. Pico_mcd->pcm_regs_dirty = 1;
  33. }
  34. unsigned int pcd_pcm_read(unsigned int a)
  35. {
  36. unsigned int d, cycles = SekCyclesDoneS68k();
  37. if ((int)(cycles - Pico_mcd->pcm.update_cycles) >= 384)
  38. pcd_pcm_sync(cycles);
  39. d = Pico_mcd->pcm.ch[(a >> 1) & 7].addr >> PCM_STEP_SHIFT;
  40. if (a & 1)
  41. d >>= 8;
  42. return d & 0xff;
  43. }
  44. void pcd_pcm_sync(unsigned int to)
  45. {
  46. unsigned int cycles = Pico_mcd->pcm.update_cycles;
  47. int mul_l, mul_r, inc, smp;
  48. struct pcm_chan *ch;
  49. unsigned int addr;
  50. int c, s, steps;
  51. int enabled;
  52. int *out;
  53. if ((int)(to - cycles) < 384)
  54. return;
  55. steps = (to - cycles) / 384;
  56. if (Pico_mcd->pcm_mixpos + steps > PCM_MIXBUF_LEN)
  57. // shouldn't happen, but occasionally does
  58. steps = PCM_MIXBUF_LEN - Pico_mcd->pcm_mixpos;
  59. // PCM disabled or all channels off
  60. enabled = Pico_mcd->pcm.enabled;
  61. if (!(Pico_mcd->pcm.control & 0x80))
  62. enabled = 0;
  63. if (!enabled && !Pico_mcd->pcm_regs_dirty)
  64. goto end;
  65. out = Pico_mcd->pcm_mixbuf + Pico_mcd->pcm_mixpos * 2;
  66. Pico_mcd->pcm_mixbuf_dirty = 1;
  67. Pico_mcd->pcm_regs_dirty = 0;
  68. for (c = 0; c < 8; c++)
  69. {
  70. ch = &Pico_mcd->pcm.ch[c];
  71. if (!(enabled & (1 << c))) {
  72. ch->addr = ch->regs[6] << (PCM_STEP_SHIFT + 8);
  73. continue; // channel disabled
  74. }
  75. addr = ch->addr;
  76. inc = ch->regs[2] + (ch->regs[3]<<8);
  77. mul_l = (int)ch->regs[0] * (ch->regs[1] & 0xf);
  78. mul_r = (int)ch->regs[0] * (ch->regs[1] >> 4);
  79. for (s = 0; s < steps; s++, addr = (addr + inc) & 0x07FFFFFF)
  80. {
  81. smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT];
  82. // test for loop signal
  83. if (smp == 0xff)
  84. {
  85. addr = ch->regs[4] + (ch->regs[5]<<8); // loop_addr
  86. smp = Pico_mcd->pcm_ram[addr];
  87. addr <<= PCM_STEP_SHIFT;
  88. if (smp == 0xff)
  89. break;
  90. }
  91. if (smp & 0x80)
  92. smp = -(smp & 0x7f);
  93. out[s*2 ] += (smp * mul_l) >> 5; // max 127 * 255 * 15 / 32 = 15180
  94. out[s*2+1] += (smp * mul_r) >> 5;
  95. }
  96. ch->addr = addr;
  97. }
  98. end:
  99. Pico_mcd->pcm.update_cycles = cycles + steps * 384;
  100. Pico_mcd->pcm_mixpos += steps;
  101. }
  102. void pcd_pcm_update(s32 *buf32, int length, int stereo)
  103. {
  104. int step, *pcm;
  105. int p = 0;
  106. pcd_pcm_sync(SekCyclesDoneS68k());
  107. if (!Pico_mcd->pcm_mixbuf_dirty || !(PicoIn.opt & POPT_EN_MCD_PCM))
  108. goto out;
  109. step = (Pico_mcd->pcm_mixpos << 16) / length;
  110. pcm = Pico_mcd->pcm_mixbuf;
  111. if (stereo) {
  112. while (length-- > 0) {
  113. *buf32++ += pcm[0];
  114. *buf32++ += pcm[1];
  115. p += step;
  116. pcm += (p >> 16) * 2;
  117. p &= 0xffff;
  118. }
  119. }
  120. else {
  121. while (length-- > 0) {
  122. // mostly unused
  123. *buf32++ += pcm[0];
  124. p += step;
  125. pcm += (p >> 16) * 2;
  126. p &= 0xffff;
  127. }
  128. }
  129. memset(Pico_mcd->pcm_mixbuf, 0,
  130. Pico_mcd->pcm_mixpos * 2 * sizeof(Pico_mcd->pcm_mixbuf[0]));
  131. out:
  132. Pico_mcd->pcm_mixbuf_dirty = 0;
  133. Pico_mcd->pcm_mixpos = 0;
  134. }
  135. // vim:shiftwidth=2:ts=2:expandtab