mirror of https://github.com/stella-emu/stella.git
A number of files have been updated, added, or removed to implement a
new sound mechanism for Stella. The TIASound library is now part of the emulation core and each time a frame is created a corresponding set of audio samples is added to a bounded queue. The GUIs are responsible for getting the samples from the MediaSource object after each update and sending them to a sound driver as needed. Currently, only the X11 port has been updated to use the new API. The new APIs are not backwards compatible so the other GUIs will not compile until they are updated. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@114 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
9d758a41b6
commit
36a5c1575d
|
@ -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: makefile,v 1.21 2002-08-15 00:29:39 stephena Exp $
|
||||
## $Id: makefile,v 1.22 2002-10-09 04:38:11 bwmott Exp $
|
||||
##============================================================================
|
||||
|
||||
##============================================================================
|
||||
|
@ -150,11 +150,11 @@ dos:
|
|||
OPTIONS+="$(OPTS.DOS)" \
|
||||
LDFLAGS="" \
|
||||
LDLIBS="" \
|
||||
OBJS="mainDOS.o PCJoys.o SndDOS.o sbdrv.o TIASound.o"
|
||||
OBJS="mainDOS.o PCJoys.o SndDOS.o sbdrv.o"
|
||||
|
||||
unix-x:
|
||||
make stella.x11 \
|
||||
INCLUDES="$(INCLUDES) -I$(UI)/x11 -I$(UI)/sound" \
|
||||
INCLUDES="$(INCLUDES) -I$(UI)/x11" \
|
||||
SYS_INCLUDES="" \
|
||||
OPTIONS="-DBSPF_UNIX=1" \
|
||||
OPTIONS+="$(OPTS.X11)" \
|
||||
|
@ -162,11 +162,11 @@ unix-x:
|
|||
LDFLAGS+="$(CFLAGS.X11)" \
|
||||
LDLIBS="-lX11 -lXext" \
|
||||
LDLIBS+="$(LIBS.X11)" \
|
||||
OBJS="mainX11.o SndUnix.o"
|
||||
OBJS="mainX11.o SoundX11.o"
|
||||
|
||||
linux-x:
|
||||
make stella.x11 \
|
||||
INCLUDES="$(INCLUDES) -I$(UI)/x11 -I$(UI)/sound" \
|
||||
INCLUDES="$(INCLUDES) -I$(UI)/x11" \
|
||||
SYS_INCLUDES="" \
|
||||
OPTIONS="-DBSPF_UNIX=1" \
|
||||
OPTIONS+="$(OPTS.X11)" \
|
||||
|
@ -174,7 +174,7 @@ linux-x:
|
|||
LDFLAGS+="$(CFLAGS.X11)" \
|
||||
LDLIBS="-lX11 -lXext" \
|
||||
LDLIBS+="$(LIBS.X11)" \
|
||||
OBJS="mainX11.o SndUnix.o" \
|
||||
OBJS="mainX11.o SoundX11.o" \
|
||||
OBJS+="$(OBJS.X11)"
|
||||
|
||||
linux-sdl:
|
||||
|
@ -187,11 +187,12 @@ linux-sdl:
|
|||
LDFLAGS+="$(CFLAGS.SDL)" \
|
||||
LDLIBS="-lX11 -lXext" \
|
||||
LDLIBS+="$(LIBS.SDL)" \
|
||||
OBJS="mainSDL.o SndSDL.o RectList.o TIASound.o" \
|
||||
OBJS="mainSDL.o SndSDL.o RectList.o" \
|
||||
OBJS+="$(OBJS.SDL)"
|
||||
|
||||
bsdi-x:
|
||||
make stella.x11 \
|
||||
INCLUDES="$(INCLUDES) -I$(UI)/x11 -I$(UI)/sound" \
|
||||
INCLUDES="$(INCLUDES) -I$(UI)/x11" \
|
||||
SYS_INCLUDES="-I/usr/X11R6/include" \
|
||||
OPTIONS="-DBSPF_UNIX=1" \
|
||||
OPTIONS+="$(OPTS.X11)" \
|
||||
|
@ -199,11 +200,11 @@ bsdi-x:
|
|||
LDFLAGS+="$(CFLAGS.X11)" \
|
||||
LDLIBS="-lX11 -lXext" \
|
||||
LDLIBS+="$(LIBS.X11)" \
|
||||
OBJS="mainX11.o SndUnix.o"
|
||||
OBJS="mainX11.o SoundX11.o"
|
||||
|
||||
solaris-x:
|
||||
make stella.x11 \
|
||||
INCLUDES="$(INCLUDES) -I$(UI)/x11 -I$(UI)/sound" \
|
||||
INCLUDES="$(INCLUDES) -I$(UI)/x11" \
|
||||
SYS_INCLUDES="-I/usr/openwin/include" \
|
||||
OPTIONS="-DBSPF_UNIX=1" \
|
||||
OPTIONS+="$(OPTS.X11)" \
|
||||
|
@ -211,7 +212,7 @@ solaris-x:
|
|||
LDFLAGS+="$(CFLAGS.X11)" \
|
||||
LDLIBS="-lX11 -lXext" \
|
||||
LDLIBS+="$(LIBS.X11)" \
|
||||
OBJS="mainX11.o SndUnix.o"
|
||||
OBJS="mainX11.o SoundX11.o"
|
||||
|
||||
###############################################################################
|
||||
## List of "core" object files
|
||||
|
@ -223,8 +224,8 @@ CORE_OBJS = Booster.o Cart.o Cart2K.o Cart3F.o Cart4K.o CartAR.o CartDPC.o \
|
|||
CartF8.o CartF8SC.o CartFASC.o CartFE.o CartMC.o CartCV.o \
|
||||
CartMB.o Console.o Control.o Driving.o \
|
||||
Event.o Joystick.o Keyboard.o M6532.o MD5.o MediaSrc.o Paddles.o \
|
||||
Props.o PropsSet.o Random.o Sound.o Switches.o Settings.o TIA.o \
|
||||
Serializer.o Deserializer.o \
|
||||
Props.o PropsSet.o Random.o Switches.o Settings.o TIA.o \
|
||||
Serializer.o Deserializer.o TIASound.o \
|
||||
$(M6502_OBJS)
|
||||
|
||||
stella.exe: $(CORE_OBJS) $(OBJS)
|
||||
|
@ -347,6 +348,9 @@ M6532.o: $(CORE)/M6532.cxx
|
|||
TIA.o: $(CORE)/TIA.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/TIA.cxx
|
||||
|
||||
TIASound.o: $(CORE)/TIASound.c
|
||||
$(CXX) -c -DWIN32 $(CXXFLAGS) $(OPTIONS) $(CORE)/TIASound.c
|
||||
|
||||
Console.o: $(CORE)/Console.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Console.cxx
|
||||
|
||||
|
@ -368,9 +372,6 @@ Random.o: $(CORE)/Random.cxx
|
|||
Switches.o: $(CORE)/Switches.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Switches.cxx
|
||||
|
||||
Sound.o: $(CORE)/Sound.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Sound.cxx
|
||||
|
||||
Serializer.o: $(CORE)/Serializer.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Serializer.cxx
|
||||
|
||||
|
@ -395,15 +396,15 @@ SndDOS.o: $(UI)/dos/SndDOS.cxx
|
|||
sbdrv.o: $(UI)/dos/sbdrv.c
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/dos/sbdrv.c
|
||||
|
||||
TIASound.o: $(UI)/sound/TIASound.c
|
||||
$(CXX) -c -DWIN32 $(CXXFLAGS) $(OPTIONS) $(UI)/sound/TIASound.c
|
||||
|
||||
TermX11.o: $(UI)/x11/TermX11.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/x11/TermX11.cxx
|
||||
|
||||
mainX11.o: $(UI)/x11/mainX11.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/x11/mainX11.cxx
|
||||
|
||||
SoundX11.o: $(UI)/x11/SoundX11.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/x11/SoundX11.cxx
|
||||
|
||||
mainSDL.o: $(UI)/sdl/mainSDL.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/sdl/mainSDL.cxx
|
||||
|
||||
|
@ -416,9 +417,6 @@ RectList.o: $(UI)/sdl/RectList.cxx $(UI)/sdl/RectList.hxx
|
|||
Snapshot.o: $(UI)/common/Snapshot.cxx $(UI)/common/Snapshot.hxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/common/Snapshot.cxx
|
||||
|
||||
SndUnix.o: $(UI)/sound/SndUnix.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/sound/SndUnix.cxx
|
||||
|
||||
D6502.o: $(CORE)/m6502/src/D6502.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/m6502/src/D6502.cxx
|
||||
|
||||
|
@ -439,3 +437,4 @@ NullDev.o: $(CORE)/m6502/src/NullDev.cxx
|
|||
|
||||
System.o: $(CORE)/m6502/src/System.cxx
|
||||
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/m6502/src/System.cxx
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-1998 by Bradford W. Mott
|
||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
||||
//
|
||||
// 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.3 2002-01-16 02:14:25 stephena Exp $
|
||||
// $Id: Console.cxx,v 1.4 2002-10-09 04:38:11 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -41,7 +41,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Console::Console(const uInt8* image, uInt32 size, const char* filename,
|
||||
const Event& event, PropertiesSet& propertiesSet, Sound& sound)
|
||||
const Event& event, PropertiesSet& propertiesSet, uInt32 sampleRate)
|
||||
: myEvent(event)
|
||||
{
|
||||
myControllers[0] = 0;
|
||||
|
@ -126,7 +126,7 @@ Console::Console(const uInt8* image, uInt32 size, const char* filename,
|
|||
}
|
||||
|
||||
M6532* m6532 = new M6532(*this);
|
||||
TIA* tia = new TIA(*this, sound);
|
||||
TIA* tia = new TIA(*this, sampleRate);
|
||||
Cartridge* cartridge = Cartridge::create(image, size, myProperties);
|
||||
|
||||
mySystem->attach(m6502);
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-1998 by Bradford W. Mott
|
||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: Console.hxx,v 1.2 2002-01-08 17:11:32 stephena Exp $
|
||||
// $Id: Console.hxx,v 1.3 2002-10-09 04:38:11 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef CONSOLE_HXX
|
||||
|
@ -36,7 +36,7 @@ class System;
|
|||
This class represents the entire game console.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: Console.hxx,v 1.2 2002-01-08 17:11:32 stephena Exp $
|
||||
@version $Id: Console.hxx,v 1.3 2002-10-09 04:38:11 bwmott Exp $
|
||||
*/
|
||||
class Console
|
||||
{
|
||||
|
@ -50,10 +50,10 @@ class Console
|
|||
@param filename The name of the file that contained the ROM image
|
||||
@param event The event object to use
|
||||
@param profiles The game profiles object to use
|
||||
@param sound The sound object to use
|
||||
@param sampleRate The rate to create audio samples at
|
||||
*/
|
||||
Console(const uInt8* image, uInt32 size, const char* filename,
|
||||
const Event& event, PropertiesSet& propertiesSet, Sound& sound);
|
||||
const Event& event, PropertiesSet& propertiesSet, uInt32 sampleRate);
|
||||
|
||||
/**
|
||||
Create a new console object by copying another one
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-1998 by Bradford W. Mott
|
||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
||||
//
|
||||
// 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.3 2002-04-18 17:18:48 stephena Exp $
|
||||
// $Id: MediaSrc.hxx,v 1.4 2002-10-09 04:38:11 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef MEDIASOURCE_HXX
|
||||
|
@ -26,10 +26,10 @@ class MediaSource;
|
|||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
This class provides an interface for accessing graphics data.
|
||||
This class provides an interface for accessing graphics and audio data.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: MediaSrc.hxx,v 1.3 2002-04-18 17:18:48 stephena Exp $
|
||||
@version $Id: MediaSrc.hxx,v 1.4 2002-10-09 04:38:11 bwmott Exp $
|
||||
*/
|
||||
class MediaSource
|
||||
{
|
||||
|
@ -46,15 +46,18 @@ class MediaSource
|
|||
|
||||
public:
|
||||
/**
|
||||
This method should be called at an interval corresponding to
|
||||
the desired frame rate to update the media source.
|
||||
This method should be called at an interval corresponding to the
|
||||
desired frame rate to update the media source. Invoking this method
|
||||
will update the graphics buffer and generate the corresponding audio
|
||||
samples.
|
||||
*/
|
||||
virtual void update() = 0;
|
||||
|
||||
/**
|
||||
This method should be called to cause further calls to 'update'
|
||||
to be ignored until an unpause is given. Will also send a mute to
|
||||
the Sound device.
|
||||
This method should be called to change the pause state of the
|
||||
media source. Once the media source is paused further calls to
|
||||
the update method will be ignored until the media source is
|
||||
unpaused.
|
||||
|
||||
@return Status of the pause, success (true) or failure (false)
|
||||
*/
|
||||
|
@ -111,6 +114,47 @@ class MediaSource
|
|||
*/
|
||||
virtual uInt32 scanlines() const = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
Enumeration of the possible audio sample types.
|
||||
*/
|
||||
enum AudioSampleType
|
||||
{
|
||||
UNSIGNED_8BIT_MONO_AUDIO
|
||||
};
|
||||
|
||||
/**
|
||||
Dequeues all of the samples in the audio sample queue.
|
||||
*/
|
||||
virtual void clearAudioSamples() = 0;
|
||||
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
virtual uInt32 dequeueAudioSamples(uInt8* buffer, int size) = 0;
|
||||
|
||||
/**
|
||||
Answers the number of samples currently available in the audio
|
||||
sample queue.
|
||||
|
||||
@return The number of samples in the audio sample queue.
|
||||
*/
|
||||
virtual uInt32 numberOfAudioSamples() const = 0;
|
||||
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
virtual AudioSampleType typeOfAudioSamples() const = 0;
|
||||
|
||||
private:
|
||||
// Copy constructor isn't supported by this class so make it private
|
||||
MediaSource(const MediaSource&);
|
||||
|
@ -119,3 +163,4 @@ class MediaSource
|
|||
MediaSource& operator = (const MediaSource&);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
||||
//
|
||||
// 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.2 2002-03-28 02:02:24 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include "Sound.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Sound::Sound()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Sound::~Sound()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Sound::set(Sound::Register r, uInt8 v, uInt32)
|
||||
{
|
||||
// For backwards compatibility we invoke the two argument version of this
|
||||
// method. This should keep all of the old derived sound classes happy.
|
||||
set(r, v);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Sound::set(Sound::Register r, uInt8 v)
|
||||
{
|
||||
// This sound class doesn't do anything when a register is set
|
||||
// since we're not handling sound
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Sound::mute(bool)
|
||||
{
|
||||
// There's nothing for us to do when the sound is muted since
|
||||
// we're not handling sound
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
||||
//
|
||||
// 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.2 2002-03-28 02:02:24 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SOUND_HXX
|
||||
#define SOUND_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
Base class that defines the standard API for sound classes. You
|
||||
should derive a new class from this one to create a new sound system
|
||||
for a specific operating system.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: Sound.hxx,v 1.2 2002-03-28 02:02:24 bwmott Exp $
|
||||
*/
|
||||
class Sound
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Enumeration of the TIA sound registers
|
||||
*/
|
||||
enum Register
|
||||
{
|
||||
AUDF0, AUDF1, AUDC0, AUDC1, AUDV0, AUDV1
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
Create a new sound object
|
||||
*/
|
||||
Sound();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~Sound();
|
||||
|
||||
public:
|
||||
/**
|
||||
Set the value of the specified sound register.
|
||||
|
||||
@param reg The sound register to set
|
||||
@param val The new value for the sound register
|
||||
@param cycles The number of elapsed CPU cycles since the last set
|
||||
*/
|
||||
virtual void set(Sound::Register reg, uInt8 val, uInt32 cycles);
|
||||
|
||||
/**
|
||||
Set the value of the specified sound register. This method is being
|
||||
kept for backwards compatibility. There's a good chance it will be
|
||||
removed in the 1.3 release of Stella as the sound system is overhauled.
|
||||
|
||||
@param reg The sound register to set
|
||||
@param val The new value for the sound register
|
||||
*/
|
||||
virtual void set(Sound::Register reg, uInt8 val);
|
||||
|
||||
/**
|
||||
Set the mute state of the sound object
|
||||
|
||||
@param state Mutes sound iff true
|
||||
*/
|
||||
virtual void mute(bool state);
|
||||
};
|
||||
#endif
|
||||
|
|
@ -13,29 +13,28 @@
|
|||
// 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.15 2002-08-17 15:29:28 stephena Exp $
|
||||
// $Id: TIA.cxx,v 1.16 2002-10-09 04:38:11 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "Console.hxx"
|
||||
#include "Control.hxx"
|
||||
#include "M6502.hxx"
|
||||
#include "Sound.hxx"
|
||||
#include "System.hxx"
|
||||
#include "TIA.hxx"
|
||||
#include "Serializer.hxx"
|
||||
#include "Deserializer.hxx"
|
||||
#include <iostream>
|
||||
#include "TIASound.h"
|
||||
|
||||
#define HBLANK 68
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TIA::TIA(const Console& console, Sound& sound)
|
||||
TIA::TIA(const Console& console, uInt32 sampleRate)
|
||||
: myConsole(console),
|
||||
mySound(sound),
|
||||
myPauseState(false),
|
||||
myMessageTime(0),
|
||||
myMessageText(""),
|
||||
|
@ -44,8 +43,15 @@ TIA::TIA(const Console& console, Sound& sound)
|
|||
myCOLUBK(myColor[0]),
|
||||
myCOLUPF(myColor[1]),
|
||||
myCOLUP0(myColor[2]),
|
||||
myCOLUP1(myColor[3])
|
||||
myCOLUP1(myColor[3]),
|
||||
mySampleQueue(sampleRate),
|
||||
mySampleRate(sampleRate)
|
||||
{
|
||||
if(mySampleRate != 0)
|
||||
{
|
||||
Tia_sound_init(31400, mySampleRate);
|
||||
}
|
||||
|
||||
// Allocate buffers for two frame buffers
|
||||
myCurrentFrameBuffer = new uInt8[160 * 300];
|
||||
myPreviousFrameBuffer = new uInt8[160 * 300];
|
||||
|
@ -526,6 +532,9 @@ 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;
|
||||
|
@ -549,10 +558,6 @@ bool TIA::pause(bool state)
|
|||
else
|
||||
{
|
||||
myPauseState = state;
|
||||
|
||||
// Propagate the pause state to the sound object
|
||||
mySound.mute(myPauseState);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -697,6 +702,30 @@ 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()
|
||||
{
|
||||
|
@ -2474,49 +2503,37 @@ void TIA::poke(uInt16 addr, uInt8 value)
|
|||
|
||||
case 0x15: // Audio control 0
|
||||
{
|
||||
mySound.set(Sound::AUDC0, value,
|
||||
mySystem->cycles() - myLastSoundUpdateCycle);
|
||||
myLastSoundUpdateCycle = mySystem->cycles();
|
||||
createAudioSamples(addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x16: // Audio control 1
|
||||
{
|
||||
mySound.set(Sound::AUDC1, value,
|
||||
mySystem->cycles() - myLastSoundUpdateCycle);
|
||||
myLastSoundUpdateCycle = mySystem->cycles();
|
||||
createAudioSamples(addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x17: // Audio frequency 0
|
||||
{
|
||||
mySound.set(Sound::AUDF0, value,
|
||||
mySystem->cycles() - myLastSoundUpdateCycle);
|
||||
myLastSoundUpdateCycle = mySystem->cycles();
|
||||
createAudioSamples(addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x18: // Audio frequency 1
|
||||
{
|
||||
mySound.set(Sound::AUDF1, value,
|
||||
mySystem->cycles() - myLastSoundUpdateCycle);
|
||||
myLastSoundUpdateCycle = mySystem->cycles();
|
||||
createAudioSamples(addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x19: // Audio volume 0
|
||||
{
|
||||
mySound.set(Sound::AUDV0, value,
|
||||
mySystem->cycles() - myLastSoundUpdateCycle);
|
||||
myLastSoundUpdateCycle = mySystem->cycles();
|
||||
createAudioSamples(addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x1A: // Audio volume 1
|
||||
{
|
||||
mySound.set(Sound::AUDV1, value,
|
||||
mySystem->cycles() - myLastSoundUpdateCycle);
|
||||
myLastSoundUpdateCycle = mySystem->cycles();
|
||||
createAudioSamples(addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2845,6 +2862,42 @@ 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];
|
||||
|
||||
|
@ -3178,11 +3231,11 @@ const uInt32 TIA::ourFontData[36] = {
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TIA::TIA(const TIA& c)
|
||||
: myConsole(c.myConsole),
|
||||
mySound(c.mySound),
|
||||
myCOLUBK(myColor[0]),
|
||||
myCOLUPF(myColor[1]),
|
||||
myCOLUP0(myColor[2]),
|
||||
myCOLUP1(myColor[3])
|
||||
myCOLUP1(myColor[3]),
|
||||
mySampleQueue(1024)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
@ -3195,3 +3248,96 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.hxx,v 1.6 2002-05-13 19:17:32 stephena Exp $
|
||||
// $Id: TIA.hxx,v 1.7 2002-10-09 04:38:12 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef TIA_HXX
|
||||
|
@ -39,10 +39,11 @@ 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.
|
||||
be displayed on screen it also creates audio samples and places them
|
||||
in a bounded queue.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: TIA.hxx,v 1.6 2002-05-13 19:17:32 stephena Exp $
|
||||
@version $Id: TIA.hxx,v 1.7 2002-10-09 04:38:12 bwmott Exp $
|
||||
*/
|
||||
class TIA : public Device , public MediaSource
|
||||
{
|
||||
|
@ -51,8 +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
|
||||
*/
|
||||
TIA(const Console& console, Sound& sound);
|
||||
TIA(const Console& console, uInt32 sampleRate);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
|
@ -184,6 +186,38 @@ 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();
|
||||
|
@ -217,22 +251,78 @@ class TIA : public Device , public MediaSource
|
|||
void waitHorizontalSync();
|
||||
|
||||
// Draw message to framebuffer
|
||||
void drawMessageText();
|
||||
void drawMessageText();
|
||||
|
||||
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 used by the TIA
|
||||
Sound& mySound;
|
||||
|
||||
// Indicates whether the emulation is paused or not
|
||||
bool myPauseState;
|
||||
|
||||
// message timer
|
||||
Int32 myMessageTime;
|
||||
// Message timer
|
||||
Int32 myMessageTime;
|
||||
|
||||
// message text
|
||||
// Message text
|
||||
string myMessageText;
|
||||
|
||||
private:
|
||||
|
@ -426,6 +516,13 @@ 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];
|
||||
|
@ -479,4 +576,6 @@ class TIA : public Device , public MediaSource
|
|||
// Assignment operator isn't supported by this class so make it private
|
||||
TIA& operator = (const TIA&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,290 +0,0 @@
|
|||
/*============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-1998 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: OSS.c,v 1.2 2002-01-08 17:11:32 stephena Exp $
|
||||
//==========================================================================*/
|
||||
|
||||
/**
|
||||
This file implements the "stella-sound" process for the
|
||||
Open Sound System (OSS) API.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: OSS.c,v 1.2 2002-01-08 17:11:32 stephena Exp $
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <machine/soundcard.h>
|
||||
#else
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
|
||||
#include "TIASound.h"
|
||||
|
||||
/**
|
||||
Compute Fragment size to use based on the sample rate
|
||||
|
||||
@param sampleRate The sample rate to compute the fragment size for
|
||||
*/
|
||||
unsigned long computeFragmentSize(int sampleRate);
|
||||
|
||||
/* Mixer function prototypes */
|
||||
void openMixer(int changeVolume);
|
||||
void closeMixer();
|
||||
|
||||
/* dsp and mixer file descriptors */
|
||||
int fd, mixer_fd;
|
||||
int originalVolume;
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int numberAndSizeOfFragments;
|
||||
int fragmentSize;
|
||||
unsigned char* fragmentBuffer;
|
||||
int sampleRate;
|
||||
int format;
|
||||
int stereo;
|
||||
int mute = 0;
|
||||
int newVolume = 75;
|
||||
|
||||
if(argc == 3) /* check to see if volume has been given */
|
||||
{
|
||||
if(!strncmp(argv[1], "-volume", 7))
|
||||
{
|
||||
if((atoi(argv[2]) >= 0) && (atoi(argv[2]) <= 100))
|
||||
newVolume = atoi(argv[2]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Open the sound device for writing */
|
||||
if((fd = open("/dev/dsp", O_WRONLY, 0)) == -1)
|
||||
{
|
||||
printf("stella-sound: Unable to open /dev/dsp device!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set the AUDIO DATA FORMAT */
|
||||
format = AFMT_U8;
|
||||
if(ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1)
|
||||
{
|
||||
printf("stella-sound: Unable to set 8-bit sample mode!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(format != AFMT_U8)
|
||||
{
|
||||
printf("stella-sound: Sound card doesn't support 8-bit sample mode!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set MONO MODE */
|
||||
stereo = 0;
|
||||
if(ioctl(fd, SNDCTL_DSP_STEREO, &stereo) == -1)
|
||||
{
|
||||
printf("stella-sound: Sound card doesn't support mono mode!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(stereo != 0)
|
||||
{
|
||||
printf("stella-sound: Sound card doesn't support mono mode!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set the SAMPLE RATE */
|
||||
sampleRate = 31400;
|
||||
if(ioctl(fd, SNDCTL_DSP_SPEED, &sampleRate) == -1)
|
||||
{
|
||||
printf("stella-sound: Unable to set sample rate for /dev/dsp!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set the NUMBER AND SIZE OF FRAGMENTS */
|
||||
numberAndSizeOfFragments = 0x00020000 | computeFragmentSize(sampleRate);
|
||||
if(ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &numberAndSizeOfFragments) == -1)
|
||||
{
|
||||
printf("stella-sound: Unable to set fragment size!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Query for the actual fragment size */
|
||||
ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &fragmentSize);
|
||||
|
||||
/* Allocate fragment buffer */
|
||||
fragmentBuffer = (unsigned char*)malloc(fragmentSize);
|
||||
|
||||
/* Now open the mixer for changing the volume */
|
||||
openMixer(newVolume);
|
||||
|
||||
/* Initialize the TIA Sound Library */
|
||||
Tia_sound_init(31400, sampleRate);
|
||||
|
||||
|
||||
/* Make sure STDIN is in nonblocking mode */
|
||||
if(fcntl(0, F_SETFL, O_NONBLOCK) == -1)
|
||||
{
|
||||
printf("stella-sound: Couldn't set non-blocking mode\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Loop reading commands from the emulator and playing sound fragments */
|
||||
for(;;)
|
||||
{
|
||||
int done = 0;
|
||||
|
||||
while(!done)
|
||||
{
|
||||
int i;
|
||||
int n;
|
||||
unsigned char input[1024];
|
||||
|
||||
/* Read as many commands as available */
|
||||
n = read(0, input, 1024);
|
||||
|
||||
/* Process all of the commands we read */
|
||||
for(i = 0; i < n; ++i)
|
||||
{
|
||||
unsigned char value = input[i];
|
||||
|
||||
switch((value >> 5) & 0x07)
|
||||
{
|
||||
case 0: /* Set AUDC0 */
|
||||
Update_tia_sound(0x15, value);
|
||||
break;
|
||||
|
||||
case 1: /* Set AUDC1 */
|
||||
Update_tia_sound(0x16, value);
|
||||
break;
|
||||
|
||||
case 2: /* Set AUDF0 */
|
||||
Update_tia_sound(0x17, value);
|
||||
break;
|
||||
|
||||
case 3: /* Set AUDF1 */
|
||||
Update_tia_sound(0x18, value);
|
||||
break;
|
||||
|
||||
case 4: /* Set AUDV0 */
|
||||
Update_tia_sound(0x19, value);
|
||||
break;
|
||||
|
||||
case 5: /* Set AUDV1 */
|
||||
Update_tia_sound(0x1A, value);
|
||||
break;
|
||||
|
||||
case 6: /* Quit */
|
||||
close(fd);
|
||||
free(fragmentBuffer);
|
||||
closeMixer();
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case 7: /* Change mute command */
|
||||
mute = value & 0x01;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
done = (n != 1024);
|
||||
}
|
||||
|
||||
/* If sound isn't muted then play something */
|
||||
if(!mute)
|
||||
{
|
||||
/* Create the next fragment to play */
|
||||
Tia_process(fragmentBuffer, fragmentSize);
|
||||
|
||||
/* Write fragment to sound device */
|
||||
write(fd, fragmentBuffer, fragmentSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Sound is muted so let's sleep for a little while */
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 10000;
|
||||
select(0, 0, 0, 0, &timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
unsigned long computeFragmentSize(int sampleRate)
|
||||
{
|
||||
int t;
|
||||
|
||||
for(t = 7; t < 24; ++t)
|
||||
{
|
||||
if((1 << t) > (sampleRate / 60))
|
||||
return t - 1;
|
||||
}
|
||||
|
||||
/* Default to 256 byte fragment size */
|
||||
return 8;
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
void openMixer(int changeVolume)
|
||||
{
|
||||
int volume;
|
||||
|
||||
if((mixer_fd = open("/dev/mixer", O_RDWR, 0)) == -1)
|
||||
{
|
||||
printf("stella-sound: Unable to open /dev/mixer device!\n");
|
||||
mixer_fd = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
volume = 0;
|
||||
if(ioctl(mixer_fd, MIXER_READ(SOUND_MIXER_PCM), &originalVolume) == -1)
|
||||
{
|
||||
printf("stella-sound: Unable to read mixer settings!\n");
|
||||
close(mixer_fd);
|
||||
mixer_fd = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
volume = changeVolume | (changeVolume << 8);
|
||||
if(ioctl(mixer_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
|
||||
{
|
||||
printf("stella-sound: Unable to set new volume!\n");
|
||||
close(mixer_fd);
|
||||
mixer_fd = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
void closeMixer()
|
||||
{
|
||||
if(mixer_fd)
|
||||
{
|
||||
if(ioctl(mixer_fd, MIXER_WRITE(SOUND_MIXER_PCM), &originalVolume) == -1)
|
||||
printf("stella-sound: Unable to set original volume!\n");
|
||||
|
||||
close(mixer_fd);
|
||||
}
|
||||
}
|
|
@ -1,233 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-1998 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: SndUnix.cxx,v 1.2 2002-01-08 17:11:32 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "SndUnix.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundUnix::SoundUnix(int volume)
|
||||
: myDisabled(false),
|
||||
myMute(false)
|
||||
{
|
||||
// Initialize to impossible values so they will be reset
|
||||
// on the first call to the set method
|
||||
myAUDC0 = myAUDC1 = myAUDF0 = myAUDF1 = myAUDV0 = myAUDV1 = 255;
|
||||
|
||||
int pfd[2];
|
||||
|
||||
// Create pipe for interprocess communication
|
||||
if(pipe(pfd))
|
||||
{
|
||||
// Oops. We were not able to create pipe so disable myself and return
|
||||
myDisabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new process, setup pipe, and start stella-sound
|
||||
myProcessId = fork();
|
||||
|
||||
if(myProcessId == 0)
|
||||
{
|
||||
// Close STDIN and put the read end of the pipe in its place
|
||||
dup2(pfd[0], 0);
|
||||
|
||||
// Close unused file descriptors in child process
|
||||
close(pfd[0]);
|
||||
close(pfd[1]);
|
||||
|
||||
// Execute the stella-sound server
|
||||
char vol[3];
|
||||
sprintf(vol, "%d", volume);
|
||||
if(execlp("stella-sound", "stella-sound", "-volume", vol, (char*)0))
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if(myProcessId > 0)
|
||||
{
|
||||
// Close unused file descriptors in parent process
|
||||
close(pfd[0]);
|
||||
|
||||
// Save the pipe's write file descriptor
|
||||
myFd = pfd[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Couldn't fork so cleanup and disabled myself
|
||||
close(pfd[0]);
|
||||
close(pfd[1]);
|
||||
|
||||
myDisabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundUnix::~SoundUnix()
|
||||
{
|
||||
if(!myDisabled)
|
||||
{
|
||||
// Send quit command to the sound server
|
||||
unsigned char command = 0xC0;
|
||||
write(myFd, &command, 1);
|
||||
|
||||
// Close descriptors
|
||||
close(myFd);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundUnix::set(Sound::Register reg, uInt8 value)
|
||||
{
|
||||
// Return if I'm currently disabled or if the stella-sound process has died
|
||||
if(myDisabled || (waitpid(myProcessId, 0, WNOHANG) == myProcessId))
|
||||
{
|
||||
myDisabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
uInt8 command;
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case AUDC0:
|
||||
{
|
||||
if(myAUDC0 != (value & 0x0f))
|
||||
{
|
||||
myAUDC0 = (value & 0x0f);
|
||||
command = myAUDC0 | 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AUDC1:
|
||||
{
|
||||
if(myAUDC1 != (value & 0x0f))
|
||||
{
|
||||
myAUDC1 = (value & 0x0f);
|
||||
command = myAUDC1 | 0x20;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AUDF0:
|
||||
{
|
||||
if(myAUDF0 != (value & 0x1f))
|
||||
{
|
||||
myAUDF0 = (value & 0x1f);
|
||||
command = myAUDF0 | 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AUDF1:
|
||||
{
|
||||
if(myAUDF1 != (value & 0x1f))
|
||||
{
|
||||
myAUDF1 = (value & 0x1f);
|
||||
command = myAUDF1 | 0x60;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AUDV0:
|
||||
{
|
||||
if(myAUDV0 != (value & 0x0f))
|
||||
{
|
||||
myAUDV0 = (value & 0x0f);
|
||||
command = myAUDV0 | 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AUDV1:
|
||||
{
|
||||
if(myAUDV1 != (value & 0x0f))
|
||||
{
|
||||
myAUDV1 = (value & 0x0f);
|
||||
command = myAUDV1 | 0xA0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Send sound command to the stella-sound process
|
||||
write(myFd, &command, 1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundUnix::mute(bool state)
|
||||
{
|
||||
// Return if I'm currently disabled or if the stella-sound process has died
|
||||
if(myDisabled || (waitpid(myProcessId, 0, WNOHANG) == myProcessId))
|
||||
{
|
||||
myDisabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
myMute = state;
|
||||
|
||||
uInt8 command;
|
||||
if(myMute)
|
||||
{
|
||||
// Setup the mute enable command
|
||||
command = 0x01 | 0xE0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Setup the mute disable command
|
||||
command = 0x00 | 0xE0;
|
||||
}
|
||||
|
||||
// Send sound command to the stella-sound process
|
||||
write(myFd, &command, 1);
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-1998 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: SndUnix.hxx,v 1.2 2002-01-08 17:11:32 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SOUNDUNIX_HXX
|
||||
#define SOUNDUNIX_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Sound.hxx"
|
||||
|
||||
/**
|
||||
This class implements the sound API for the Unix operating system.
|
||||
Under Unix the real work of the sound system is in another process
|
||||
called "stella-sound". This process is started when an instance
|
||||
of the SoundUnix class is created. Communicattion with the
|
||||
"stella-sound" process is done through a pipe.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: SndUnix.hxx,v 1.2 2002-01-08 17:11:32 stephena Exp $
|
||||
*/
|
||||
class SoundUnix : public Sound
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new sound object
|
||||
*/
|
||||
SoundUnix(int volume);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~SoundUnix();
|
||||
|
||||
public:
|
||||
/**
|
||||
Set the value of the specified sound register
|
||||
|
||||
@param reg The sound register to set
|
||||
@param val The new value for the sound register
|
||||
*/
|
||||
virtual void set(Sound::Register reg, uInt8 val);
|
||||
|
||||
/**
|
||||
Set the mute state of the sound object
|
||||
|
||||
@param state Mutes sound iff true
|
||||
*/
|
||||
virtual void mute(bool state);
|
||||
|
||||
private:
|
||||
// Indicates if the sound system couldn't be initialized
|
||||
bool myDisabled;
|
||||
|
||||
// Indicates if the sound is muted or not
|
||||
bool myMute;
|
||||
|
||||
// ProcessId of the stella-sound process
|
||||
int myProcessId;
|
||||
|
||||
// Write file descriptor for IPC
|
||||
int myFd;
|
||||
|
||||
// Buffers for the audio registers used so we only
|
||||
// send "changes" to the stella-sound process
|
||||
uInt8 myAUDC0;
|
||||
uInt8 myAUDC1;
|
||||
uInt8 myAUDF0;
|
||||
uInt8 myAUDF1;
|
||||
uInt8 myAUDV0;
|
||||
uInt8 myAUDV1;
|
||||
};
|
||||
#endif
|
|
@ -1,36 +0,0 @@
|
|||
###############################################################################
|
||||
## C compiler to use
|
||||
###############################################################################
|
||||
CC = gcc
|
||||
|
||||
CFLAGS = -DWIN32 -O -ansi -Wall
|
||||
|
||||
OBJS = TIASound.o
|
||||
|
||||
all:
|
||||
@echo ""
|
||||
@echo "To build stella-sound, type: 'make <version>'"
|
||||
@echo ""
|
||||
@echo "where <version> is one of:"
|
||||
@echo ""
|
||||
@echo " linux Linux (same as uss)"
|
||||
@echo " uss Systems with the Unix Sound System (same as oss)"
|
||||
@echo " oss systems with the Open Sound System"
|
||||
@echo " bsdi BSD/OS 4.0"
|
||||
@echo ""
|
||||
@echo "Hopefully new versions will be added soon!"
|
||||
@echo ""
|
||||
|
||||
bsdi:
|
||||
make oss CFLAGS="-DWIN32 -O3 -Wall"
|
||||
|
||||
linux: oss
|
||||
|
||||
uss: oss
|
||||
|
||||
oss: $(OBJS) OSS.o
|
||||
$(CC) -o stella-sound OSS.o $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f *.o stella-sound
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: SoundX11.cxx,v 1.1 2002-10-09 04:38:12 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <machine/soundcard.h>
|
||||
#else
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
|
||||
#define DSP_DEVICE "/dev/dsp"
|
||||
#define MIXER_DEVICE "/dev/mixer"
|
||||
|
||||
#include "SoundX11.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundX11::SoundX11()
|
||||
: myIsInitializedFlag(false),
|
||||
myDspFd(-1),
|
||||
myMixerFd(-1),
|
||||
myOriginalVolume(-1),
|
||||
mySampleRate(0)
|
||||
{
|
||||
// Open the sound device for writing
|
||||
if((myDspFd = open(DSP_DEVICE, O_WRONLY, 0)) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the number and size of fragments
|
||||
int numberAndSizeOfFragments = 0x00020009;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_SETFRAGMENT, &numberAndSizeOfFragments) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the audio data format
|
||||
int format = AFMT_U8;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_SETFMT, &format) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the U8 format was selected
|
||||
if(format != AFMT_U8)
|
||||
{
|
||||
cerr << DSP_DEVICE << ": Doesn't support 8-bit sample format!" << endl;
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the number of audio channels to 1 (mono mode)
|
||||
int channels = 1;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_CHANNELS, &channels) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure mono mode was selected
|
||||
if(channels != 1)
|
||||
{
|
||||
cerr << DSP_DEVICE << ": Doesn't support mono mode!" << endl;
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the audio sample rate
|
||||
mySampleRate = 31400;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_SPEED, &mySampleRate) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
mySampleRate = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Now, open the mixer so we'll be able to change the volume
|
||||
if((myMixerFd = open(MIXER_DEVICE, O_RDWR, 0)) == -1)
|
||||
{
|
||||
perror(MIXER_DEVICE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ioctl(myMixerFd, MIXER_READ(SOUND_MIXER_PCM), &myOriginalVolume) == -1)
|
||||
{
|
||||
myOriginalVolume = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Indicate that the sound system is fully initialized
|
||||
myIsInitializedFlag = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundX11::~SoundX11()
|
||||
{
|
||||
if(myMixerFd != -1)
|
||||
{
|
||||
if(myOriginalVolume != -1)
|
||||
{
|
||||
if(ioctl(myMixerFd, MIXER_WRITE(SOUND_MIXER_PCM),
|
||||
&myOriginalVolume) == -1)
|
||||
{
|
||||
perror(MIXER_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
close(myMixerFd);
|
||||
}
|
||||
|
||||
if(myDspFd != -1)
|
||||
{
|
||||
close(myDspFd);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundX11::getSampleRate() const
|
||||
{
|
||||
return myIsInitializedFlag ? mySampleRate : 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundX11::isSuccessfullyInitialized() const
|
||||
{
|
||||
return myIsInitializedFlag;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundX11::setSoundVolume(uInt32 volume)
|
||||
{
|
||||
if(myIsInitializedFlag && (myMixerFd != -1))
|
||||
{
|
||||
if(volume < 0)
|
||||
{
|
||||
volume = 0;
|
||||
}
|
||||
if(volume > 100)
|
||||
{
|
||||
volume = 100;
|
||||
}
|
||||
|
||||
int v = volume | (volume << 8);
|
||||
if(ioctl(myMixerFd, MIXER_WRITE(SOUND_MIXER_PCM), &v) == -1)
|
||||
{
|
||||
perror(MIXER_DEVICE);
|
||||
close(myMixerFd);
|
||||
myMixerFd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundX11::updateSound(MediaSource& mediaSource)
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
// Get audio buffer information
|
||||
audio_buf_info info;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_GETOSPACE, &info) == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Dequeue samples as long as full fragments are available
|
||||
while(mediaSource.numberOfAudioSamples() >= (uInt32)info.fragsize)
|
||||
{
|
||||
uInt8 buffer[info.fragsize];
|
||||
mediaSource.dequeueAudioSamples(buffer, (uInt32)info.fragsize);
|
||||
write(myDspFd, buffer, info.fragsize);
|
||||
}
|
||||
|
||||
// Fill any unused fragments with silence so that we have a lower
|
||||
// risk of having playback underruns
|
||||
for(;;)
|
||||
{
|
||||
// Get audio buffer information
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_GETOSPACE, &info) == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(info.fragments > 0)
|
||||
{
|
||||
uInt8 buffer[info.fragsize];
|
||||
memset((void*)buffer, 0, info.fragsize);
|
||||
write(myDspFd, buffer, info.fragsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: SoundX11.hxx,v 1.1 2002-10-09 04:38:12 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SOUNDX11_HXX
|
||||
#define SOUNDX11_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
|
||||
/**
|
||||
This class implements a sound class for the X11 front-end. The
|
||||
Open Sound System (OSS) API is currently supported.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: SoundX11.hxx,v 1.1 2002-10-09 04:38:12 bwmott Exp $
|
||||
*/
|
||||
class SoundX11
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new sound object
|
||||
*/
|
||||
SoundX11();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~SoundX11();
|
||||
|
||||
public:
|
||||
/**
|
||||
Return the playback sample rate for the sound device.
|
||||
|
||||
@return The playback sample rate
|
||||
*/
|
||||
uInt32 getSampleRate() const;
|
||||
|
||||
/**
|
||||
Return true iff the sound device was successfully initlaized.
|
||||
|
||||
@return true iff the sound device was successfully initlaized.
|
||||
*/
|
||||
bool isSuccessfullyInitialized() const;
|
||||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
volume is given as a precentage from 0 to 100.
|
||||
|
||||
@param volume The new volume for the sound device
|
||||
*/
|
||||
void setSoundVolume(uInt32 volume);
|
||||
|
||||
/**
|
||||
Update the sound device using the audio sample from the specified
|
||||
media source.
|
||||
|
||||
@param mediaSource The media source to get audio samples from.
|
||||
*/
|
||||
void updateSound(MediaSource& mediaSource);
|
||||
|
||||
private:
|
||||
// Indicates if the sound device was successfully initialized
|
||||
bool myIsInitializedFlag;
|
||||
|
||||
// DSP file descriptor
|
||||
int myDspFd;
|
||||
|
||||
// Mixer file descriptor
|
||||
int myMixerFd;
|
||||
|
||||
// Original mixer volume when the sound device was opened
|
||||
int myOriginalVolume;
|
||||
|
||||
// DSP sample rate
|
||||
uInt32 mySampleRate;
|
||||
};
|
||||
#endif
|
||||
|
|
@ -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: mainX11.cxx,v 1.27 2002-10-05 12:49:49 stephena Exp $
|
||||
// $Id: mainX11.cxx,v 1.28 2002-10-09 04:38:12 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <fstream>
|
||||
|
@ -39,9 +39,9 @@
|
|||
#include "Event.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
#include "PropsSet.hxx"
|
||||
#include "SndUnix.hxx"
|
||||
#include "System.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "SoundX11.hxx"
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
#include "Snapshot.hxx"
|
||||
|
@ -286,7 +286,8 @@ bool setupDisplay()
|
|||
char name[512];
|
||||
sprintf(name, "Stella: \"%s\"",
|
||||
theConsole->properties().get("Cartridge.Name").c_str());
|
||||
XmbSetWMProperties(theDisplay, theWindow, name, "stella", 0, 0, &hints, None, None);
|
||||
XmbSetWMProperties(theDisplay, theWindow, name, "stella", 0, 0, &hints,
|
||||
None, None);
|
||||
|
||||
// Set up the palette for the screen
|
||||
setupPalette();
|
||||
|
@ -314,8 +315,8 @@ bool setupDisplay()
|
|||
XNextEvent(theDisplay, &event);
|
||||
} while (event.type != Expose);
|
||||
|
||||
eventMask = ExposureMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask |
|
||||
StructureNotifyMask;
|
||||
eventMask = ExposureMask | KeyPressMask | KeyReleaseMask |
|
||||
PropertyChangeMask | StructureNotifyMask;
|
||||
|
||||
// If we're using the mouse for paddle emulation then enable mouse events
|
||||
if(((theConsole->properties().get("Controller.Left") == "Paddles") ||
|
||||
|
@ -387,9 +388,9 @@ void setupPalette()
|
|||
{
|
||||
XColor color;
|
||||
|
||||
color.red = (short unsigned int) (((palette[t] & 0x00ff0000) >> 8) * shade);
|
||||
color.green = (short unsigned int) ((palette[t] & 0x0000ff00) * shade);
|
||||
color.blue = (short unsigned int) (((palette[t] & 0x000000ff) << 8) * shade);
|
||||
color.red = (short unsigned int)(((palette[t] & 0x00ff0000) >> 8) * shade);
|
||||
color.green = (short unsigned int)((palette[t] & 0x0000ff00) * shade);
|
||||
color.blue = (short unsigned int)(((palette[t] & 0x000000ff) << 8) * shade);
|
||||
color.flags = DoRed | DoGreen | DoBlue;
|
||||
|
||||
if(settings->theUsePrivateColormapFlag)
|
||||
|
@ -556,7 +557,7 @@ void handleEvents()
|
|||
// Handle the WM_DELETE_WINDOW message outside the event loop
|
||||
if(XCheckTypedWindowEvent(theDisplay, theWindow, ClientMessage, &event))
|
||||
{
|
||||
if(event.xclient.data.l[0] == wm_delete_window)
|
||||
if((unsigned long)event.xclient.data.l[0] == wm_delete_window)
|
||||
{
|
||||
doQuit();
|
||||
return;
|
||||
|
@ -1161,7 +1162,8 @@ void takeSnapshot()
|
|||
filename = filename + ".png";
|
||||
|
||||
// Now save the snapshot file
|
||||
snapshot->savePNG(filename, theConsole->mediaSource(), settings->theWindowSize);
|
||||
snapshot->savePNG(filename, theConsole->mediaSource(),
|
||||
settings->theWindowSize);
|
||||
|
||||
if(access(filename.c_str(), F_OK) == 0)
|
||||
cerr << "Snapshot saved as " << filename << endl;
|
||||
|
@ -1214,28 +1216,28 @@ void usage()
|
|||
"",
|
||||
"Valid options are:",
|
||||
"",
|
||||
" -fps <number> Display the given number of frames per second",
|
||||
" -owncmap <0|1> Install a private colormap",
|
||||
" -zoom <size> Makes window be 'size' times normal (1 - 4)",
|
||||
// " -fullscreen <0|1> Play the game in fullscreen mode",
|
||||
" -grabmouse <0|1> Keeps the mouse in the game window",
|
||||
" -hidecursor <0|1> Hides the mouse cursor in the game window",
|
||||
" -center <0|1> Centers the game window onscreen",
|
||||
" -volume <number> Set the volume (0 - 100)",
|
||||
" -fps <number> Display the given number of frames per second",
|
||||
" -owncmap <0|1> Install a private colormap",
|
||||
" -zoom <size> Makes window be 'size' times normal (1 - 4)",
|
||||
// " -fullscreen <0|1> Play the game in fullscreen mode",
|
||||
" -grabmouse <0|1> Keeps the mouse in the game window",
|
||||
" -hidecursor <0|1> Hides the mouse cursor in the game window",
|
||||
" -center <0|1> Centers the game window onscreen",
|
||||
" -volume <number> Set the volume (0 - 100)",
|
||||
#ifdef HAVE_JOYSTICK
|
||||
" -paddle <0|1|2|3|real> Indicates which paddle the mouse should emulate",
|
||||
" or that real Atari 2600 paddles are being used",
|
||||
" -paddle <0|1|2|3|real> Indicates which paddle the mouse should emulate",
|
||||
" or that real Atari 2600 paddles are being used",
|
||||
#else
|
||||
" -paddle <0|1|2|3> Indicates which paddle the mouse should emulate",
|
||||
" -paddle <0|1|2|3> Indicates which paddle the mouse should emulate",
|
||||
#endif
|
||||
" -showinfo <0|1> Shows some game info on exit",
|
||||
" -showinfo <0|1> Shows some game info on exit",
|
||||
#ifdef HAVE_PNG
|
||||
" -ssdir <path> The directory to save snapshot files to",
|
||||
" -ssname <name> How to name the snapshot (romname or md5sum)",
|
||||
" -sssingle <0|1> Generate single snapshot instead of many",
|
||||
" -ssdir <path> The directory to save snapshot files to",
|
||||
" -ssname <name> How to name the snapshot (romname or md5sum)",
|
||||
" -sssingle <0|1> Generate single snapshot instead of many",
|
||||
#endif
|
||||
" -pro <props file> Use the given properties file instead of stella.pro",
|
||||
" -accurate <0|1> Accurate game timing (uses more CPU)",
|
||||
" -pro <props file> Use the given properties file instead of stella.pro",
|
||||
" -accurate <0|1> Accurate game timing (uses more CPU)",
|
||||
"",
|
||||
0
|
||||
};
|
||||
|
@ -1266,7 +1268,8 @@ bool setupProperties(PropertiesSet& set)
|
|||
{
|
||||
if(access(settings->theAlternateProFile.c_str(), R_OK) == 0)
|
||||
{
|
||||
set.load(settings->theAlternateProFile, &Console::defaultProperties(), false);
|
||||
set.load(settings->theAlternateProFile,
|
||||
&Console::defaultProperties(), false);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -1436,15 +1439,16 @@ int main(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Create a sound object for use with the console
|
||||
SoundUnix sound(settings->theDesiredVolume);
|
||||
// Create a sound object for playing audio
|
||||
SoundX11 sound;
|
||||
sound.setSoundVolume(settings->theDesiredVolume);
|
||||
|
||||
// Get just the filename of the file containing the ROM image
|
||||
const char* filename = (!strrchr(file, '/')) ? file : strrchr(file, '/') + 1;
|
||||
|
||||
// Create the 2600 game console
|
||||
theConsole = new Console(image, size, filename,
|
||||
theEvent, propertiesSet, sound);
|
||||
theEvent, propertiesSet, sound.getSampleRate());
|
||||
|
||||
// Free the image since we don't need it any longer
|
||||
delete[] image;
|
||||
|
@ -1471,7 +1475,8 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
// Set up timing stuff
|
||||
uInt32 startTime, delta;
|
||||
uInt32 timePerFrame = (uInt32) (1000000.0 / (double) settings->theDesiredFrameRate);
|
||||
uInt32 timePerFrame =
|
||||
(uInt32)(1000000.0 / (double)settings->theDesiredFrameRate);
|
||||
|
||||
// Set the base for the timers
|
||||
frameTime = 0;
|
||||
|
@ -1496,6 +1501,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
startTime = getTicks();
|
||||
theConsole->mediaSource().update();
|
||||
sound.updateSound(theConsole->mediaSource());
|
||||
updateDisplay(theConsole->mediaSource());
|
||||
handleEvents();
|
||||
|
||||
|
@ -1516,7 +1522,8 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
// Set up timing stuff
|
||||
uInt32 startTime, virtualTime, currentTime;
|
||||
uInt32 timePerFrame = (uInt32) (1000000.0 / (double) settings->theDesiredFrameRate);
|
||||
uInt32 timePerFrame =
|
||||
(uInt32)(1000000.0 / (double)settings->theDesiredFrameRate);
|
||||
|
||||
// Set the base for the timers
|
||||
virtualTime = getTicks();
|
||||
|
@ -1536,6 +1543,7 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
theConsole->mediaSource().update();
|
||||
}
|
||||
sound.updateSound(theConsole->mediaSource());
|
||||
updateDisplay(theConsole->mediaSource());
|
||||
handleEvents();
|
||||
|
||||
|
@ -1561,9 +1569,11 @@ int main(int argc, char* argv[])
|
|||
cout << numberOfFrames << " total frames drawn\n";
|
||||
cout << framesPerSecond << " frames/second\n";
|
||||
cout << endl;
|
||||
cout << "Cartridge Name: " << theConsole->properties().get("Cartridge.Name");
|
||||
cout << "Cartridge Name: "
|
||||
<< theConsole->properties().get("Cartridge.Name");
|
||||
cout << endl;
|
||||
cout << "Cartridge MD5: " << theConsole->properties().get("Cartridge.MD5");
|
||||
cout << "Cartridge MD5: "
|
||||
<< theConsole->properties().get("Cartridge.MD5");
|
||||
cout << endl << endl;
|
||||
}
|
||||
|
||||
|
@ -1588,3 +1598,4 @@ inline uInt32 getTicks()
|
|||
#else
|
||||
#error We need gettimeofday for the X11 version!!!
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue