Fade out function of audio between samplerate changes - algorithm

I'm trying to create a simple function that will decrease audio volume in a buffer (like a fade out) each iteration through the buffer. Here's my simple function.
double iterationSum = 1.0;
double iteration(double sample)
{
iterationSum *= 0.9;
//and then multiply that sum with the current sample.
sample *= iterationSum;
return sample;
}
This works fine when set to a 44100 kHz samplerate but the problem I'm having is that if the samplerate is for an example changed to 88200 kHz it should only reduce the volume half that step each time because the samplerate is twice as much and will otherwise end the "fade out" in halftime, and I've tried to use a factor like 44100 / 88200 = 0.5 but this will not make it half the step in any way.
I'm stuck with this simple problem and need a guide to lead me through, what can I do to make it half step in each iteration as this function is called if the samplerate is changed during programtime?
Regards, Morgan

The most robust way to fade out independent of sample rate is to keep track of the time since the fadeout started, and use an explicit fadeout(time) function.
If for some reason you can't do that, you can set your exponential decay rate based on the sample rate, as follows:
double decay_time = 0.01; // time to fall to ~37% of original amplitude
double sample_time = 1.0 / sampleRate;
double natural_decay_factor = exp(- sample_time / decay_time);
...
double iteration(double sample) {
iterationSum *= natural_decay_factor;
...
}
The reason for the ~37% is because exp(x) = e^x, where e is the "natural log" base, and 1/e ~ 0.3678.... If you want a different decay factor for your decay time, you need to scale it by a constant:
// for decay to 50% amplitude (~ -6dB) over the given decay_time:
double halflife_decay_factor = exp(- log(2) * sample_time / decay_time);
// for decay to 10% amplitude (-20dB) over the given decay_time:
double db20_decay_factor = exp(- log(10) * sample_time / decay_time);

im not sure if i understood, but what about something like this:
public void fadeOut(double sampleRate)
{
//run 1 iteration per sec?
int defaultIterations=10;
double decrement = calculateIteration(sampleRate, defaultIterations);
for(int i=0; i < defaultIterations; i++)
{
//maybe run each one of these loops every x ms?
sampleRate = processIteration(sampleRate, decrement);
}
}
public double calculateIteration(double sampleRate, int numIterations)
{
return sampleRate/numIterations;
}
private double processIteration(double sampleRate, double decrement)
{
return sampleRate -= decrement;
}

Related

How to create a sinusoidal wave of a line so that the start of the wave returns to being flat

I know how to create a sinusoidal movement with particles as per the code below. What I would like to do however is to create an effect which is more of a ripple along a string. The idea is that a wave moves along a string but the section that is not currently in a wave returns to the zero position and doesn't undergo a further wave- ie just one wave passing down the line.
How do I amend the sinusoidal movement below to achieve this?
int xspacing = 16; // How far apart should each horizontal location be spaced
int w; // Width of entire wave
float theta = 0.0; // Start angle at 0
float amplitude = 75.0; // Height of wave
float period = 500.0; // How many pixels before the wave repeats
float dx; // Value for incrementing X, a function of period and xspacing
float[] yvalues; // Using an array to store height values for the wave
void setup() {
size(640, 360);
w = width+16;
dx = (TWO_PI / period) * xspacing;
yvalues = new float[w/xspacing];
}
void draw() {
background(0);
calcWave();
renderWave();
}
void calcWave() {
// Increment theta (try different values for 'angular velocity' here
theta += 0.02;
// For every x value, calculate a y value with sine function
float x = theta;
for (int i = 0; i < yvalues.length; i++) {
yvalues[i] = sin(x)*amplitude;
x+=dx;
}
}
void renderWave() {
noStroke();
fill(255);
// A simple way to draw the wave with an ellipse at each location
for (int x = 0; x < yvalues.length; x++) {
ellipse(x*xspacing, height/2+yvalues[x], 16, 16);
}
}
I'm not totally sure exactly what you're going for. Drawing out some examples might help explain it better.
But the short answer to your question is: you'd change the height of the sin wave by modifying this line:
yvalues[i] = sin(x)*amplitude;
Right now every particle has the same amplitude, so it your wave has a uniform height. Instead, what you want to do is give each particle a different amplitude. Here's a very simple example:
yvalues[i] = sin(x) * x * 10;
This causes particles towards the left of the screen to have a smaller amplitude, and particles at the right of the screen to have a larger amplitude. In other words, the wave starts out flat and gets larger as it moves to the right.
What I would probably do is create a Particle class that encapsulates each particle's position, movement, and amplitude. Then I'd decrease the amplitude of each particle over time, maybe increasing it when the user clicks (or whatever event you want to spawn your waves).
Shameless self-promotion: I've written a tutorial on creating classes in Processing available here.

