stella/src/common/SoundSDL2.hxx

299 lines
8.4 KiB
C++

//============================================================================
//
// 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-2017 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifdef SOUND_SUPPORT
#ifndef SOUND_SDL2_HXX
#define SOUND_SDL2_HXX
class OSystem;
#include "SDL_lib.hxx"
#include "bspf.hxx"
#include "TIASnd.hxx"
#include "Sound.hxx"
/**
This class implements the sound API for SDL.
@author Stephen Anthony and Bradford W. Mott
*/
class SoundSDL2 : public Sound
{
public:
/**
Create a new sound object. The init method must be invoked before
using the object.
*/
SoundSDL2(OSystem& osystem);
/**
Destructor
*/
virtual ~SoundSDL2();
public:
/**
Enables/disables the sound subsystem.
@param state True or false, to enable or disable the sound system
*/
void setEnabled(bool state) override;
/**
The system cycle counter is being adjusting by the specified amount. Any
members using the system cycle counter should be adjusted as needed.
@param amount The amount the cycle counter is being adjusted by
*/
void adjustCycleCounter(Int32 amount) override;
/**
Sets the number of channels (mono or stereo sound). Note that this
determines how the emulation should 'mix' the channels of the TIA sound
system (of which there are always two). It does not specify the actual
number of hardware channels that SDL should use; it will always attempt
to use two channels in hardware.
@param channels The number of channels
*/
void setChannels(uInt32 channels) override;
/**
Sets the display framerate. Sound generation for NTSC and PAL games
depends on the framerate, so we need to set it here.
@param framerate The base framerate depending on NTSC or PAL ROM
*/
void setFrameRate(float framerate) override;
/**
Initializes the sound device. This must be called before any
calls are made to derived methods.
*/
void open() override;
/**
Should be called to close the sound device. Once called the sound
device can be started again using the open method.
*/
void close() override;
/**
Set the mute state of the sound object. While muted no sound is played.
@param state Mutes sound if true, unmute if false
*/
void mute(bool state) override;
/**
Reset the sound device.
*/
void reset() override;
/**
Sets the sound register to a given value.
@param addr The register address
@param value The value to save into the register
@param cycle The system cycle at which the register is being updated
*/
void set(uInt16 addr, uInt8 value, Int32 cycle) override;
/**
Sets the volume of the sound device to the specified level. The
volume is given as a percentage from 0 to 100. Values outside
this range indicate that the volume shouldn't be changed at all.
@param percent The new volume percentage level for the sound device
*/
void setVolume(Int32 percent) override;
/**
Adjusts the volume of the sound device based on the given direction.
@param direction Increase or decrease the current volume by a predefined
amount based on the direction (1 = increase, -1 = decrease)
*/
void adjustVolume(Int8 direction) override;
public:
/**
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) const override;
/**
Loads the current state of this device from the given Serializer.
@param in The Serializer device to load from.
@return The result of the load. True on success, false on failure.
*/
bool load(Serializer& in) override;
/**
Get a descriptor for this console class (used in error checking).
@return The name of the object
*/
string name() const override { return "TIASound"; }
protected:
/**
Invoked by the sound callback to process the next sound fragment.
The stream is 16-bits (even though the callback is 8-bits), since
the TIASnd class always generates signed 16-bit stereo samples.
@param stream Pointer to the start of the fragment
@param length Length of the fragment
*/
void processFragment(Int16* stream, uInt32 length);
protected:
// Struct to hold information regarding a TIA sound register write
struct RegWrite
{
uInt16 addr;
uInt8 value;
double delta;
};
/**
A queue class used to hold TIA sound register writes before being
processed while creating a sound fragment.
*/
class RegWriteQueue
{
public:
/**
Create a new queue instance with the specified initial
capacity. If the queue ever reaches its capacity then it will
automatically increase its size.
*/
RegWriteQueue(uInt32 capacity = 512);
public:
/**
Clear any items stored in the queue.
*/
void clear();
/**
Dequeue the first object in the queue.
*/
void dequeue();
/**
Return the duration of all the items in the queue.
*/
double duration() const;
/**
Enqueue the specified object.
*/
void enqueue(const RegWrite& info);
/**
Return the item at the front on the queue.
@return The item at the front of the queue.
*/
RegWrite& front() const;
/**
Answers the number of items currently in the queue.
@return The number of items in the queue.
*/
uInt32 size() const;
private:
// Increase the size of the queue
void grow();
private:
unique_ptr<RegWrite[]> myBuffer;
uInt32 myCapacity;
uInt32 mySize;
uInt32 myHead;
uInt32 myTail;
private:
// Following constructors and assignment operators not supported
RegWriteQueue(const RegWriteQueue&) = delete;
RegWriteQueue(RegWriteQueue&&) = delete;
RegWriteQueue& operator=(const RegWriteQueue&) = delete;
RegWriteQueue& operator=(RegWriteQueue&&) = delete;
};
private:
// TIASound emulation object
TIASound myTIASound;
// Indicates if the sound subsystem is to be initialized
bool myIsEnabled;
// Indicates if the sound device was successfully initialized
bool myIsInitializedFlag;
// Indicates the cycle when a sound register was last set
Int32 myLastRegisterSetCycle;
// Indicates the number of channels (mono or stereo)
uInt32 myNumChannels;
// Log base 2 of the selected fragment size
double myFragmentSizeLogBase2;
// The myFragmentSizeLogBase2 variable is used in only two places,
// both of which involve an expensive division in the sound
// processing callback
// These are pre-computed to speed up the callback as much as possible
double myFragmentSizeLogDiv1, myFragmentSizeLogDiv2;
// Indicates if the sound is currently muted
bool myIsMuted;
// Current volume as a percentage (0 - 100)
uInt32 myVolume;
// Audio specification structure
SDL_AudioSpec myHardwareSpec;
// Queue of TIA register writes
RegWriteQueue myRegWriteQueue;
private:
// Callback function invoked by the SDL Audio library when it needs data
static void callback(void* udata, uInt8* stream, int len);
// Following constructors and assignment operators not supported
SoundSDL2() = delete;
SoundSDL2(const SoundSDL2&) = delete;
SoundSDL2(SoundSDL2&&) = delete;
SoundSDL2& operator=(const SoundSDL2&) = delete;
SoundSDL2& operator=(SoundSDL2&&) = delete;
};
#endif
#endif // SOUND_SUPPORT