diff --git a/stella/src/common/SoundSDL.cxx b/stella/src/common/SoundSDL.cxx index 44736e168..2d96c6d54 100644 --- a/stella/src/common/SoundSDL.cxx +++ b/stella/src/common/SoundSDL.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: SoundSDL.cxx,v 1.22 2005-09-04 23:59:30 bwmott Exp $ +// $Id: SoundSDL.cxx,v 1.23 2005-09-05 01:12:56 stephena Exp $ //============================================================================ #ifdef SOUND_SUPPORT @@ -23,7 +23,7 @@ #include #include -#include "TIASound.h" +#include "TIASnd.hxx" #include "FrameBuffer.hxx" #include "Serializer.hxx" #include "Deserializer.hxx" @@ -576,4 +576,4 @@ void SoundSDL::RegWriteQueue::grow() myBuffer = buffer; } -#endif // SOUND_SUPPORT \ No newline at end of file +#endif // SOUND_SUPPORT diff --git a/stella/src/emucore/TIASnd.cxx b/stella/src/emucore/TIASnd.cxx index da4266c17..dbaf8adac 100644 --- a/stella/src/emucore/TIASnd.cxx +++ b/stella/src/emucore/TIASnd.cxx @@ -13,361 +13,361 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIASnd.cxx,v 1.1 2005-09-04 23:48:33 bwmott Exp $ -//============================================================================ - -#include "System.hxx" -#include "TIASnd.hxx" - +// $Id: TIASnd.cxx,v 1.2 2005-09-05 01:12:56 stephena Exp $ +//============================================================================ + +#include "System.hxx" +#include "TIASnd.hxx" + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -TIASound::TIASound(Int32 outputFrequency, uInt32 channels) - : myOutputFrequency(outputFrequency), - myChannels(channels), - myOutputCounter(0), - myVolumePercentage(100) -{ - reset(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -TIASound::~TIASound() -{ -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::reset() -{ - myAUDC[0] = myAUDC[1] = myAUDF[0] = myAUDF[1] = myAUDV[0] = myAUDV[1] = 0; - myP4[0] = myP5[0] = myP4[1] = myP5[1] = 1; - myFreqDiv[0].set(0); - myFreqDiv[1].set(0); - myOutputCounter = 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::outputFrequency(uInt32 freq) -{ - myOutputFrequency = freq; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::channels(uInt32 number) -{ - if(number == 2) - myChannels = 2; - else - myChannels = 1; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::set(uInt16 address, uInt8 value) -{ - switch(address) - { - case 0x15: // AUDC0 - myAUDC[0] = value & 0x0f; - break; - - case 0x16: // AUDC1 - myAUDC[1] = value & 0x0f; - break; - - case 0x17: // AUDF0 - myAUDF[0] = value & 0x1f; - myFreqDiv[0].set(myAUDF[0]); - break; - - case 0x18: // AUDF1 - myAUDF[1] = value & 0x1f; - myFreqDiv[1].set(myAUDF[1]); - break; - - case 0x19: // AUDV0 - myAUDV[0] = value & 0x0f; - break; - - case 0x1a: // AUDV1 - myAUDV[1] = value & 0x0f; - break; - - default: - break; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 TIASound::get(uInt16 address) -{ - switch(address) - { - case 0x15: // AUDC0 - return myAUDC[0]; - - case 0x16: // AUDC1 - return myAUDC[1]; - - case 0x17: // AUDF0 - return myAUDF[0]; - - case 0x18: // AUDF1 - return myAUDF[1]; - - case 0x19: // AUDV0 - return myAUDV[0]; - - case 0x1a: // AUDV1 - return myAUDV[1]; - - default: - return 0; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::volume(uInt32 percent) -{ - if((percent >= 0) && (percent <= 100)) - { - myVolumePercentage = percent; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASound::process(uInt8* buffer, uInt32 samples) -{ - Int32 v0 = ((myAUDV[0] << 2) * myVolumePercentage) / 100; - Int32 v1 = ((myAUDV[1] << 2) * myVolumePercentage) / 100; - - // Loop until the sample buffer is full - while(samples > 0) - { - // Process both sound channels - for(uInt32 c = 0; c < 2; ++c) - { - // Update P4 & P5 registers for channel if freq divider outputs a pulse - if((myFreqDiv[c].clock())) - { - switch(myAUDC[c]) - { - case 0x00: // Set to 1 - { - // Shift a 1 into the 4-bit register each clock - myP4[c] = (myP4[c] << 1) | 0x01; - break; - } - - case 0x01: // 4 bit poly - { - // Clock P4 as a standard 4-bit LSFR taps at bits 3 & 2 - myP4[c] = (myP4[c] & 0x0f) ? - ((myP4[c] << 1) | (((myP4[c] & 0x08) ? 1 : 0) ^ - ((myP4[c] & 0x04) ? 1 : 0))) : 1; - break; - } - - case 0x02: // div 31 -> 4 bit poly - { - // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 - myP5[c] = (myP5[c] & 0x1f) ? - ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ - ((myP5[c] & 0x04) ? 1 : 0))) : 1; - - // This does the divide-by 31 with length 13:18 - if((myP5[c] & 0x0f) == 0x08) - { - // Clock P4 as a standard 4-bit LSFR taps at bits 3 & 2 - myP4[c] = (myP4[c] & 0x0f) ? - ((myP4[c] << 1) | (((myP4[c] & 0x08) ? 1 : 0) ^ - ((myP4[c] & 0x04) ? 1 : 0))) : 1; - } - break; - } - - case 0x03: // 5 bit poly -> 4 bit poly - { - // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 - myP5[c] = (myP5[c] & 0x1f) ? - ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ - ((myP5[c] & 0x04) ? 1 : 0))) : 1; - - // P5 clocks the 4 bit poly - if(myP5[c] & 0x10) - { - // Clock P4 as a standard 4-bit LSFR taps at bits 3 & 2 - myP4[c] = (myP4[c] & 0x0f) ? - ((myP4[c] << 1) | (((myP4[c] & 0x08) ? 1 : 0) ^ - ((myP4[c] & 0x04) ? 1 : 0))) : 1; - } - break; - } - - case 0x04: // div 2 - { - // Clock P4 toggling the lower bit (divide by 2) - myP4[c] = (myP4[c] << 1) | ((myP4[c] & 0x01) ? 0 : 1); - break; - } - - case 0x05: // div 2 - { - // Clock P4 toggling the lower bit (divide by 2) - myP4[c] = (myP4[c] << 1) | ((myP4[c] & 0x01) ? 0 : 1); - break; - } - - case 0x06: // div 31 -> div 2 - { - // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 - myP5[c] = (myP5[c] & 0x1f) ? - ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ - ((myP5[c] & 0x04) ? 1 : 0))) : 1; - - // This does the divide-by 31 with length 13:18 - if((myP5[c] & 0x0f) == 0x08) - { - // Clock P4 toggling the lower bit (divide by 2) - myP4[c] = (myP4[c] << 1) | ((myP4[c] & 0x01) ? 0 : 1); - } - break; - } - - case 0x07: // 5 bit poly -> div 2 - { - // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 - myP5[c] = (myP5[c] & 0x1f) ? - ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ - ((myP5[c] & 0x04) ? 1 : 0))) : 1; - - // P5 clocks the 4 bit register - if(myP5[c] & 0x10) - { - // Clock P4 toggling the lower bit (divide by 2) - myP4[c] = (myP4[c] << 1) | ((myP4[c] & 0x01) ? 0 : 1); - } - break; - } - - case 0x08: // 9 bit poly - { - // Clock P5 & P4 as a standard 9-bit LSFR taps at 8 & 4 - myP5[c] = ((myP5[c] & 0x1f) || (myP4[c] & 0x0f)) ? - ((myP5[c] << 1) | (((myP4[c] & 0x08) ? 1 : 0) ^ - ((myP5[c] & 0x10) ? 1 : 0))) : 1; - myP4[c] = (myP4[c] << 1) | ((myP5[c] & 0x20) ? 1 : 0); - break; - } - - case 0x09: // 5 bit poly - { - // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 - myP5[c] = (myP5[c] & 0x1f) ? - ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ - ((myP5[c] & 0x04) ? 1 : 0))) : 1; - - // Clock value out of P5 into P4 with no modification - myP4[c] = (myP4[c] << 1) | ((myP5[c] & 0x20) ? 1 : 0); - break; - } - - case 0x0a: // div 31 - { - // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 - myP5[c] = (myP5[c] & 0x1f) ? - ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ - ((myP5[c] & 0x04) ? 1 : 0))) : 1; - - // This does the divide-by 31 with length 13:18 - if((myP5[c] & 0x0f) == 0x08) - { - // Feed bit 4 of P5 into P4 (this will toggle back and forth) - myP4[c] = (myP4[c] << 1) | ((myP5[c] & 0x10) ? 1 : 0); - } - break; - } - - case 0x0b: // Set last 4 bits to 1 - { - // A 1 is shifted into the 4-bit register each clock - myP4[c] = (myP4[c] << 1) | 0x01; - break; - } - - case 0x0c: // div 6 - { - // Use 4-bit register to generate sequence 000111000111 - myP4[c] = (~myP4[c] << 1) | - ((!(!(myP4[c] & 4) && ((myP4[c] & 7)))) ? 0 : 1); - break; - } - - case 0x0d: // div 6 - { - // Use 4-bit register to generate sequence 000111000111 - myP4[c] = (~myP4[c] << 1) | - ((!(!(myP4[c] & 4) && ((myP4[c] & 7)))) ? 0 : 1); - break; - } - - case 0x0e: // div 31 -> div 6 - { - // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 - myP5[c] = (myP5[c] & 0x1f) ? - ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ - ((myP5[c] & 0x04) ? 1 : 0))) : 1; - - // This does the divide-by 31 with length 13:18 - if((myP5[c] & 0x0f) == 0x08) - { - // Use 4-bit register to generate sequence 000111000111 - myP4[c] = (~myP4[c] << 1) | - ((!(!(myP4[c] & 4) && ((myP4[c] & 7)))) ? 0 : 1); - } - break; - } - - case 0x0f: // poly 5 -> div 6 - { - // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 - myP5[c] = (myP5[c] & 0x1f) ? - ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ - ((myP5[c] & 0x04) ? 1 : 0))) : 1; - - // Use poly 5 to clock 4-bit div register - if(myP5[c] & 0x10) - { - // Use 4-bit register to generate sequence 000111000111 - myP4[c] = (~myP4[c] << 1) | - ((!(!(myP4[c] & 4) && ((myP4[c] & 7)))) ? 0 : 1); - } - break; - } - } - } - } - - myOutputCounter += myOutputFrequency; - - if(myChannels == 1) - { - // Handle mono sample generation - while((samples > 0) && (myOutputCounter >= TIASoundFrequency)) - { - *(buffer++) = (((myP4[0] & 8) ? v0 : 0) + - ((myP4[1] & 8) ? v1 : 0)) + 128; - myOutputCounter -= TIASoundFrequency; - samples--; - } - } - else - { - // Handle stereo sample generation - while((samples > 0) && (myOutputCounter >= TIASoundFrequency)) - { - *(buffer++) = ((myP4[0] & 8) ? v0 : 0) + 128; - *(buffer++) = ((myP4[1] & 8) ? v1 : 0) + 128; - myOutputCounter -= TIASoundFrequency; - samples--; - } - } - } -} \ No newline at end of file +TIASound::TIASound(Int32 outputFrequency, uInt32 channels) + : myOutputFrequency(outputFrequency), + myChannels(channels), + myOutputCounter(0), + myVolumePercentage(100) +{ + reset(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +TIASound::~TIASound() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASound::reset() +{ + myAUDC[0] = myAUDC[1] = myAUDF[0] = myAUDF[1] = myAUDV[0] = myAUDV[1] = 0; + myP4[0] = myP5[0] = myP4[1] = myP5[1] = 1; + myFreqDiv[0].set(0); + myFreqDiv[1].set(0); + myOutputCounter = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASound::outputFrequency(uInt32 freq) +{ + myOutputFrequency = freq; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASound::channels(uInt32 number) +{ + if(number == 2) + myChannels = 2; + else + myChannels = 1; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASound::set(uInt16 address, uInt8 value) +{ + switch(address) + { + case 0x15: // AUDC0 + myAUDC[0] = value & 0x0f; + break; + + case 0x16: // AUDC1 + myAUDC[1] = value & 0x0f; + break; + + case 0x17: // AUDF0 + myAUDF[0] = value & 0x1f; + myFreqDiv[0].set(myAUDF[0]); + break; + + case 0x18: // AUDF1 + myAUDF[1] = value & 0x1f; + myFreqDiv[1].set(myAUDF[1]); + break; + + case 0x19: // AUDV0 + myAUDV[0] = value & 0x0f; + break; + + case 0x1a: // AUDV1 + myAUDV[1] = value & 0x0f; + break; + + default: + break; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 TIASound::get(uInt16 address) +{ + switch(address) + { + case 0x15: // AUDC0 + return myAUDC[0]; + + case 0x16: // AUDC1 + return myAUDC[1]; + + case 0x17: // AUDF0 + return myAUDF[0]; + + case 0x18: // AUDF1 + return myAUDF[1]; + + case 0x19: // AUDV0 + return myAUDV[0]; + + case 0x1a: // AUDV1 + return myAUDV[1]; + + default: + return 0; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASound::volume(uInt32 percent) +{ + if((percent >= 0) && (percent <= 100)) + { + myVolumePercentage = percent; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASound::process(uInt8* buffer, uInt32 samples) +{ + Int32 v0 = ((myAUDV[0] << 2) * myVolumePercentage) / 100; + Int32 v1 = ((myAUDV[1] << 2) * myVolumePercentage) / 100; + + // Loop until the sample buffer is full + while(samples > 0) + { + // Process both sound channels + for(uInt32 c = 0; c < 2; ++c) + { + // Update P4 & P5 registers for channel if freq divider outputs a pulse + if((myFreqDiv[c].clock())) + { + switch(myAUDC[c]) + { + case 0x00: // Set to 1 + { + // Shift a 1 into the 4-bit register each clock + myP4[c] = (myP4[c] << 1) | 0x01; + break; + } + + case 0x01: // 4 bit poly + { + // Clock P4 as a standard 4-bit LSFR taps at bits 3 & 2 + myP4[c] = (myP4[c] & 0x0f) ? + ((myP4[c] << 1) | (((myP4[c] & 0x08) ? 1 : 0) ^ + ((myP4[c] & 0x04) ? 1 : 0))) : 1; + break; + } + + case 0x02: // div 31 -> 4 bit poly + { + // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 + myP5[c] = (myP5[c] & 0x1f) ? + ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ + ((myP5[c] & 0x04) ? 1 : 0))) : 1; + + // This does the divide-by 31 with length 13:18 + if((myP5[c] & 0x0f) == 0x08) + { + // Clock P4 as a standard 4-bit LSFR taps at bits 3 & 2 + myP4[c] = (myP4[c] & 0x0f) ? + ((myP4[c] << 1) | (((myP4[c] & 0x08) ? 1 : 0) ^ + ((myP4[c] & 0x04) ? 1 : 0))) : 1; + } + break; + } + + case 0x03: // 5 bit poly -> 4 bit poly + { + // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 + myP5[c] = (myP5[c] & 0x1f) ? + ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ + ((myP5[c] & 0x04) ? 1 : 0))) : 1; + + // P5 clocks the 4 bit poly + if(myP5[c] & 0x10) + { + // Clock P4 as a standard 4-bit LSFR taps at bits 3 & 2 + myP4[c] = (myP4[c] & 0x0f) ? + ((myP4[c] << 1) | (((myP4[c] & 0x08) ? 1 : 0) ^ + ((myP4[c] & 0x04) ? 1 : 0))) : 1; + } + break; + } + + case 0x04: // div 2 + { + // Clock P4 toggling the lower bit (divide by 2) + myP4[c] = (myP4[c] << 1) | ((myP4[c] & 0x01) ? 0 : 1); + break; + } + + case 0x05: // div 2 + { + // Clock P4 toggling the lower bit (divide by 2) + myP4[c] = (myP4[c] << 1) | ((myP4[c] & 0x01) ? 0 : 1); + break; + } + + case 0x06: // div 31 -> div 2 + { + // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 + myP5[c] = (myP5[c] & 0x1f) ? + ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ + ((myP5[c] & 0x04) ? 1 : 0))) : 1; + + // This does the divide-by 31 with length 13:18 + if((myP5[c] & 0x0f) == 0x08) + { + // Clock P4 toggling the lower bit (divide by 2) + myP4[c] = (myP4[c] << 1) | ((myP4[c] & 0x01) ? 0 : 1); + } + break; + } + + case 0x07: // 5 bit poly -> div 2 + { + // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 + myP5[c] = (myP5[c] & 0x1f) ? + ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ + ((myP5[c] & 0x04) ? 1 : 0))) : 1; + + // P5 clocks the 4 bit register + if(myP5[c] & 0x10) + { + // Clock P4 toggling the lower bit (divide by 2) + myP4[c] = (myP4[c] << 1) | ((myP4[c] & 0x01) ? 0 : 1); + } + break; + } + + case 0x08: // 9 bit poly + { + // Clock P5 & P4 as a standard 9-bit LSFR taps at 8 & 4 + myP5[c] = ((myP5[c] & 0x1f) || (myP4[c] & 0x0f)) ? + ((myP5[c] << 1) | (((myP4[c] & 0x08) ? 1 : 0) ^ + ((myP5[c] & 0x10) ? 1 : 0))) : 1; + myP4[c] = (myP4[c] << 1) | ((myP5[c] & 0x20) ? 1 : 0); + break; + } + + case 0x09: // 5 bit poly + { + // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 + myP5[c] = (myP5[c] & 0x1f) ? + ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ + ((myP5[c] & 0x04) ? 1 : 0))) : 1; + + // Clock value out of P5 into P4 with no modification + myP4[c] = (myP4[c] << 1) | ((myP5[c] & 0x20) ? 1 : 0); + break; + } + + case 0x0a: // div 31 + { + // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 + myP5[c] = (myP5[c] & 0x1f) ? + ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ + ((myP5[c] & 0x04) ? 1 : 0))) : 1; + + // This does the divide-by 31 with length 13:18 + if((myP5[c] & 0x0f) == 0x08) + { + // Feed bit 4 of P5 into P4 (this will toggle back and forth) + myP4[c] = (myP4[c] << 1) | ((myP5[c] & 0x10) ? 1 : 0); + } + break; + } + + case 0x0b: // Set last 4 bits to 1 + { + // A 1 is shifted into the 4-bit register each clock + myP4[c] = (myP4[c] << 1) | 0x01; + break; + } + + case 0x0c: // div 6 + { + // Use 4-bit register to generate sequence 000111000111 + myP4[c] = (~myP4[c] << 1) | + ((!(!(myP4[c] & 4) && ((myP4[c] & 7)))) ? 0 : 1); + break; + } + + case 0x0d: // div 6 + { + // Use 4-bit register to generate sequence 000111000111 + myP4[c] = (~myP4[c] << 1) | + ((!(!(myP4[c] & 4) && ((myP4[c] & 7)))) ? 0 : 1); + break; + } + + case 0x0e: // div 31 -> div 6 + { + // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 + myP5[c] = (myP5[c] & 0x1f) ? + ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ + ((myP5[c] & 0x04) ? 1 : 0))) : 1; + + // This does the divide-by 31 with length 13:18 + if((myP5[c] & 0x0f) == 0x08) + { + // Use 4-bit register to generate sequence 000111000111 + myP4[c] = (~myP4[c] << 1) | + ((!(!(myP4[c] & 4) && ((myP4[c] & 7)))) ? 0 : 1); + } + break; + } + + case 0x0f: // poly 5 -> div 6 + { + // Clock P5 as a standard 5-bit LSFR taps at bits 4 & 2 + myP5[c] = (myP5[c] & 0x1f) ? + ((myP5[c] << 1) | (((myP5[c] & 0x10) ? 1 : 0) ^ + ((myP5[c] & 0x04) ? 1 : 0))) : 1; + + // Use poly 5 to clock 4-bit div register + if(myP5[c] & 0x10) + { + // Use 4-bit register to generate sequence 000111000111 + myP4[c] = (~myP4[c] << 1) | + ((!(!(myP4[c] & 4) && ((myP4[c] & 7)))) ? 0 : 1); + } + break; + } + } + } + } + + myOutputCounter += myOutputFrequency; + + if(myChannels == 1) + { + // Handle mono sample generation + while((samples > 0) && (myOutputCounter >= TIASoundFrequency)) + { + *(buffer++) = (((myP4[0] & 8) ? v0 : 0) + + ((myP4[1] & 8) ? v1 : 0)) + 128; + myOutputCounter -= TIASoundFrequency; + samples--; + } + } + else + { + // Handle stereo sample generation + while((samples > 0) && (myOutputCounter >= TIASoundFrequency)) + { + *(buffer++) = ((myP4[0] & 8) ? v0 : 0) + 128; + *(buffer++) = ((myP4[1] & 8) ? v1 : 0) + 128; + myOutputCounter -= TIASoundFrequency; + samples--; + } + } + } +} diff --git a/stella/src/emucore/TIASnd.hxx b/stella/src/emucore/TIASnd.hxx index 9ecd35dbf..d2e3891fa 100644 --- a/stella/src/emucore/TIASnd.hxx +++ b/stella/src/emucore/TIASnd.hxx @@ -13,20 +13,20 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIASnd.hxx,v 1.1 2005-09-04 23:48:33 bwmott Exp $ -//============================================================================ - -#ifndef TIASOUND_HXX -#define TIASOUND_HXX - -#include "bspf.hxx" - +// $Id: TIASnd.hxx,v 1.2 2005-09-05 01:12:56 stephena Exp $ +//============================================================================ + +#ifndef TIASOUND_HXX +#define TIASOUND_HXX + +#include "bspf.hxx" + /** This class implements a fairly accurate emulation of the TIA sound hardware. @author Bradford W. Mott - @version $Id: TIASnd.hxx,v 1.1 2005-09-04 23:48:33 bwmott Exp $ + @version $Id: TIASnd.hxx,v 1.2 2005-09-05 01:12:56 stephena Exp $ */ class TIASound { @@ -37,105 +37,106 @@ class TIASound /** Create a new TIA Sound object using the specified output frequency */ - TIASound(Int32 outputFrequency = TIASoundFrequency, uInt32 channels = 1); - - /** - Destructor - */ - virtual ~TIASound(); - - public: + TIASound(Int32 outputFrequency = TIASoundFrequency, uInt32 channels = 1); + + /** + 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(uInt32 freq); - - /** - Selects the number of audio channels per sample (1 = mono, 2 = stereo) - */ - void channels(uInt32 number); - - 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); - - /** - 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(uInt8* buffer, uInt32 samples); - - /** - Set the volume of the samples created (0-100) - */ - void volume(uInt32 percent); - - private: - /** - Frequency divider class which outputs 1 after "divide-by" clocks. This - is used to divide the main frequency by the values 1 to 32. - */ - class FreqDiv - { - public: - FreqDiv() - { - myDivideByValue = myCounter = 0; - } - - void set(uInt32 divideBy) - { - myDivideByValue = divideBy; - } - - bool clock() - { - if(++myCounter > myDivideByValue) - { - myCounter = 0; - return true; - } - return false; - } - - private: - uInt32 myDivideByValue; - uInt32 myCounter; - }; - - private: - uInt8 myAUDC[2]; - uInt8 myAUDF[2]; - uInt8 myAUDV[2]; - - FreqDiv myFreqDiv[2]; // Frequency dividers - uInt8 myP4[2]; // 4-bit register LFSR (lower 4 bits used) - uInt8 myP5[2]; // 5-bit register LFSR (lower 5 bits used) - - Int32 myOutputFrequency; - Int32 myOutputCounter; - uInt32 myChannels; - uInt32 myVolumePercentage; -}; -#endif \ No newline at end of file + void reset(); + + /** + Set the frequency output samples should be generated at + */ + void outputFrequency(uInt32 freq); + + /** + Selects the number of audio channels per sample (1 = mono, 2 = stereo) + */ + void channels(uInt32 number); + + 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); + + /** + 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(uInt8* buffer, uInt32 samples); + + /** + Set the volume of the samples created (0-100) + */ + void volume(uInt32 percent); + + private: + /** + Frequency divider class which outputs 1 after "divide-by" clocks. This + is used to divide the main frequency by the values 1 to 32. + */ + class FreqDiv + { + public: + FreqDiv() + { + myDivideByValue = myCounter = 0; + } + + void set(uInt32 divideBy) + { + myDivideByValue = divideBy; + } + + bool clock() + { + if(++myCounter > myDivideByValue) + { + myCounter = 0; + return true; + } + return false; + } + + private: + uInt32 myDivideByValue; + uInt32 myCounter; + }; + + private: + uInt8 myAUDC[2]; + uInt8 myAUDF[2]; + uInt8 myAUDV[2]; + + FreqDiv myFreqDiv[2]; // Frequency dividers + uInt8 myP4[2]; // 4-bit register LFSR (lower 4 bits used) + uInt8 myP5[2]; // 5-bit register LFSR (lower 5 bits used) + + Int32 myOutputFrequency; + uInt32 myChannels; + Int32 myOutputCounter; + uInt32 myVolumePercentage; +}; + +#endif diff --git a/stella/src/emucore/module.mk b/stella/src/emucore/module.mk index 78326074d..64ef7029e 100644 --- a/stella/src/emucore/module.mk +++ b/stella/src/emucore/module.mk @@ -45,7 +45,7 @@ MODULE_OBJS := \ src/emucore/Settings.o \ src/emucore/Switches.o \ src/emucore/TIA.o \ - src/emucore/TIASound.o \ + src/emucore/TIASnd.o \ src/emucore/unzip.o MODULE_DIRS += \