1 /*
2 * libpsg - a simple YM-2149 soundchip emulation library.
3 *
4 * Copyright (C) 2000 Stefan Berndtsson (NoCrew)
5 * Copyright (C) 2011 Thomas Huth
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18 #include <sys/types.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <math.h>
22 #include <SDL.h>
23
24 #include "psg.h"
25
26
27 psg psg_struct;
28
29 //#define FIXED_MATH 1
30
31 #ifdef FIXED_MATH
32 # define FIXED_TYPE int
33 # define FIXED(x) ((int)((x) * 256))
34 # define DIV(x, y) ((((x) + ((y) >> 1)) << 8) / (y))
35 # define MOD(x, y) ((x) % (y))
36 # define FIXED_TO_INT(x) (((x) + 128) >> 8)
37 #else
38 # define FIXED_TYPE double
39 # define FIXED(x) x
40 # define DIV(x, y) ((x) / (y))
41 # define MOD(x, y) fmod (x, y)
42 # define FIXED_TO_INT(x) (x)
43 #endif
44
45 #define INLINE static __inline__
46
47 #define TYPE_SQUARE 0
48
49 #if 0 /* undefined at the moment */
50 # define TYPE_SINUS 1
51 # define TYPE_PSGSQR 2
52 #endif
53
54 #define MFP_FREQUENCY 2457600
55 #define PSG_FREQUENCY 2000000
56 #define QUALITY (1<<14)
57 #define SAMPLE_TYPE TYPE_SQUARE
58 #define SAMPLE_MAX 0x7fff
59 #define SAMPLE_MIN 0x8000
60 #define NOISE_MAX 0xffff
61
62 struct frame
63 {
64 int wave_period[3];
65 int rfreq[3];
66 int rvol[3];
67 int tone[3];
68 int noise[3];
69 int env[3];
70 int env_mode;
71 int env_period;
72 double env_freq;
73 int sample_freq;
74 };
75
76
77 #define ONE FIXED (1)
78 #define PI FIXED (M_PI)
79
env_wave_00XX(FIXED_TYPE in)80 INLINE FIXED_TYPE env_wave_00XX(FIXED_TYPE in)
81 {
82 if(in < PI)
83 return ONE - DIV (in, PI);
84 else
85 return 0;
86 }
87
env_wave_01XX(FIXED_TYPE in)88 INLINE FIXED_TYPE env_wave_01XX(FIXED_TYPE in)
89 {
90 if(in < PI)
91 return DIV (in, PI);
92 else
93 return 0;
94 }
95
env_wave_1000(FIXED_TYPE in)96 INLINE FIXED_TYPE env_wave_1000(FIXED_TYPE in)
97 {
98 return ONE - DIV (MOD (in, PI), PI);
99 }
100
env_wave_1001(FIXED_TYPE in)101 INLINE FIXED_TYPE env_wave_1001(FIXED_TYPE in)
102 {
103 if(in < PI)
104 return ONE - DIV (in, PI);
105 else
106 return 0;
107 }
108
env_wave_1010(FIXED_TYPE in)109 INLINE FIXED_TYPE env_wave_1010(FIXED_TYPE in)
110 {
111 FIXED_TYPE tmp;
112 tmp = MOD (in, PI*2);
113 if(tmp < PI)
114 return ONE - DIV (tmp, PI);
115 else
116 return DIV (tmp - PI, PI);
117 }
118
env_wave_1011(FIXED_TYPE in)119 INLINE FIXED_TYPE env_wave_1011(FIXED_TYPE in)
120 {
121 if(in < PI)
122 return ONE - DIV (in, PI);
123 else
124 return ONE;
125 }
126
env_wave_1100(FIXED_TYPE in)127 INLINE FIXED_TYPE env_wave_1100(FIXED_TYPE in)
128 {
129 return DIV (MOD (in, PI), PI);
130 }
131
env_wave_1101(FIXED_TYPE in)132 INLINE FIXED_TYPE env_wave_1101(FIXED_TYPE in)
133 {
134 if(in < PI)
135 return DIV (in, PI);
136 else
137 return ONE;
138 }
139
env_wave_1110(FIXED_TYPE in)140 INLINE FIXED_TYPE env_wave_1110(FIXED_TYPE in)
141 {
142 FIXED_TYPE tmp;
143 tmp = MOD (in, PI*2);
144 if(tmp < PI)
145 return DIV (tmp, PI);
146 else
147 return ONE - DIV (tmp - PI, PI);
148 }
149
env_wave_1111(FIXED_TYPE in)150 INLINE FIXED_TYPE env_wave_1111(FIXED_TYPE in)
151 {
152 if(in < PI)
153 return DIV (in, PI);
154 else
155 return ONE;
156 }
157
env_wave(FIXED_TYPE in,int mode)158 static FIXED_TYPE env_wave(FIXED_TYPE in, int mode)
159 {
160 switch(mode)
161 {
162 case 0:
163 case 1:
164 case 2:
165 case 3:
166 return env_wave_00XX(in);
167 break;
168 case 4:
169 case 5:
170 case 6:
171 case 7:
172 return env_wave_01XX(in);
173 break;
174 case 8:
175 return env_wave_1000(in);
176 break;
177 case 9:
178 return env_wave_1001(in);
179 break;
180 case 10:
181 return env_wave_1010(in);
182 break;
183 case 11:
184 return env_wave_1011(in);
185 break;
186 case 12:
187 return env_wave_1100(in);
188 break;
189 case 13:
190 return env_wave_1101(in);
191 break;
192 case 14:
193 return env_wave_1110(in);
194 break;
195 case 15:
196 return env_wave_1111(in);
197 break;
198 }
199 return 0;
200 }
201
202
203
204 /* Period counter for seamless frames */
205 struct frame tdata;
206
207 /* Values stolen from STonX */
208 static int amps[16]= {0,1,1,2,3,4,5,7,12,20,28,44,70,110,165,255};
209
_clip(int input)210 static int16_t _clip(int input)
211 {
212 if(input < -32768) return (int16_t)-32768;
213 if(input > 32767) return (int16_t) 32767;
214 return input;
215 }
216
psg_init(int mode,int bits,int freq)217 psg *psg_init(int mode, int bits, int freq)
218 {
219 int i;
220
221 if((bits != 16))
222 {
223 fprintf(stderr, "Unsupported bitvalue\n");
224 return (psg *)NULL;
225 }
226
227 if((mode < 0) || (mode > 1))
228 {
229 fprintf(stderr, "Unsupported mode\n");
230 return (psg *)NULL;
231 }
232
233 if(freq != 44100 && freq != 22050)
234 {
235 fprintf(stderr, "Unsupported frequency\n");
236 return (psg *)NULL;
237 }
238
239 psg_struct.output.mode = mode;
240 psg_struct.output.bits = bits;
241 psg_struct.output.freq = freq;
242 tdata.sample_freq = freq;
243
244 for(i=0; i<3; i++)
245 {
246 tdata.wave_period[i] = 0;
247 }
248
249 return &psg_struct;
250 }
251
252 static
_get_one_tonesample(int offset)253 int16_t _get_one_tonesample(int offset)
254 {
255 if((offset&(QUALITY-1)) < (QUALITY/2))
256 return SAMPLE_MAX;
257 else
258 return SAMPLE_MIN;
259 }
260
261 static
_get_one_noisesample(int offset)262 int16_t _get_one_noisesample(int offset)
263 {
264 return (NOISE_MAX&rand())-SAMPLE_MAX;
265 }
266
267 static
_get_real_freq(int psgfreq,int sample_freq)268 int _get_real_freq(int psgfreq, int sample_freq)
269 {
270 int denominator;
271
272 if(psgfreq)
273 {
274 denominator = sample_freq * psgfreq;
275 return (QUALITY *(PSG_FREQUENCY/16.0) + (denominator >> 1)) / denominator;
276 }
277 else
278 return 0;
279 }
280
psg_update_values(psg * psg)281 static void psg_update_values(psg *psg)
282 {
283 int i, tmp;
284
285 for(i=0; i<3; i++)
286 {
287 if(psg->regs[8+i] == 16)
288 {
289 tdata.rvol[i] = 0;
290 tdata.env[i] = 1;
291 if(psg->regs[13] != 0xff)
292 {
293 //tdata.env_period = 0;
294 tdata.env_mode = psg->regs[13];
295 }
296 }
297 else
298 {
299 tdata.rvol[i] = psg->regs[8+i];
300 tdata.env[i] = 0;
301 }
302 tmp = psg->regs[11] + (psg->regs[12] << 8);
303 if(tmp)
304 tdata.env_freq = ((double)PSG_FREQUENCY/(256.0 * tmp));
305 else
306 tdata.env_freq = 0;
307 tdata.rfreq[i] = _get_real_freq((psg->regs[1+i*2]<<8) + psg->regs[0+i*2], psg->output.freq);
308 tdata.tone[i] = !(psg->regs[7] & (1<<i));
309 tdata.noise[i] = !(psg->regs[7] & (8<<i));
310 }
311 }
312
313
314 static
_get_one_sample(void)315 int16_t _get_one_sample(void)
316 {
317 int i;
318 int32_t tmp;
319
320 tmp = 0;
321
322 for(i=0; i<3; i++)
323 {
324 // printf("%i: noise=%i tone=%i env=%i\n",i,tdata.noise[i], tdata.tone[i], tdata.env[i]);
325 if(tdata.tone[i] && !tdata.noise[i])
326 {
327 if(tdata.env[i])
328 {
329 tmp = _clip(tmp + ((_get_one_tonesample(tdata.wave_period[i])*
330 amps[(int)
331 (15*env_wave(tdata.env_period*M_PI*2/QUALITY,
332 tdata.env_mode))]>>8)));
333 }
334 else
335 {
336 tmp = _clip(tmp + ((_get_one_tonesample(tdata.wave_period[i])*
337 amps[tdata.rvol[i]])>>8));
338 }
339 tdata.wave_period[i] += tdata.rfreq[i];
340 }
341 if(tdata.noise[i] && !tdata.tone[i])
342 {
343 if(tdata.env[i])
344 {
345 tmp = _clip(tmp + ((_get_one_noisesample(tdata.wave_period[i])*
346 amps[(int)
347 (15*env_wave(tdata.env_period*M_PI*2/QUALITY,
348 tdata.env_mode))]>>8)));
349 }
350 else
351 {
352 tmp = _clip(tmp + ((_get_one_noisesample(tdata.wave_period[i])*
353 amps[tdata.rvol[i]])>>8));
354 }
355 // tdata.wave_period[i] += tdata.rfreq[i];
356 }
357 if(tdata.noise[i] && tdata.tone[i])
358 {
359 if(tdata.env[i])
360 {
361 tmp = _clip(tmp + ((_clip(_get_one_tonesample(tdata.wave_period[i])+
362 _get_one_noisesample(tdata.wave_period[i]))*
363 amps[(int)
364 (15*env_wave(tdata.env_period*M_PI*2/QUALITY,
365 tdata.env_mode))]>>8)));
366 }
367 else
368 {
369 tmp = _clip(tmp + (_clip(_get_one_tonesample(tdata.wave_period[i])+
370 _get_one_noisesample(tdata.wave_period[i]))*
371 amps[tdata.rvol[i]]>>8));
372 }
373 tdata.wave_period[i] += tdata.rfreq[i];
374 }
375 }
376
377 if(tdata.env_freq)
378 tdata.env_period += 2*(QUALITY/(tdata.sample_freq * tdata.env_freq));
379
380 return tmp;
381 }
382
383
psg_create_samples(void * buffer,psg * psg,int samples)384 int psg_create_samples(void *buffer, psg *psg, int samples)
385 {
386 int16_t *tmp;
387 int i, tval;
388
389 tmp = (int16_t *) buffer;
390
391 for(i=0; i<samples; i++)
392 {
393 tval = _get_one_sample();
394 *tmp++ = tval;
395 if(psg->output.mode)
396 *tmp++ = tval;
397 }
398
399
400 return 0;
401 }
402
403
404 /**
405 * SDL audio callback function - copy emulation sound to audio system.
406 */
Audio_CallBack(void * userdata,Uint8 * stream,int len)407 static void Audio_CallBack(void *userdata, Uint8 *stream, int len)
408 {
409 psg_create_samples(stream, &psg_struct, len/4);
410 }
411
412
Giaccess(unsigned int data,unsigned int reg)413 unsigned int Giaccess(unsigned int data, unsigned int reg)
414 {
415 if (reg & 0x80)
416 {
417 psg_struct.regs[reg&0x0f] = data;
418 psg_update_values(&psg_struct);
419 if ((reg&0x0f) == 13)
420 tdata.env_period = 0;
421 return 0;
422 }
423 else
424 {
425 return psg_struct.regs[reg&0x0f];
426 }
427 }
428
429
Dosound(const unsigned char * buf)430 void Dosound(const unsigned char *buf)
431 {
432 int i = 0;
433 while (buf[i] != 0xff)
434 {
435 if (buf[i] >= 16)
436 {
437 printf("Dosound: Unsupported opcode 0x%02x\n", buf[i]);
438 }
439 else
440 {
441 psg_struct.regs[buf[i]] = buf[i+1];
442 if (buf[i] == 13)
443 tdata.env_period = 0;
444 }
445 i += 2;
446 }
447
448 psg_update_values(&psg_struct);
449 }
450
451
452 /**
453 * Initialize the audio subsystem. Return true if all OK.
454 */
psg_audio_init(void)455 void psg_audio_init(void)
456 {
457 SDL_AudioSpec desiredAudioSpec; /* We fill in the desired SDL audio options here */
458
459 /* Init the SDL's audio subsystem: */
460 if (SDL_WasInit(SDL_INIT_AUDIO) == 0)
461 {
462 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
463 {
464 fprintf(stderr, "Could not init audio: %s\n", SDL_GetError() );
465 return;
466 }
467 }
468
469 psg_init(1, 16, 44100);
470
471 /* Set up SDL audio: */
472 desiredAudioSpec.freq = 22050;
473 desiredAudioSpec.format = AUDIO_S16SYS; /* 16-Bit signed */
474 desiredAudioSpec.channels = 2; /* stereo */
475 desiredAudioSpec.callback = Audio_CallBack;
476 desiredAudioSpec.userdata = NULL;
477 desiredAudioSpec.samples = 512; /* buffer size in samples */
478
479 if (SDL_OpenAudio(&desiredAudioSpec, NULL)) /* Open audio device */
480 {
481 fprintf(stderr, "Can't use audio: %s\n", SDL_GetError());
482 SDL_QuitSubSystem(SDL_INIT_AUDIO);
483 return;
484 }
485
486 SDL_PauseAudio(0);
487 }
488