]> Shamusworld >> Repos - thunder/blob - src/sound.cpp
e366830664797c133f64079200cbd2c9ae5b41d4
[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
73         // Also, should check to see if it got the hardware it needed, correct sample size, etc.
74         if (SDL_OpenAudio(&desired, &obtained) < 0)
75         {
76                 soundInitialized = false;
77                 printf("SOUND: Couldn't open audio: %s\n", SDL_GetError());
78                 return;
79         }
80
81         // Get that audio going!
82         SDL_PauseAudio(0);
83         soundInitialized = true;
84 }
85
86
87 void SpawnSound(int type, int snd, int channel/* = 0*/)
88 {
89 //      extern uint32_t psg_lens[16];
90 //      extern uint8_t * psg_adrs[16];
91 //      extern uint32_t voc_lens[32];
92 //      extern uint8_t * voc_adrs[32];
93 //      extern uint32_t fm_lens[14];
94 //      extern uint8_t * fm_adrs[14];
95
96         if (!soundInitialized)
97                 return;
98
99         snd_num = snd;
100 //      SpawnMsg(MSHOWNUMS);
101
102         // Voice type sounds...
103         if (type == GAMESOUND)
104         {
105                 // Will that do it???  Yes!!!
106                 snd--;
107
108                 if (channel == 0)
109                 {
110                         // 00 nn ss (nn # of repeats of sample ss)
111                         uint32_t st = 0;
112
113                         if (snd & 0x40)
114                         {
115                                 st = 0x10000;
116                                 snd &= 0x0F;
117                         }
118
119                         spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
120                         spos1 += st;                                                            // Need to add start somewhere...
121                         prevSamp1 = 128;
122                         sample1 = 0;
123                         chan1_go = true;
124                 }
125                 else
126                 {
127                         uint32_t st = 0;
128
129                         if (snd & 0x40)
130                         {
131                                 st = 0x10000;
132                                 snd &= 0x0F;
133                         }
134
135                         spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
136                         spos2 += st;                                                            // Need to add start somewhere...
137                         prevSamp2 = 128;
138                         sample2 = 0;
139                         chan2_go = true;
140                 }
141         }
142 #if 0
143         else if (type == PSGSOUND)
144         {
145                 if (snd_num & 0x10)                                                             // Second channel?
146                 {
147                         spos3 = 0;
148                         end_pos3 = psg_lens[snd_num & 0x0F];
149                         sndp3 = psg_adrs[snd_num & 0x0F];
150                         chan3_go = true;
151
152                         if (spos3 == end_pos3)
153                                 chan3_go = false;                                               // No sound loaded, so don't do it!
154                 }
155                 else                                                                                    // First channel
156                 {
157                         spos4 = 0;
158                         end_pos4 = psg_lens[snd_num & 0x0F];
159                         sndp4 = psg_adrs[snd_num & 0x0F];
160                         chan4_go = true;
161
162                         if (spos4 == end_pos4)
163                                 chan4_go = false;                                               // No sound loaded, so don't do it!
164                 }
165         }
166 #endif
167 #if 0
168         else if (type == FMSOUND)
169         {
170                 spos5 = 0;
171                 end_pos5 = fm_lens[snd_num];
172                 sndp5 = fm_adrs[snd_num];
173                 chan5_go = true;
174
175                 if (spos5 == end_pos5)
176                         chan5_go = false;                                                       // No sound loaded, so don't do it!
177         }
178 #endif
179         else if (type == USERSOUND)
180         {
181                 spos6 = 0;
182                 end_pos6 = snd_lens[snd_num];                                   // User sound
183                 sndp6 = snd_array[snd_num];                                             // Load pointer
184                 chan6_go = true;
185         }
186 }
187
188
189 void SoundFunc(void * userdata, Uint8 * buffer, int num)
190 {
191         static bool psg1go = false, psg2go = false;
192         // Length / 2 is because it's set up for 16-bit samples
193 //      YM2151UpdateOne(buffer, length / 2);
194         // Have to go into ym2151.cpp and change this manually back to 8 bit
195         YM2151UpdateOne(buffer, num / 2);
196 //      return;
197         UpdatePSG(buffer, num / 2);
198
199         // 0-22 different sounds...
200         uint16_t cnt = 0;//, sample;
201         uint8_t start_samp1, end_samp1, start_samp2, end_samp2;
202         int16_t samp1 = 0, samp2 = 0, samp6 = 0;                        // Zero samples...
203
204         if (!(chan1_go || chan2_go /*|| chan3_go || chan4_go || chan5_go*/ || chan6_go))
205                 return;
206
207         while (cnt != (num / 2))
208         {
209                 if (chan1_go)
210                 {
211                         if (sample1 < 1)
212                         {
213                                 uint8_t voiceSample = voice_rom[spos1++];
214                                 samp1 = ((int16_t)voiceSample - 128) * 160;
215
216                                 // Kill channel 1 if done...
217                                 if (voiceSample == 0xFF)
218                                 {
219                                         chan1_go = false;
220                                         samp1 = 0;
221                                 }
222                                 // RLE compression...
223                                 else if (voiceSample == 0x00)
224                                 {
225                                         // # of repeats
226                                         sample1 += (float)voice_rom[spos1++] * sampleBase;
227                                         // Get last good sample
228                                         samp1   = prevSamp1;
229                                 }
230                                 else
231                                         // Keep fractional part intact
232                                         sample1 += sampleBase;
233                         }
234
235                         prevSamp1 = samp1;              // Save last sample value
236                         sample1 -= 1.0;                 // Decrement repeat counter
237                 }
238
239 // Stretching 5KHz samples to 22KHz:
240 //   numRepeats = 4;
241 //            6KHz -> 22KHz:  22/6 repeats...
242                 if (chan2_go)
243                 {
244                         if (sample2 < 1)
245                         {
246                                 uint8_t voiceSample = voice_rom[spos2++];
247                                 samp2 = ((int16_t)voiceSample - 128) * 160;
248 //                              samp2 = voice_rom[spos2++];
249
250                                 if (voiceSample == 0xFF)
251                                 {
252                                         chan2_go = false;
253                                         samp2 = 128;                                    // Kill channel 2 if done...
254                                 }
255                                 else if (voiceSample == 0x00)                           // RLE compression...
256                                 {
257                                         sample2 += (float)voice_rom[spos2++] * sampleBase;      // # of repeats
258                                         samp2   = prevSamp2;
259                                 }
260                                 else
261                                         sample2 += sampleBase;
262                         }
263
264 // Delta-X values were making the samples sound like crap...
265 //                              start_samp2 += delta_x2;
266                         prevSamp2 = samp2;
267                         sample2 -= 1.0;
268                 }
269
270 #if 0
271                 if (chan3_go)
272                 {
273                         samp3 = ((psg1go ? sndp3[spos3++] : sndp3[spos3]) - 128) * 160;
274                         psg1go = !psg1go;
275
276                         if (spos3 == end_pos3)
277                         {
278                                 chan3_go = false;
279                                 samp3 = 0; // Kill channel 3 if done...
280                         }
281                 }
282
283                 if (chan4_go)
284                 {
285                         samp4 = ((psg2go ? sndp4[spos4++] : sndp4[spos4]) - 128) * 160;
286                         psg2go = !psg2go;
287
288                         if (spos4 == end_pos4)
289                         {
290                                 chan4_go = false;
291                                 samp4 = 0; // Kill channel 4 if done...
292                         }
293                 }
294
295                 if (chan5_go)
296                 {
297                         samp5 = sndp5[spos5++];
298
299                         if (spos5 == end_pos5)
300                         {
301                                 chan5_go = false;
302                                 samp5 = 128; // Kill channel 5 if done...
303                         }
304                 }
305 #endif
306                 if (chan6_go)
307                 {
308                         samp6 = sndp6[spos6++];
309
310                         if (spos6 == end_pos6)
311                         {
312                                 chan6_go = false;
313                                 samp6 = 0;              // Kill channel 6...
314                         }
315                 }
316
317                 // Mix 'em...
318 //              sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640;
319                 int32_t sample = samp1 + samp2 + samp6;
320                 sample += ((int16_t *)buffer)[cnt];
321
322                 // If it overflowed, clip it
323 //              if (sample & 0xFFFF0000)
324 //                      sample = (sample & 0x8000 ? 0x00 : 0xFF);
325 //                      sample = (sample & 0x80000000 ? 0x0000 : 0xFFFF);
326                 if (sample > 32767)
327                         sample = 32767;
328                 else if (sample < -32767)
329                         sample = -32767;
330
331                 ((int16_t *)buffer)[cnt++] = (int16_t)sample;
332         }
333 }
334