- 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
This commit is contained in:
stephena 2004-04-04 02:03:15 +00:00
parent 7c5ebdddf3
commit 1f45ed9744
15 changed files with 274 additions and 431 deletions

View File

@ -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 <assert.h>
@ -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();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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

View File

@ -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 <iostream>
@ -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);

View File

@ -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.

View File

@ -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 <cassert>
@ -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");

View File

@ -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;
}

View File

@ -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.

View File

@ -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 <cassert>
@ -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(&reg1, &reg2, &reg3, &reg4, &reg5, &reg6);
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;
}

View File

@ -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];

View File

@ -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 <SDL.h>
@ -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);

View File

@ -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 <cstdlib>
@ -87,6 +87,8 @@ void SettingsUNIX::usage(string& message)
<< endl
#endif
<< " -sound <0|1> Enable sound generation\n"
<< " -fragsize <number> The size of sound fragments (should be a power of two)\n"
<< " -bufsize <number> The size of the sound buffer\n"
<< " -framerate <number> Display the given number of frames per second\n"
<< " -zoom <size> Makes window be 'size' times normal\n"
<< " -fullscreen <0|1> Play the game in fullscreen mode\n"

View File

@ -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 <cstdlib>
@ -93,6 +93,8 @@ void SettingsWin32::usage(string& message)
<< endl
#endif
<< " -sound <0|1> Enable sound generation\n"
<< " -fragsize <number> The size of sound fragments (should be a power of two)\n"
<< " -bufsize <number> The size of the sound buffer\n"
<< " -framerate <number> Display the given number of frames per second\n"
<< " -zoom <size> Makes window be 'size' times normal\n"
<< " -fullscreen <0|1> Play the game in fullscreen mode\n"

View File

@ -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 <fstream>
@ -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
{

View File

@ -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 <SDL.h>
#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(&reg1, &reg2, &reg3, &reg4, &reg5, &reg6);
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;
}

View File

@ -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;