5 // (C) 2014 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- -----------------------------------------------------------
11 // JLH 04/18/2014 Created this file
20 #define SAMPLE_RATE 48000
21 #define BUFFER_SIZE 512
23 // Function prototypes
24 void SoundFunc(void *, Uint8 *, int);
27 extern uint8_t voice_rom[]; // PCM data pointer
29 static bool soundInitialized = false;
30 const float sampleBase = (float)SAMPLE_RATE / 6000.0; // Voice is between 5512.5 and 6000 Hz
31 bool chan1_go = false, chan2_go = false;
32 bool chan6_go = false;
33 uint8_t * sndp1, * sndp2, * sndp6;
34 uint32_t spos1, end_pos1;
35 uint32_t spos2, end_pos2;
36 uint32_t spos6, end_pos6;
37 float sample1, sample2;
38 int16_t prevSamp1, prevSamp2;
41 uint8_t * snd_array[3] = { sunknown, scya, scamera };
42 uint32_t snd_lens[3] = { sunknownlen, scyalen, scameralen };
46 if (YMInit(3579580, SAMPLE_RATE))
48 printf("SOUND: Could not init YM2151 emulator!\n");
54 SDL_AudioSpec desired, obtained;
55 desired.freq = SAMPLE_RATE;
56 desired.format = AUDIO_S16;
58 desired.samples = BUFFER_SIZE * 2; // Size is in BYTES, so x2
59 desired.callback = SoundFunc;
60 desired.userdata = NULL;
62 // Also, should check to see if it got the hardware it needed, correct sample size, etc. (actually, SDL guarantees we get what we asked for--I think)
63 if (SDL_OpenAudio(&desired, &obtained) < 0)
65 soundInitialized = false;
66 printf("SOUND: Couldn't open audio: %s\n", SDL_GetError());
70 // Get that audio going!
72 soundInitialized = true;
75 void SpawnSound(int type, int snd, int channel/* = 0*/)
77 if (!soundInitialized)
82 // Voice type sounds...
83 if (type == GAMESOUND)
85 // Will that do it??? Yes!!!
90 // 00 nn ss (nn # of repeats of sample ss)
99 spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
100 spos1 += st; // Need to add start somewhere...
115 spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
116 spos2 += st; // Need to add start somewhere...
122 else if (type == USERSOUND)
125 end_pos6 = snd_lens[snd_num]; // User sound
126 sndp6 = snd_array[snd_num]; // Load pointer
131 void SoundFunc(void * userdata, Uint8 * buffer, int num)
133 // We do num / 2 because num is in BYTES, and the buffer uses signed WORDs.
134 YM2151UpdateOne(buffer, num / 2);
135 UpdatePSG(buffer, num / 2);
137 // 0-22 different sounds...
139 uint8_t start_samp1, end_samp1, start_samp2, end_samp2;
140 int16_t samp1 = 0, samp2 = 0, samp6 = 0; // Zero samples...
142 if (!(chan1_go || chan2_go || chan6_go))
145 while (cnt != (num / 2))
151 uint8_t voiceSample = voice_rom[spos1++];
152 samp1 = ((int16_t)voiceSample - 128) * 160;
154 // Kill channel 1 if done...
155 if (voiceSample == 0xFF)
160 // RLE compression...
161 else if (voiceSample == 0x00)
164 sample1 += (float)voice_rom[spos1++] * sampleBase;
165 // Get last good sample
169 // Keep fractional part intact
170 sample1 += sampleBase;
173 prevSamp1 = samp1; // Save last sample value
174 sample1 -= 1.0; // Decrement repeat counter
177 // Stretching 5KHz samples to 22KHz:
179 // 6KHz -> 22KHz: 22/6 repeats...
184 uint8_t voiceSample = voice_rom[spos2++];
185 samp2 = ((int16_t)voiceSample - 128) * 160;
187 if (voiceSample == 0xFF)
190 samp2 = 128; // Kill channel 2 if done...
192 else if (voiceSample == 0x00) // RLE compression...
194 sample2 += (float)voice_rom[spos2++] * sampleBase; // # of repeats
198 sample2 += sampleBase;
201 // Delta-X values were making the samples sound like crap...
202 // start_samp2 += delta_x2;
209 samp6 = sndp6[spos6++];
211 if (spos6 == end_pos6)
214 samp6 = 0; // Kill channel 6...
219 int32_t sample = samp1 + samp2 + samp6;
220 sample += ((int16_t *)buffer)[cnt];
222 // If it overflowed, clip it
225 else if (sample < -32767)
228 ((int16_t *)buffer)[cnt++] = (int16_t)sample;