1 /* FIXME: move ugly-ass legalese somewhere where it won't be seen
2 // by anyone other than lawyers. (/dev/null would be ideal but sadly
3 // we live in an imperfect world). */
4 /* Copyright (c) 2012/2013, Peter Barfuss
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
26
27 /* Quick, somewhat hacky PSG implementation. Seems to work fine in most cases.
28 // Known bugs: volume *may* still be off for a lot of samples. Importantly,
29 // waveform volume is too quiet but setting it at the correct volume makes
30 // the noise volume too loud and vice-versa. I *think* what I have currently
31 // is mostly correct (I'm basing this mostly on how good Strawberry Crisis
32 // sounds with the given settings), but it's possible that more fine-tuning
33 // is needed. Apart from that, this is probably the sketchiest part of all
34 // of my emulator code, but then again there's a bit-exact VHDL core of
35 // the YM2149F/AY-3-8910, so while I do want to make this as good
36 // as the code in opna.c, it's the lowest-priority of all of the code here.
37 // --bofh */
38 #include <stdint.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <math.h>
42 #include "op.h"
43 #include "psg.h"
44
45 /* ---------------------------------------------------------------------------
46 // ????
47 */
48 int EmitTable[0x20] = { -1, };
49 uint32_t enveloptable[16][64] = { { 0, }, };
50
51 /* ---------------------------------------------------------------------------
52 // PSG reset to power-on defaults
53 */
PSGReset(PSG * psg)54 void PSGReset(PSG *psg)
55 {
56 int i;
57 for (i=0; i<14; i++)
58 PSGSetReg(psg, i, 0);
59 PSGSetReg(psg, 7, 0xff);
60 PSGSetReg(psg, 14, 0xff);
61 PSGSetReg(psg, 15, 0xff);
62 }
63
64 /* ---------------------------------------------------------------------------
65 // This code is strongly inspired by some random PSG emulator code I found,
66 // and is probably not the optimal way to define periods. It *is* at least
67 // among the fastest, given that it uses the hilarious hack of using the
68 // integer overflow on a 32-bit unsigned integer to compute ""moduli"".
69 */
PSGSetClock(PSG * psg,uint32_t clock,uint32_t rate)70 void PSGSetClock(PSG *psg, uint32_t clock, uint32_t rate)
71 {
72 int tmp;
73 psg->tperiodbase = (uint32_t)((1 << toneshift ) / 4.0f * clock / rate);
74 psg->eperiodbase = (uint32_t)((1 << envshift ) / 4.0f * clock / rate);
75
76 tmp = ((psg->reg[0] + psg->reg[1] * 256) & 0xfff);
77 psg->speriod[0] = tmp ? psg->tperiodbase / tmp : psg->tperiodbase;
78 tmp = ((psg->reg[2] + psg->reg[3] * 256) & 0xfff);
79 psg->speriod[1] = tmp ? psg->tperiodbase / tmp : psg->tperiodbase;
80 tmp = ((psg->reg[4] + psg->reg[5] * 256) & 0xfff);
81 psg->speriod[2] = tmp ? psg->tperiodbase / tmp : psg->tperiodbase;
82 tmp = psg->reg[6] & 0x1f;
83 psg->nperiod = tmp;
84 tmp = ((psg->reg[11] + psg->reg[12] * 256) & 0xffff);
85 psg->eperiod = tmp ? psg->eperiodbase / tmp : psg->eperiodbase * 2;
86 }
87
88 /* ---------------------------------------------------------------------------
89 // ????????????
90 */
91 static uint8_t table3[4] = { 0, 1, -1, 0 };
MakeEnvelopTable(void)92 void MakeEnvelopTable(void)
93 {
94 /* 0 lo 1 up 2 down 3 hi */
95 static uint8_t table1[16*2] =
96 {
97 2,0, 2,0, 2,0, 2,0, 1,0, 1,0, 1,0, 1,0,
98 2,2, 2,0, 2,1, 2,3, 1,1, 1,3, 1,2, 1,0,
99 };
100 int i, j;
101
102 if (!enveloptable[0][0]) {
103 uint32_t *ptr = enveloptable[0];
104 for (i=0; i<16*2; i++) {
105 uint8_t v = ((table1[i] & 0x2) ? 31 : 0);
106 for (j=0; j<32; j++) {
107 *ptr++ = EmitTable[v];
108 v += table3[table1[i]];
109 }
110 }
111 }
112 }
113
114 /* ---------------------------------------------------------------------------
115 // Sets the channel output mask for the PSG device.
116 // c is a bitvector where the 3 LSBs are set to 0 to disable a given
117 // PSG channel and 1 to enable it.
118 // TODO: Possibly allow enabling tone/noise output for each channel independently?
119 */
PSGSetChannelMask(PSG * psg,int c)120 void PSGSetChannelMask(PSG *psg, int c)
121 {
122 int i;
123 psg->mask = c;
124 for (i=0; i<3; i++)
125 psg->olevel[i] = psg->mask & (1 << i) ? EmitTable[(psg->reg[8+i] & 15) * 2 + 1] : 0;
126 }
127
128 /* ---------------------------------------------------------------------------
129 // PSG register set routine. Mostly just what you'd expect from reading the manual.
130 // Fairly boring code overall. regnum can be 0 - 15, data can be 0x00 - 0xFF.
131 // (This should not be surprising - the YM2149F *did* use an 8-bit bus, after all).
132 // Interesting quirk: the task of register 7 (channel enable/disable) is basically
133 // entirely duplicated by other registers, to the point where you can basically
134 // just ignore any writes to register 7 entirely. I save it here in case some
135 // braindead routine wants to read its value and do something based on that
136 // (Another curiosity: register 7 on the PSG appears to be the only register
137 // between *both* the OPNA and the PSG which is actually *read from* by
138 // pmdwin.cpp and not just written to. Amusingly enough, the only reason
139 // that it is ever read is so that it can then OR something with what it just read
140 // and then write that back to register 7. Hilarity).
141 // HACK ALERT: The output levels for channels 0 and 1 are increased by a factor of 4
142 // to make them match the actual chip in loudness, but without causing the noise channel
143 // to overtake everything in intensity. This is almost certainly wrong, and moreover
144 // it assumes that channel 2 will be playing back Speak Board effects which usually means
145 // drum kit only (for the most part, at least), and not being used as a separate tonal
146 // channel in its own right. To the best of my knowledge, this does hold for all of ZUN's
147 // songs, however, once you step outside that set of music, it's trivial to find
148 // all sorts of counterexamples to that assumption. Therefore, this should be fixed ASAP.
149 */
PSGSetReg(PSG * psg,uint8_t regnum,uint8_t data)150 void PSGSetReg(PSG *psg, uint8_t regnum, uint8_t data)
151 {
152 if (regnum < 0x10)
153 {
154 psg->reg[regnum] = data;
155 switch (regnum)
156 {
157 int tmp;
158
159 case 0: /* ChA Fine Tune */
160 case 1: /* ChA Coarse Tune */
161 tmp = ((psg->reg[0] + psg->reg[1] * 256) & 0xfff);
162 psg->speriod[0] = tmp ? psg->tperiodbase / tmp : psg->tperiodbase;
163 break;
164
165 case 2: /* ChB Fine Tune */
166 case 3: /* ChB Coarse Tune */
167 tmp = ((psg->reg[2] + psg->reg[3] * 256) & 0xfff);
168 psg->speriod[1] = tmp ? psg->tperiodbase / tmp : psg->tperiodbase;
169 break;
170
171 case 4: /* ChC Fine Tune */
172 case 5: /* ChC Coarse Tune */
173 tmp = ((psg->reg[4] + psg->reg[5] * 256) & 0xfff);
174 psg->speriod[2] = tmp ? psg->tperiodbase / tmp : psg->tperiodbase;
175 break;
176
177 case 6: /* Noise generator control */
178 data &= 0x1f;
179 psg->nperiod = data;
180 break;
181
182 case 8:
183 psg->olevel[0] = psg->mask & 1 ? EmitTable[(data & 15) * 2 + 1] : 0;
184 break;
185
186 case 9:
187 psg->olevel[1] = psg->mask & 2 ? EmitTable[(data & 15) * 2 + 1] : 0;
188 break;
189
190 case 10:
191 psg->olevel[2] = psg->mask & 4 ? EmitTable[(data & 15) * 2 + 1] : 0;
192 break;
193
194 case 11: /* Envelope period */
195 case 12:
196 tmp = ((psg->reg[11] + psg->reg[12] * 256) & 0xffff);
197 psg->eperiod = tmp ? psg->eperiodbase / tmp : psg->eperiodbase * 2;
198 break;
199
200 case 13: /* Envelope shape */
201 psg->ecount = 0;
202 psg->envelop = enveloptable[data & 15];
203 break;
204 }
205 }
206 }
207
208 /* ---------------------------------------------------------------------------
209 // Init code. Set volume to 0, reset the chip, enable all channels, seed the RNG.
210 // RNG seed lifted from MAME's YM2149F emulation routine, appears to be correct.
211 */
PSGInit(PSG * psg)212 void PSGInit(PSG *psg)
213 {
214 int i;
215 float base = 0x4000 / 3.0f;
216 for (i=31; i>=2; i--)
217 {
218 EmitTable[i] = lrintf(base);
219 base *= 0.840896415f; /* 1.0f / 1.189207115f */
220 }
221 EmitTable[1] = 0;
222 EmitTable[0] = 0;
223 MakeEnvelopTable();
224
225 PSGSetChannelMask(psg, psg->mask);
226 psg->rng = 14231;
227 psg->ncount = 0;
228 PSGReset(psg);
229 psg->mask = 0x3f;
230 }
231
232 /* ---------------------------------------------------------------------------
233 // The main output routine for the PSG emulation.
234 // dest should be an array of size nsamples, and of type Sample
235 // (one of int16_t, int32_t or float - any will work here without causing
236 // clipping/precision problems).
237 // Everything is implemented using some form of fixed-point arithmetic
238 // that currently needs no more than 32-bits for its implementation,
239 // but I'm pretty certain that you can get by with much less than that
240 // and still have mostly correct-to-fully-correct emulation.
241 //
242 // TODO: In the future, test the veracity of the above statement. Moreover,
243 // if it turns out to be correct, rewrite this routine to not use more than
244 // the required precision. This is irrelevant for any PC newer than, well,
245 // a 386DX/68040, but important for efficient hardware implementation.
246 */
PSGMix(PSG * psg,int32_t * dest,uint32_t nsamples)247 void PSGMix(PSG *psg, int32_t *dest, uint32_t nsamples)
248 {
249 uint8_t chenable[3];
250 uint8_t r7 = ~psg->reg[7];
251 unsigned int i, k = 0;
252 int x, y, z;
253
254 if ((r7 & 0x3f) | ((psg->reg[8] | psg->reg[9] | psg->reg[10]) & 0x1f)) {
255 int noise, sample;
256 uint32_t env;
257 uint32_t* p1;
258 uint32_t* p2;
259 uint32_t* p3;
260
261 chenable[0] = (r7 & 0x01) && (psg->speriod[0] <= (1 << toneshift));
262 chenable[1] = (r7 & 0x02) && (psg->speriod[1] <= (1 << toneshift));
263 chenable[2] = (r7 & 0x04) && (psg->speriod[2] <= (1 << toneshift));
264
265 p1 = ((psg->mask & 1) && (psg->reg[ 8] & 0x10)) ? &env : &psg->olevel[0];
266 p2 = ((psg->mask & 2) && (psg->reg[ 9] & 0x10)) ? &env : &psg->olevel[1];
267 p3 = ((psg->mask & 4) && (psg->reg[10] & 0x10)) ? &env : &psg->olevel[2];
268 #define SCOUNT(ch) (psg->scount[ch] >> toneshift)
269
270 if (p1 != &env && p2 != &env && p3 != &env) {
271 for (i=0; i<nsamples; i++) {
272 psg->ncount++;
273 if(psg->ncount >= psg->nperiod) {
274 if(psg->rng & 1)
275 psg->rng ^= 0x24000;
276 psg->rng >>= 1;
277 psg->ncount = 0;
278 }
279 noise = (psg->rng & 1);
280 sample = 0;
281 {
282 x = ((SCOUNT(0) & chenable[0]) | ((r7 >> 3) & noise)) - 1; /* 0 or -1 */
283 sample += (psg->olevel[0] + x) ^ x;
284 psg->scount[0] += psg->speriod[0];
285 y = ((SCOUNT(1) & chenable[1]) | ((r7 >> 4) & noise)) - 1;
286 sample += (psg->olevel[1] + y) ^ y;
287 psg->scount[1] += psg->speriod[1];
288 /*z = ((SCOUNT(2) & chenable[2]) | ((r7 >> 5) & noise)) - 1;*/
289 z = ((r7 >> 5) & noise) - 1;
290 sample += (psg->olevel[2] + z) ^ z;
291 psg->scount[2] += psg->speriod[2];
292 }
293 sample = Limit16(sample);
294 dest[k++] += sample;
295 dest[k++] += sample;
296 }
297
298 psg->ecount = (psg->ecount >> 8) + (psg->eperiod >> 8) * nsamples;
299 if (psg->ecount >= (1 << (envshift+6-8))) {
300 if ((psg->reg[0x0d] & 0x0b) != 0x0a)
301 psg->ecount |= (1 << (envshift+5-8));
302 psg->ecount &= (1 << (envshift+6-8)) - 1;
303 }
304 psg->ecount <<= 8;
305 } else {
306 for (i=0; i<nsamples; i++) {
307 psg->ncount++;
308 if(psg->ncount >= psg->nperiod) {
309 if(psg->rng & 1)
310 psg->rng ^= 0x24000;
311 psg->rng >>= 1;
312 psg->ncount = 0;
313 }
314 noise = (psg->rng & 1);
315 sample = 0;
316 {
317 env = psg->envelop[psg->ecount >> envshift];
318 psg->ecount += psg->eperiod;
319 if (psg->ecount >= (1 << (envshift+6))) {
320 if ((psg->reg[0x0d] & 0x0b) != 0x0a)
321 psg->ecount |= (1 << (envshift+5));
322 psg->ecount &= (1 << (envshift+6)) - 1;
323 }
324 x = ((SCOUNT(0) & chenable[0]) | ((r7 >> 3) & noise)) - 1; /* 0 or -1 */
325 sample += (*p1 + x) ^ x;
326 psg->scount[0] += psg->speriod[0];
327 y = ((SCOUNT(1) & chenable[1]) | ((r7 >> 4) & noise)) - 1;
328 sample += (*p2 + y) ^ y;
329 psg->scount[1] += psg->speriod[1];
330 /*z = ((SCOUNT(2) & chenable[2]) | ((r7 >> 5) & noise)) - 1;*/
331 z = ((r7 >> 5) & noise) - 1;
332 sample += (*p3 + z) ^ z;
333 psg->scount[2] += psg->speriod[2];
334 }
335 sample = Limit16(sample);
336 dest[k++] += sample;
337 dest[k++] += sample;
338 }
339 }
340 }
341 }
342
343