GP32 Fast Calculations


ConsoleTom

Member
Joined
Dec 4, 2003
Messages
106
Age
48
Location
Germany
Website
Visit site
I would like to calculate new volumes to my sounds and need a possibility to lower it by 3DB (about 70%). Then i could use bitshifts to generate a new volume:

100% -> 50% -> 25% etc
70% -> 35% -> 17.5% etc

Let's say i have a 20k sample (16 Bit):

unsigned short WaveData[20000] = { sampledata };

As i know this one is too slow:

for (i=0;i<20000;i++)
{
WaveData *= 0.7
}

How can i do it faster ? Should i create a table where all results from 1*0.7 to 65535*0.7 are stored ? Or what should i do here ?

Greetings

Tobias
 
A lookup table is not recommended in that case (65536 * 2bytes (because the results are 16 bit) = 128kB used just for this array.

Instead, use an easier (and faster also) method:

Insted of just shifting the bits, you could just multiply your value by a constant, and then shift right.

2000 >> 1 gives 1000.

(2000 * 3) >> 2 gives 1500 (this would give 75%)

And you keep a good precision. But to avoid weird saturation, do this calculation in 32 bits.
 
mATkEUpON posted on Oct 12 2004 at 02:28 PM said:
A lookup table is not recommended in that case (65536 * 2bytes (because the results are 16 bit) = 128kB used just for this array.

Erm, the gp32 has 8mb of ram, 128k is not that significant. :p
 
Last edited by a moderator:
ConsoleTom posted on Oct 12 2004 at 01:23 PM said:
for (i=0;i<20000;i++)
{
WaveData *= 0.7
}

How can i do it faster ?

I'm not sure if this will work faster, but you can try:

unsigned short i, wd;
for (i=0, wd=WaveData; i<20000; ++i, ++wd) {
(*wd)*=((*wd) * 3) >> 2;
}

Also, if memory isn't really a problem, I agree with RobertJ in using a lookup table.
 
Last edited by a moderator:
Well, I just believe 128kB for a lookup table is enormous regarding the time it will save you, which is none in fact.

Using a lookup table makes the Gp32 read a value at an address (which can take some time considering that cache misses will occur most of the time as you'll never be reading the same values of your big table) for EACH value you wan to multiply.

On the other hand, a multiply (as long as you don't multiply by 2^16 or more) takes only one instruction time (and so does the shift).

And last thing:
(*wd)*=((*wd) * 3) >> 2;

If the data contained by wd (which should be declared as a unsigned short *) is 10000, then the result would be 75000000 (which makes a weird 75%, I don't have the same here). LOL.

So:
Code:
for (i=0;i<20000;i++)
{
WaveData[i] = (WaveData[i] * 3) >> 2;
}

Will do fine, and should be fast enough (faster than a lookup table anyway).
 
Oh, I'm sorry! You are right, there are two typos (two typos... or a walking asterisk!). Those lines should be:
Code:
unsigned short i, *wd; // The asterisk is in this line...
for (i=0, wd=WaveData; i<20000; ++i, ++wd) {
  (*wd)=((*wd) * 3) >> 2; // ...but not in this one.
}
 
Right, this is better, but still there is something:
for (i=0, wd=WaveData; i<20000; ++i, ++wd) {

Here you typed ++i, ++wd, which will increase i and the address pointed by wd BEFORE you enter the loop. So the 1st sample will not have its volume modified.
 
No, the increment part of the for loop is evaluated always after the statements block.
The difference between i++ (postincrement) and ++i (preincrement) is that in the first case, i is evaluated then i is incremented and stored back; and in the second case, i is incremented, then evaluated (if necesary) and finally stored back.
When compiling to debug code (i.e.: without optimizations) ++i is slightly faster than i++ because it requires one less evaluation.

Another version (one less dereference):
Code:
unsigned short i, *wd;
for (i=0, wd=WaveData; i<20000; ++i, ++wd)
  ((*wd)*=3)>>=2;
 
Back
Top