An Audio Synthesis Textbook For Musicians, Digital Artists and Programmers by Mike Krzyzaniak

  1. //PlayingChords.c
  2. //gcc MKAiff.c PlayingChords.c -o PlayingChords
  3. #include "MKAiff.h"
  4. #include <math.h>
  5. #define SAMPLE_RATE 44100
  6. #define NUM_CHANNELS 1
  7. #define BITS_PER_SAMPLE 16
  8. #define NUM_SECONDS 3
  9. const int numSamples = NUM_SECONDS * NUM_CHANNELS * SAMPLE_RATE;
  10. #define PI 3.141592653589793
  11. const double TWO_PI_OVER_SAMPLE_RATE = 2*PI/SAMPLE_RATE;
  12. int main()
  13. {
  14. MKAiff* aiff = aiffWithDurationInSeconds(NUM_CHANNELS, SAMPLE_RATE, BITS_PER_SAMPLE, NUM_SECONDS);
  15. if(aiff == NULL) return 0;
  16. float audioBuffer[numSamples];
  17. double frequency1 = 440, angle1 = 0;
  18. double frequency2 = 550, angle2 = 0;
  19. double frequency3 = 660, angle3 = 0;
  20. int i;
  21. for(i=0; i<numSamples; i+=NUM_CHANNELS)
  22. {
  23. audioBuffer[i] = sin(angle1) + sin(angle2) + sin(angle3);
  24. audioBuffer[i] /= 3;
  25. angle1 += frequency1 * TWO_PI_OVER_SAMPLE_RATE;
  26. angle2 += frequency2 * TWO_PI_OVER_SAMPLE_RATE;
  27. angle3 += frequency3 * TWO_PI_OVER_SAMPLE_RATE;
  28. }
  29. aiffAppendFloatingPointSamples(aiff, audioBuffer, numSamples, aiffFloatSampleType);
  30. aiffSaveWithFilename(aiff, "PlayingChords.aif");
  31. aiffDestroy(aiff);
  32. return 0;
  33. }

Output:

Explanation of the Concepts

So far, we have been creating single sounds and sending them to a single channel. If, however, we want to create multiple sounds and send them to the same channel we will need to mix them together. This can be done by simply adding them to one-another. Why this works is neither obvious nor trivial. It is a fact of physics that sound waves add when they collide. Consider an actual sound wave in the air. The wave is created by many individual molecules moving back and forth. In silence, any given molecule is still, but if I, say, pluck a guitar string, as the string moves forward, it pushes the air molecules in front of it forward. These molecules, in turn, push the air molecules in front of them forward, and so forth. If we then imagine pausing time while some molecule has been displaced forward, and further imagine striking a key on a piano. The piano string similarly moves forward, displacing air molecules forward in its wake. Those molecules push on other molecules which push on other molecules, so when this train of pushing reaches our 'paused' molecule that has already been displaced by the guitar string, it will be even further displaced by the piano string. If the piano string, on the other hand, is moving backwards, it will pull the molecules in front of it back, which could pull our paused molecule back to its rest position or further. In other words the actual displacement of the molecule is the sum of the displacement due to both the guitar and piano.

This example sums 3 sine waves whose frequencies are 440, 550, and 660 Hz, or A, C# and E, respectively. The resultant wave will be the yellow line in the plot below (amplitude is plotted as a function of time). The three sine waves of which it is a sum are plotted in white for the sake of illustration.

major chord

The amazing part is that, even if we are listening to Stravinkii's Firebird, with over a hundred instruments playing at once, the air contains only one sound-wave that is the sum of everything acting on it. Summing audio signals is mathematically simple (it is just addition), but separating them out again once they have been summed is very mathematically complicated. If the summed audio waves are not sinusoidal, like here, but are complex, real life musical timbres, then separating them is beyond the current capabilities of mathematics entirely. Nonetheless, our ear separates them with little difficulty. Our ear basically acts as a peripheral analyzer, like a Fourier spectrograph that separates out the sinusoidal constituents. However, we don't just hear a whole bunch of sine-waves, as you might expect by looking at a spectrograph. Somehow our auditory cortex reconstructs the individual sound sources, so that we actually hear the guitar and piano, or individual timbres of the orchestra separately.

Explanation of the Code

The 3 sine waves are summed on line 29. On line 30, the resultant sample is divided by three to prevent clipping (as Discussed in the chapter on Digital Sound). This does not mimic any property actually present in nature. It is only there only to prevent clipping, as the sum of all three waves will, at times, be as high as 3 or as low as -3, and MKAiff requires that the maximum forward and backward displacement of the speaker be represented by the numbers 1 and -1 respectively.