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

  1. //WindowFunctions.c
  2. //gcc MKAiff.c WindowFunctions.c -o WindowFunctions
  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 GRAIN_DURATION 1
  9. const int framesPerGrain = GRAIN_DURATION * SAMPLE_RATE;
  10. const int samplesPerGrain = GRAIN_DURATION * SAMPLE_RATE * NUM_CHANNELS;
  11. #define PI 3.141592653589793
  12. #define e 2.718281828459045
  13. const double TWO_PI_OVER_SAMPLE_RATE = 2 * PI / SAMPLE_RATE;
  14. int main()
  15. {
  16. MKAiff* aiff = aiffWithDurationInSeconds(NUM_CHANNELS, SAMPLE_RATE, BITS_PER_SAMPLE, GRAIN_DURATION);
  17. if(aiff == NULL) return 1;
  18. float windowFunction[framesPerGrain];
  19. int i;
  20. for(i=0; i<framesPerGrain; i++)
  21. {
  22. //SINE
  23. //windowFunction[i] = sin( PI * (double)i / samplesPerGrain );
  24. //HANN
  25. //windowFunction[i] = 0.5 * (1-cos(2*PI*i/samplesPerGrain));
  26. //HAMMING
  27. //windowFunction[i] = 0.54 - 0.46 * cos(2*PI*i/samplesPerGrain);
  28. //TUKEY
  29. //float truncationHeight = 0.5;
  30. //float f = 1/(2*truncationHeight) * (1-cos(2*PI*i/samplesPerGrain));
  31. //windowFunction[i] = f < 1 ? f : 1;
  32. //GAUSSIAN
  33. float sigma = 0.3;
  34. windowFunction[i] = pow(e, -0.5* pow(((i-samplesPerGrain/2) / (sigma*samplesPerGrain/2)), 2) );
  35. //TRAPEZOIDAL
  36. //float slope = 10;
  37. //float x = (float) i / framesPerGrain;
  38. //float f1 = slope * x;
  39. //float f2 = -1 * slope * (x-(slope-1) / slope) + 1;
  40. //windowFunction[i] = x < 0.5 ? (f1 < 1 ? f1 : 1) : (f2 < 1 ? f2 : 1);
  41. }
  42. float audioBuffer[samplesPerGrain];
  43. double frequency = 440, angle = 0;
  44. for(i=0; i<samplesPerGrain; i+=NUM_CHANNELS)
  45. {
  46. audioBuffer[i] = sin(angle) * windowFunction[i/NUM_CHANNELS];
  47. angle += frequency * TWO_PI_OVER_SAMPLE_RATE;
  48. }
  49. aiffAppendFloatingPointSamples(aiff, audioBuffer, samplesPerGrain, aiffFloatSampleType);
  50. aiffSaveWithFilename(aiff, "WindowFunctions.aif");
  51. aiffDestroy(aiff);
  52. return 0;
  53. }

Output:

Explanation of the Concepts

This example shows how to create several various window functions for creating 'grains' for use in granular synthesis. Here, for the sake of demonstration, the window function is applied to a simple audio-rate sine-wave, and the result is one very simple (and somewhat long) grain of audio.

The following graphs represent amplitude plotted as a function of time for various window functions.

SINE

The sine window function is just the top half of a sine wave, between 0 and 180 degrees:

Sine

HANN

A Hann window is an entire cosine wave, between 0 and 360 degrees, but it is raised up so that it does not dip below y=0. For this reason, it is also known as a "raised cosine" window.

Hann

HAMMING

An Hamming window is also a type of "raised cosine" window, but it has been raised a little further, so the bottom does not touch y=0. This type of window is often used in DFT algorithms (discussed in the chapter on Fourier Synthesis) because it produces a very accurate spectrum. It, however, is not great for granular synthesis because, since it does not reach y=0, it can cause popping noises as it is begins and ends.

Hamming

TUKEY

A Tukey window is a Hann window that has had its top chopped off, and the result has been stretched to fit between y=0 and y=1. The height at which it has been chopped of is known as H. Tukey windows are good for making grains out of speech. If the window is chopped off low, then it reaches its maximum amplitude quickly and stays there for a large percentage of the windows duration, which preserves the intelligibility of individual words. Higher values of H decrease the intelligibility.

Tukey from Hann Tukey 0.1 Tukey 0.5 Tukey 0.9 Tukey 1.0

GAUSSIAN

A Gaussian function is the plot of the familiar "bell curve", that often represents natural probability distributions. Its shape makes it good for use here. The coefficient 'Sigma' determines the width of the function. Because the function never reaches y=0, it can cause popping as the grain begins and ends, especially for values of sigma much above 0.3. Nonetheless, in a dense, granular music, manipulating sigma gives an interesting control over the overall texture of the music. Low values of sigma produce choppy textures and higher values produce a smoother texture. For high values of sigma, popping can be avoided by multiplying the Gaussian function by a trapezoidal function (or another function that reaches 0).

Gaussian 0.1 Gaussian 0.5 Gaussian 1.0

TRAPEZOIDAL

Trapezoidal windows are useful for convolving other window functions that do not reach y=0. Notice too, that a triangular window is just the special case of a trapezoidal window in which Slope=2;

Trapezoid 2.0 Trapezoid 3.0 Trapezoid 201.0

Explanation of the Code

In this example, the window function is written into a separate buffer for before being applied to the audio buffer. The window buffer is allocated on line 22. Lines 22-40 then write a window function into the buffer, according to which lines of code are not commented out. Lines 52-59 then applies the window function to the a sine wave that is written into an audio buffer, Identical to the usage in many of the examples in the chapter on envelopes.