Scrubbing Audio Samples Randomly in the Removers Library

Scrubbing Audio Samples Randomly in the Removers Library

Alignment of data in the Removers Library or development on the Jaguar in general. In particular when you need to access a block of data. I recently ran into bugs with Odd-It Will Be Watching when adding gibberish voices to characters when they speak.

The Goal

I wanted to take a very short audio sample of gibberish, and then in game start playback at random points in the sample for a random amount of time. The end result is to produce a sound that sounds like speech when a character is talking in-game.

The Trouble

Implementing this was fairly simple. After properly unpacking my audio data and running the state where the character talks, I used a local integer variable for a count down timer to check before picking a random point, using another variable to store the offset for playback, and then resetting playback at the offset. When testing in an emulator, Virtual Jaguar, there doesn’t seem to be any problem. The gibberish voice plays back as expected. It is a different story on actual Jaguar hardware though.

When playing back on hardware, the voice obviously starts playback from odd points in memory marked by the sound of a loud white noise. Instead of withing the audio sample’s block of memory.

The solution

After some troubleshooting, I remembered that inside of the Removers Documentation Seb mentions that every parameter passed to a function and on to the stack is 32-bits (long-word) long. This gave me an ideas that accessing and trying to play back from the middle of 32-bit block of data might cause a problem I actually don’t know exactly why this is a problem. Regardless, by forcing my offset to look at a the beginning of a 32-bit block of the audio sample’s data, this seems to have fixed the problem.

With this in mind, below are two examples. The first is accessing data without taking into account that you should access the audio data at the beginning of every 32-bits, causing the white noise during playback, and the second example which forces the offset to a 32-bit boundary doing offset modulo 32.

char *voiceSampleData;  //Our audio sample data
int voiceSampleDataSize = 140693;  //Arbitrary size of our audio sample data
int voiceStartPoint = 0;  //To store our offset for playback
int countdown = 20; //Time between picking new offset and playing sample at new offset.
    
//countdown timer
if(timer > 1){
    countdown--;
}

//when timer hits zero pick new place in sample to play back from and then reset timer
else{
    //pick random point in the sample using the total byte size of the sample
    voiceStartPoint = rand()%voiceSampleDataSize;
    
    //Play sample with the offset defined by "voiceStartPoint", and adjust our sample 
    length to make sure we don't play data beyond the boundary of the audio sample. 
    set_voice(4, VOICE_16|VOICE_BALANCE(8)|VOICE_VOLUME(volume)|VOICE_FREQ(replayFrequency, playbackRate), voiceSampleData + voiceStartPoint, voiceSampleDataSize - voiceStartPoint, voiceSampleData + voiceStartPoint, voiceSampleDataSize - voiceStartPoint);

    countdown = rand()%20 + 5;  //Set random time for timer
}
char *voiceSampleData;  //Our audio sample data
int voiceSampleDataSize = 140693;  //Arbitrary size of our audio sample data
int voiceStartPoint = 0;  //To store our offset for playback
int countdown = 20; //Time between picking new offset and playing sample at new offset.
    
//countdown timer
if(timer > 1){
    countdown--;
}

//when timer hits zero pick new place in sample to play back from and then reset timer
else{
    //pick random point in the sample using the total byte size of the sample
    voiceStartPoint = rand()%voiceSampleDataSize;

/*!!NEXT LINE OF CODE IS THE ONLY CODE NEEDED TO FIX OUR PROBLEM!!*/ //minus the remainder of the new start point divided by 32 to make sure we are starting at the beginning of a 32-bit block voiceStartPoint -= voiceStartPoint%sizeof(int);

//Play sample with the offset defined by "voiceStartPoint", and adjust our sample length to make sure we don't play data beyond the boundary of the audio sample. set_voice(4, VOICE_16|VOICE_BALANCE(8)|VOICE_VOLUME(volume)|VOICE_FREQ(replayFrequency, playbackRate), voiceSampleData + voiceStartPoint, voiceSampleDataSize - voiceStartPoint, voiceSampleData + voiceStartPoint, voiceSampleDataSize - voiceStartPoint); countdown = rand()%20 + 5; //Set random time for timer }