From 1f45ed97449785725c013a921821636689d9a6b0 Mon Sep 17 00:00:00 2001 From: stephena Date: Sun, 4 Apr 2004 02:03:15 +0000 Subject: [PATCH] - Major changes across the board with respect to sound. The sound code has basically been reverted to 1.2 functionality. The good news is that the video and audio are always in sync, even in Windows. The bad news is that we've lost advanced sound in Pitfall2. I know what's required to fix it, but I'm seriously considering doing a new release and waiting until the release after that to fix it. Right now (with release 1.3), most games have laggy sound, even under Linux, but the background music in Pitfall2 is there. I'd rather do a new release with Pitfall2 not completely working, but having everything else working great, than wait another month or two. I'm sure most people will agree ... - The Windows port has some slight popping every now and then. Damn, I really hate Windows sound programming. It just can't handle low-latency sound generation as well as Linux (shameless plug). - Added options '-fragsize' and '-bufsize', which set the sound fragment and buffer sizes, respectively. They're currently set to 512 and 1536, and this seems to work best. - Fixed an error in calling 'putenv' in mainSDL. Now the Windows port actually starts with the game window centered. - Finally, IMHO (baring Pitfall2) Stella now works better wrt A/V sync on Linux than z26 does on Windows (a bit of friendly competition :) git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@232 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- stella/src/emucore/Console.cxx | 6 +- stella/src/emucore/MediaSrc.hxx | 6 +- stella/src/emucore/Serializer.cxx | 4 +- stella/src/emucore/Serializer.hxx | 6 +- stella/src/emucore/Settings.cxx | 4 +- stella/src/emucore/Sound.cxx | 57 +++++-- stella/src/emucore/Sound.hxx | 47 +++--- stella/src/emucore/TIA.cxx | 229 +++------------------------- stella/src/emucore/TIA.hxx | 113 ++------------ stella/src/ui/sdl/FrameBufferGL.cxx | 6 +- stella/src/ui/sdl/SettingsUNIX.cxx | 4 +- stella/src/ui/sdl/SettingsWin32.cxx | 4 +- stella/src/ui/sdl/mainSDL.cxx | 16 +- stella/src/ui/sound/SoundSDL.cxx | 163 ++++++++++++-------- stella/src/ui/sound/SoundSDL.hxx | 40 ++++- 15 files changed, 274 insertions(+), 431 deletions(-) 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;