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