]> Shamusworld >> Repos - thunder/blob - src/sound.cpp
Added DIP switch fungibility, misc. code cleanups.
[thunder] / src / sound.cpp
1 //
2 // Sound Handler
3 //
4 // by James Hammons
5 // (C) 2014 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // Who  When        What
10 // ---  ----------  -----------------------------------------------------------
11 // JLH  04/18/2014  Created this file
12 //
13
14 #include "sound.h"
15 #include <SDL2/SDL.h>
16 #include "psg.h"
17 #include "resource.h"
18 #include "ym2151.h"
19
20
21 #define SAMPLE_RATE 48000
22
23 // Function prototypes
24 void SoundFunc(void *, Uint8 *, int);
25
26 // Vars
27 extern uint8_t voice_rom[];                     // PCM data pointer
28
29 static bool soundInitialized = false;
30 const float sampleBase = (float)SAMPLE_RATE/6000.0;  // Voice is between 5512.5 and 6000 Hz
31 bool snd_go = false;
32 bool chan1_go = false, chan2_go = false;//, chan3_go = false;
33 bool /*chan4_go = false, chan5_go = false,*/ chan6_go = false;
34 uint8_t * sndp1, * sndp2, /* sndp3, * sndp4, * sndp5,*/ * sndp6;
35 uint32_t rom_pos, end_pos;
36 uint32_t spos1, end_pos1;
37 uint32_t spos2, end_pos2;
38 //uint32_t spos3, end_pos3;
39 //uint32_t spos4, end_pos4;
40 //uint32_t spos5, end_pos5;
41 uint32_t spos6, end_pos6;
42 float sample1;
43 int16_t prevSamp1;
44 //int8_t delta_x1;
45 float sample2;
46 int16_t prevSamp2;
47 //int8_t delta_x2;
48 uint16_t snd_num;
49 uint8_t * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H
50 uint32_t snd_lens[3]   = { sunknownlen, scyalen, scameralen };
51
52
53 void InitSound(void)
54 {
55         // params 1, 4 & 5 are useless
56 //      if (YMInit(1, 3579580, 22050, 16, 512))//, (SAMPLE **)sbp))
57         if (YMInit(1, 3579580, SAMPLE_RATE, 16, 512))
58         {
59                 printf("SOUND: Could not init YM2151 emulator!\n");
60                 return;// -1;
61         }
62
63         InitPSG(SAMPLE_RATE);
64
65         SDL_AudioSpec desired, obtained;
66         desired.freq = SAMPLE_RATE;
67         desired.format = AUDIO_S16;
68         desired.channels = 1;
69         desired.samples = 1024;
70         desired.callback = SoundFunc;
71         desired.userdata = NULL;
72         // Also, should check to see if it got the hardware it needed, correct sample size, etc.
73         if (SDL_OpenAudio(&desired, &obtained) < 0)
74         {
75                 soundInitialized = false;
76                 printf("SOUND: Couldn't open audio: %s\n", SDL_GetError());
77                 return;
78         }
79
80         // Get that audio going!
81         SDL_PauseAudio(0);
82         soundInitialized = true;
83 }
84
85
86 void SpawnSound(int type, int snd, int channel/* = 0*/)
87 {
88         extern uint32_t psg_lens[16];
89         extern uint8_t * psg_adrs[16];
90 //      extern uint32_t voc_lens[32];
91 //      extern uint8_t * voc_adrs[32];
92 //      extern uint32_t fm_lens[14];
93 //      extern uint8_t * fm_adrs[14];
94
95         if (!soundInitialized)
96                 return;
97
98         snd_num = snd;
99 //      SpawnMsg(MSHOWNUMS);
100
101         // Voice type sounds...
102         if (type == GAMESOUND)
103         {
104                 // Will that do it???  Yes!!!
105                 snd--;
106
107                 if (channel == 0)
108                 {
109                         // 00 nn ss (nn # of repeats of sample ss)
110                         uint32_t st = 0;
111
112                         if (snd & 0x40)
113                         {
114                                 st = 0x10000;
115                                 snd &= 0x0F;
116                         }
117
118                         spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
119                         spos1 += st;                                                            // Need to add start somewhere...
120                         prevSamp1 = 128;
121                         sample1 = 0;
122                         chan1_go = true;
123                 }
124                 else
125                 {
126                         uint32_t st = 0;
127
128                         if (snd & 0x40)
129                         {
130                                 st = 0x10000;
131                                 snd &= 0x0F;
132                         }
133
134                         spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
135                         spos2 += st;                                                            // Need to add start somewhere...
136                         prevSamp2 = 128;
137                         sample2 = 0;
138                         chan2_go = true;
139                 }
140         }
141 #if 0
142         else if (type == PSGSOUND)
143         {
144                 if (snd_num & 0x10)                                                             // Second channel?
145                 {
146                         spos3 = 0;
147                         end_pos3 = psg_lens[snd_num & 0x0F];
148                         sndp3 = psg_adrs[snd_num & 0x0F];
149                         chan3_go = true;
150
151                         if (spos3 == end_pos3)
152                                 chan3_go = false;                                               // No sound loaded, so don't do it!
153                 }
154                 else                                                                                    // First channel
155                 {
156                         spos4 = 0;
157                         end_pos4 = psg_lens[snd_num & 0x0F];
158                         sndp4 = psg_adrs[snd_num & 0x0F];
159                         chan4_go = true;
160
161                         if (spos4 == end_pos4)
162                                 chan4_go = false;                                               // No sound loaded, so don't do it!
163                 }
164         }
165 #endif
166 #if 0
167         else if (type == FMSOUND)
168         {
169                 spos5 = 0;
170                 end_pos5 = fm_lens[snd_num];
171                 sndp5 = fm_adrs[snd_num];
172                 chan5_go = true;
173
174                 if (spos5 == end_pos5)
175                         chan5_go = false;                                                       // No sound loaded, so don't do it!
176         }
177 #endif
178         else if (type == USERSOUND)
179         {
180                 spos6 = 0;
181                 end_pos6 = snd_lens[snd_num];                                   // User sound
182                 sndp6 = snd_array[snd_num];                                             // Load pointer
183                 chan6_go = true;
184         }
185 }
186
187
188 void SoundFunc(void * userdata, Uint8 * buffer, int num)
189 {
190         static bool psg1go = false, psg2go = false;
191         // Length / 2 is because it's set up for 16-bit samples
192 //      YM2151UpdateOne(buffer, length / 2);
193         // Have to go into ym2151.cpp and change this manually back to 8 bit
194         YM2151UpdateOne(buffer, num / 2);
195 //      return;
196         UpdatePSG(buffer, num / 2);
197
198         // 0-22 different sounds...
199         uint16_t cnt = 0;//, sample;
200         uint8_t start_samp1, end_samp1, start_samp2, end_samp2;
201         int16_t samp1 = 0, samp2 = 0, samp6 = 0;                        // Zero samples...
202
203         if (!(chan1_go || chan2_go /*|| chan3_go || chan4_go || chan5_go*/ || chan6_go))
204                 return;
205
206         while (cnt != (num / 2))
207         {
208                 if (chan1_go)
209                 {
210                         if (sample1 < 1)
211                         {
212                                 uint8_t voiceSample = voice_rom[spos1++];
213                                 samp1 = ((int16_t)voiceSample - 128) * 160;
214
215                                 // Kill channel 1 if done...
216                                 if (voiceSample == 0xFF)
217                                 {
218                                         chan1_go = false;
219                                         samp1 = 0;
220                                 }
221                                 // RLE compression...
222                                 else if (voiceSample == 0x00)
223                                 {
224                                         // # of repeats
225                                         sample1 += (float)voice_rom[spos1++] * sampleBase;
226                                         // Get last good sample
227                                         samp1   = prevSamp1;
228                                 }
229                                 else
230                                         // Keep fractional part intact
231                                         sample1 += sampleBase;
232                         }
233
234                         prevSamp1 = samp1;              // Save last sample value
235                         sample1 -= 1.0;                 // Decrement repeat counter
236                 }
237
238 // Stretching 5KHz samples to 22KHz:
239 //   numRepeats = 4;
240 //            6KHz -> 22KHz:  22/6 repeats...
241                 if (chan2_go)
242                 {
243                         if (sample2 < 1)
244                         {
245                                 uint8_t voiceSample = voice_rom[spos2++];
246                                 samp2 = ((int16_t)voiceSample - 128) * 160;
247 //                              samp2 = voice_rom[spos2++];
248
249                                 if (voiceSample == 0xFF)
250                                 {
251                                         chan2_go = false;
252                                         samp2 = 128;                                    // Kill channel 2 if done...
253                                 }
254                                 else if (voiceSample == 0x00)                           // RLE compression...
255                                 {
256                                         sample2 += (float)voice_rom[spos2++] * sampleBase;      // # of repeats
257                                         samp2   = prevSamp2;
258                                 }
259                                 else
260                                         sample2 += sampleBase;
261                         }
262
263 // Delta-X values were making the samples sound like crap...
264 //                              start_samp2 += delta_x2;
265                         prevSamp2 = samp2;
266                         sample2 -= 1.0;
267                 }
268
269 #if 0
270                 if (chan3_go)
271                 {
272                         samp3 = ((psg1go ? sndp3[spos3++] : sndp3[spos3]) - 128) * 160;
273                         psg1go = !psg1go;
274
275                         if (spos3 == end_pos3)
276                         {
277                                 chan3_go = false;
278                                 samp3 = 0; // Kill channel 3 if done...
279                         }
280                 }
281
282                 if (chan4_go)
283                 {
284                         samp4 = ((psg2go ? sndp4[spos4++] : sndp4[spos4]) - 128) * 160;
285                         psg2go = !psg2go;
286
287                         if (spos4 == end_pos4)
288                         {
289                                 chan4_go = false;
290                                 samp4 = 0; // Kill channel 4 if done...
291                         }
292                 }
293
294                 if (chan5_go)
295                 {
296                         samp5 = sndp5[spos5++];
297
298                         if (spos5 == end_pos5)
299                         {
300                                 chan5_go = false;
301                                 samp5 = 128; // Kill channel 5 if done...
302                         }
303                 }
304 #endif
305                 if (chan6_go)
306                 {
307                         samp6 = sndp6[spos6++];
308
309                         if (spos6 == end_pos6)
310                         {
311                                 chan6_go = false;
312                                 samp6 = 0;              // Kill channel 6...
313                         }
314                 }
315
316                 // Mix 'em...
317 //              sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640;
318                 int32_t sample = samp1 + samp2 + samp6;
319                 sample += ((int16_t *)buffer)[cnt];
320
321                 // If it overflowed, clip it
322 //              if (sample & 0xFFFF0000)
323 //                      sample = (sample & 0x8000 ? 0x00 : 0xFF);
324 //                      sample = (sample & 0x80000000 ? 0x0000 : 0xFFFF);
325                 if (sample > 32767)
326                         sample = 32767;
327                 else if (sample < -32767)
328                         sample = -32767;
329
330                 ((int16_t *)buffer)[cnt++] = (int16_t)sample;
331         }
332 }
333