1 
2 /*
3   sound.c
4 
5   Gameboy sound emulation support for Linux.
6 
7   *****************************************************
8   EXPERIMENTAL !!!!!
9   SOUNDS TERRIBLE !!!!!!!!
10   *****************************************************
11 
12   */
13 
14 
15 #ifdef SOUND
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <sys/ioctl.h>
22 #include <pthread.h>
23 
24 #ifndef AUDIO
25 #include <sys/soundcard.h>
26 #else
27 #include <sys/audioio.h>
28 #endif
29 
30 #include "globals.h"
31 #include "gameboy.h"
32 
33 
34 int sd;                       /* dsp/audio device descriptor */
35 
36 int gain;
37 int snd_count1,snd_count2,snd_count3,snd_count4;
38 int snd_reload1,snd_init1,snd_length1,snd_count1,snd1_st,snd1_str;
39 int snd_reload2,snd_init2,snd_length2,snd_count2;
40 int snd_reload3,snd_init3,snd_length3,snd_count3,snd_shr;
41 int snd_reload4,snd_init4,snd_length4,snd4_rand;
42 
43 #define FIXPOINT_SHIFT 16
44 #define FIXPOINT_MASK  ((1L<<FIXPOINT_SHIFT)-1)
45 #define FIXPOINT_HALF  (1L<<(FIXPOINT_SHIFT-1))
46 
47 /* current sound rate (set it higher, if you dare) */
48 
49 int sound_frequency=22050;
50 int frequency_div256;
51 
52 char *dspdev="/dev/dsp";
53 char *audiodev="/dev/audio";
54 
55 int *pattern[4];
56 int chn3_tab[16];   /*={-32,-28,-24,-20,-16,-12,-8,-4,
57 		     0,4,8,12,16,20,24,28}*/
58 
59 #define SND4_RNDPATTERNLEN 16384
60 int snd4_rndpattern[SND4_RNDPATTERNLEN];
61 
62 int gbfreq(unsigned short int);
63 void outsample(int s);
64 /*void* processSound(void *);*/
65 
66 
67 /* sound initialisation */
68 
initsound(void)69 int initsound(void)
70 {
71   /*  pthread_t tid;*/
72   int value;
73 
74 #ifdef AUDIO
75   audio_info_t audio;
76 #endif
77 
78 #ifndef AUDIO
79   if ((sd=open(dspdev,O_WRONLY))<0) {
80     fprintf(OUTSTREAM,"Error opening %s\n",dspdev);
81     return 0;
82   }
83 
84   value=AFMT_U8;
85   if (ioctl(sd,SNDCTL_DSP_SETFMT,&value)<0) {
86     fprintf(OUTSTREAM,"Error: SNDCLT_DSP_SETFMT\n");
87     close(sd);
88     return 0;
89   }
90 
91   value=sound_frequency;
92   if (ioctl(sd,SNDCTL_DSP_SPEED,&value)<0) {
93     fprintf(OUTSTREAM,"Error: SNDCLT_DSP_SPEED\n");
94     close(sd);
95     return 0;
96   }
97 
98   value=0x0003000a;  /* 3 bufs, 2^8 bytes */
99   if (ioctl(sd,SNDCTL_DSP_SETFRAGMENT,&value)<0) {
100     fprintf(OUTSTREAM,"Error: SNDCLT_DSP_SETFRAGMENT\n");
101     close(sd);
102     return 0;
103   }
104 #else
105   if ((sd=open(audiodev,O_WRONLY))<0) {
106     fprintf(OUTSTREAM,"Error opening %s\n",audiodev);
107     close(sd);
108     return 0;
109   }
110 
111   AUDIO_INITINFO (&audio);
112   audio.play.sample_rate = sound_frequency;
113   audio.play.channels = 1;
114   audio.play.precision = 8;
115   audio.play.encoding = AUDIO_ENCODING_LINEAR;
116 
117   if (ioctl (sd, AUDIO_SETINFO, &audio)<0) {
118     fprintf(OUTSTREAM,"Failed to set %s.\n",audiodev);
119     return 0;
120   }
121   if (ioctl (sd, AUDIO_GETINFO, &audio) != 0) return (0);
122 #endif
123 
124   fprintf(OUTSTREAM,"Allocating sound pattern memory 4x%lu bytes.\n",
125 	  (long unsigned int)sound_frequency*sizeof(int));
126   for (value=0;value<4;value++) {
127     if ((pattern[value]=malloc(sound_frequency*sizeof(int)))==NULL) {
128       fprintf(OUTSTREAM,"Error allocating sound pattern memory.\n");
129       close(sd);
130       return 0;
131     }
132   }
133 
134   snd_updateclks=(4096*1024)/sound_frequency;
135 
136   snd_init1=snd_length1=snd_count1=0;
137   snd_init2=snd_length2=snd_count2=0;
138   snd_init3=snd_length3=snd_count3=0;
139   snd_init4=snd_length4=snd_count4=0;
140 
141   fprintf(OUTSTREAM,"Initializing sound pattern memory.\n");
142   for (value=0;value<sound_frequency;value++) {
143     /*    pattern[2][value]=sin((float)value/DSP_FREQ*2*M_PI)*128+128;
144     if (value>=DSP_FREQ/2)
145       pattern[1][value]=sin((float)value/DSP_FREQ*4*M_PI)*128+128;
146     else pattern[1][value]=0;
147     if (value>=DSP_FREQ/4)
148       pattern[0][value]=sin((float)value/DSP_FREQ*8*M_PI)*128+128;
149     else pattern[0][value]=0;
150     if (value>=3*DSP_FREQ/4)
151       pattern[3][value]=sin((float)value/DSP_FREQ*1.5*M_PI)*128+128;
152     else pattern[3][value]=0;
153             pattern[value]=255-((float)value/DSP_FREQ*255.0);*/
154     if (value>=sound_frequency/2) pattern[2][value]=128-32;
155     else pattern[2][value]=128+32;
156     if (value>=sound_frequency/4) pattern[1][value]=128-32;
157     else pattern[1][value]=128+32;
158     if (value>=sound_frequency/8) pattern[0][value]=128-32;
159     else pattern[0][value]=128+32;
160     if (value>=sound_frequency/4) pattern[3][value]=128+32;
161     else pattern[3][value]=128-32;
162   }
163 
164   srand(time(NULL));
165   for (value=0;value<SND4_RNDPATTERNLEN;value++) {
166 
167     snd4_rndpattern[value]=(rand()>>26)+128-32;
168     if (value<16) {
169       snd4_rndpattern[value]*=(value/16.0);
170     }
171       /*      printf("%d\n",snd4_rndpattern[value]);*/
172   }
173 
174   for (value=0;value<16;value++)
175     chn3_tab[value]=(value-8)*4+128;
176 
177   fprintf(OUTSTREAM,"Sound pattern memory OK.\n");
178 
179   frequency_div256=sound_frequency/256;
180 
181   /*  value=pthread_create(&tid,NULL,processSound,NULL);
182   fprintf(OUTSTREAM,"Sound thread initialized %s.\n", value==0 ? "OK" : "FAILED");
183   if (value!=0) {
184     fprintf(OUTSTREAM,"Failed with value %d.\n",value);
185     }*/
186 
187   return 1; /* sound will be emulated */
188 }
189 
190 /* closing sound */
donesound(void)191 void donesound(void)
192 {
193   int value;
194 
195   for (value=0;value<4;value++) free(pattern[value]);
196   if (sd>0) close(sd);
197 }
198 
199 #if 0
200 #ifdef USE_LITTLE_ENDIAN
201 #define SND_BUFSIZE 1024
202 #define SND_BUFCOUNT 3
203 static int snd_bufptr=0;
204 static int snd_bufnr=0;
205 static char snd_buffer[SND_BUFCOUNT][SND_BUFSIZE];
206 #endif
207 #endif
208 
outsample(int s)209 void outsample(int s)
210 {
211 #if 0
212 #ifdef USE_LITTLE_ENDIAN
213 
214   snd_buffer[snd_bufnr][snd_bufptr++]=(char)s;
215 
216   if (snd_bufptr>=SND_BUFSIZE) {
217     int playbuf=snd_bufnr-1;
218     if (playbuf<0) playbuf=SND_BUFCOUNT-1;
219 
220     write(sd,snd_buffer[playbuf],SND_BUFSIZE);
221     snd_bufnr++;
222     snd_bufptr=0;
223     if (snd_bufnr>=SND_BUFCOUNT) snd_bufnr=0;
224   }
225 #else
226 #endif
227 #endif
228   char lf;
229   lf=(char)s;
230 
231   write(sd,&lf,1);
232 
233   /*      printf("%d",s);*/
234 }
235 
mixsample(int s1,int s2)236 int mixsample(int s1,int s2)
237 {
238   register int s;
239 
240   s=((s1-128)+(s2-128))+128;
241 
242   return s<=0 ? 0 :
243     s>=255 ? 255 : s;
244 }
245 
processSound(void)246 void processSound(void)
247 {
248 
249   /*  while (1) {*/
250 
251     int sample=128,gain=128,pos;
252 
253     /*    usleep(1);*/
254 
255     /*printf("THREAD\n");*/
256     /*while (Z80_CPUCLKS & 0x03);*/
257 
258     if (((NR50&0x77)==0)||((NR52&0x80)==0)) {
259       if (producesound) outsample(sample);
260       else outsample(0);
261     }
262 
263 #if 1
264   if (NR51&0x11 && NR12&0xF8) {
265     if (snd_init1) {
266       snd_init1=0;
267       snd_count1=frequency_div256;
268     }
269 
270     if ((snd_reload1>0)&&(snd_length1>0)) {
271       if (snd_count1--<=0) {
272 	snd_length1--;
273 	snd_count1=frequency_div256;
274 
275 	/* sweep */
276 	if (snd1_str>0) {
277 	  if (--snd1_st==0) {
278 	    snd1_st=snd1_str;
279 
280 	    pos=((NR14&7)<<8)|NR13;
281 	    if (NR10&8)
282 	      pos-=pos>>(NR10&7);
283 	    else
284 	      pos+=pos>>(NR10&7);
285 
286 	    NR14=(NR14&0xF8)|((pos>>8)&7);
287 	    NR13=pos&0xFF;
288 
289 	    snd_reload1=gbfreq(pos);
290 	  }
291 	}
292       }
293 
294       snd_count1+=snd_reload1;
295       /*      if (snd_count1>=sound_frequency) snd_count1-=sound_frequency;
296 	      gain=pattern[NR11>>6][snd_count1];*/
297 
298       gain=((snd_count1&FIXPOINT_MASK)>FIXPOINT_HALF) ? 128-32 : 128+32;
299 
300       sample=gain;
301     } else {
302       gain=128;
303       NR52&=0xFE;
304     }
305   }
306 #endif
307 
308 #if 1
309   if (NR51&0x22) {
310     if (snd_init2) {
311       snd_init2=0;
312       snd_count2=frequency_div256;
313     }
314 
315     if ((snd_reload2>0)&&(snd_length2>0)) {
316       if (snd_count2--<=0) {
317 	snd_length2--;
318 	snd_count2=frequency_div256;
319       }
320 
321       snd_count2+=snd_reload2;
322       /*      if (snd_count2>=sound_frequency) snd_count2-=sound_frequency;
323 	      gain=pattern[NR21>>6][snd_count2];*/
324 
325       gain=((snd_count2&FIXPOINT_MASK)>FIXPOINT_HALF) ? 128-32 : 128+32;
326 
327       sample=mixsample(gain,sample);
328     } else {
329       gain=128;
330       NR52&=0xFD;
331     }
332   }
333 #endif
334 
335 #if 1
336   if (NR51&0x44 && NR30&0x80 && NR32&60) {
337     if (snd_init3) {
338       snd_init3=0;
339       snd_count3=frequency_div256;
340     }
341 
342     if ((snd_reload3>0)&&(snd_length3>0)) {
343       if (snd_count3--<=0) {
344 	snd_length3--;
345 	snd_count3=frequency_div256;
346       }
347 
348       snd_count3+=snd_reload3;
349       /*      if (snd_count3>=sound_frequency) snd_count3-=sound_frequency;*/
350 
351       pos=((snd_count3<<5)>>FIXPOINT_SHIFT)&0x1F;
352 
353       if (pos&1) gain=chn3_tab[(io[0x30+(pos>>1)]&0x0F)>>snd_shr];
354       else gain=chn3_tab[(io[0x30+(pos>>1)]>>4)>>snd_shr];
355 
356       sample=mixsample(gain,sample);
357     } else {
358       gain=128;
359       NR52&=0xFB;
360     }
361   }
362 #endif
363 
364 #if 1
365   if (NR51&0x88) {
366     if (snd_init4) {
367       snd_init4=0;
368       snd_count4=frequency_div256;
369     }
370 
371     if (snd_length4>0) {
372       /*      snd_reload4=0;*/
373       if (snd_count4--<=0) {
374 	snd_length4--;
375 	snd_count4=frequency_div256;
376       }
377       /*            printf("sound4 (i:%d,l:%d,c:%d)\n",snd_init4,snd_length4,snd_count4);*/
378 
379       if (snd4_rand>=SND4_RNDPATTERNLEN) snd4_rand=0;
380       gain=snd4_rndpattern[snd4_rand++];
381 
382       /*      snd4_rand=snd4_rand*0x111163+0x3211234;
383 	      gain=rand()>>24;*/
384 
385       /* printf("sample: %d\n",gain);*/
386 
387       sample=mixsample(gain,sample);
388     } else {
389       gain=128;
390       NR52&=0xF7;
391     }
392   }
393 #endif
394 
395      if (producesound) outsample(sample);
396      else outsample(128);
397      /*  }*/
398 }
399 
gbfreq(unsigned short int value)400 int gbfreq(unsigned short int value)
401 {
402   /*int freq;*/
403 
404   /* printf("%09f\n",(float)((131072<<13)/((2048L-value)<<13))); */
405 
406   return value>0 ? ((((131072<<13)/(2048L-value))<<3)/sound_frequency) : 0;
407 
408   /*  freq=value>0 ?  131072/(2048-value) : 0;
409   if (freq>=sound_frequency/2) freq=0;
410   return freq;*/
411 }
412 
413 #endif
414