5 // (C) 2005 Underground Software
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 12/02/2005 Fixed a problem with sound callback thread signaling the
13 // JLH 12/03/2005 Fixed sound callback dropping samples when the sample buffer
14 // is shorter than the callback sample buffer
19 // - Figure out why it's losing samples (Bard's Tale) [DONE]
24 #include <string.h> // For memset, memcpy
35 static SDL_AudioSpec desired;
36 static bool soundInitialized = false;
37 static uint8 amplitude = 0x88; // $78 - $88 seems to be plenty loud!
38 //static uint8 lastValue;
40 static bool speakerState;
41 static uint8 soundBuffer[4096];
42 static uint32 soundBufferPos;
43 static uint32 sampleBase;
44 static SDL_cond * conditional = NULL;
45 static SDL_mutex * mutex = NULL;
47 // Private function prototypes
49 static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
52 // Initialize the SDL sound system
56 // To weed out problems for now...
61 desired.freq = 44100; // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
62 desired.format = AUDIO_U8; // This uses the native endian (for portability)...
64 // desired.samples = 4096; // Let's try a 4K buffer (can always go lower)
65 desired.samples = 2048; // Let's try a 2K buffer (can always go lower)
66 desired.callback = SDLSoundCallback;
68 if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
70 WriteLog("Sound: Failed to initialize SDL sound.\n");
75 conditional = SDL_CreateCond();
76 mutex = SDL_CreateMutex();
77 SDL_mutexP(mutex); // Must lock the mutex for the cond to work properly...
78 // lastValue = (speakerState ? amplitude : 0xFF - amplitude);
82 SDL_PauseAudio(false); // Start playback!
83 soundInitialized = true;
84 WriteLog("Sound: Successfully initialized.\n");
88 // Close down the SDL sound subsystem
96 SDL_DestroyCond(conditional);
97 SDL_DestroyMutex(mutex);
98 WriteLog("Sound: Done.\n");
103 // Sound card callback handler
105 static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
107 // The sound buffer should only starve when starting which will cause it to
108 // lag behind the emulation at most by around 1 frame...
110 if (soundBufferPos < (uint32)length) // The sound buffer is starved...
112 //printf("Sound buffer starved!\n");
114 for(uint32 i=0; i<soundBufferPos; i++)
115 buffer[i] = soundBuffer[i];
116 // Fill buffer with last value
117 uint8 lastValue = (speakerState ? amplitude : 0xFF - amplitude);
118 // uint8 lastValue = (speakerState ? amplitude : amplitude ^ 0xFF);
119 // memset(buffer, lastValue, length); // Fill buffer with last value
120 memset(buffer + soundBufferPos, lastValue, length - soundBufferPos);
121 soundBufferPos = 0; // Reset soundBufferPos to start of buffer...
122 sampleBase = 0; // & sampleBase...
123 //Ick. This should never happen!
124 SDL_CondSignal(conditional); // Wake up any threads waiting for the buffer to drain...
128 memcpy(buffer, soundBuffer, length); // Fill sound buffer with frame buffered sound
129 soundBufferPos -= length;
130 sampleBase -= length;
132 // if (soundBufferPos > 0)
133 // memcpy(soundBuffer, soundBuffer + length, soundBufferPos); // Move current buffer down to start
134 // memcpy(soundBuffer, soundBuffer + length, length);
135 // Move current buffer down to start
136 for(uint32 i=0; i<soundBufferPos; i++)
137 soundBuffer[i] = soundBuffer[length + i];
139 // lastValue = buffer[length - 1];
140 SDL_CondSignal(conditional); // Wake up any threads waiting for the buffer to drain...
143 // Need some interface functions here to take care of flipping the
144 // waveform at the correct time in the sound stream...
147 Maybe set up a buffer 1 frame long (44100 / 60 = 735 bytes per frame)
149 Hmm. That's smaller than the sound buffer 2048 bytes... (About 2.75 frames needed to fill)
151 So... I guess what we could do is this:
153 -- Execute V65C02 for one frame. The read/writes at I/O address $C030 fill up the buffer
154 to the current time position.
155 -- The sound callback function copies the pertinent area out of the buffer, resets
156 the time position back (or copies data down from what it took out)
159 void ToggleSpeaker(uint32 time)
161 if (!soundInitialized)
165 if (time > 95085)//(time & 0x80000000)
167 WriteLog("ToggleSpeaker() given bad time value: %08X (%u)!\n", time, time);
172 // 1.024 MHz / 60 = 17066.6... cycles (23.2199 cycles per sample)
173 // Need the last frame position in order to calculate correctly...
176 uint8 sample = (speakerState ? amplitude : 0xFF - amplitude);
177 // uint8 sample = (speakerState ? amplitude : amplitude ^ 0xFF);
178 uint32 currentPos = sampleBase + (uint32)((double)time / 23.2199);
180 if (currentPos > 4095)
183 WriteLog("ToggleSpeaker() about to go into spinlock at time: %08X (%u) (sampleBase=%u)!\n", time, time, sampleBase);
185 // Still hanging on this spinlock...
186 // That could be because the "time" value is too high and so the buffer will NEVER be
188 // Now that we're using a conditional, it seems to be working OK--though not perfectly...
190 ToggleSpeaker() about to go into spinlock at time: 00004011 (16401) (sampleBase=3504)!
191 16401 -> 706 samples, 3504 + 706 = 4210
193 And it still thrashed the sound even though it didn't run into a spinlock...
195 Seems like it's OK now that I've fixed the buffer-less-than-length bug...
198 SDL_CondWait(conditional, mutex);
200 // while (currentPos > 4095) // Spin until buffer empties a bit...
201 currentPos = sampleBase + (uint32)((double)time / 23.2199);
204 WriteLog("--> after spinlock (sampleBase=%u)...\n", sampleBase);
208 while (soundBufferPos < currentPos)
209 soundBuffer[soundBufferPos++] = sample;
211 speakerState = !speakerState;
215 void HandleSoundAtFrameEdge(void)
217 if (!soundInitialized)
223 /* uint8 sample = (speakerState ? amplitude : 0xFF - amplitude);
225 //This shouldn't happen (buffer overflow), but it seems like it *is* happening...
226 if (sampleBase >= 4096)
227 // sampleBase = 4095;
228 //Kludge, for now... Until I can figure out why it's still stomping on the buffer...
231 while (soundBufferPos < sampleBase)
232 soundBuffer[soundBufferPos++] = sample;//*/