A fairly major rewrite of the class to improve the sound support. The

enhanced sound in games like Pitfall II and Quadrun should be working
now.  Also the overall sound in most has should be improved since the
TIA sound register writes and sample generation are somewhat synchronized.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@262 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
bwmott 2004-06-13 05:03:26 +00:00
parent 3d231acd53
commit 2e09e2c00c
2 changed files with 309 additions and 211 deletions

View File

@ -13,26 +13,24 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SoundSDL.cxx,v 1.1 2004-05-24 17:18:22 stephena Exp $ // $Id: SoundSDL.cxx,v 1.2 2004-06-13 05:03:26 bwmott Exp $
//============================================================================ //============================================================================
#include <cassert>
#include <SDL.h> #include <SDL.h>
#include "TIASound.h" #include "TIASound.h"
#include "Console.hxx"
#include "Serializer.hxx" #include "Serializer.hxx"
#include "Deserializer.hxx" #include "Deserializer.hxx"
#include "System.hxx" #include "System.hxx"
#include "SoundSDL.hxx" #include "SoundSDL.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundSDL::SoundSDL(uInt32 fragsize, uInt32 queuesize) SoundSDL::SoundSDL(uInt32 fragsize)
: myCurrentVolume(SDL_MIX_MAXVOLUME), : myIsInitializedFlag(false),
myFragmentSize(fragsize),
myIsInitializedFlag(false),
myIsMuted(false), myIsMuted(false),
mySampleRate(31400), myVolume(100)
mySampleQueue(queuesize)
{ {
if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
{ {
@ -43,10 +41,10 @@ SoundSDL::SoundSDL(uInt32 fragsize, uInt32 queuesize)
else else
{ {
SDL_AudioSpec desired; SDL_AudioSpec desired;
desired.freq = mySampleRate; desired.freq = 31400;
desired.format = AUDIO_U8; desired.format = AUDIO_U8;
desired.channels = 1; desired.channels = 1;
desired.samples = myFragmentSize; desired.samples = fragsize;
desired.callback = callback; desired.callback = callback;
desired.userdata = (void*)this; desired.userdata = (void*)this;
@ -71,18 +69,18 @@ SoundSDL::SoundSDL(uInt32 fragsize, uInt32 queuesize)
myIsInitializedFlag = true; myIsInitializedFlag = true;
myIsMuted = false; myIsMuted = false;
mySampleRate = myHardwareSpec.freq;
myFragmentSize = myHardwareSpec.samples;
/*
cerr << "Freq: " << (int)myHardwareSpec.freq << endl; cerr << "Freq: " << (int)myHardwareSpec.freq << endl;
cerr << "Format: " << (int)myHardwareSpec.format << endl; cerr << "Format: " << (int)myHardwareSpec.format << endl;
cerr << "Channels: " << (int)myHardwareSpec.channels << endl; cerr << "Channels: " << (int)myHardwareSpec.channels << endl;
cerr << "Silence: " << (int)myHardwareSpec.silence << endl; cerr << "Silence: " << (int)myHardwareSpec.silence << endl;
cerr << "Samples: " << (int)myHardwareSpec.samples << endl; cerr << "Samples: " << (int)myHardwareSpec.samples << endl;
cerr << "Size: " << (int)myHardwareSpec.size << endl; cerr << "Size: " << (int)myHardwareSpec.size << endl;
*/
// Now initialize the TIASound object which will actually generate sound // Now initialize the TIASound object which will actually generate sound
Tia_sound_init(31400, mySampleRate); Tia_sound_init(31400, myHardwareSpec.freq);
// And start the SDL sound subsystem ... // And start the SDL sound subsystem ...
SDL_PauseAudio(0); SDL_PauseAudio(0);
@ -92,8 +90,10 @@ SoundSDL::SoundSDL(uInt32 fragsize, uInt32 queuesize)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundSDL::~SoundSDL() SoundSDL::~SoundSDL()
{ {
// Close the SDL audio system if it's initialized
if(myIsInitializedFlag) if(myIsInitializedFlag)
{ {
SDL_PauseAudio(1);
SDL_CloseAudio(); SDL_CloseAudio();
} }
@ -120,37 +120,186 @@ void SoundSDL::mute(bool state)
myIsMuted = state; myIsMuted = state;
SDL_PauseAudio(myIsMuted ? 1 : 0); SDL_PauseAudio(myIsMuted ? 1 : 0);
myRegWriteQueue.clear();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::reset()
{
if(myIsInitializedFlag)
{
SDL_PauseAudio(1);
myIsMuted = false;
myLastRegisterSetCycle = 0;
myRegWriteQueue.clear();
SDL_PauseAudio(0);
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::setVolume(Int32 percent) void SoundSDL::setVolume(Int32 percent)
{ {
// TODO: Verify that this works...
if(myIsInitializedFlag) if(myIsInitializedFlag)
{ {
if((percent >= 0) && (percent <= 100)) if((percent >= 0) && (percent <= 100))
{ {
SDL_LockAudio(); SDL_LockAudio();
myCurrentVolume = (uInt32)(((float)percent / 100.0) * SDL_MIX_MAXVOLUME); myVolume = percent;
Tia_volume(percent);
SDL_UnlockAudio(); SDL_UnlockAudio();
} }
else if(percent == -1) // If -1 has been specified, play sound at default volume
{
myCurrentVolume = SDL_MIX_MAXVOLUME;
}
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::update() void SoundSDL::set(uInt16 addr, uInt8 value, Int32 cycle)
{ {
SDL_LockAudio();
// First, calulate how many seconds would have past since the last
// register write on a real 2600
double delta = (((double)(cycle - myLastRegisterSetCycle)) /
(1193191.66666667));
// Now, adjust the time based on the frame rate the user has selected
delta = delta * (60.0 / (double)myConsole->frameRate());
RegWrite info;
info.addr = addr;
info.value = value;
info.delta = delta;
myRegWriteQueue.enqueue(info);
// Update last cycle counter to the current cycle
myLastRegisterSetCycle = cycle;
SDL_UnlockAudio();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::set(uInt16 addr, uInt8 value) void SoundSDL::processFragment(uInt8* stream, Int32 length)
{ {
Update_tia_sound(addr, value); if(!myIsInitializedFlag)
{
return;
}
// If there are excessive items on the queue then we'll remove some
if(myRegWriteQueue.duration() > (10.0 / 60.0))
{
double removed = 0.0;
while(removed < (8.0 / 60.0))
{
RegWrite& info = myRegWriteQueue.front();
removed += info.delta;
Update_tia_sound(info.addr, info.value);
myRegWriteQueue.dequeue();
}
// cout << "Removed Items from RegWriteQueue!" << endl;
}
double position = 0.0;
double remaining = length;
while(remaining > 0.0)
{
if(myRegWriteQueue.size() == 0)
{
// There are no more pending TIA sound register updates so we'll
// use the current settings to finish filling the sound fragment
Tia_process(stream + (uInt32)position, length - (uInt32)position);
// Since we had to fill the fragment we'll reset the cycle counter
// to zero. NOTE: This isn't 100% correct, however, it'll do for
// now. We should really remember the overrun and remove it from
// the delta of the next write.
myLastRegisterSetCycle = 0;
break;
}
else
{
// There are pending TIA sound register updates so we need to
// update the sound buffer to the point of the next register update
RegWrite& info = myRegWriteQueue.front();
// How long will the remaing samples in the fragment take to play
double duration = remaining / (double)myHardwareSpec.freq;
// Does the register update occur before the end of the fragment?
if(info.delta <= duration)
{
if(info.delta > 0.0)
{
// Process the fragment upto the next TIA register write
double samples = (myHardwareSpec.freq * info.delta);
Tia_process(stream + (uInt32)position, (uInt32)samples +
(uInt32)(position + samples) -
((uInt32)position + (uInt32)samples));
position += samples;
remaining -= samples;
}
Update_tia_sound(info.addr, info.value);
myRegWriteQueue.dequeue();
}
else
{
// The next register update occurs in the next fragment so finish
// this fragment with the current TIA settings and reduce the register
// update delay by the corresponding amount of time
Tia_process(stream + (uInt32)position, length - (uInt32)position);
info.delta -= duration;
break;
}
}
}
//cout << myRegWriteQueue.size() << endl;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::callback(void* udata, uInt8* stream, int len)
{
SoundSDL* sound = (SoundSDL*)udata;
sound->processFragment(stream, (Int32)len);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundSDL::load(Deserializer& in)
{
string device = "TIASound";
try
{
if(in.getString() != device)
return false;
uInt8 reg1 = 0, reg2 = 0, reg3 = 0, reg4 = 0, reg5 = 0, reg6 = 0;
reg1 = (uInt8) in.getLong();
reg2 = (uInt8) in.getLong();
reg3 = (uInt8) in.getLong();
reg4 = (uInt8) in.getLong();
reg5 = (uInt8) in.getLong();
reg6 = (uInt8) in.getLong();
myLastRegisterSetCycle = (Int32) in.getLong();
// Only update the TIA sound registers if sound is enabled
if(myIsInitializedFlag)
Tia_set_registers(reg1, reg2, reg3, reg4, reg5, reg6);
}
catch(char *msg)
{
cerr << msg << endl;
return false;
}
catch(...)
{
cerr << "Unknown error in load state for " << device << endl;
return false;
}
return true;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -175,7 +324,7 @@ bool SoundSDL::save(Serializer& out)
out.putLong(reg5); out.putLong(reg5);
out.putLong(reg6); out.putLong(reg6);
out.putLong(myLastSoundUpdateCycle); out.putLong(myLastRegisterSetCycle);
} }
catch(char *msg) catch(char *msg)
{ {
@ -192,143 +341,88 @@ bool SoundSDL::save(Serializer& out)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundSDL::load(Deserializer& in) SoundSDL::RegWriteQueue::RegWriteQueue(uInt32 capacity)
{
string device = "TIASound";
try
{
if(in.getString() != device)
return false;
uInt8 reg1 = 0, reg2 = 0, reg3 = 0, reg4 = 0, reg5 = 0, reg6 = 0;
reg1 = (uInt8) in.getLong();
reg2 = (uInt8) in.getLong();
reg3 = (uInt8) in.getLong();
reg4 = (uInt8) in.getLong();
reg5 = (uInt8) in.getLong();
reg6 = (uInt8) in.getLong();
myLastSoundUpdateCycle = (Int32) in.getLong();
// Only update the TIA sound registers if sound is enabled
if(myIsInitializedFlag)
Tia_set_registers(reg1, reg2, reg3, reg4, reg5, reg6);
}
catch(char *msg)
{
cerr << msg << endl;
return false;
}
catch(...)
{
cerr << "Unknown error in load state for " << device << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::callback(void* udata, uInt8* stream, int len)
{
SoundSDL* sound = (SoundSDL*)udata;
if(sound->isSuccessfullyInitialized())
{
Tia_process(stream, len);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundSDL::SampleQueue::SampleQueue(uInt32 capacity)
: myCapacity(capacity), : myCapacity(capacity),
myBuffer(0), myBuffer(0),
mySize(0), mySize(0),
myHead(0), myHead(0),
myTail(0) myTail(0)
{ {
myBuffer = new uInt8[myCapacity]; myBuffer = new RegWrite[myCapacity];
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundSDL::SampleQueue::~SampleQueue() SoundSDL::RegWriteQueue::~RegWriteQueue()
{ {
delete[] myBuffer; delete[] myBuffer;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::SampleQueue::clear() void SoundSDL::RegWriteQueue::clear()
{ {
myHead = myTail = mySize = 0; myHead = myTail = mySize = 0;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 SoundSDL::SampleQueue::dequeue(uInt8* buffer, uInt32 size) void SoundSDL::RegWriteQueue::dequeue()
{ {
// We can only dequeue up to the number of items in the queue if(mySize > 0)
if(size > mySize)
{ {
size = mySize; myHead = (myHead + 1) % myCapacity;
--mySize;
} }
if((myHead + size) < myCapacity)
{
memcpy((void*)buffer, (const void*)(myBuffer + myHead), size);
myHead += size;
}
else
{
uInt32 s1 = myCapacity - myHead;
uInt32 s2 = size - s1;
memcpy((void*)buffer, (const void*)(myBuffer + myHead), s1);
memcpy((void*)(buffer + s1), (const void*)myBuffer, s2);
myHead = (myHead + size) % myCapacity;
}
mySize -= size;
return size;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::SampleQueue::enqueue(uInt8* buffer, uInt32 size) double SoundSDL::RegWriteQueue::duration()
{
double duration = 0.0;
for(uInt32 i = 0; i < mySize; ++i)
{
duration += myBuffer[(myHead + i) % myCapacity].delta;
}
return duration;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::RegWriteQueue::enqueue(const RegWrite& info)
{ {
// If an attempt is made to enqueue more than the queue can hold then // If an attempt is made to enqueue more than the queue can hold then
// we'll only enqueue the last myCapacity elements. // we'll enlarge the queue's capacity.
if(size > myCapacity) if(mySize == myCapacity)
{ {
buffer += (size - myCapacity); grow();
size = myCapacity;
} }
if((myTail + size) < myCapacity) myBuffer[myTail] = info;
{ myTail = (myTail + 1) % myCapacity;
memcpy((void*)(myBuffer + myTail), (const void*)buffer, size); ++mySize;
myTail += size;
}
else
{
uInt32 s1 = myCapacity - myTail;
uInt32 s2 = size - s1;
memcpy((void*)(myBuffer + myTail), (const void*)buffer, s1);
memcpy((void*)myBuffer, (const void*)(buffer + s1), s2);
myTail = (myTail + size) % myCapacity;
}
if((mySize + size) > myCapacity)
{
myHead = (myHead + ((mySize + size) - myCapacity)) % myCapacity;
mySize = myCapacity;
}
else
{
mySize += size;
}
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 SoundSDL::SampleQueue::size() const SoundSDL::RegWrite& SoundSDL::RegWriteQueue::front()
{
assert(mySize != 0);
return myBuffer[myHead];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 SoundSDL::RegWriteQueue::size() const
{ {
return mySize; return mySize;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::RegWriteQueue::grow()
{
RegWrite* buffer = new RegWrite[myCapacity * 2];
for(uInt32 i = 0; i < mySize; ++i)
{
buffer[i] = myBuffer[(myHead + i) % myCapacity];
}
myHead = 0;
myTail = mySize;
myCapacity = myCapacity * 2;
delete[] myBuffer;
myBuffer = buffer;
}

View File

@ -8,12 +8,12 @@
// SS SS tt ee ll ll aa aa // SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa // SSSS ttt eeeee llll llll aaaaa
// //
// Copyright (c) 1995-2002 by Bradford W. Mott // Copyright (c) 1995-2004 by Bradford W. Mott
// //
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SoundSDL.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $ // $Id: SoundSDL.hxx,v 1.2 2004-06-13 05:03:26 bwmott Exp $
//============================================================================ //============================================================================
#ifndef SOUNDSDL_HXX #ifndef SOUNDSDL_HXX
@ -29,15 +29,16 @@
This class implements the sound API for SDL. This class implements the sound API for SDL.
@author Stephen Anthony and Bradford W. Mott @author Stephen Anthony and Bradford W. Mott
@version $Id: SoundSDL.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $ @version $Id: SoundSDL.hxx,v 1.2 2004-06-13 05:03:26 bwmott Exp $
*/ */
class SoundSDL : public Sound class SoundSDL : public Sound
{ {
public: public:
/** /**
Create a new sound object Create a new sound object. The init method must be invoked before
using the object.
*/ */
SoundSDL(uInt32 fragsize, uInt32 queuesize); SoundSDL(uInt32 fragsize);
/** /**
Destructor Destructor
@ -45,53 +46,51 @@ class SoundSDL : public Sound
virtual ~SoundSDL(); virtual ~SoundSDL();
public: public:
/**
Closes the sound device
*/
void closeDevice();
/**
Return the playback sample rate for the sound device.
@return The playback sample rate
*/
uInt32 getSampleRate() const;
/** /**
Return true iff the sound device was successfully initialized. Return true iff the sound device was successfully initialized.
@return true iff the sound device was successfully initialized @return true iff the sound device was successfully initialized
*/ */
bool isSuccessfullyInitialized() const; virtual bool isSuccessfullyInitialized() const;
/** /**
Set the mute state of the sound object. Set the mute state of the sound object. While muted no sound is played.
@param state Mutes sound if true, unmute if false @param state Mutes sound if true, unmute if false
*/ */
void mute(bool state); virtual void mute(bool state);
/** /**
Sets the volume of the sound device to the specified level. The Resets the sound device.
volume is given as a percentage from 0 to 100. A -1 indicates
that the volume shouldn't be changed at all.
@param percent The new volume percentage level for the sound device
*/ */
void setVolume(Int32 percent); virtual void reset();
/**
Generates audio samples to fill the sample queue.
*/
void update();
/** /**
Sets the sound register to a given value. Sets the sound register to a given value.
@param addr The register address @param addr The register address
@param value The value to save into the register @param value The value to save into the register
@param cycle The CPU cycle at which the register is being updated
*/ */
void set(uInt16 addr, uInt8 value); virtual void set(uInt16 addr, uInt8 value, Int32 cycle);
/**
Sets the volume of the sound device to the specified level. The
volume is given as a percentage from 0 to 100. Values outside
this range indicate that the volume shouldn't be changed at all.
@param percent The new volume percentage level for the sound device
*/
virtual void setVolume(Int32 percent);
public:
/**
Loads the current state of this device from the given Deserializer.
@param in The deserializer device to load from.
@return The result of the load. True on success, false on failure.
*/
bool load(Deserializer& in);
/** /**
Saves the current state of this device to the given Serializer. Saves the current state of this device to the given Serializer.
@ -101,83 +100,91 @@ class SoundSDL : public Sound
*/ */
bool save(Serializer& out); bool save(Serializer& out);
protected:
/** /**
Loads the current state of this device from the given Deserializer. Invoked by the sound callback to process the next sound fragment.
@param in The deserializer device to load from. @param stream Pointer to the start of the fragment
@return The result of the load. True on success, false on failure. @param length Length of the fragment
*/ */
bool load(Deserializer& in); void processFragment(uInt8* stream, Int32 length);
protected:
// Struct to hold information regarding a TIA sound register write
struct RegWrite
{
uInt16 addr;
uInt8 value;
double delta;
};
private:
/** /**
A bounded queue class used to hold audio samples after they are A queue class used to hold TIA sound register writes before being
produced by the MediaSource. processed while creating a sound fragment.
*/ */
class SampleQueue class RegWriteQueue
{ {
public: public:
/** /**
Create a new SampleQueue instance which can hold the specified Create a new queue instance with the specified initial
number of samples. If the queue ever reaches its capacity then capacity. If the queue ever reaches its capacity then it will
older samples are discarded. automatically increase its size.
*/ */
SampleQueue(uInt32 capacity); RegWriteQueue(uInt32 capacity = 512);
/** /**
Destroy this SampleQueue instance. Destroy this queue instance.
*/ */
virtual ~SampleQueue(); virtual ~RegWriteQueue();
public: public:
/** /**
Clear any samples stored in the queue. Clear any items stored in the queue.
*/ */
void clear(); void clear();
/** /**
Dequeue the upto the specified number of samples and store them Dequeue the first object in the queue.
in the buffer. Returns the actual number of samples removed from
the queue.
@return the actual number of samples removed from the queue.
*/ */
uInt32 dequeue(uInt8* buffer, uInt32 size); void dequeue();
/** /**
Enqueue the specified number of samples from the buffer. Return the duration of all the items in the queue.
*/ */
void enqueue(uInt8* buffer, uInt32 size); double duration();
/** /**
Answers the number of samples currently in the queue. Enqueue the specified object.
*/
void enqueue(const RegWrite& info);
@return The number of samples in the queue. /**
Return the item at the front on the queue.
@return The item at the front of the queue.
*/
RegWrite& front();
/**
Answers the number of items currently in the queue.
@return The number of items in the queue.
*/ */
uInt32 size() const; uInt32 size() const;
/** private:
Answers the maximum number of samples the queue can hold. // Increase the size of the queue
void grow();
@return The maximum number of samples in the queue.
*/
uInt32 capacity() const { return myCapacity; }
private: private:
const uInt32 myCapacity; uInt32 myCapacity;
uInt8* myBuffer; RegWrite* myBuffer;
uInt32 mySize; uInt32 mySize;
uInt32 myHead; uInt32 myHead;
uInt32 myTail; uInt32 myTail;
}; };
private: private:
// Current volume
uInt32 myCurrentVolume;
// SDL fragment size
uInt32 myFragmentSize;
// Audio specification structure // Audio specification structure
SDL_AudioSpec myHardwareSpec; SDL_AudioSpec myHardwareSpec;
@ -187,14 +194,11 @@ class SoundSDL : public Sound
// Indicates if the sound is currently muted // Indicates if the sound is currently muted
bool myIsMuted; bool myIsMuted;
// DSP sample rate // Current volume as a percentage (0 - 100)
uInt32 mySampleRate; uInt32 myVolume;
// The sample queue size (which is auto-adapting) // Queue of TIA register writes
uInt32 mySampleQueueSize; RegWriteQueue myRegWriteQueue;
// Queue which holds samples from the media source before they are played
SampleQueue mySampleQueue;
private: private:
// Callback function invoked by the SDL Audio library when it needs data // Callback function invoked by the SDL Audio library when it needs data