--- /dev/null
+//
+// Sound Handler
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who When What
+// --- ---------- -----------------------------------------------------------
+// JLH 04/18/2014 Created this file
+//
+
+#include "sound.h"
+#include <SDL2/SDL.h>
+#include "resource.h"
+
+// Function prototypes
+void SoundFunc(void *, Uint8 *, int);
+
+// Vars
+extern uint8_t voice_rom[]; // PCM data pointer
+
+static bool soundInitialized = false;
+const float sampleBase = 22050.0/6000.0; // Btwn 5512.5 and 6000
+bool snd_go = false;
+bool chan1_go = false, chan2_go = false, chan3_go = false;
+bool chan4_go = false, chan5_go = false, chan6_go = false;
+uint8_t * sndp1, * sndp2, * sndp3, * sndp4, * sndp5, * sndp6;
+uint32_t rom_pos, end_pos;
+uint32_t spos1, end_pos1;
+uint32_t spos2, end_pos2;
+uint32_t spos3, end_pos3;
+uint32_t spos4, end_pos4;
+uint32_t spos5, end_pos5;
+uint32_t spos6, end_pos6;
+float sample1;
+uint8_t prevSamp1;
+int8_t delta_x1;
+float sample2;
+uint8_t prevSamp2;
+int8_t delta_x2;
+uint16_t snd_num;
+uint8_t * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H
+uint32_t snd_lens[3] = { sunknownlen, scyalen, scameralen };
+
+
+void InitSound(void)
+{
+ SDL_AudioSpec desired, obtained;
+ desired.freq = 22050;
+ desired.format = AUDIO_U8;
+ desired.channels = 1;
+ desired.samples = 1024;
+ desired.callback = SoundFunc;
+ desired.userdata = NULL;
+ // Also, should check to see if it got the hardware it needed, correct sample size, etc.
+ if (SDL_OpenAudio(&desired, &obtained) < 0)
+ {
+ soundInitialized = false;
+ printf("Couldn't open audio: %s\n", SDL_GetError());
+ return;
+ }
+
+ // Get that audio going!
+ SDL_PauseAudio(0);
+ soundInitialized = true;
+}
+
+
+void SpawnSound(int type, int snd, int channel/* = 0*/)
+{
+ extern uint32_t psg_lens[16];
+ extern uint8_t * psg_adrs[16];
+ extern uint32_t voc_lens[32];
+ extern uint8_t * voc_adrs[32];
+ extern uint32_t fm_lens[14];
+ extern uint8_t * fm_adrs[14];
+
+ if (!soundInitialized)
+ return;
+
+ snd_num = snd;
+// SpawnMsg(MSHOWNUMS);
+
+ if (type == GAMESOUND)
+ {
+ // Will that do it??? Yes!!!
+ snd--;
+
+ if (channel == 0)
+ {
+ // 00 nn ss (nn # of repeats of sample ss)
+ uint32_t st = 0;
+
+ if (snd & 0x40)
+ {
+ st = 0x10000;
+ snd &= 0x0F;
+ }
+
+ spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
+ spos1 += st; // Need to add start somewhere...
+ prevSamp1 = 128;
+ sample1 = 0;
+ chan1_go = true;
+ }
+ else
+ {
+ uint32_t st = 0;
+
+ if (snd & 0x40)
+ {
+ st = 0x10000;
+ snd &= 0x0F;
+ }
+
+ spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
+ spos2 += st; // Need to add start somewhere...
+ prevSamp2 = 128;
+ sample2 = 0;
+ chan2_go = true;
+ }
+ }
+ else if (type == PSGSOUND)
+ {
+ if (snd_num & 0x10) // Second channel?
+ {
+ spos3 = 0;
+ end_pos3 = psg_lens[snd_num & 0x0F];
+ sndp3 = psg_adrs[snd_num & 0x0F];
+ chan3_go = true;
+
+ if (spos3 == end_pos3)
+ chan3_go = false; // No sound loaded, so don't do it!
+ }
+ else // First channel
+ {
+ spos4 = 0;
+ end_pos4 = psg_lens[snd_num & 0x0F];
+ sndp4 = psg_adrs[snd_num & 0x0F];
+ chan4_go = true;
+
+ if (spos4 == end_pos4)
+ chan4_go = false; // No sound loaded, so don't do it!
+ }
+ }
+ else if (type == FMSOUND)
+ {
+ spos5 = 0;
+ end_pos5 = fm_lens[snd_num];
+ sndp5 = fm_adrs[snd_num];
+ chan5_go = true;
+
+ if (spos5 == end_pos5)
+ chan5_go = false; // No sound loaded, so don't do it!
+ }
+ else if (type == USERSOUND)
+ {
+ spos6 = 0;
+ end_pos6 = snd_lens[snd_num]; // User sound
+ sndp6 = snd_array[snd_num]; // Load pointer
+ chan6_go = true;
+ }
+}
+
+
+void SoundFunc(void * userdata, Uint8 * buff, int num)
+{
+ // 0-22 different sounds...
+ uint16_t cnt = 0, sample;
+ uint8_t start_samp1, end_samp1, start_samp2, end_samp2;
+ uint8_t samp1 = 128, samp2 = 128, samp3 = 128,
+ samp4 = 128, samp5 = 128, samp6 = 128; // Zero samples...
+
+ // Kill sound...
+ memset(buff, 128, num);
+
+ if (chan1_go || chan2_go || chan3_go || chan4_go || chan5_go || chan6_go)
+ {
+ while (cnt != num)
+ {
+ if (chan1_go)
+ {
+ if (sample1 < 1)
+ {
+ samp1 = voice_rom[spos1++];
+
+ // Kill channel 1 if done...
+ if (samp1 == 0xFF)
+ {
+ chan1_go = false;
+ samp1 = 128;
+ }
+ // RLE compression...
+ else if (samp1 == 0x00)
+ {
+ // # of repeats
+ sample1 += (float)voice_rom[spos1++] * sampleBase;
+ // Get last good sample
+ samp1 = prevSamp1;
+ }
+ else
+ // Keep fractional part intact
+ sample1 += sampleBase;
+ }
+
+ prevSamp1 = samp1; // Save last sample value
+ sample1 -= 1.0; // Decrement repeat counter
+ }
+
+// Stretching 5KHz samples to 22KHz:
+// numRepeats = 4;
+// 6KHz -> 22KHz: 22/6 repeats...
+ if (chan2_go)
+ {
+ if (sample2 < 1)
+ {
+ samp2 = voice_rom[spos2++];
+
+ if (samp2 == 0xFF)
+ {
+ chan2_go = false;
+ samp2 = 128; // Kill channel 2 if done...
+ }
+ else if (samp2 == 0x00) // RLE compression...
+ {
+ sample2 += (float)voice_rom[spos2++] * sampleBase; // # of repeats
+ samp2 = prevSamp2;
+ }
+ else
+ sample2 += sampleBase;
+ }
+
+// Delta-X values were making the samples sound like crap...
+// start_samp2 += delta_x2;
+ prevSamp2 = samp2;
+ sample2 -= 1.0;
+ }
+
+ if (chan3_go)
+ {
+ samp3 = sndp3[spos3++];
+
+ if (spos3 == end_pos3)
+ {
+ chan3_go = false;
+ samp3 = 128; // Kill channel 3 if done...
+ }
+ }
+
+ if (chan4_go)
+ {
+ samp4 = sndp4[spos4++];
+
+ if (spos4 == end_pos4)
+ {
+ chan4_go = false;
+ samp4 = 128; // Kill channel 4 if done...
+ }
+ }
+
+ if (chan5_go)
+ {
+ samp5 = sndp5[spos5++];
+
+ if (spos5 == end_pos5)
+ {
+ chan5_go = false;
+ samp5 = 128; // Kill channel 5 if done...
+ }
+ }
+
+ if (chan6_go)
+ {
+ samp6 = sndp6[spos6++];
+
+ if (spos6 == end_pos6)
+ {
+ chan6_go = false;
+ samp6 = 128; // Kill channel 6...
+ }
+ }
+
+ // Mix 'em...
+ sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640;
+
+ // If it overflowed, clip it
+ if (sample & 0xFF00)
+ sample = (sample & 0x8000 ? 0x00 : 0xFF);
+
+ buff[cnt++] = sample;
+ }
+ }
+}
+