Sounds in Q-Bert remake

I have settled on the following solution…

I mix only two samples but I do if over and over for how many samples are playing while adding to the current sample. I add and then half each sample, so that the result is 50% mix of the two, but if either of the samples are zero, then I just select the other so that the volume doesn’t suffer is only one sample is being played.

uint8_t mixSound(int samplePos)
{
	int temp = 0;
	for(int t=0; t<10; t++){
        if(snd[t].playSample!=0){
            int currentSample = (snd[t].currentSound[(snd[t].soundPoint*snd[t].speed)>>8]*snd[t].volume)>>8;
            if(temp==0 && currentSample!=0){
                temp = currentSample;
            }else if(temp!=0 && currentSample!=0){
                temp = (temp+currentSample)>>1;
            } // else temp = temp
        }
	}
	return temp;
}


void updateSample(){

 int quart = soundbufindex / 512;
 int sndOffset[]={512,1024,1536,0};

    if(oldQuart != quart){
        oldQuart = quart;
        for(int t=0; t<SBUFSIZE/4;){
            uint8_t sample = mixSound(t);
            soundbuf[t+sndOffset[quart]] = sample;

            for(int s=0; s<10; s++){
                ++snd[s].soundPoint;
                if(snd[s].soundPoint >= snd[s].currentSoundSize){
                    snd[s].playSample=0;
                }
            }
            t++;
        }
    }
}
1 Like

A very reasonable sounding* compromise

*pun intended

You don’t seem to be clamping the sound, so you might end up with integer overflow, which will probably result in strange sound distortion.


Disregard the following section, it turns out I’m even worse at sound programming than I thought :P


Also I’m a bit confused about why you’re skipping 0 samples.
127 is silence, 0 is audible.

Like @Hanski said:

255 = maximum positive phase
0 = maximum negative phase
(255 + 0) / 2 = 127
127 is silence.

Amplitude is the absolute distance from 127, i.e.

constexpr std::uint8_t amplitude(std::uint8_t sample)
{
	return (sample > 127) ? (sample - 127) : (127 - sample);
}

Or at least, that’s what I’ve understood from this thread, I could be wrong though.

Constant 127 is just as audible as constant 0. Amplitude is the absolute distance from whatever your wave oscillates around. You can make sound by oscillating between 0 and 10, in which case 5 would be the amplitude.

2 Likes

Then why not just fill the array with signed deltas?
I.e. have { +10, -10, +10, -10 } instead of { 0, 10, 0, 10 }

I think I’ll stick to language-lawyering, this sound stuff is too confusing. :P

You could do that if the buffer was a signed data type. You see this with APIs that expect data in floats.

1 Like

Because is you convert your samples with Audacity, the default 8-bit PCM output is unsigned (in fact , there is no option for signed 8-bit)

In higher bit samples, signed is also available. But not in 8-bit.

I’m more confused about this that I was when I started. It seems that what I’m doing works, but it’s wrong.
I tried detecting 127 as silence, but that resulted in distortion.
My above implementation is also not good enough, if multiple sounds are playing, the first ones the code adds will be quieter than the later ones as their volume will be adjusted more than once.

Because 127 can and will be used as a valid instant signal value, like any value of the range could be. You can’t use a single, instant value as a way to detect silence!

Silence = a whole, uninterrupted succession of the same value (like 127, but could actually be anything).

That makes things more complex of course. You might want to take the problem from another point of view - isn’t it silence when you play nothing?

Additionally, detecting the same value only twice isn’t a valid option either. That could happen frequently as well, because of how signals work. It’s especially true with low resolution output like 8bit one is.

If you really want to detect perfect silence, you have to calculate the lowest frequency that can be heard AND outputted by the pokitto.
Let’s say it’s 100hz: you’d have to check for 10ms (1/100 hz) of output for silence.
If no variation happens in those 10ms, then you won’t have any sound coming out.
What does it imply thought? Well you have to retain those 10ms somewhere in memory. At a sampling rate of 8Kb/s - 1KB/s, that means you’ll have to retain the last 10 bytes and check on them on a regular basis. At 16Kb/s, it’ll be 20 bytes, and so on. If you want to have a lower cut frequency, that’ll be more bytes too.

2 Likes