Unity3D - How to control Light.Intensity without animation

I have the following animation:
See on video: Animation Light
Note: Below image of animation control
How can I get the same result using a script? My intention is that the script has no "if".
Don't like this:
public float minIntensity;
public float maxIntensity;
public float intensityAmount;
private Light light;
void Awake(){
light = GetComponent<Light>();
}
void Update(){
if (light.intensity > maxIntensity) {
light.intensity -= intensityAmount * Time.deltaTime;
}
else if (light.intensity < minIntensity) {
light.intensity += intensityAmount * Time.deltaTime;
}
}
I wonder if there is any possibility to do this using some native function ... like: (Math.Clamp, Math.Lerp, Quaternion.Slerp) without any condition as "if" in the code.
Thank you in advance.
Well like you mentioned, you can just use a clamp:
light.intensity = Mathf.Clamp(value, minIntensity, maxIntensity)
However, despite the lack of detail on what type of animation you want, I am assuming you want to "ping pong" between the min and the max. If that is the case, we can use our friendly neighborhood sine wave for that.
public float Frequency = 10f;
public float Magnitude = 2f;
void Update() {
light.Intensity = Magnitude + Mathf.Sin(Time.timeSinceLevelLoad * Frequency) * Magnitude;
}
The sine wave will go from -1 to 1, the magnitude value will make it go from (-magnitude to +magnitude) Since we don't want a negative light intensity, we add magnitude to the start, so the end result is (0 to 2 * magnitude) You can change this to work however you desire, but the point should be clear.
The Frequency variable will change how fast we animate back and forth.

How to control sound speed AND volume in AS3?

I need to control the sound play speed so I extract sample data from the sound file but how can I control the volume then as SoundTranform.volume has no effect?
private function onSampleData(event:SampleDataEvent):void
{
var l:Number;
var r:Number;
var outputLength:int = 0;
while (outputLength < 2048)
{
_loadedMP3Samples.position = int(_phase) * 8; // 4 bytes per float and two channels so the actual position in the ByteArray is a factor of 8 bigger than the phase
l = _loadedMP3Samples.readFloat(); // read out the left and right channels at this position
r = _loadedMP3Samples.readFloat(); // read out the left and right channels at this position
event.data.writeFloat(l); // write the samples to our output buffer
event.data.writeFloat(r); // write the samples to our output buffer
outputLength++;
_phase += _playbackSpeed;
if (_phase < 0)
_phase += _numSamples;
else if (_phase >= _numSamples)
_phase -= _numSamples;
}
}
Volume:
use say var volume: Number = 1.0 as a field variable. 0.0 for mute, 1.0 for original volume. Alter in other methods. However tweening this variable will be appreciated by listeners.
event.data.writeFloat(volume * l);
event.data.writeFloat(volume * r);
Speed:
You have to resample and use interpolation to define the intermediate values.
It's mathematically involved, but I'm sure there's a ton of libraries that can do this for you. But hey, here's a tutorial that tells you how apparently:
http://www.kelvinluck.com/2008/11/first-steps-with-flash-10-audio-programming/
Edit: Oh, You used this tutorial... You could have said.
modify _playbackSpeed. 1.0 is full speed. 2.0 is double speed.

Generating Sine Waves at Changing Frequency [duplicate]

