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