Skip to content

Commit

Permalink
Improvement to volume sampling in TIA audio (#1038)
Browse files Browse the repository at this point in the history
volume of audio channels sampled every on every tick. sum of samples is
averaged and a new sample output twice per scanline

this fixes issues with ROMs that change the volume of the audio multiple
times per scanline. for example, the experimental ROM in the following
thread now works correctly

https://forums.atariage.com/topic/370460-8-bit-digital-audio-from-2600/

(note that the ROM does not initialise the machine cleanly and so running
the emulator with developer options (random memory etc.) can cause
incorrect audio)
  • Loading branch information
JetSetIlly authored Aug 7, 2024
1 parent 56e6bd6 commit e8a9fe2
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 7 deletions.
14 changes: 11 additions & 3 deletions src/emucore/tia/Audio.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ void Audio::reset()
{
myCounter = 0;
mySampleIndex = 0;
sumChannel0 = 0;
sumChannel1 = 0;
sumCt = 0;

myChannel0.reset();
myChannel1.reset();
Expand All @@ -62,10 +65,15 @@ void Audio::setAudioQueue(const shared_ptr<AudioQueue>& queue)
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Audio::phase1()
void Audio::createSample()
{
const uInt8 sample0 = myChannel0.phase1();
const uInt8 sample1 = myChannel1.phase1();
// calculate average of all recent volume samples. the average for each
// channel is mixed to create a single audible value
const uInt8 sample0 = (uInt8)(sumChannel0/sumCt);
const uInt8 sample1 = (uInt8)(sumChannel1/sumCt);
sumChannel0 = 0;
sumChannel1 = 0;
sumCt = 0;

addSample(sample0, sample1);
#ifdef GUI_SUPPORT
Expand Down
16 changes: 14 additions & 2 deletions src/emucore/tia/Audio.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class Audio : public Serializable
bool load(Serializer& in) override;

private:
void phase1();
void createSample();
void addSample(uInt8 sample0, uInt8 sample1);

private:
Expand All @@ -68,6 +68,10 @@ class Audio : public Serializable
AudioChannel myChannel0;
AudioChannel myChannel1;

uInt32 sumChannel0;
uInt32 sumChannel1;
uInt32 sumCt;

std::array<Int16, 0x1e + 1> myMixingTableSum;
std::array<Int16, 0x0f + 1> myMixingTableIndividual;

Expand All @@ -92,6 +96,12 @@ class Audio : public Serializable
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Audio::tick()
{
// volume for each channel is sampled every color clock. the average of
// these samples will be taken twice a scanline in the phase1() function
sumChannel0 += (uInt32)myChannel0.actualVolume();
sumChannel1 += (uInt32)myChannel1.actualVolume();
sumCt++;

switch (myCounter) {
case 9:
case 81:
Expand All @@ -101,7 +111,9 @@ void Audio::tick()

case 37:
case 149:
phase1();
myChannel0.phase1();
myChannel1.phase1();
createSample();
break;

default:
Expand Down
7 changes: 6 additions & 1 deletion src/emucore/tia/AudioChannel.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void AudioChannel::phase0()
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 AudioChannel::phase1()
void AudioChannel::phase1()
{
if (myClockEnable) {
bool pulseFeedback = false;
Expand Down Expand Up @@ -118,7 +118,12 @@ uInt8 AudioChannel::phase1()
}
}
}
}

// the actual volume of a chaneel is the volume register multiplied by the
// lowest of the pulse counter
uInt8 AudioChannel::actualVolume()
{
return (myPulseCounter & 0x01) * myAudv;
}

Expand Down
4 changes: 3 additions & 1 deletion src/emucore/tia/AudioChannel.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ class AudioChannel : public Serializable

void phase0();

uInt8 phase1();
void phase1();

uInt8 actualVolume();

void audc(uInt8 value);

Expand Down

0 comments on commit e8a9fe2

Please sign in to comment.