//
// Sound Interface v2.0
//
-// by James L. Hammons
+// by James Hammons
// (c) 2006 Underground Software
//
-// JLH = James L. Hammons <jlhamm@acm.org>
+// JLH = James Hammons <jlhamm@acm.org>
//
// WHO WHEN WHAT
// --- ---------- ------------------------------------------------------------
// JLH 06/15/2006 Added changelog ;-)
// JLH 06/15/2006 Scrubbed all BYTE, WORD & DWORD references from the code
+// JLH 02/10/2009 Fixed sound IRQ callback so that CPU samples are taken at
+// cycle exact boundaries
+// JLH 07/21/2009 Moved numeric constants into macros for sanity's sake
//
// Notes:
// The sound CPU (6808) runs at 894,750 (3,579,000 / 4) Hz.
-// At 44.1 KHz, this works out to 894750 / 44100 = 20.289115646... cycles per sample.
+// At 44.1 KHz, this works out to 894750 / 44100 = 20.289115646... cycles per
+// sample.
//
// Still need to add volume control...
#include "sound.h"
-#include "SDL.h"
-#include "types.h"
+#include <SDL2/SDL.h>
+#include <stdint.h>
#include "log.h"
#include "v6808.h"
+#include "timing.h"
//using namespace std;
+#define AUDIO_SAMPLE_RATE 48000.0
+#define CYCLES_TO_EXECUTE (M6808_CLOCK_SPEED_IN_HZ / AUDIO_SAMPLE_RATE)
+
// Local variables
-SDL_AudioSpec desired;
-bool soundInitialized = false;
+static SDL_AudioSpec desired;
+static bool soundInitialized = false;
+static uint32_t cyclesToExecuteWholePart;
+static double cyclesToExecuteFractionalPart;
// Private function prototypes
//
void SoundInit(void)
{
-// memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
-
- desired.freq = 44100; // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
- desired.format = AUDIO_U8; // This uses the native endian (for portability)...
+ desired.freq = AUDIO_SAMPLE_RATE; // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
+ desired.format = AUDIO_U8; // This uses the native endian (for portability)...
desired.channels = 1;
-// desired.samples = 4096; // Let's try a 4K buffer (can always go lower)
- desired.samples = 2048; // Let's try a 2K buffer (can always go lower)
+ desired.samples = 2048; // Let's try a 2K buffer (can always go lower)
desired.callback = SDLSoundCallback;
- if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
+ if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
{
WriteLog("Sound: Failed to initialize SDL sound.\n");
-// exit(1);
return;
}
+ // Setup clock cycles & etc.
+ cyclesToExecuteWholePart = (uint32_t)CYCLES_TO_EXECUTE;
+ cyclesToExecuteFractionalPart = CYCLES_TO_EXECUTE - (double)cyclesToExecuteWholePart;
+
SDL_PauseAudio(false); // Start playback!
soundInitialized = true;
WriteLog("Sound: Successfully initialized.\n");
void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
{
extern V6808REGS soundCPU;
- extern uint8 * sram;
+ extern uint8_t sram[];
int cnt = 0;
+ static float overflow = 0.0;
+ static uint32_t time = cyclesToExecuteWholePart;
+
while (cnt != length)
{
- // This is close, but not cycle exact (exact would be 20.289115646...)
-
-//Need to figure out how to get that fraction to execute... !!! FIX !!!
- Execute6808(&soundCPU, 20);
- soundCPU.clock -= 20;
- buffer[cnt++] = sram[0x0400]; // Fill the buffer with the PIA output value
+ Execute6808(&soundCPU, time);
+ soundCPU.clock -= time;
+// buffer[cnt++] = sram[0x0400]; // Fill the buffer with the PIA output value
+ // Do some simple volume control...
+ buffer[cnt++] = sram[0x0400] / 4; // Fill the buffer with the PIA output value
+ time = cyclesToExecuteWholePart;
+ overflow += cyclesToExecuteFractionalPart;
+
+ if (overflow > 1.0)
+ {
+ overflow -= 1.0;
+ time++;
+ }
}
}