views:

95

answers:

3

Hi Folks, First time poster here.

A quick question about setting up a loop here. I want to set up a for loop for the first 1/3 of the main loop that will increase a value from .00001 or similar to 1. So I can use it to multiply a sample variable so as to create a fade-in in this simple audio file playback routine.

So far it's turning out to be a bit of a head scratcher, any help greatfully recieved.

for(i=0; i < end && !feof(fpin); i+=blockframes) 
{ 
    samples = fread(audioblock, sizeof(short), blocksamples, fpin); 
    frames = samples; 
    for(j=0; j < frames; j++)
    {   
        for (f = 0; f< frames/3 ;f++)
        {
            fade = fade--;
        } 
    output[j] = audioblock[j]/fade;
    }

    fwrite(output,sizeof(short), frames, fpoutput); 
} 

Apologies, So far I've read and re-write the file successfully. My problem is I'm trying to figure out a way to loop the variable 'fade' so it either increases or decreases to 1, so as I can modify the output variable.

I wanted to do this in say 3 stages: 1. From 0 to frames/3 to increace a multiplication factor from .0001 to 1 2. from frames 1/3 to frames 2/3 to do nothing (multiply by 1) and 3. For the factor to decrease again below 1 so as for the output variable to decrease back to the original point.

How can I create a loop that will increase and decrease these values over the outside loop?

A: 

My first observation:

fade = fade--;

will not work, as it is equivalent to

int temp = fade - 1;
fade = fade;

This is how the post-increment operator works. So you should simply write

fade--;

instead (or --fade - whichever you prefer :-).

You should then build up your loops something like this:

for(j=0; j < frames/3; j++)
{   
    fade--;
    output[j] = audioblock[j]/fade;
}
for( ; j < 2*frames/3; j++)
{   
    output[j] = audioblock[j]/fade;
}
for( ; j < frames; j++)
{   
    fade++;
    output[j] = audioblock[j]/fade;
}
Péter Török
but fade = --fade will work fine
thorkia
@thorkia Indeed, but then again, `--fade` would have the same effect in a simpler form.
Péter Török
Of course, thanks. Still experimenting....Thanks Peter.
Dave Slevin
+1  A: 

I think you thought yourself into a corner, to say so. There's no need to create a nested loop to modify the fade gain, you can simply keep track of it through the loop and adapt it if necessary. Also, your variable naming of frames/samples seems a bit muddy to me, I hope I got that one right.

float fadeTime = 0.5f;
float outputGain = 0.0f;
float gainProgressionPerSample = 1.0f/(fadeTime*SAMPLERATE);
float fadeInStop = fadeTime*SAMPLERATE;
float fadeOutBegin;

for(i=0; i < end && !feof(fpin); i+=blockframes) 
{ 
    samples = fread(audioblock, sizeof(short), blocksamples, fpin); 
    fadeOutBegin = samples - fadeTime*SAMPLERATE;
    for(j=0; j < samples; j++)
    {
       if (j < fadeInStop)   
       {
         outputGain += gainProgressionPerSample;
       }
       // else is not used intentionally to allow fade in/out blending for short tracks
       if (j > fadeOutBegin)
       {
         outputGain -= gainProgressionPerSample;
       }
       output[j] = audioblock[j]*outputGain;
    }

    fwrite(output,sizeof(short), samples, fpoutput); 
} 
Johannes Rudolph
@Johannes Rudolph May be my blindness, but I fail to see how this code would do the fadeout part.
Péter Török
yup, doesn't do this atm, but would be easy to add. I'm too tired now, will get back to you tomorrow.
Johannes Rudolph
The naming is indeed muddy. The original routine splits an interleaved file into two mono ones. I've broken it down for experimentation. Hence the double variables here and there, there was a few lines to write every second sample to seperate files.
Dave Slevin
If the sum of outputGain * progress doesn't end up equaling exactly 1.0 then this code will overshoot 1.0 and keep increasing the gain forever.
John Knoeller
@John: good spot, have adapted fading to be bound by time. Good point about he log fade too.
Johannes Rudolph
I don't know why I didn't notice this before, but `outputGain = outputGain + outputGain * gainProgressionPerSample;` always evaluates to 0 if outputGain is 0, I'm pretty sure you just want to add outputGain to progression without the multiply.
John Knoeller
A: 

In modern processors there's no real reason not to use floating point for the math. It's more accurate and the performance is about the same as integer math. And if you are using floating point, there's not reason not to have all of your temp variables be doubles. declaring them as float actually costs performance.

This code will give you a linear fade in over (frames/3) samples

double gain = 0.0f;
double deltaGain = (1.0 - gain)/(frames/3);
for (int i=0; i < end && !feof(fpin); i += blockframes) 
{ 
    samples = fread(audioblock, sizeof(short), blocksamples, fpin); 

    j = 0;
    // do the fade in.
    for ( ; j < samples; ++j)
    {
       gain += deltaGain; // adjust the gain
       if (gain >= 1.0)
          break;

       output[j] = (short)(audioblock[j] * gain);
    }

    // copy the remainder.
    for ( ; j < samples; ++j)
       output[j] = audioblock[j];

    fwrite(output,sizeof(short), samples, fpoutput); 
} 

The basic trick is to figure out up front the starting point and ending point for your gain multiplier, then divide (end-start)/steps to get the amount that the gain should change for each sample. Then in your inner loop, adjusting the gain is just an addition. You can get an x-squared gain curve with just two additions in the inner loop. x-squared is a reasonable approximation of a log fade in which sounds more 'natural' since our ears hear in log scale.

John Knoeller
You Guys Rock! Tried Peters code first. Though the 'fade' variable seems to equal the no. of samples at the end of the loop. Though I could be wrong. It does however fade in and out, but has induced clipping. I'm persuming leaving out the j=0 part of the second if statement just makes it pick up where the last one left off. That's nice, I didn't know you could do that. Thanks all for the help.D.
Dave Slevin