So as simply as making snd[t].volume range from 0 to 255 instead of 100 will be faster? sounds useful.

[edit]
I think once I have this game out of the way, I should separate the sound stuff out into a separate example, currently it is capable of playing a sample at any (?) speed or volume, possibly multiple sounds at once, it might be helpful for other people.

shift by 1 bit ( >>1) is same as /2
shift by 2 bits (>>2) is /4
shift by 3 (>>3) is /8 and so on

ARM Cortex M0+ (crowd cheering) has a so called ābarrel shifterā meaning any number of bits can be shifted in one instruction. Division by powers of two is very fast.

Atmel AVR (audience hissing) has no barrel shifter. Shifting by 8 bits takes 8 instructions

yes, in the specific case of 8 bits that is so. but as a general rule, there is no n bit shift single cycle operand as on the ARM Cortex. That was what I intended to say.

and yes, i know and have used combinations of multiplications and bit shifts on atmegas to get around this missing barrel shifter issue.

You mean Z = (2 * (A + B)) - ((A * B) / 128) - 256?

If so thatās an easy change:

std::uint8_t mixToth(std::uint8_t sample0, std::uint8_t sample1)
{
constexpr std::uint8_t maximum = 0xFF;
constexpr std::uint8_t midpoint = 0x7F;
const unsigned int s0 = static_cast<unsigned int>(sample0);
const unsigned int s1 = static_cast<unsigned int>(sample1);
const unsigned int result = 2 * (s0 + s1) - ((s0 * s1) / midpoint) - maximum;
return static_cast<std::uint8_t>((result < maximum) ? result : maximum);
}

Thatās confusing.

This is why Iām terrible with sound, the idea that negative values are audible always throws me.
Does that mean amplitude is actually the absolute distance from the midpoint (0 signed, 127 unsigned)?

Does that imply negative pressure is audible?
(Iāve forgotten a large chunk of what I learnt for my GCSEs because I never had a use for it.)

This is why so many programmers are obsessed with powers of two.
Working with powers of two is almost always faster because mathetmatical operations can be replaced with bitwise operations (sometimes called bithacks/bithax).

@spinal
To clarify why this is, pow(2, 1) == 2, pow(2, 2) == 4, pow(2, 3) == 8 (where pow is expotentiation, or āto the power ofā).

Or to put it another way, shifting right divides by 2, so shifting right a second time divides by 2 again, and dividing by 2 twice is the same as dividing by 4.
I.e. ((x >> 1) >> 1) == (x >> 2) == ((x / 2) / 2) == (x / 4)

As for why shifting works as division and multiplication by a power of two, you need to understand binary to see why.

This was always something that annoyed me with AVR chips.
Not having a barrel shifter is criminal.

Actually, the compiler doesnāt always perform that optimisation.
See here:

(I still havenāt got round to fixing the issue yet, itās somewhere on my ever growing todo list.)

You need to come to terms with the idea that the absolute value is meaningless. Only the velocity matters. When you make your first transistor amp and you read -200V peak from your 3.3V circuit, then youāre getting the feeling you need your head checked. The world, alas, is not digital

Iāve heard a legend it was an honest mistake and the oversight was noticed only after the chip had been taped out. Whether this story is true, i donāt know.

Though that might be a bit of a problem in a loop because of the division.

Also, now I think about it, the compiler might be able to optimise better with result <= maximum.

That sounded like ādivision must be a software operation if thereās no FPUā.

I presume you meant āthereās no integer division hardware and not floating point division hardware, therefore division is done by a software routineā?

clipping causes nasty distortion. if you add alot of stuff and get >255 values, uint8_t wraps around and you get all sorts of crap (sorry but that is the right word) coming out