robmcmullen-apple2/src/sound.cpp

224 lines
5.6 KiB
C++
Raw Permalink Normal View History

2007-05-29 03:06:33 +00:00
//
// Sound Interface
//
// by James Hammons
// (C) 2005-2018 Underground Software
2007-05-29 03:06:33 +00:00
//
// JLH = James Hammons <jlhamm@acm.org>
2007-05-29 03:06:33 +00:00
//
// WHO WHEN WHAT
2017-06-02 02:42:15 +00:00
// --- ---------- -----------------------------------------------------------
2007-05-29 03:06:33 +00:00
// JLH 12/02/2005 Fixed a problem with sound callback thread signaling the
// main thread
2017-06-02 02:42:15 +00:00
// JLH 12/03/2005 Fixed sound callback dropping samples when the sample
// buffer is shorter than the callback sample buffer
2007-05-29 03:06:33 +00:00
//
// STILL TO DO:
//
// - Figure out why it's losing samples (Bard's Tale) [DONE]
// - Figure out why it's playing too fast [DONE]
2007-05-29 03:06:33 +00:00
//
#include "sound.h"
#include <string.h> // For memset, memcpy
#include <SDL2/SDL.h>
2007-05-29 03:06:33 +00:00
#include "log.h"
Misc. improvements, added WOZ file support to floppy emulation - Refactored old MMU slot code to be more flexible - Moved all Mockingboard related code to its own compilation unit - Refactored old 6522 & AY-3-8910 code into v6522VIA & vAY8910 :-) - Fixed BCD mode for ADC and SBC in v65C02 - Finally fixed text mode characters in both ALTCHARSET and regular modes - Added new floppy disk controller Logic State Sequencer emulation - Fixed v65C02 to be cycle exact (as far as I can tell) - Fixed a bunch of bugs in v65C02 - Dropped NIB support - Added WOZ 1.0 file support That last item is a bit of a big deal, as I had been thinking about writing a new file format that would be bit-based--since the NIB nybble format, while better than pretty much all the other formats out there, fails hard in things like extra sync bits and half tracks. So, somewhat serendipitously, I stumbled upon the Applesauce project and found out that not only had other people been thinking in more or less the same direction, they had created it and had made disk images to try! So now, because of this, WOZ is the internal format used by the floppy emulation (as opposed to NIB) which, along with the new disk Logic State Sequencer emulator, makes it possible to format floppy disks correctly for the first time. :-) One ironic consequence of this is that NIB format can no longer be properly supported. The irony comes from the fact that before there was LSS emulation, NIB was the most accurate format you could get to represent the low level format of a disk, but now, with proper LSS emulation, it's the worst format for representing a floppy disk. And the main reason for this is that NIB doesn't contain sync bits, and has no mechanism to represent them--so when feeding them to the new LSS emulation, they will fail horribly because without sync bits, the bitstream represented by a NIB formatted disk can and will be misinterpreted by the LSS. And since there is now a format that properly represents the bitstream on a floppy disk (WOZ), there's absolutely no reason to keep NIB around or support it anymore. While it was a nice interim format to have around (when the emulation of the disk was "imperfectly perfect"), it now no longer has a place in disk preservation and/or emulation. Another consequence of this new format is that Apple2 only supports writing of WOZ images--it will no longer support writing of DSK and its bretheren. However, since those formats are extremely limited in their scope (they literally only represented the contents of the sectors on a disk) we still support reading them; Apple2 will automagically upconvert them and save them as WOZs (it will use the same filename but substitute "woz" for the old extension). So if you're wondering why your DSKs are unchanged when saving to them, you now know why. :-) Big, big thanks to the Applesauce guys and everyone who contributed and continues to contribute to that project; your efforts are very much appreciated--you guys are awesome!
2019-01-24 02:33:05 +00:00
#include "mockingboard.h"
2007-05-29 03:06:33 +00:00
// Useful defines
//#define DEBUG
#define SAMPLES_PER_FRAME (SAMPLE_RATE / 60.0)
#define CYCLES_PER_SAMPLE (1024000.0 / SAMPLE_RATE)
// 32K ought to be enough for anybody
#define SOUND_BUFFER_SIZE (32768)
2007-05-29 03:06:33 +00:00
// Global variables
// Local variables
static SDL_AudioSpec desired, obtained;
static SDL_AudioDeviceID device;
2007-05-29 03:06:33 +00:00
static bool soundInitialized = false;
static bool speakerState = false;
static uint16_t soundBuffer[SOUND_BUFFER_SIZE];
static uint32_t soundBufferPos;
static uint16_t sample;
static uint8_t ampPtr = 12; // Start with -2047 - +2047
static int16_t amplitude[17] = { 0, 1, 2, 3, 7, 15, 31, 63, 127, 255,
511, 1023, 2047, 4095, 8191, 16383, 32767 };
2007-05-29 03:06:33 +00:00
// Private function prototypes
static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
/*
N.B: We can convert this from the current callback model to a push model by using SDL_QueueAudio(SDL_AudioDeviceID id, const void * data, Uint32 len) where id is the audio device ID, data is a pointer to the sound buffer, and len is the size of the buffer in *bytes* (not samples!). To use this method, we need to set up things as usual but instead of putting the callback function pointer in desired.callback, we put a NULL there. The downside is that we can't tell if the buffer is being starved or not, which is why we haven't kicked it to the curb just yet--we want to know why we're still getting buffer starvation even if it's not as frequent as it used to be. :-/
You can get the size of the audio already queued with SDL_GetQueuedAudioSize(SDL_AudioDeviceID id), which will return the size of the buffer in bytes (again, *not* samples!).
*/
2007-05-29 03:06:33 +00:00
//
// Initialize the SDL sound system
//
void SoundInit(void)
{
SDL_zero(desired);
desired.freq = SAMPLE_RATE; // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
desired.format = AUDIO_U16SYS; // This uses the native endian (for portability)...
2007-05-29 03:06:33 +00:00
desired.channels = 1;
desired.samples = 512; // Let's try a 1/2K buffer
2007-05-29 03:06:33 +00:00
desired.callback = SDLSoundCallback;
device = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
if (device == 0)
2007-05-29 03:06:33 +00:00
{
WriteLog("Sound: Failed to initialize SDL sound.\n");
WriteLog("SDL sez: %s\n", SDL_GetError());
2007-05-29 03:06:33 +00:00
return;
}
soundBufferPos = 0;
sample = desired.silence; // ? wilwok ? yes
2007-05-29 03:06:33 +00:00
SDL_PauseAudioDevice(device, 0);// Start playback!
2007-05-29 03:06:33 +00:00
soundInitialized = true;
WriteLog("Sound: Successfully initialized.\n");
}
2007-05-29 03:06:33 +00:00
//
// Close down the SDL sound subsystem
//
void SoundDone(void)
{
if (soundInitialized)
{
SDL_PauseAudioDevice(device, 1);
SDL_CloseAudioDevice(device);
2007-05-29 03:06:33 +00:00
WriteLog("Sound: Done.\n");
}
}
void SoundPause(void)
{
if (soundInitialized)
SDL_PauseAudioDevice(device, 1);
}
void SoundResume(void)
{
if (soundInitialized)
SDL_PauseAudioDevice(device, 0);
}
2007-05-29 03:06:33 +00:00
//
// Sound card callback handler
//
static uint32_t sndFrmCnt = 0;
static uint32_t lastStarve = 0;
static void SDLSoundCallback(void * /*userdata*/, Uint8 * buffer8, int length8)
2007-05-29 03:06:33 +00:00
{
sndFrmCnt++;
// Recast this as a 16-bit type...
uint16_t * buffer = (uint16_t *)buffer8;
uint32_t length = (uint32_t)length8 / 2;
if (soundBufferPos < length)
2007-05-29 03:06:33 +00:00
{
Misc. improvements, added WOZ file support to floppy emulation - Refactored old MMU slot code to be more flexible - Moved all Mockingboard related code to its own compilation unit - Refactored old 6522 & AY-3-8910 code into v6522VIA & vAY8910 :-) - Fixed BCD mode for ADC and SBC in v65C02 - Finally fixed text mode characters in both ALTCHARSET and regular modes - Added new floppy disk controller Logic State Sequencer emulation - Fixed v65C02 to be cycle exact (as far as I can tell) - Fixed a bunch of bugs in v65C02 - Dropped NIB support - Added WOZ 1.0 file support That last item is a bit of a big deal, as I had been thinking about writing a new file format that would be bit-based--since the NIB nybble format, while better than pretty much all the other formats out there, fails hard in things like extra sync bits and half tracks. So, somewhat serendipitously, I stumbled upon the Applesauce project and found out that not only had other people been thinking in more or less the same direction, they had created it and had made disk images to try! So now, because of this, WOZ is the internal format used by the floppy emulation (as opposed to NIB) which, along with the new disk Logic State Sequencer emulator, makes it possible to format floppy disks correctly for the first time. :-) One ironic consequence of this is that NIB format can no longer be properly supported. The irony comes from the fact that before there was LSS emulation, NIB was the most accurate format you could get to represent the low level format of a disk, but now, with proper LSS emulation, it's the worst format for representing a floppy disk. And the main reason for this is that NIB doesn't contain sync bits, and has no mechanism to represent them--so when feeding them to the new LSS emulation, they will fail horribly because without sync bits, the bitstream represented by a NIB formatted disk can and will be misinterpreted by the LSS. And since there is now a format that properly represents the bitstream on a floppy disk (WOZ), there's absolutely no reason to keep NIB around or support it anymore. While it was a nice interim format to have around (when the emulation of the disk was "imperfectly perfect"), it now no longer has a place in disk preservation and/or emulation. Another consequence of this new format is that Apple2 only supports writing of WOZ images--it will no longer support writing of DSK and its bretheren. However, since those formats are extremely limited in their scope (they literally only represented the contents of the sectors on a disk) we still support reading them; Apple2 will automagically upconvert them and save them as WOZs (it will use the same filename but substitute "woz" for the old extension). So if you're wondering why your DSKs are unchanged when saving to them, you now know why. :-) Big, big thanks to the Applesauce guys and everyone who contributed and continues to contribute to that project; your efforts are very much appreciated--you guys are awesome!
2019-01-24 02:33:05 +00:00
//WriteLog("*** Sound buffer starved (%d short) *** [%d delta %d]\n", length - soundBufferPos, sndFrmCnt, sndFrmCnt - lastStarve);
lastStarve = sndFrmCnt;
#if 1
for(uint32_t i=0; i<length; i++)
buffer[i] = desired.silence;
#else
// The sound buffer is starved...
for(uint32_t i=0; i<soundBufferPos; i++)
2007-05-29 03:06:33 +00:00
buffer[i] = soundBuffer[i];
2007-05-29 03:06:33 +00:00
// Fill buffer with last value
for(uint32_t i=soundBufferPos; i<length; i++)
buffer[i] = sample;
// Reset soundBufferPos to start of buffer...
soundBufferPos = 0;
#endif
2007-05-29 03:06:33 +00:00
}
else
{
// Fill sound buffer with frame buffered sound
for(uint32_t i=0; i<length; i++)
buffer[i] = soundBuffer[i];
soundBufferPos -= length;
2007-05-29 03:06:33 +00:00
// Move current buffer down to start
for(uint32_t i=0; i<soundBufferPos; i++)
soundBuffer[i] = soundBuffer[length + i];
}
2007-05-29 03:06:33 +00:00
}
//
// This is called by the main CPU thread every ~21.666 cycles.
//
void WriteSampleToBuffer(void)
{
Misc. improvements, added WOZ file support to floppy emulation - Refactored old MMU slot code to be more flexible - Moved all Mockingboard related code to its own compilation unit - Refactored old 6522 & AY-3-8910 code into v6522VIA & vAY8910 :-) - Fixed BCD mode for ADC and SBC in v65C02 - Finally fixed text mode characters in both ALTCHARSET and regular modes - Added new floppy disk controller Logic State Sequencer emulation - Fixed v65C02 to be cycle exact (as far as I can tell) - Fixed a bunch of bugs in v65C02 - Dropped NIB support - Added WOZ 1.0 file support That last item is a bit of a big deal, as I had been thinking about writing a new file format that would be bit-based--since the NIB nybble format, while better than pretty much all the other formats out there, fails hard in things like extra sync bits and half tracks. So, somewhat serendipitously, I stumbled upon the Applesauce project and found out that not only had other people been thinking in more or less the same direction, they had created it and had made disk images to try! So now, because of this, WOZ is the internal format used by the floppy emulation (as opposed to NIB) which, along with the new disk Logic State Sequencer emulator, makes it possible to format floppy disks correctly for the first time. :-) One ironic consequence of this is that NIB format can no longer be properly supported. The irony comes from the fact that before there was LSS emulation, NIB was the most accurate format you could get to represent the low level format of a disk, but now, with proper LSS emulation, it's the worst format for representing a floppy disk. And the main reason for this is that NIB doesn't contain sync bits, and has no mechanism to represent them--so when feeding them to the new LSS emulation, they will fail horribly because without sync bits, the bitstream represented by a NIB formatted disk can and will be misinterpreted by the LSS. And since there is now a format that properly represents the bitstream on a floppy disk (WOZ), there's absolutely no reason to keep NIB around or support it anymore. While it was a nice interim format to have around (when the emulation of the disk was "imperfectly perfect"), it now no longer has a place in disk preservation and/or emulation. Another consequence of this new format is that Apple2 only supports writing of WOZ images--it will no longer support writing of DSK and its bretheren. However, since those formats are extremely limited in their scope (they literally only represented the contents of the sectors on a disk) we still support reading them; Apple2 will automagically upconvert them and save them as WOZs (it will use the same filename but substitute "woz" for the old extension). So if you're wondering why your DSKs are unchanged when saving to them, you now know why. :-) Big, big thanks to the Applesauce guys and everyone who contributed and continues to contribute to that project; your efforts are very much appreciated--you guys are awesome!
2019-01-24 02:33:05 +00:00
// uint16_t s1 = AYGetSample(0);
// uint16_t s2 = AYGetSample(1);
uint16_t s1 = mb[0].ay[0].GetSample();
uint16_t s2 = mb[0].ay[1].GetSample();
// This should almost never happen, but, if it does...
while (soundBufferPos >= (SOUND_BUFFER_SIZE - 1))
{
//WriteLog("WriteSampleToBuffer(): Waiting for sound thread. soundBufferPos=%i, SOUNDBUFFERSIZE-1=%i\n", soundBufferPos, SOUND_BUFFER_SIZE-1);
SDL_Delay(1);
}
SDL_LockAudioDevice(device);
Misc. improvements, added WOZ file support to floppy emulation - Refactored old MMU slot code to be more flexible - Moved all Mockingboard related code to its own compilation unit - Refactored old 6522 & AY-3-8910 code into v6522VIA & vAY8910 :-) - Fixed BCD mode for ADC and SBC in v65C02 - Finally fixed text mode characters in both ALTCHARSET and regular modes - Added new floppy disk controller Logic State Sequencer emulation - Fixed v65C02 to be cycle exact (as far as I can tell) - Fixed a bunch of bugs in v65C02 - Dropped NIB support - Added WOZ 1.0 file support That last item is a bit of a big deal, as I had been thinking about writing a new file format that would be bit-based--since the NIB nybble format, while better than pretty much all the other formats out there, fails hard in things like extra sync bits and half tracks. So, somewhat serendipitously, I stumbled upon the Applesauce project and found out that not only had other people been thinking in more or less the same direction, they had created it and had made disk images to try! So now, because of this, WOZ is the internal format used by the floppy emulation (as opposed to NIB) which, along with the new disk Logic State Sequencer emulator, makes it possible to format floppy disks correctly for the first time. :-) One ironic consequence of this is that NIB format can no longer be properly supported. The irony comes from the fact that before there was LSS emulation, NIB was the most accurate format you could get to represent the low level format of a disk, but now, with proper LSS emulation, it's the worst format for representing a floppy disk. And the main reason for this is that NIB doesn't contain sync bits, and has no mechanism to represent them--so when feeding them to the new LSS emulation, they will fail horribly because without sync bits, the bitstream represented by a NIB formatted disk can and will be misinterpreted by the LSS. And since there is now a format that properly represents the bitstream on a floppy disk (WOZ), there's absolutely no reason to keep NIB around or support it anymore. While it was a nice interim format to have around (when the emulation of the disk was "imperfectly perfect"), it now no longer has a place in disk preservation and/or emulation. Another consequence of this new format is that Apple2 only supports writing of WOZ images--it will no longer support writing of DSK and its bretheren. However, since those formats are extremely limited in their scope (they literally only represented the contents of the sectors on a disk) we still support reading them; Apple2 will automagically upconvert them and save them as WOZs (it will use the same filename but substitute "woz" for the old extension). So if you're wondering why your DSKs are unchanged when saving to them, you now know why. :-) Big, big thanks to the Applesauce guys and everyone who contributed and continues to contribute to that project; your efforts are very much appreciated--you guys are awesome!
2019-01-24 02:33:05 +00:00
soundBuffer[soundBufferPos++] = sample + s1 + s2;
SDL_UnlockAudioDevice(device);
}
void ToggleSpeaker(void)
2007-05-29 03:06:33 +00:00
{
if (!soundInitialized)
return;
speakerState = !speakerState;
sample = (speakerState ? amplitude[ampPtr] : 0);
2007-05-29 03:06:33 +00:00
}
void VolumeUp(void)
{
// Currently set for 16-bit samples
if (ampPtr < 16)
ampPtr++;
}
void VolumeDown(void)
{
if (ampPtr > 0)
ampPtr--;
}
uint8_t GetVolume(void)
{
return ampPtr;
}