2 // Sound Interface v2.0
5 // (c) 2006 Underground Software
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 06/15/2006 Added changelog ;-)
12 // JLH 06/15/2006 Scrubbed all BYTE, WORD & DWORD references from the code
13 // JLH 02/10/2009 Fixed sound IRQ callback so that CPU samples are taken at
14 // cycle exact boundaries
15 // JLH 07/21/2009 Moved numeric constants into macros for sanity's sake
18 // The sound CPU (6808) runs at 894,750 (3,579,000 / 4) Hz.
19 // At 44.1 KHz, this works out to 894750 / 44100 = 20.289115646... cycles per sample.
22 // Still need to add volume control...
32 //using namespace std;
34 //#define AUDIO_SAMPLE_RATE 44100.0
35 #define AUDIO_SAMPLE_RATE 48000.0
36 #define CYCLES_TO_EXECUTE (M6808_CLOCK_SPEED_IN_HZ / AUDIO_SAMPLE_RATE)
40 static SDL_AudioSpec desired;
41 static bool soundInitialized = false;
42 static uint32_t cyclesToExecuteWholePart;
43 static double cyclesToExecuteFractionalPart;
45 // Private function prototypes
47 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
51 // Initialize the SDL sound system
55 // memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
57 desired.freq = AUDIO_SAMPLE_RATE; // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
58 desired.format = AUDIO_U8; // This uses the native endian (for portability)...
60 // desired.samples = 4096; // Let's try a 4K buffer (can always go lower)
61 desired.samples = 2048; // Let's try a 2K buffer (can always go lower)
62 desired.callback = SDLSoundCallback;
64 if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
66 WriteLog("Sound: Failed to initialize SDL sound.\n");
70 // Setup clock cycles & etc.
71 cyclesToExecuteWholePart = (uint32_t)CYCLES_TO_EXECUTE;
72 cyclesToExecuteFractionalPart = CYCLES_TO_EXECUTE - (double)cyclesToExecuteWholePart;
74 printf("Cycles to execute: %lf; cycles W: %u; cycles F: %lf\n", CYCLES_TO_EXECUTE, cyclesToExecuteWholePart, cyclesToExecuteFractionalPart);
77 SDL_PauseAudio(false); // Start playback!
78 soundInitialized = true;
79 WriteLog("Sound: Successfully initialized.\n");
84 // Close down the SDL sound subsystem
92 WriteLog("Sound: Done.\n");
98 // Sound card callback handler
100 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
102 extern V6808REGS soundCPU;
103 extern uint8_t sram[];
106 static float overflow = 0.0;
107 static uint32_t time = cyclesToExecuteWholePart;
109 while (cnt != length)
111 Execute6808(&soundCPU, time);
112 soundCPU.clock -= time;
113 buffer[cnt++] = sram[0x0400]; // Fill the buffer with the PIA output value
114 time = cyclesToExecuteWholePart;
115 overflow += cyclesToExecuteFractionalPart;