I'm writing a c program to generate a sinusoidal wave that slowly ramps up frequency from f1 to f2 for a giving time interval.
I have written this c program to ramp the frequency from 0 to 10 Hz but the problem is that the frequency changes after completion of 360 degrees. If I try to change the frequency between 0 and 360 degree that the transition is not smooth and it is abrupt.
This is the equation the sin that I have used y = Amplitude*sin(freq*phase)
int main(int argc, char *argv[]) {
double y, freq,phase;
int count; // for convenience of plotting in matlab so all the waves are spread on x axis.
for (freq = 0; freq < 10; freq+=1) {
for (phase = 0; phase < 360; phase++) { // phase is 360 degrees
y = 3 * sin((count*6.283185)+(freq*(phase*(3.14159/180))));
printf("%f %f %f \n", freq, phase, y);
}
count++;
}
return EXIT_SUCCESS;
}
How do I change frequency smoothly for a given time period?
should I be looking into Fourier transformations?
if you want angular frequency (w=2 pi f) to vary linearly with time then dw/dt = a and w = w0 + (wn-w0)*t/tn (where t goes from 0 to tn, w goes from w0 to wn). phase is the integral of that, so phase = w0 t + (wn-w0)*t^2/(2tn) (as oli says):
void sweep(double f_start, double f_end, double interval, int n_steps) {
for (int i = 0; i < n_steps; ++i) {
double delta = i / (float)n_steps;
double t = interval * delta;
double phase = 2 * PI * t * (f_start + (f_end - f_start) * delta / 2);
while (phase > 2 * PI) phase -= 2 * PI; // optional
printf("%f %f %f", t, phase * 180 / PI, 3 * sin(phase));
}
}
(where interval is tn and delta is t/tn).
here's the output for the equivalent python code (1-10Hz over 5 seconds):
from math import pi, sin
def sweep(f_start, f_end, interval, n_steps):
for i in range(n_steps):
delta = i / float(n_steps)
t = interval * delta
phase = 2 * pi * t * (f_start + (f_end - f_start) * delta / 2)
print t, phase * 180 / pi, 3 * sin(phase)
sweep(1, 10, 5, 1000)
ps incidentally, if you're listening to this (or looking at it - anything that involves human perception) i suspect you don't want a linear increase, but an exponential one. but that's a different question...
How do I change frequency smoothly for a given time period?
A smooth sinusoid requires continuous phase. Phase is the integral of frequency, so if you have a linear function for frequency (i.e. a constant-rate increase from f1 to f2), then phase will be a quadratic function of time.
You can figure out the maths with pen and paper, or I can tell you that the resulting waveform is called a linear chirp.
Should I be looking into Fourier transformations?
The Fourier transform of a linear chirp is itself a linear chirp, so probably no.
It should be fairly simple. Rather than thinking of varying the frequency, think of making an object spin faster and faster. The angular distance it has traveled might be X after N seconds, but will be more that 2X (maybe 4X) after 2N seconds. So come up with a formula for the angular distance (eg, alpha = k1 * T + k2 * T**2) and take the sine of that angular distance to find the value of the waveform at any time T.
+ (void) appendChirp:(int[])sampleData size:(int)len
withStartFrequency:(double)startFreq withEndFrequency:(double)endFreq
withGain:(double)gain {
double sampleRate = 44100.0;
for (int i = 0; i < len; i++) {
double progress = (double)i / (double)len;
double frequency = startFreq + (progress * (endFreq - startFreq));
double waveLength = 1.0 / frequency;
double timePos = (double)i / sampleRate;
double pos = timePos / waveLength;
double val = sin(pos * 2.0 * M_PI); // -1 to +1
sampleData[i] += (int)(val * 32767.0 * gain);
}
}

Goertzel algorithm to get the phase?

I am using Goertzel algorithm to get the amplitude of a certain frequency.
I am trying now to get the phase from it, and I don't know how.
Can some one explain, and show me how to get the phase of a certain-f from this code?
Also, I am using it to 16khz, with sample rate 44.1. What's the smallest length of samples that I can run it on?
double AlgorithmGoertzel( int16_t *sample,int sampleRate, double Freq, int len )
{
double realW = 2.0 * cos(2.0 * M_PI * Freq / sampleRate);
double imagW = 2.0 * sin(2.0 * M_PI * Freq / sampleRate);
double d1 = 0;
double d2 = 0;
double y;
for (int i = 0; i < len; i++) {
y=(double)(signed short)sample[i] +realW * d1 - d2;
d2 = d1;
d1 = y;
}
double rR = 0.5 * realW *d1-d2;
double rI = 0.5 * imagW *d1-d2;
return (sqrt(pow(rR, 2)+pow(rI,2)))/len;
}
Do a rectangular to polar conversion. That will give you phase and magnitude.
magnitude = sqrt ((Vreal * Vreal) + (Vimag * Vimag))
phase = atan2 (Vimag, Vreal)
I don't think the algorithm consists of multiplying the sequence by a constant, but by the complex signal exp(n*i*2pi*freq/samplerate); 0<=n<=length, and getting the average magnitude (or power of the signal).
As the complex output is R*exp(i theta), R gives the power at the given frequency and theta gives the phase. (theta == atan2 ( imag, real))
The number of samples you need to feed a Goertzel filter will be inversely proportional to your desired or required filter bandwidth. A Goertzel provides a Sinc shaped bandpass filter, with the main lobe width proportional to 2*Fs/N.
If you use a complex Goertzel, the resulting phase will be relative to some point in the filter's data window. You may thus have to calculate an offset to get phase relative to some other reference point in time.

Resources