- //VolumeControl.c
- //gcc MKAiff.c VolumeControl.c -o VolumeControl
- #include "MKAiff.h"
- #include <math.h>
- #define SAMPLE_RATE 44100
- #define NUM_CHANNELS 1
- #define BITS_PER_SAMPLE 16
- #define NUM_SECONDS 3
- const int numSamples = NUM_SECONDS * NUM_CHANNELS * SAMPLE_RATE;
- #define PI 3.141592653589793
- const double TWO_PI_OVER_SAMPLE_RATE = 2*PI/SAMPLE_RATE;
- int main()
- {
- MKAiff* aiff = aiffWithDurationInSeconds(NUM_CHANNELS, SAMPLE_RATE, BITS_PER_SAMPLE, NUM_SECONDS);
- if(aiff == NULL) return 0;
- float audioBuffer[numSamples];
- double frequency = 440, angle = 0;
- double loudness = 0.5;
- int i;
- for(i=0; i<numSamples; i+=NUM_CHANNELS)
- {
- audioBuffer[i] = sin(angle) * pow(loudness, 2);
- angle += frequency * TWO_PI_OVER_SAMPLE_RATE;
- }
- aiffAppendFloatingPointSamples(aiff, audioBuffer, numSamples, aiffFloatSampleType);
- aiffSaveWithFilename(aiff, "VolumeControl.aif");
- aiffDestroy(aiff);
- return 0;
- }
Output:
Explanation of the Concepts
Thusfar, all of the waveforms discussed have had maximum amplitude. The Sine wave, for instance, oscillates between -1 and +1. Since amplitude is proportional to the loudness of an audio wave, this means that all of the sounds have been maximally loud with respect to the volume settings of your speakers and amplifiers. Most music makes artistic use of loudness, so we will probably want control over the amplitude of the sounds we create. This can be accomplished by scaling the wave, or multiplying the a signal by some number between 1 and 0. Of course, any number multiplied by 0 is zero, so multiplying the entire signal by 0 silences it. Multiplying it by 1 leaves the signal unchanged. Multiplying a sine-wave by 0.5 will cause it to oscillate between -0.5 and +0.5, which, obviously, gives it half the amplitude, and likewise, makes it less loud. Half the amplitude, however, does not mean half as loud. Relative loudness, measured in decibels, is not directly proportional relative amplitude, but rather it is proportional to the log of the relative amplitudes, like so:
Loudness = 20*log(Amplitude1/Amplitude2)
Where 'Amplitude2' is, in the above example, the sine-wave with an amplitude of 1, Amplitude2 is the sine-wave with an amplitude of 0.5, and log is a base-10 logarithm. Notice that this equation does not measure absolute loudness of an individual sound, only the relative loudness of two sounds, or, by analogy, the increase in loudness of a sound after adjusting the amplitude. A plot of this equation is here:
This plot has a steeper slope towards the left, and the slope becomes more gentle as Amplitude1/Amplitude1 increases. This means that increasing the amplitude a little will have a great effect on the loudness, but continuing to increase it will have less and less effect on the loudness. A volume knob, for example, that is designed so that the amplitude increases evenly (linearly) as the knob is turned, will be 'touchy' at the quiet end, and will seem to have little effect at the loud end. For this reason, many physical volume controls are designed to have an exponential response curve, so that they only affect the amplitude a little in the quiet part of their range, but affect the amplitude greatly in the loud part of their range. This tends to 'smooth out' the loudness curve, so that the perceived loudness increases linearly as the knob is turned.
Explanation of the Code
On line 23, a loudness is specified where 0 would be silent, 1 is maximum loudness, 0.5 is half as loud as maximum, and so forth. This loudness is given a exponential relationship to the amplitude of the wave on line 28, where the audio signal is multiplied by the square of the loudness.