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