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