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

  1. //AdditiveNonharmonic.c
  2. //gcc MKAiff.c AdditiveNonharmonic.c -o AdditiveNonharmonic
  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 BYTES_PER_SAMPLE 2
  9. #define NUM_SECONDS 3
  10. const int numSamples = NUM_SECONDS * NUM_CHANNELS * SAMPLE_RATE;
  11. #define PI 3.141592653589793
  12. const double TWO_PI_OVER_SAMPLE_RATE = 2*PI/SAMPLE_RATE;
  13. #define numFrequenciesToAdd 5
  14. int main()
  15. {
  16. int i, j;
  17. float audioBuffer[numSamples], nextSample;
  18. for(i=0; i<numSamples; audioBuffer[i++]=0);
  19. double fundamentalFrequency = 440, phase, frequency,
  20. freqRatio[numFrequenciesToAdd] = {1 , 1.213, 1.471, 1.785, 2.165 },
  21. amplitude[numFrequenciesToAdd] = {0.1, 0.1 , 0.1 , 0.1 , 0.1 },
  22. attack [numFrequenciesToAdd] = {1 , 0.4 , 0.3 , 0.5 , 0.2 },
  23. decay [numFrequenciesToAdd] = {0.5, 0.4 , 0.3 , 0.2 , 0.1 },
  24. sustain [numFrequenciesToAdd] = {0.3, 0.3 , 0.3 , 0.3 , 0.3 },
  25. release [numFrequenciesToAdd] = {1 , 0.4 , 0.5 , 1 , 2 };
  26. for(i=0; i<numFrequenciesToAdd; attack[i]*=SAMPLE_RATE,
  27. decay[i]*=SAMPLE_RATE,
  28. release[i]*=SAMPLE_RATE, i++);
  29. for(j=0; j<numFrequenciesToAdd; j++)
  30. {
  31. phase = 0;
  32. frequency = freqRatio[j] * fundamentalFrequency;
  33. for(i=0; i<numSamples; i+=NUM_CHANNELS)
  34. {
  35. nextSample = sin(phase) * amplitude[j];
  36. //ADSR ENVELOPE
  37. if(i/NUM_CHANNELS<=attack[j])
  38. nextSample *= i/attack[j];
  39. else if(i/NUM_CHANNELS<=(attack[j]+decay[j]))
  40. nextSample *= 1-(1-sustain[j])*((i-attack[j])/decay[j]);
  41. else if(i/NUM_CHANNELS<=((numSamples/NUM_CHANNELS)-release[j]))
  42. nextSample *= sustain[j];
  43. else
  44. nextSample *= sustain[j]*(((numSamples/NUM_CHANNELS-i)/release[j]));
  45. audioBuffer[i] += nextSample;
  46. phase += frequency * TWO_PI_OVER_SAMPLE_RATE;
  47. }
  48. }
  49. MKAiff* aiff = aiffWithDurationInSeconds(NUM_CHANNELS, SAMPLE_RATE, BITS_PER_SAMPLE, NUM_SECONDS);
  50. if(aiff == NULL) return 1;
  51. aiffAppendFloatingPointSamples(aiff, audioBuffer, numSamples, aiffFloatSampleType);
  52. aiffSaveWithFilename(aiff, "AdditiveNonharmonic.aif");
  53. aiffDestroy(aiff);
  54. return 0;
  55. }

Output:

Explanation of the Concepts

This example uses additive synthesis to create a timbre whose overtones are not harmonically related to the fundamental.

So far, all of the sounds we have made with additive synthesis have been "harmonic". In other words, the frequencies of the constituent sine waves have all bee integer-multiples of the fundamental. Virtually all acoustic instruments that are not percussion have this quality. Nonetheless, a great number of interesting sounds can be created by using overtones that are "non harmonic", or that are non-integer multiples of the fundamental. This technique features prominently in the early electronic works of Karlheinz Stockhausen. In his Studie II (1954), Stockhausen uses combinations of 5 sine waves whose frequencies are related to one another by the 25th root of various powers of 5(which forms a scale whose basic interval is about 111.451378 cents, or just bigger than a semitone, and which does not repeat at the octave). Here, we will imitate his timbres by choosing overtones that conform to these ratios. Additionally, we will give each sinusoid its own amplitude envelope, as before, so that the timbre is dynamic.

Explanation of the Code

The only difference between this and the previous example is that here the frequency ratios have been stored in an array on line 23, so that they can be looked up on line 36, whereas before they were just calculated as integer multiples of the fundamental on successive passes through the loop.