mirror of https://github.com/JorjBauer/aiie.git
rebuilt SDL speaker driver
This commit is contained in:
parent
a93b14bc9c
commit
e15db839e3
|
@ -7,11 +7,15 @@ class PhysicalSpeaker {
|
||||||
public:
|
public:
|
||||||
virtual ~PhysicalSpeaker() {}
|
virtual ~PhysicalSpeaker() {}
|
||||||
|
|
||||||
|
virtual void begin() = 0;
|
||||||
|
|
||||||
virtual void toggle(uint32_t c) = 0;
|
virtual void toggle(uint32_t c) = 0;
|
||||||
virtual void maintainSpeaker(uint32_t c, uint64_t microseconds) = 0;
|
virtual void maintainSpeaker(uint32_t c, uint64_t microseconds) = 0;
|
||||||
virtual void beginMixing() = 0;
|
virtual void beginMixing() = 0;
|
||||||
virtual void mixOutput(uint8_t v) = 0;
|
virtual void mixOutput(uint8_t v) = 0;
|
||||||
|
|
||||||
|
virtual uint32_t bufferedContentSize() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
57
sdl/aiie.cpp
57
sdl/aiie.cpp
|
@ -27,7 +27,7 @@
|
||||||
BIOS bios;
|
BIOS bios;
|
||||||
Debugger debugger;
|
Debugger debugger;
|
||||||
|
|
||||||
static struct timespec nextInstructionTime, startTime;
|
struct timespec nextInstructionTime, startTime;
|
||||||
|
|
||||||
#define NB_ENABLE 1
|
#define NB_ENABLE 1
|
||||||
#define NB_DISABLE 0
|
#define NB_DISABLE 0
|
||||||
|
@ -91,8 +91,6 @@ void write(void *arg, uint16_t address, uint8_t v)
|
||||||
|
|
||||||
static void *cpu_thread(void *dummyptr) {
|
static void *cpu_thread(void *dummyptr) {
|
||||||
struct timespec currentTime;
|
struct timespec currentTime;
|
||||||
struct timespec nextSpeakerCycleTime;
|
|
||||||
uint32_t nextSpeakerCycle = 0;
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
int policy;
|
int policy;
|
||||||
|
@ -109,10 +107,9 @@ static void *cpu_thread(void *dummyptr) {
|
||||||
|
|
||||||
printf("free-running\n");
|
printf("free-running\n");
|
||||||
|
|
||||||
// In this loop, we determine when the next CPU or Speaker event is;
|
// In this loop, we determine when the next CPU event is; sleep until
|
||||||
// sleep until that event; and then perform the event. There are a
|
// that event; and then perform the event. There are also peripheral
|
||||||
// number of maintenance tasks that also happen to be sure that
|
// maintenance calls embedded in the loop...
|
||||||
// peripherals are updated appropriately.
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (g_biosInterrupt) {
|
if (g_biosInterrupt) {
|
||||||
|
@ -140,55 +137,24 @@ static void *cpu_thread(void *dummyptr) {
|
||||||
|
|
||||||
do_gettime(¤tTime);
|
do_gettime(¤tTime);
|
||||||
|
|
||||||
// FIXME: these first two can go in their respective loops after execution
|
|
||||||
|
|
||||||
// Determine the next speaker runtime (nextSpeakerCycle).
|
|
||||||
// The speaker runs 48 cycles behind the CPU (an arbitrary number).
|
|
||||||
timespec_add_cycles(&startTime, nextSpeakerCycle-48, &nextSpeakerCycleTime);
|
|
||||||
|
|
||||||
// Determine the next CPU runtime (nextInstructionTime)
|
// Determine the next CPU runtime (nextInstructionTime)
|
||||||
timespec_add_cycles(&startTime, g_cpu->cycles, &nextInstructionTime);
|
timespec_add_cycles(&startTime, g_cpu->cycles, &nextInstructionTime);
|
||||||
|
|
||||||
// Sleep until one of them is ready to run.
|
// Sleep until the CPU is ready to run.
|
||||||
|
|
||||||
// tsSubtract doesn't return negatives; it bounds at zero. So if
|
// tsSubtract doesn't return negatives; it bounds at zero. So if
|
||||||
// either result is zero then it's time to run something.
|
// either result is zero then it's time to run something.
|
||||||
|
|
||||||
struct timespec cpudiff = tsSubtract(nextInstructionTime, currentTime);
|
struct timespec cpudiff = tsSubtract(nextInstructionTime, currentTime);
|
||||||
struct timespec spkrdiff = tsSubtract(nextSpeakerCycleTime, currentTime);
|
|
||||||
|
|
||||||
struct timespec mindiff;
|
if (cpudiff.tv_sec > 0 || cpudiff.tv_nsec > 0) {
|
||||||
if (cpudiff.tv_sec < spkrdiff.tv_sec) {
|
// Sleep until the it's ready and loop...
|
||||||
memcpy(&mindiff, &cpudiff, sizeof(struct timespec));
|
nanosleep(&cpudiff, NULL);
|
||||||
} else if (spkrdiff.tv_sec < cpudiff.tv_sec) {
|
|
||||||
memcpy(&mindiff, &spkrdiff, sizeof(struct timespec));
|
|
||||||
} else if (cpudiff.tv_nsec < spkrdiff.tv_nsec) {
|
|
||||||
memcpy(&mindiff, &cpudiff, sizeof(struct timespec));
|
|
||||||
} else {
|
|
||||||
memcpy(&mindiff, &spkrdiff, sizeof(struct timespec));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mindiff.tv_sec > 0 || mindiff.tv_nsec > 0) {
|
|
||||||
// Sleep until the first of them is ready & loop...
|
|
||||||
nanosleep(&mindiff, NULL);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we know either the speaker or the CPU is ready to
|
|
||||||
// run. Figure out which and run it.
|
|
||||||
|
|
||||||
if (spkrdiff.tv_sec == 0 && spkrdiff.tv_nsec == 0) {
|
|
||||||
// Run the speaker
|
|
||||||
|
|
||||||
uint64_t microseconds = nextSpeakerCycleTime.tv_sec * 1000000 +
|
|
||||||
(double)nextSpeakerCycleTime.tv_nsec / 1000.0;
|
|
||||||
g_speaker->maintainSpeaker(nextSpeakerCycle-48, microseconds);
|
|
||||||
|
|
||||||
nextSpeakerCycle++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cpudiff.tv_sec == 0 && cpudiff.tv_nsec == 0) {
|
if (cpudiff.tv_sec == 0 && cpudiff.tv_nsec == 0) {
|
||||||
// Run the CPU
|
// Run the CPU; it's caught up to "real time"
|
||||||
|
|
||||||
uint8_t executed = 0;
|
uint8_t executed = 0;
|
||||||
if (debugger.active()) {
|
if (debugger.active()) {
|
||||||
|
@ -288,6 +254,8 @@ int main(int argc, char *argv[])
|
||||||
// pthread_setschedparam(cpuThreadID, SCHED_RR, PTHREAD_MAX_PRIORITY);
|
// pthread_setschedparam(cpuThreadID, SCHED_RR, PTHREAD_MAX_PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_speaker->begin();
|
||||||
|
|
||||||
uint32_t lastCycleCount = -1;
|
uint32_t lastCycleCount = -1;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
|
@ -311,8 +279,7 @@ int main(int argc, char *argv[])
|
||||||
do_gettime(&startTime);
|
do_gettime(&startTime);
|
||||||
do_gettime(&nextInstructionTime);
|
do_gettime(&nextInstructionTime);
|
||||||
|
|
||||||
// Drain the speaker queue (FIXME: a little hacky)
|
// FIXME: drain whatever's in the speaker queue
|
||||||
g_speaker->maintainSpeaker(-1, -1);
|
|
||||||
|
|
||||||
/* FIXME
|
/* FIXME
|
||||||
// Force the display to redraw
|
// Force the display to redraw
|
||||||
|
|
|
@ -12,26 +12,37 @@ extern "C"
|
||||||
|
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
|
|
||||||
|
// FIXME: 4096 is the right value here, I'm just debugging
|
||||||
|
#define SDLSIZE (4096)
|
||||||
|
|
||||||
// FIXME: Globals; ick.
|
// FIXME: Globals; ick.
|
||||||
static volatile uint32_t bufIdx = 0;
|
static volatile uint32_t bufIdx = 0;
|
||||||
static uint8_t soundBuf[44100]; // 1 second of audio
|
static uint8_t soundBuf[44100];
|
||||||
static pthread_mutex_t sndmutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
static pthread_mutex_t togmutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t togmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static struct timespec sdlEmptyTime, sdlStartTime;
|
||||||
|
extern struct timespec startTime; // defined in aiie (main)
|
||||||
|
|
||||||
static void audioCallback(void *unused, Uint8 *stream, int len)
|
static void audioCallback(void *unused, Uint8 *stream, int len)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&sndmutex);
|
pthread_mutex_lock(&togmutex);
|
||||||
|
|
||||||
if (g_biosInterrupt) {
|
if (g_biosInterrupt) {
|
||||||
// While the BIOS is running, we don't put samples in the audio
|
// While the BIOS is running, we don't put samples in the audio
|
||||||
// queue.
|
// queue.
|
||||||
memset(stream, 0x80, len);
|
memset(stream, 0x80, len);
|
||||||
pthread_mutex_unlock(&sndmutex);
|
pthread_mutex_unlock(&togmutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculate when the buffer will be empty again
|
||||||
|
do_gettime(&sdlEmptyTime);
|
||||||
|
timespec_add_us(&sdlEmptyTime, ((float)len * (float)1000000)/(float)44100, &sdlEmptyTime);
|
||||||
|
sdlEmptyTime = tsSubtract(sdlEmptyTime, sdlStartTime);
|
||||||
|
|
||||||
|
static uint8_t lastKnownSample = 0; // saved for when the apple is quiescent
|
||||||
|
|
||||||
if (bufIdx >= len) {
|
if (bufIdx >= len) {
|
||||||
memcpy(stream, soundBuf, len);
|
memcpy(stream, soundBuf, len);
|
||||||
|
lastKnownSample = stream[len-1];
|
||||||
|
|
||||||
if (bufIdx > len) {
|
if (bufIdx > len) {
|
||||||
// move the remaining data down
|
// move the remaining data down
|
||||||
|
@ -39,17 +50,20 @@ static void audioCallback(void *unused, Uint8 *stream, int len)
|
||||||
bufIdx -= len;
|
bufIdx -= len;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Audio underrun
|
if (bufIdx) {
|
||||||
static uint8_t occurrenceCount = 0;
|
// partial buffer exists
|
||||||
if (++occurrenceCount < 10) {
|
memcpy(stream, soundBuf, bufIdx);
|
||||||
printf("Audio underrun!\n");
|
|
||||||
if (occurrenceCount == 9) {
|
// and it's a partial underrun
|
||||||
printf(" (Suppressing further audio errors)\n");
|
memset(&stream[bufIdx], lastKnownSample, len-bufIdx);
|
||||||
}
|
bufIdx = 0;
|
||||||
|
} else {
|
||||||
|
// Total audio underrun. This is normal if nothing is toggling the
|
||||||
|
// speaker; we stay at the last known level.
|
||||||
|
memset(stream, lastKnownSample, len);
|
||||||
}
|
}
|
||||||
memset(stream, 0, len);
|
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&sndmutex);
|
pthread_mutex_unlock(&togmutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetDCFilter(); // FIXME: remove
|
void ResetDCFilter(); // FIXME: remove
|
||||||
|
@ -59,10 +73,7 @@ SDLSpeaker::SDLSpeaker()
|
||||||
toggleState = false;
|
toggleState = false;
|
||||||
mixerValue = 0x80;
|
mixerValue = 0x80;
|
||||||
|
|
||||||
toggleCount = toggleReadPtr = toggleWritePtr = 0;
|
|
||||||
|
|
||||||
pthread_mutex_init(&togmutex, NULL);
|
pthread_mutex_init(&togmutex, NULL);
|
||||||
pthread_mutex_init(&sndmutex, NULL);
|
|
||||||
|
|
||||||
_init_darwin_shim();
|
_init_darwin_shim();
|
||||||
|
|
||||||
|
@ -70,48 +81,112 @@ SDLSpeaker::SDLSpeaker()
|
||||||
|
|
||||||
lastCycleCount = 0;
|
lastCycleCount = 0;
|
||||||
lastSampleCount = 0;
|
lastSampleCount = 0;
|
||||||
|
|
||||||
SDL_AudioSpec audioDevice;
|
|
||||||
SDL_AudioSpec audioActual;
|
|
||||||
SDL_memset(&audioDevice, 0, sizeof(audioDevice));
|
|
||||||
audioDevice.freq = 44100;
|
|
||||||
audioDevice.format = AUDIO_U8;
|
|
||||||
audioDevice.channels = 1;
|
|
||||||
audioDevice.samples = 4096; // 4096 bytes @ 44100Hz is about 1/10th second out of sync - should be okay for this testing
|
|
||||||
audioDevice.callback = audioCallback;
|
|
||||||
audioDevice.userdata = NULL;
|
|
||||||
|
|
||||||
SDL_OpenAudio(&audioDevice, &audioActual); // FIXME retval
|
|
||||||
printf("Actual: freq %d channels %d samples %d\n",
|
|
||||||
audioActual.freq, audioActual.channels, audioActual.samples);
|
|
||||||
|
|
||||||
SDL_PauseAudio(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLSpeaker::~SDLSpeaker()
|
SDLSpeaker::~SDLSpeaker()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDLSpeaker::begin()
|
||||||
|
{
|
||||||
|
do_gettime(&sdlStartTime);
|
||||||
|
do_gettime(&sdlEmptyTime);
|
||||||
|
sdlEmptyTime = tsSubtract(sdlEmptyTime, sdlStartTime);
|
||||||
|
|
||||||
|
SDL_AudioSpec audioDevice;
|
||||||
|
SDL_AudioSpec audioActual;
|
||||||
|
SDL_memset(&audioDevice, 0, sizeof(audioDevice));
|
||||||
|
audioDevice.freq = 44100; // count of 8-bit samples
|
||||||
|
audioDevice.format = AUDIO_U8;
|
||||||
|
audioDevice.channels = 1;
|
||||||
|
audioDevice.samples = SDLSIZE; // SDLSIZE 8-bit samples @ 44100Hz: 4096 is about 1/10th second out of sync
|
||||||
|
audioDevice.callback = audioCallback;
|
||||||
|
audioDevice.userdata = NULL;
|
||||||
|
|
||||||
|
memset(&soundBuf[0], 0, SDLSIZE);
|
||||||
|
bufIdx = SDLSIZE/2;
|
||||||
|
|
||||||
|
SDL_OpenAudio(&audioDevice, &audioActual); // FIXME retval
|
||||||
|
printf("Actual: freq %d channels %d samples %d\n",
|
||||||
|
audioActual.freq, audioActual.channels, audioActual.samples);
|
||||||
|
SDL_PauseAudio(0);
|
||||||
|
}
|
||||||
|
|
||||||
void SDLSpeaker::toggle(uint32_t c)
|
void SDLSpeaker::toggle(uint32_t c)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&togmutex);
|
pthread_mutex_lock(&togmutex);
|
||||||
|
|
||||||
toggleTimes[toggleWritePtr] = c;
|
/* Figuring out what to do:
|
||||||
if (toggleCount < SPEAKERQUEUESIZE-1) {
|
*
|
||||||
toggleWritePtr++;
|
* The wallclock time we started the app is in startTime.
|
||||||
if (toggleWritePtr >= SPEAKERQUEUESIZE)
|
*
|
||||||
toggleWritePtr = 0;
|
* The wallclock time when the SDL audio buffer will be totally
|
||||||
toggleCount++;
|
* drained is in sdlEmptyTime. When that time comes, we want to have
|
||||||
} else {
|
* at least SDLSIZE samples in soundBuf[] - which is currently filled
|
||||||
printf("speaker overflow @ cycle %d\n", c);
|
* to bufIdx samples.
|
||||||
for (int i=0; i<SPEAKERQUEUESIZE; i++) {
|
*
|
||||||
printf(" %d [%d]\n", toggleTimes[(toggleReadPtr + i)%SPEAKERQUEUESIZE],
|
* So given the cycle number at which this toggle happened (c), we
|
||||||
toggleTimes[(toggleReadPtr + i - 1)%SPEAKERQUEUESIZE] -
|
* know we need to fill soundBuf[bufIdx..?] with either 0 or 127
|
||||||
toggleTimes[(toggleReadPtr + i)%SPEAKERQUEUESIZE]
|
* (adjusted for volume). The end of that area that we need to fill is
|
||||||
);
|
* based on what time cycle 'c' refers to,
|
||||||
}
|
*
|
||||||
exit(1);
|
* The wallclock time of cycle (c) is calculable from
|
||||||
|
* timespec_add_cycles(&startTime, c, &outputTime);
|
||||||
|
*
|
||||||
|
* And the point at which the SDL buffer will be drained is the same
|
||||||
|
* as the time at which soundBuf begins. So the difference between
|
||||||
|
* the two tells us where the end point is.
|
||||||
|
*
|
||||||
|
* Then we need to fill soundBuf[bufIdx .. endPoint] with that 0 or 127,
|
||||||
|
* and set bufIdx = endPoint.
|
||||||
|
*
|
||||||
|
* Bonus: if it looks like we're not filling enough buffer, then we
|
||||||
|
* should tell the emulation layer above to run more cycles in bulk
|
||||||
|
* to build up more speaker backlog.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// calculate the timespec that refers to the cycle where this
|
||||||
|
// speaker toggle happened
|
||||||
|
struct timespec blipTime;
|
||||||
|
timespec_add_cycles(&startTime, c, &blipTime);
|
||||||
|
timespec_add_us(&blipTime, ((float)SDLSIZE * (float)1000000)/(float)44100, &blipTime); // it's delayed one SDL buffer naturally, and there's some drift between the start of the CPU and the start of the speaker. :/
|
||||||
|
|
||||||
|
// determine how long there will be between the start of the buffer
|
||||||
|
// and that cycle time. (tsSubtract bounds at 0 and is never
|
||||||
|
// negative.)
|
||||||
|
struct timespec timeOffset = tsSubtract(blipTime, sdlEmptyTime);
|
||||||
|
|
||||||
|
// Turn that in to a sample index in the soundBuf[] buffer. There are 44100 of them per second,
|
||||||
|
// so this is straightforward
|
||||||
|
float newIdx = (float)timeOffset.tv_sec + ((float)timeOffset.tv_nsec / (float)NANOSECONDS_PER_SECOND);
|
||||||
|
newIdx *= 44100.0;
|
||||||
|
|
||||||
|
if (newIdx >= sizeof(soundBuf)) {
|
||||||
|
// Buffer overrun
|
||||||
|
printf("ERROR: buffer overrun, dropping data\n");
|
||||||
|
newIdx = sizeof(soundBuf)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flip the toggle state
|
||||||
|
toggleState = !toggleState;
|
||||||
|
|
||||||
|
// Fill from bufIdx .. newIdx and set bufIdx to newIdx when done
|
||||||
|
if (newIdx > bufIdx) {
|
||||||
|
long count = (long)newIdx - bufIdx;
|
||||||
|
memset(&soundBuf[bufIdx], toggleState ? 127 : 0, count);
|
||||||
|
bufIdx = newIdx;
|
||||||
|
} else {
|
||||||
|
// Why are we backtracking? This does happen, and it's a bug.
|
||||||
|
if (newIdx >= 1) {
|
||||||
|
bufIdx = newIdx-1;
|
||||||
|
long count = (long)newIdx - bufIdx;
|
||||||
|
memset(&soundBuf[bufIdx], toggleState ? 127 : 0, count);
|
||||||
|
bufIdx = newIdx;
|
||||||
|
} else {
|
||||||
|
// ... and it's zero?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&togmutex);
|
pthread_mutex_unlock(&togmutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,60 +214,6 @@ int16_t DCFilter(int16_t in)
|
||||||
|
|
||||||
void SDLSpeaker::maintainSpeaker(uint32_t c, uint64_t microseconds)
|
void SDLSpeaker::maintainSpeaker(uint32_t c, uint64_t microseconds)
|
||||||
{
|
{
|
||||||
bool didChange = false;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&togmutex);
|
|
||||||
|
|
||||||
if (c == -1 && microseconds == -1) {
|
|
||||||
// flushing
|
|
||||||
printf("Flush sound output\n");
|
|
||||||
toggleReadPtr = toggleWritePtr = 0;
|
|
||||||
toggleCount = 0;
|
|
||||||
} else {
|
|
||||||
while (toggleCount && c >= toggleTimes[toggleReadPtr]) {
|
|
||||||
// Override the mixer with a 1-bit "Terribad" audio sample change
|
|
||||||
toggleState = !toggleState;
|
|
||||||
toggleCount--;
|
|
||||||
toggleReadPtr++;
|
|
||||||
if (toggleReadPtr >= SPEAKERQUEUESIZE)
|
|
||||||
toggleReadPtr = 0;
|
|
||||||
didChange = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&togmutex);
|
|
||||||
|
|
||||||
// FIXME: removed all the mixing code
|
|
||||||
|
|
||||||
// Add samples from the last time to this time
|
|
||||||
// mixerValue = (toggleState ? 0x1FF : 0x00);
|
|
||||||
mixerValue = (toggleState ? 0x00 : ~0x80);
|
|
||||||
// FIXME: DC filter isn't correct yet
|
|
||||||
// mixerValue = DCFilter(mixerValue);
|
|
||||||
|
|
||||||
uint64_t sampleCount = (microseconds * 44100) / 1000000;
|
|
||||||
uint64_t numSamples = sampleCount - lastSampleCount;
|
|
||||||
|
|
||||||
if (numSamples) {
|
|
||||||
lastSampleCount = sampleCount;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&sndmutex);
|
|
||||||
|
|
||||||
if (bufIdx + numSamples >= sizeof(soundBuf)) {
|
|
||||||
static uint8_t errcnt = 0;
|
|
||||||
if (++errcnt <= 10) {
|
|
||||||
printf("Sound overrun!\n");
|
|
||||||
}
|
|
||||||
numSamples = sizeof(soundBuf) - bufIdx - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mixerValue >>= (8-(g_volume/2));
|
|
||||||
|
|
||||||
memset(&soundBuf[bufIdx], mixerValue, numSamples);
|
|
||||||
bufIdx += numSamples;
|
|
||||||
pthread_mutex_unlock(&sndmutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLSpeaker::beginMixing()
|
void SDLSpeaker::beginMixing()
|
||||||
|
@ -202,3 +223,8 @@ void SDLSpeaker::beginMixing()
|
||||||
void SDLSpeaker::mixOutput(uint8_t v)
|
void SDLSpeaker::mixOutput(uint8_t v)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t SDLSpeaker::bufferedContentSize()
|
||||||
|
{
|
||||||
|
return bufIdx;
|
||||||
|
}
|
||||||
|
|
|
@ -12,19 +12,19 @@ class SDLSpeaker : public PhysicalSpeaker {
|
||||||
SDLSpeaker();
|
SDLSpeaker();
|
||||||
virtual ~SDLSpeaker();
|
virtual ~SDLSpeaker();
|
||||||
|
|
||||||
|
virtual void begin();
|
||||||
|
|
||||||
virtual void toggle(uint32_t c);
|
virtual void toggle(uint32_t c);
|
||||||
virtual void maintainSpeaker(uint32_t c, uint64_t microseconds);
|
virtual void maintainSpeaker(uint32_t c, uint64_t microseconds);
|
||||||
virtual void beginMixing();
|
virtual void beginMixing();
|
||||||
virtual void mixOutput(uint8_t v);
|
virtual void mixOutput(uint8_t v);
|
||||||
|
|
||||||
|
virtual uint32_t bufferedContentSize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t mixerValue;
|
uint8_t mixerValue;
|
||||||
bool toggleState;
|
bool toggleState;
|
||||||
|
|
||||||
uint32_t toggleTimes[SPEAKERQUEUESIZE];
|
|
||||||
uint8_t toggleCount; // # of entries still in queue
|
|
||||||
uint8_t toggleReadPtr; // ring buffer pointer in queue
|
|
||||||
uint8_t toggleWritePtr; // ring buffer pointer in queue
|
|
||||||
|
|
||||||
uint64_t lastCycleCount;
|
uint64_t lastCycleCount;
|
||||||
uint64_t lastSampleCount;
|
uint64_t lastSampleCount;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue