mirror of https://github.com/stella-emu/stella.git
188 lines
5.5 KiB
C++
188 lines
5.5 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-2012 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.
|
|
//
|
|
// $Id$
|
|
//============================================================================
|
|
|
|
#ifndef TIASOUND_HXX
|
|
#define TIASOUND_HXX
|
|
|
|
#include "bspf.hxx"
|
|
|
|
/**
|
|
This class implements a fairly accurate emulation of the TIA sound
|
|
hardware. This class uses code/ideas from z26 and MESS.
|
|
|
|
@author Bradford W. Mott, Stephen Anthony, z26 and MESS teams
|
|
@version $Id$
|
|
*/
|
|
class TIASound
|
|
{
|
|
public:
|
|
/**
|
|
Create a new TIA Sound object using the specified output frequency
|
|
*/
|
|
TIASound(Int32 outputFrequency = 31400, Int32 tiaFrequency = 31400);
|
|
|
|
/**
|
|
Destructor
|
|
*/
|
|
virtual ~TIASound();
|
|
|
|
public:
|
|
/**
|
|
Reset the sound emulation to its power-on state
|
|
*/
|
|
void reset();
|
|
|
|
/**
|
|
Set the frequency output samples should be generated at
|
|
*/
|
|
void outputFrequency(Int32 freq);
|
|
|
|
/**
|
|
Set the frequency the of the TIA device
|
|
*/
|
|
void tiaFrequency(Int32 freq);
|
|
|
|
/**
|
|
Selects the number of audio channels per sample. There are two factors
|
|
to consider: hardware capability and desired mixing.
|
|
|
|
@param hardware The number of channels supported by the sound system
|
|
@param stereo Whether to output the internal sound signals into 1
|
|
or 2 channels
|
|
|
|
@return Status of the channel configuration used
|
|
*/
|
|
string channels(uInt32 hardware, bool stereo);
|
|
|
|
public:
|
|
/**
|
|
Sets the specified sound register to the given value
|
|
|
|
@param address Register address
|
|
@param value Value to store in the register
|
|
*/
|
|
void set(uInt16 address, uInt8 value);
|
|
|
|
/**
|
|
Gets the specified sound register's value
|
|
|
|
@param address Register address
|
|
*/
|
|
uInt8 get(uInt16 address) const;
|
|
|
|
/**
|
|
Create sound samples based on the current sound register settings
|
|
in the specified buffer. NOTE: If channels is set to stereo then
|
|
the buffer will need to be twice as long as the number of samples.
|
|
|
|
@param buffer The location to store generated samples
|
|
@param samples The number of samples to generate
|
|
*/
|
|
void process(Int16* buffer, uInt32 samples);
|
|
|
|
/**
|
|
Set the volume of the samples created (0-100)
|
|
*/
|
|
void volume(uInt32 percent);
|
|
|
|
private:
|
|
void polyInit(uInt8* poly, int size, int f0, int f1);
|
|
|
|
private:
|
|
// Definitions for AUDCx (15, 16)
|
|
enum AUDCxRegister
|
|
{
|
|
SET_TO_1 = 0x00, // 0000
|
|
POLY4 = 0x01, // 0001
|
|
DIV31_POLY4 = 0x02, // 0010
|
|
POLY5_POLY4 = 0x03, // 0011
|
|
PURE = 0x04, // 0100
|
|
PURE2 = 0x05, // 0101
|
|
DIV31_PURE = 0x06, // 0110
|
|
POLY5_2 = 0x07, // 0111
|
|
POLY9 = 0x08, // 1000
|
|
POLY5 = 0x09, // 1001
|
|
DIV31_POLY5 = 0x0a, // 1010
|
|
POLY5_POLY5 = 0x0b, // 1011
|
|
DIV3_PURE = 0x0c, // 1100
|
|
DIV3_PURE2 = 0x0d, // 1101
|
|
DIV93_PURE = 0x0e, // 1110
|
|
POLY5_DIV3 = 0x0f // 1111
|
|
};
|
|
|
|
enum {
|
|
POLY4_SIZE = 0x000f,
|
|
POLY5_SIZE = 0x001f,
|
|
POLY9_SIZE = 0x01ff,
|
|
DIV3_MASK = 0x0c,
|
|
AUDV_SHIFT = 10 // shift 2 positions for AUDV,
|
|
// then another 8 for 16-bit sound
|
|
};
|
|
|
|
enum ChannelMode {
|
|
Hardware2Mono, // mono sampling with 2 hardware channels
|
|
Hardware2Stereo, // stereo sampling with 2 hardware channels
|
|
Hardware1 // mono/stereo sampling with only 1 hardware channel
|
|
};
|
|
|
|
private:
|
|
// Structures to hold the 6 tia sound control bytes
|
|
uInt8 myAUDC[2]; // AUDCx (15, 16)
|
|
uInt8 myAUDF[2]; // AUDFx (17, 18)
|
|
Int16 myAUDV[2]; // AUDVx (19, 1A)
|
|
|
|
Int16 myVolume[2]; // Last output volume for each channel
|
|
|
|
uInt8 myP4[2]; // Position pointer for the 4-bit POLY array
|
|
uInt8 myP5[2]; // Position pointer for the 5-bit POLY array
|
|
uInt16 myP9[2]; // Position pointer for the 9-bit POLY array
|
|
|
|
uInt8 myDivNCnt[2]; // Divide by n counter. one for each channel
|
|
uInt8 myDivNMax[2]; // Divide by n maximum, one for each channel
|
|
uInt8 myDiv3Cnt[2]; // Div 3 counter, used for POLY5_DIV3 mode
|
|
|
|
ChannelMode myChannelMode;
|
|
Int32 myOutputFrequency;
|
|
Int32 myTIAFrequency;
|
|
Int32 myOutputCounter;
|
|
uInt32 myVolumePercentage;
|
|
|
|
/*
|
|
Initialize the bit patterns for the polynomials (at runtime).
|
|
|
|
The 4bit and 5bit patterns are the identical ones used in the tia chip.
|
|
Though the patterns could be packed with 8 bits per byte, using only a
|
|
single bit per byte keeps the math simple, which is important for
|
|
efficient processing.
|
|
*/
|
|
uInt8 Bit4[POLY4_SIZE];
|
|
uInt8 Bit5[POLY5_SIZE];
|
|
uInt8 Bit9[POLY9_SIZE];
|
|
|
|
/*
|
|
The 'Div by 31' counter is treated as another polynomial because of
|
|
the way it operates. It does not have a 50% duty cycle, but instead
|
|
has a 13:18 ratio (of course, 13+18 = 31). This could also be
|
|
implemented by using counters.
|
|
*/
|
|
static const uInt8 Div31[POLY5_SIZE];
|
|
};
|
|
|
|
#endif
|