diff --git a/stella/src/emucore/Console.cxx b/stella/src/emucore/Console.cxx index b10df7836..6ff6c0c53 100644 --- a/stella/src/emucore/Console.cxx +++ b/stella/src/emucore/Console.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: Console.cxx,v 1.22 2003-12-04 19:18:45 stephena Exp $ +// $Id: Console.cxx,v 1.23 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #include @@ -155,7 +155,7 @@ Console::Console(const uInt8* image, uInt32 size, const char* filename, } M6532* m6532 = new M6532(*this); - TIA* tia = new TIA(*this, mySound.getSampleRate()); + TIA* tia = new TIA(*this, mySound); Cartridge* cartridge = Cartridge::create(image, size, myProperties); mySystem->attach(m6502); @@ -207,7 +207,7 @@ Console::~Console() void Console::update() { myFrameBuffer.update(); - mySound.update(); +// FIXME mySound.update(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/stella/src/emucore/MediaSrc.hxx b/stella/src/emucore/MediaSrc.hxx index 2e8392ccf..b4a9b5a47 100644 --- a/stella/src/emucore/MediaSrc.hxx +++ b/stella/src/emucore/MediaSrc.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: MediaSrc.hxx,v 1.6 2003-10-26 19:40:39 stephena Exp $ +// $Id: MediaSrc.hxx,v 1.7 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #ifndef MEDIASOURCE_HXX @@ -29,7 +29,7 @@ class MediaSource; This class provides an interface for accessing graphics and audio data. @author Bradford W. Mott - @version $Id: MediaSrc.hxx,v 1.6 2003-10-26 19:40:39 stephena Exp $ + @version $Id: MediaSrc.hxx,v 1.7 2004-04-04 02:03:15 stephena Exp $ */ class MediaSource { @@ -99,6 +99,7 @@ class MediaSource virtual uInt32 scanlines() const = 0; public: +#if 0 //FIXME /** Enumeration of the possible audio sample types. */ @@ -138,6 +139,7 @@ class MediaSource @return The type of audio sample stored in the sample queue. */ virtual AudioSampleType typeOfAudioSamples() const = 0; +#endif private: // Copy constructor isn't supported by this class so make it private diff --git a/stella/src/emucore/Serializer.cxx b/stella/src/emucore/Serializer.cxx index d83ddca3f..87a766baf 100644 --- a/stella/src/emucore/Serializer.cxx +++ b/stella/src/emucore/Serializer.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: Serializer.cxx,v 1.2 2002-08-11 17:48:13 stephena Exp $ +// $Id: Serializer.cxx,v 1.3 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #include @@ -68,7 +68,7 @@ void Serializer::putLong(long value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Serializer::putString(string& str) +void Serializer::putString(const string& str) { int len = str.length(); putLong(len); diff --git a/stella/src/emucore/Serializer.hxx b/stella/src/emucore/Serializer.hxx index c7162d394..a81f30099 100644 --- a/stella/src/emucore/Serializer.hxx +++ b/stella/src/emucore/Serializer.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: Serializer.hxx,v 1.4 2002-08-11 17:48:13 stephena Exp $ +// $Id: Serializer.hxx,v 1.5 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #ifndef SERIALIZER_HXX @@ -33,7 +33,7 @@ Boolean values are written using a special pattern. @author Stephen Anthony - @version $Id: Serializer.hxx,v 1.4 2002-08-11 17:48:13 stephena Exp $ + @version $Id: Serializer.hxx,v 1.5 2004-04-04 02:03:15 stephena Exp $ */ class Serializer { @@ -78,7 +78,7 @@ class Serializer @param str The string to write to the output stream. */ - void putString(string& str); + void putString(const string& str); /** Writes a boolean value to the current output stream. diff --git a/stella/src/emucore/Settings.cxx b/stella/src/emucore/Settings.cxx index 9811d061e..cb9610100 100644 --- a/stella/src/emucore/Settings.cxx +++ b/stella/src/emucore/Settings.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: Settings.cxx,v 1.17 2004-04-03 18:54:22 stephena Exp $ +// $Id: Settings.cxx,v 1.18 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #include @@ -46,6 +46,8 @@ Settings::Settings() set("gl_aspect", "2"); #endif set("sound", "true"); + set("fragsize", "512"); + set("bufsize", "1536"); set("fullscreen", "false"); set("grabmouse", "false"); set("hidecursor", "false"); diff --git a/stella/src/emucore/Sound.cxx b/stella/src/emucore/Sound.cxx index ad322ce96..c1f5f73b7 100644 --- a/stella/src/emucore/Sound.cxx +++ b/stella/src/emucore/Sound.cxx @@ -13,13 +13,16 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: Sound.cxx,v 1.8 2003-11-19 15:57:10 stephena Exp $ +// $Id: Sound.cxx,v 1.9 2004-04-04 02:03:15 stephena Exp $ //============================================================================ +#include "Serializer.hxx" +#include "Deserializer.hxx" + #include "Sound.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Sound::Sound() +Sound::Sound(uInt32 fragsize, uInt32 queuesize) : myPauseStatus(false) { } @@ -36,17 +39,6 @@ void Sound::init(Console* console, MediaSource* mediasrc) myMediaSource = mediasrc; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Sound::closeDevice() -{ -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 Sound::getSampleRate() const -{ - return 0; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Sound::isSuccessfullyInitialized() const { @@ -62,3 +54,42 @@ void Sound::setVolume(Int32 volume) void Sound::update() { } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Sound::set(uInt16 addr, uInt8 value) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Sound::save(Serializer& out) +{ + out.putString("TIASound"); + + uInt8 reg = 0; + out.putLong(reg); + out.putLong(reg); + out.putLong(reg); + out.putLong(reg); + out.putLong(reg); + out.putLong(reg); + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Sound::load(Deserializer& in) +{ + string soundDevice = "TIASound"; + if(in.getString() != soundDevice) + return false; + + uInt8 reg; + reg = (uInt8) in.getLong(); + reg = (uInt8) in.getLong(); + reg = (uInt8) in.getLong(); + reg = (uInt8) in.getLong(); + reg = (uInt8) in.getLong(); + reg = (uInt8) in.getLong(); + + return true; +} diff --git a/stella/src/emucore/Sound.hxx b/stella/src/emucore/Sound.hxx index 40c07968c..8a12bb00c 100644 --- a/stella/src/emucore/Sound.hxx +++ b/stella/src/emucore/Sound.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: Sound.hxx,v 1.8 2003-11-19 15:57:10 stephena Exp $ +// $Id: Sound.hxx,v 1.9 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #ifndef SOUND_HXX @@ -21,6 +21,8 @@ class Console; class MediaSource; +class Serializer; +class Deserializer; #include "bspf.hxx" @@ -30,7 +32,7 @@ class MediaSource; to compile Stella with no sound support whatsoever. @author Stephen Anthony - @version $Id: Sound.hxx,v 1.8 2003-11-19 15:57:10 stephena Exp $ + @version $Id: Sound.hxx,v 1.9 2004-04-04 02:03:15 stephena Exp $ */ class Sound { @@ -38,7 +40,7 @@ class Sound /** Create a new sound object */ - Sound(); + Sound(uInt32 fragsize = 0, uInt32 queuesize = 0); /** Destructor @@ -55,18 +57,6 @@ class Sound */ void init(Console* console, MediaSource* mediasrc); - /** - Closes the sound device - */ - virtual void closeDevice(); - - /** - Return the playback sample rate for the sound device. - - @return The playback sample rate - */ - virtual uInt32 getSampleRate() const; - /** Return true iff the sound device was successfully initialized. @@ -84,11 +74,34 @@ class Sound virtual void setVolume(Int32 percent); /** - Update the sound device using the audio sample from the - media source. + Update the sound device with audio samples. */ virtual void update(); + /** + Sets the sound register to a given value. + + @param addr The register address + @param value The value to save into the register + */ + virtual void set(uInt16 addr, uInt8 value); + + /** + Saves the current state of this device to the given Serializer. + + @param out The serializer device to save to. + @return The result of the save. True on success, false on failure. + */ + virtual bool save(Serializer& out); + + /** + 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. + */ + virtual bool load(Deserializer& in); + /** Sets the pause status. While pause is selected, update() should not play any sound. diff --git a/stella/src/emucore/TIA.cxx b/stella/src/emucore/TIA.cxx index 4bf16da92..d8ee7d340 100644 --- a/stella/src/emucore/TIA.cxx +++ b/stella/src/emucore/TIA.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIA.cxx,v 1.26 2003-12-04 19:18:45 stephena Exp $ +// $Id: TIA.cxx,v 1.27 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #include @@ -29,27 +29,21 @@ #include "Serializer.hxx" #include "Deserializer.hxx" #include "Settings.hxx" -#include "TIASound.h" +#include "Sound.hxx" #define HBLANK 68 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -TIA::TIA(const Console& console, uInt32 sampleRate) +TIA::TIA(const Console& console, Sound& sound) : myConsole(console), - myLastSoundUpdateCycle(0), + mySound(sound), + myLastSoundUpdateCycle(0), // FIXME this may disappear myColorLossEnabled(false), myCOLUBK(myColor[0]), myCOLUPF(myColor[1]), myCOLUP0(myColor[2]), - myCOLUP1(myColor[3]), - mySampleQueue(sampleRate), - mySampleRate(sampleRate) + myCOLUP1(myColor[3]) { - if(mySampleRate != 0) - { - Tia_sound_init(31400, mySampleRate); - } - // Allocate buffers for two frame buffers myCurrentFrameBuffer = new uInt8[160 * 300]; myPreviousFrameBuffer = new uInt8[160 * 300]; @@ -365,22 +359,8 @@ bool TIA::save(Serializer& out) out.putBool(myDumpEnabled); out.putLong(myDumpDisabledCycle); - // Save the sample stuff ... - string soundDevice = "TIASound"; - out.putString(soundDevice); - - uInt8 reg1 = 0, reg2 = 0, reg3 = 0, reg4 = 0, reg5 = 0, reg6 = 0; - - // Only get the TIA sound registers if sound is enabled - if(mySampleRate != 0) - Tia_get_registers(®1, ®2, ®3, ®4, ®5, ®6); - - out.putLong(reg1); - out.putLong(reg2); - out.putLong(reg3); - out.putLong(reg4); - out.putLong(reg5); - out.putLong(reg6); + // Save the sound sample stuff ... + mySound.save(out); } catch(char *msg) { @@ -476,22 +456,8 @@ bool TIA::load(Deserializer& in) myDumpEnabled = in.getBool(); myDumpDisabledCycle = (Int32) in.getLong(); - // Load the sample stuff ... - string soundDevice = "TIASound"; - if(in.getString() != soundDevice) - 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(); - - // Only update the TIA sound registers if sound is enabled - if(mySampleRate != 0) - Tia_set_registers(reg1, reg2, reg3, reg4, reg5, reg6); + // Load the sound sample stuff ... + mySound.load(in); } catch(char *msg) { @@ -558,9 +524,6 @@ void TIA::update() // TODO: have code here that handles errors.... - // Make sure all of the audio samples have been created - createAudioSamples(0, 0); - // Compute the number of scanlines in the frame uInt32 totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted; myScanlineCountForLastFrame = totalClocks / 228; @@ -601,30 +564,6 @@ uInt32 TIA::scanlines() const return (uInt32)myScanlineCountForLastFrame; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::clearAudioSamples() -{ - mySampleQueue.clear(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 TIA::dequeueAudioSamples(uInt8* buffer, int size) -{ - return mySampleQueue.dequeue(buffer, size); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 TIA::numberOfAudioSamples() const -{ - return mySampleQueue.size(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -MediaSource::AudioSampleType TIA::typeOfAudioSamples() const -{ - return MediaSource::UNSIGNED_8BIT_MONO_AUDIO; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::computeBallMaskTable() { @@ -1696,6 +1635,9 @@ inline void TIA::updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos) } } myFramePointer = ending; + + // Add sound bytes to the sound queue every scanline + mySound.update(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2402,37 +2344,37 @@ void TIA::poke(uInt16 addr, uInt8 value) case 0x15: // Audio control 0 { - createAudioSamples(addr, value); + mySound.set(addr, value); break; } case 0x16: // Audio control 1 { - createAudioSamples(addr, value); + mySound.set(addr, value); break; } case 0x17: // Audio frequency 0 { - createAudioSamples(addr, value); + mySound.set(addr, value); break; } case 0x18: // Audio frequency 1 { - createAudioSamples(addr, value); + mySound.set(addr, value); break; } case 0x19: // Audio volume 0 { - createAudioSamples(addr, value); + mySound.set(addr, value); break; } case 0x1A: // Audio volume 1 { - createAudioSamples(addr, value); + mySound.set(addr, value); break; } @@ -2761,42 +2703,6 @@ void TIA::poke(uInt16 addr, uInt8 value) } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::createAudioSamples(uInt16 addr, uInt8 value) -{ - // If the sample rate is zero then we should not create any audio samples - if(mySampleRate == 0) - { - return; - } - - // Calculate the number of samples that need to be generated based on the - // number of CPU cycles which have passed since the last sound update - uInt32 samplesToGenerate = - (mySampleRate * (mySystem->cycles() - myLastSoundUpdateCycle)) / 1190000; - - // Update counters and create samples if there's one sample to generate - // TODO: This doesn't handle rounding quite right (10/08/2002) - if(samplesToGenerate >= 1) - { - uInt8 buffer[1024]; - - for(Int32 sg = (Int32)samplesToGenerate; sg > 0; sg -= 1024) - { - Tia_process(buffer, ((sg >= 1024) ? 1024 : sg)); - mySampleQueue.enqueue(buffer, ((sg >= 1024) ? 1024 : sg)); - } - - myLastSoundUpdateCycle = myLastSoundUpdateCycle + - ((samplesToGenerate * 1190000) / mySampleRate); - } - - if(addr != 0) - { - Update_tia_sound(addr, value); - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::ourBallMaskTable[4][4][320]; @@ -3232,11 +3138,11 @@ const uInt32 TIA::ourPALPaletteZ26[256] = { 0 }; // FIXME // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA::TIA(const TIA& c) : myConsole(c.myConsole), + mySound(c.mySound), myCOLUBK(myColor[0]), myCOLUPF(myColor[1]), myCOLUP0(myColor[2]), - myCOLUP1(myColor[3]), - mySampleQueue(1024) + myCOLUP1(myColor[3]) { assert(false); } @@ -3248,96 +3154,3 @@ TIA& TIA::operator = (const TIA&) return *this; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -TIA::SampleQueue::SampleQueue(uInt32 capacity) - : myCapacity(capacity), - myBuffer(0), - mySize(0), - myHead(0), - myTail(0) -{ - myBuffer = new uInt8[myCapacity]; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -TIA::SampleQueue::~SampleQueue() -{ - delete[] myBuffer; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::SampleQueue::clear() -{ - myHead = myTail = mySize = 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 TIA::SampleQueue::dequeue(uInt8* buffer, uInt32 size) -{ - // We can only dequeue up to the number of items in the queue - if(size > mySize) - { - size = 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 TIA::SampleQueue::enqueue(uInt8* buffer, uInt32 size) -{ - // If an attempt is made to enqueue more than the queue can hold then - // we'll only enqueue the last myCapacity elements. - if(size > myCapacity) - { - buffer += (size - myCapacity); - size = myCapacity; - } - - if((myTail + size) < myCapacity) - { - memcpy((void*)(myBuffer + myTail), (const void*)buffer, size); - 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 TIA::SampleQueue::size() const -{ - return mySize; -} diff --git a/stella/src/emucore/TIA.hxx b/stella/src/emucore/TIA.hxx index a7d6d598f..43626dd29 100644 --- a/stella/src/emucore/TIA.hxx +++ b/stella/src/emucore/TIA.hxx @@ -13,13 +13,14 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIA.hxx,v 1.11 2003-12-04 19:18:45 stephena Exp $ +// $Id: TIA.hxx,v 1.12 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #ifndef TIA_HXX #define TIA_HXX class Console; +class Sound; class System; class Serializer; class Deserializer; @@ -39,11 +40,10 @@ class Deserializer; and composite sync required by a video modulator. This class outputs the serial data into a frame buffer which can then - be displayed on screen it also creates audio samples and places them - in a bounded queue. + be displayed on screen. @author Bradford W. Mott - @version $Id: TIA.hxx,v 1.11 2003-12-04 19:18:45 stephena Exp $ + @version $Id: TIA.hxx,v 1.12 2004-04-04 02:03:15 stephena Exp $ */ class TIA : public Device , public MediaSource { @@ -52,9 +52,9 @@ class TIA : public Device , public MediaSource Create a new TIA for the specified console @param console The console the TIA is associated with - @param sampleRate The sample rate to create audio samples at + @param sound The sound object the TIA is associated with */ - TIA(const Console& console, uInt32 sampleRate); + TIA(const Console& console, Sound& sound); /** Destructor @@ -171,38 +171,6 @@ class TIA : public Device , public MediaSource */ uInt32 scanlines() const; - /** - Dequeues all of the samples in the audio sample queue. - */ - void clearAudioSamples(); - - /** - Dequeues up to the specified number of samples from the audio sample - queue into the buffer. If the requested number of samples are not - available then all of samples are dequeued. The method returns the - actual number of samples removed from the queue. - - @return The actual number of samples which were dequeued. - */ - uInt32 dequeueAudioSamples(uInt8* buffer, int size); - - /** - Answers the number of samples currently available in the audio - sample queue. - - @return The number of samples in the audio sample queue. - */ - uInt32 numberOfAudioSamples() const; - - /** - Returns the type of audio samples which are being stored in the audio - sample queue. Currently, only unsigned 8-bit audio samples are created, - however, in the future this will be extended to support stereo samples. - - @return The type of audio sample stored in the sample queue. - */ - MediaSource::AudioSampleType typeOfAudioSamples() const; - private: // Compute the ball mask table void computeBallMaskTable(); @@ -235,69 +203,13 @@ class TIA : public Device , public MediaSource // Waste cycles until the current scanline is finished void waitHorizontalSync(); - private: - /** - A bounded queue class used to hold audio samples after they are - produced by the TIA sound emulation. - */ - class SampleQueue - { - public: - /** - Create a new SampleQueue instance which can hold the specified - number of samples. If the queue ever reaches its capacity then - older samples are discarded. - */ - SampleQueue(uInt32 capacity); - - /** - Destroy this SampleQueue instance. - */ - virtual ~SampleQueue(); - - public: - /** - Clear any samples stored in the queue. - */ - void clear(); - - /** - Dequeue the upto the specified number of samples and store them - 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); - - /** - Enqueue the specified number of samples from the buffer. - */ - void enqueue(uInt8* buffer, uInt32 size); - - /** - Answers the number of samples currently in the queue. - - @return The number of samples in the queue. - */ - uInt32 size() const; - - private: - const uInt32 myCapacity; - uInt8* myBuffer; - uInt32 mySize; - uInt32 myHead; - uInt32 myTail; - }; - - // Invoked to create and store audio samples into the sample queue - // whenever a TIA audio register is changed or a frame is finished - void createAudioSamples(uInt16 addr, uInt8 value); - private: // Console the TIA is associated with const Console& myConsole; + // Sound object the TIA is associated with + Sound& mySound; + private: // Indicates the CPU cycle when a TIA sound register was last updated Int32 myLastSoundUpdateCycle; @@ -489,13 +401,6 @@ class TIA : public Device , public MediaSource // Counter used for TIA M0 "bug" uInt32 myM0CosmicArkCounter; - private: - // Sample queue instance for storing audio samples - SampleQueue mySampleQueue; - - // Sample rate requested for the audio samples - uInt32 mySampleRate; - private: // Ball mask table (entries are true or false) static uInt8 ourBallMaskTable[4][4][320]; diff --git a/stella/src/ui/sdl/FrameBufferGL.cxx b/stella/src/ui/sdl/FrameBufferGL.cxx index cb24cf539..15c598892 100644 --- a/stella/src/ui/sdl/FrameBufferGL.cxx +++ b/stella/src/ui/sdl/FrameBufferGL.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: FrameBufferGL.cxx,v 1.13 2003-12-10 18:58:56 stephena Exp $ +// $Id: FrameBufferGL.cxx,v 1.14 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #include @@ -371,13 +371,13 @@ bool FrameBufferGL::createTextures() { myFilterParam = GL_LINEAR; if(showinfo) - cout << "Using GL_LINEAR filtering.\n\n"; + cout << "Using GL_LINEAR filtering.\n"; } else if(filter == "nearest") { myFilterParam = GL_NEAREST; if(showinfo) - cout << "Using GL_NEAREST filtering.\n\n"; + cout << "Using GL_NEAREST filtering.\n"; } glGenTextures(1, &myTextureID); diff --git a/stella/src/ui/sdl/SettingsUNIX.cxx b/stella/src/ui/sdl/SettingsUNIX.cxx index e9dab400d..7051cff30 100644 --- a/stella/src/ui/sdl/SettingsUNIX.cxx +++ b/stella/src/ui/sdl/SettingsUNIX.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: SettingsUNIX.cxx,v 1.7 2004-04-03 18:54:23 stephena Exp $ +// $Id: SettingsUNIX.cxx,v 1.8 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #include @@ -87,6 +87,8 @@ void SettingsUNIX::usage(string& message) << endl #endif << " -sound <0|1> Enable sound generation\n" + << " -fragsize The size of sound fragments (should be a power of two)\n" + << " -bufsize The size of the sound buffer\n" << " -framerate Display the given number of frames per second\n" << " -zoom Makes window be 'size' times normal\n" << " -fullscreen <0|1> Play the game in fullscreen mode\n" diff --git a/stella/src/ui/sdl/SettingsWin32.cxx b/stella/src/ui/sdl/SettingsWin32.cxx index a3e4debfc..521d6ed5a 100644 --- a/stella/src/ui/sdl/SettingsWin32.cxx +++ b/stella/src/ui/sdl/SettingsWin32.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: SettingsWin32.cxx,v 1.2 2004-04-03 18:54:23 stephena Exp $ +// $Id: SettingsWin32.cxx,v 1.3 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #include @@ -93,6 +93,8 @@ void SettingsWin32::usage(string& message) << endl #endif << " -sound <0|1> Enable sound generation\n" + << " -fragsize The size of sound fragments (should be a power of two)\n" + << " -bufsize The size of the sound buffer\n" << " -framerate Display the given number of frames per second\n" << " -zoom Makes window be 'size' times normal\n" << " -fullscreen <0|1> Play the game in fullscreen mode\n" diff --git a/stella/src/ui/sdl/mainSDL.cxx b/stella/src/ui/sdl/mainSDL.cxx index 150ee6a6d..d060d59f7 100644 --- a/stella/src/ui/sdl/mainSDL.cxx +++ b/stella/src/ui/sdl/mainSDL.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: mainSDL.cxx,v 1.68 2004-04-03 18:54:23 stephena Exp $ +// $Id: mainSDL.cxx,v 1.69 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #include @@ -637,10 +637,7 @@ void cleanup() delete theConsole; if(theSound) - { - theSound->closeDevice(); delete theSound; - } if(theDisplay) delete theDisplay; @@ -693,7 +690,7 @@ int main(int argc, char* argv[]) #if defined(UNIX) setenv("SDL_VIDEO_CENTERED", "1", 1); #else - putenv("SDL_VIDEO_CENTERED"); + putenv("SDL_VIDEO_CENTERED=1"); #endif // Get a pointer to the file which contains the cartridge ROM @@ -756,9 +753,14 @@ int main(int argc, char* argv[]) // Create a sound object for playing audio if(theSettings->getBool("sound")) { - theSound = new SoundSDL(); + uInt32 fragsize = theSettings->getInt("fragsize"); + uInt32 bufsize = theSettings->getInt("bufsize"); + theSound = new SoundSDL(fragsize, bufsize); if(theShowInfoFlag) - cout << "Sound enabled.\n"; + { + cout << "Sound enabled, using fragment size = " << fragsize; + cout << " and buffer size = " << bufsize << "." << endl; + } } else // even if sound has been disabled, we still need a sound object { diff --git a/stella/src/ui/sound/SoundSDL.cxx b/stella/src/ui/sound/SoundSDL.cxx index 553c75d4a..51c384f95 100644 --- a/stella/src/ui/sound/SoundSDL.cxx +++ b/stella/src/ui/sound/SoundSDL.cxx @@ -13,22 +13,25 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: SoundSDL.cxx,v 1.6 2003-12-04 22:22:53 stephena Exp $ +// $Id: SoundSDL.cxx,v 1.7 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #include +#include "TIASound.h" +#include "Serializer.hxx" +#include "Deserializer.hxx" + #include "SoundSDL.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -SoundSDL::SoundSDL() +SoundSDL::SoundSDL(uInt32 fragsize, uInt32 queuesize) : myCurrentVolume(SDL_MIX_MAXVOLUME), - myFragmentSize(2048), + myFragmentSize(fragsize), myIsInitializedFlag(false), myIsMuted(false), mySampleRate(31400), - mySampleQueueSize(8000), - mySampleQueue(mySampleQueueSize)//mySampleRate) + mySampleQueue(queuesize) { if(1) { @@ -85,6 +88,10 @@ SoundSDL::SoundSDL() // cerr << "Samples: " << (int)myHardwareSpec.samples << endl; // cerr << "Size: " << (int)myHardwareSpec.size << endl; + // Now initialize the TIASound object which will actually generate sound + Tia_sound_init(31400, mySampleRate); + + // And start the SDL sound subsystem ... SDL_PauseAudio(0); } else @@ -98,13 +105,12 @@ SoundSDL::SoundSDL() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL::~SoundSDL() { - closeDevice(); -} + if(myIsInitializedFlag) + { + SDL_CloseAudio(); + } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 SoundSDL::getSampleRate() const -{ - return myIsInitializedFlag ? mySampleRate : 0; + myIsInitializedFlag = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -132,17 +138,6 @@ void SoundSDL::mute(bool state) SDL_PauseAudio(myIsMuted ? 1 : 0); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void SoundSDL::closeDevice() -{ - if(myIsInitializedFlag) - { - SDL_CloseAudio(); - } - - myIsInitializedFlag = false; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::setVolume(Int32 percent) { @@ -164,46 +159,101 @@ void SoundSDL::setVolume(Int32 percent) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::update() { - if(myIsInitializedFlag) - { - if(myPauseStatus) - return; + if(!myPauseStatus && myIsInitializedFlag) + { // Make sure we have exclusive access to the sample queue SDL_LockAudio(); - // Move all of the generated samples into the our private sample queue - uInt8 buffer[2048]; - while(myMediaSource->numberOfAudioSamples() > 0) - { - uInt32 size = myMediaSource->dequeueAudioSamples(buffer, 2048); - mySampleQueue.enqueue(buffer, size); - } + // Generate enough samples to keep the sample queue full to capacity + uInt32 numbytes = mySampleQueue.capacity() - mySampleQueue.size(); + uInt8 buffer[numbytes]; + Tia_process(buffer, numbytes); + mySampleQueue.enqueue(buffer, numbytes); // Release lock on the sample queue SDL_UnlockAudio(); - - // Block until the sound thread has consumed all but 142 milliseconds - // of the available audio samples - uInt32 left = mySampleRate / 3; - for(;;) - { - uInt32 size = 0; - - SDL_LockAudio(); - size = mySampleQueue.size(); - SDL_UnlockAudio(); - - if(size < left) - { - break; - } - - SDL_Delay(1); - } } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void SoundSDL::set(uInt16 addr, uInt8 value) +{ + Update_tia_sound(addr, value); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool SoundSDL::save(Serializer& out) +{ + string device = "TIASound"; + + try + { + out.putString(device); + + uInt8 reg1 = 0, reg2 = 0, reg3 = 0, reg4 = 0, reg5 = 0, reg6 = 0; + + // Only get the TIA sound registers if sound is enabled + if(myIsInitializedFlag) + Tia_get_registers(®1, ®2, ®3, ®4, ®5, ®6); + + out.putLong(reg1); + out.putLong(reg2); + out.putLong(reg3); + out.putLong(reg4); + out.putLong(reg5); + out.putLong(reg6); + } + catch(char *msg) + { + cerr << msg << endl; + return false; + } + catch(...) + { + cerr << "Unknown error in save state for " << device << endl; + return false; + } + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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(); + + // 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) { @@ -214,14 +264,6 @@ void SoundSDL::callback(void* udata, uInt8* stream, int len) return; } - // Don't use samples unless there's at least 76 milliseconds worth of data - if(sound->mySampleQueue.size() < (sound->mySampleRate / 16)) - { - return; - } - -//cerr << "len: " << len << " Q.size: " << sound->mySampleQueue.size() << endl; - if(sound->mySampleQueue.size() > 0) { Int32 offset; @@ -328,4 +370,3 @@ uInt32 SoundSDL::SampleQueue::size() const { return mySize; } - diff --git a/stella/src/ui/sound/SoundSDL.hxx b/stella/src/ui/sound/SoundSDL.hxx index be52e91e4..815ca54cc 100644 --- a/stella/src/ui/sound/SoundSDL.hxx +++ b/stella/src/ui/sound/SoundSDL.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: SoundSDL.hxx,v 1.6 2003-12-04 22:22:53 stephena Exp $ +// $Id: SoundSDL.hxx,v 1.7 2004-04-04 02:03:15 stephena Exp $ //============================================================================ #ifndef SOUNDSDL_HXX @@ -29,7 +29,7 @@ This class implements the sound API for SDL. @author Stephen Anthony and Bradford W. Mott - @version $Id: SoundSDL.hxx,v 1.6 2003-12-04 22:22:53 stephena Exp $ + @version $Id: SoundSDL.hxx,v 1.7 2004-04-04 02:03:15 stephena Exp $ */ class SoundSDL : public Sound { @@ -37,7 +37,7 @@ class SoundSDL : public Sound /** Create a new sound object */ - SoundSDL(); + SoundSDL(uInt32 fragsize, uInt32 queuesize); /** Destructor @@ -81,11 +81,34 @@ class SoundSDL : public Sound void setVolume(Int32 percent); /** - Update the sound device using the audio sample from the - media source. + Generates audio samples to fill the sample queue. */ void update(); + /** + Sets the sound register to a given value. + + @param addr The register address + @param value The value to save into the register + */ + void set(uInt16 addr, uInt8 value); + + /** + Saves the current state of this device to the given Serializer. + + @param out The serializer device to save to. + @return The result of the save. True on success, false on failure. + */ + bool save(Serializer& out); + + /** + 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); + private: /** A bounded queue class used to hold audio samples after they are @@ -133,6 +156,13 @@ class SoundSDL : public Sound */ uInt32 size() const; + /** + Answers the maximum number of samples the queue can hold. + + @return The maximum number of samples in the queue. + */ + uInt32 capacity() const { return myCapacity; } + private: const uInt32 myCapacity; uInt8* myBuffer;