in atari_py/ale_interface/src/common/SoundSDL.cxx [313:409]
void SoundSDL::processFragment(uInt8* stream, Int32 length)
{
if(!myIsInitializedFlag)
return;
uInt32 channels = myHardwareSpec.channels;
length = length / channels;
// If there are excessive items on the queue then we'll remove some
if(myRegWriteQueue.duration() >
(myFragmentSizeLogBase2 / myDisplayFrameRate))
{
double removed = 0.0;
while(removed < ((myFragmentSizeLogBase2 - 1) / myDisplayFrameRate))
{
RegWrite& info = myRegWriteQueue.front();
removed += info.delta;
myTIASound.set(info.addr, info.value);
myRegWriteQueue.dequeue();
}
// cerr << "Removed Items from RegWriteQueue!" << endl;
}
double position = 0.0;
double remaining = length;
while(remaining > 0.0)
{
if(myRegWriteQueue.size() == 0)
{
// There are no more pending TIA sound register updates so we'll
// use the current settings to finish filling the sound fragment
// myTIASound.process(stream + (uInt32)position, length - (uInt32)position);
myTIASound.process(stream + ((uInt32)position * channels),
length - (uInt32)position);
// Since we had to fill the fragment we'll reset the cycle counter
// to zero. NOTE: This isn't 100% correct, however, it'll do for
// now. We should really remember the overrun and remove it from
// the delta of the next write.
myLastRegisterSetCycle = 0;
break;
}
else
{
// There are pending TIA sound register updates so we need to
// update the sound buffer to the point of the next register update
RegWrite& info = myRegWriteQueue.front();
// How long will the remaining samples in the fragment take to play
double duration = remaining / (double)myHardwareSpec.freq;
// Does the register update occur before the end of the fragment?
if(info.delta <= duration)
{
// If the register update time hasn't already passed then
// process samples upto the point where it should occur
if(info.delta > 0.0)
{
// Process the fragment upto the next TIA register write. We
// round the count passed to process up if needed.
double samples = (myHardwareSpec.freq * info.delta);
// myTIASound.process(stream + (uInt32)position, (uInt32)samples +
// (uInt32)(position + samples) -
// ((uInt32)position + (uInt32)samples));
myTIASound.process(stream + ((uInt32)position * channels),
(uInt32)samples + (uInt32)(position + samples) -
((uInt32)position + (uInt32)samples));
position += samples;
remaining -= samples;
}
myTIASound.set(info.addr, info.value);
myRegWriteQueue.dequeue();
}
else
{
// The next register update occurs in the next fragment so finish
// this fragment with the current TIA settings and reduce the register
// update delay by the corresponding amount of time
// myTIASound.process(stream + (uInt32)position, length - (uInt32)position);
myTIASound.process(stream + ((uInt32)position * channels),
length - (uInt32)position);
info.delta -= duration;
break;
}
}
}
// If recording sound, do so now
if (mySoundExporter.get() != NULL && myNumRecordSamplesNeeded > 0) {
mySoundExporter->addSamples(stream, length);
// Consume this many samples
myNumRecordSamplesNeeded -= length;
}
}