Post by microfarad on Jul 24, 2012 2:13:05 GMT -5
This thread will be about how to synthesize music with programs. It shouldn't be language specific and users should avoid relying on code whenever possible so that people who can't even program can still get something out of this.
Synthesis of simple sine wave:
Programs that synthesize sine waves should avoid the simple approach of sin(2*pi*frequency*time) because if you change the frequency while generating the note there will be a distinct jump in the amplitude level at that point which sounds like an annoying pop. If you steadily change the frequency over time the side effects are even worse and more confusing, with wild pitch changes resulting. Programs generating sine waves should instead maintain a domain variable which is incremented by 2*pi*frequency/framerate every frame. The amplitude of the synth for any given moment can be found by taking sin(domain). In practice, the precision of floating point numbers decreases steadily as the value contained increases. If your domain variable simply continues to grow slowly over time, the quality of the tone will get worse and worse. To avoid this, you will need to find a way to lower the domain variable every once and a while without causing a pop.
Useful waves:
Saw, ramp, triangle, and square waves can also be synthesized. The formulas for these periodic functions are relatively easy to figure out. Many of the tips that apply to sine wave synthesis apply to these waves.
Additive synthesis:
Add waves together, see what happens. Add harmonics to change the voice of an instrument.
AM synthesis:
Multiply one wave by another. Can be interesting!
FM synthesis:
Modulate the frequency of one wave slightly (or a lot) with another wave. If the frequency of the second wave is low this sounds like vibrato. If it is high, this can make new and interesting noises.
Bells, Dings, Xylophones, Bips, etc:
Similar to sine wave synthesis. Use a cosine wave instead. At the beginning of the sound, initialize the domain to 0. Initialize a volume variable to 1. Every frame, multiply the volume by a number just slightly less than one (like .9999) and store the result back into volume, causing exponential decay in the volume over time. The amplitude of the sound at any time can be found with cos(domain)*volume. To choose a half life for the decay (in seconds, assuming your framerate is measured in fps), the number you multiply the volume by should be (1/(framerate*halflife))^(1/2).
Filters:
Wikipedia has good articles on high and low pass filters. Low pass filters try to remove frequencies higher than the cutoff frequency from a signal while high pass filters do the opposite. Band pass filters try to eliminate all frequencies but those in a certain range, and can be made by running the output of a high pass filter through a low pass filter or visa versa. Adding the outputs of high and low pass filters will render a band reject filter which eliminates frequencies in a certain range. By modulating the cutoff frequency of a low pass filter with a very low frequency sine wave and running a deep bass wave through it you can get started making your own dubstep!
Goertzel algorithm:
The Goertzel Algorithm is a way to find the amplitude of a given frequency in an audio sample. This can be used for many things, most of which are not at all related to music. Still, it's good to know about. Read more on Wikipedia.
Envelope filter:
An envelope filter tries to outline the peaks of an audio signal to give a general idea of its volume throughout the signal.
Vocoder:
A vocoder can be used to make voices sound strange or robotic. Kraftwerk made extensive use of vocoders. ELO's Mr Blue Sky also has vocals that have been run through a vocoder. Vocoders are also used extensively in Sci-Fi movies. The basic idea is to find the envelopes for several (usually evenly spaced) frequencies in an audio track then use the envelopes to modulate filtered samples with corresponding frequency (bandpass) of a carrier wave. The Goertzel Algorithm or a Fast Fourier Transform will directly give these envelopes, but band pass filters and envelope filters can be used together to achieve the same end. In fact, because of the frequency response of some of the other algorithms, band pass filters are usually preferred.
White noise:
Simple random samples. Completely random samples. Very annoying.
Brown noise:
Every frame an amplitude variable (initialized to 0) is incremented or decremented by a small, random quantity. This variable will give you your brown noise. In practice, audio programs need to keep their values in a small range, like -1 to 1. In this case, the amplitude can simply be multiplied by a number slightly less than one every frame, pulling it in towards 0 as it jitters up and down, producing the static. Just to be sure, the amplitude should be tested every frame to ensure it still lies in an acceptable range. If not, it should be moved in. Numbers very close to one will give brown noise with more low frequency content. Numbers that are much less than one (depending on your framerate, maybe something like .99) will begin to filter out the low frequency content. An easy way to make ocean noises is to instead multiply the amplitude by a very very low frequency sine wave (like .1hz or less). When the sine wave is at 1 it sounds like a wave is crashing in. As it retreats to 0 the surf is running along the beach. As it falls below 0 the water is retreating, pulling in the sand and making that hissing noise.
Making sound in practice:
Sounds can be generated in .NET languages using DirectX (or so I hear, I've never done it myself). The Wave module can be used to write .wav files in Python as this language is too slow to write audio samples fast enough to be played directly through the speakers. Either SDL or PortAudio can be used with C (or C++?).
Soon I will talk about the Fourier Transform since the Wikipedia article is far too confusing for most people.
Synthesis of simple sine wave:
Programs that synthesize sine waves should avoid the simple approach of sin(2*pi*frequency*time) because if you change the frequency while generating the note there will be a distinct jump in the amplitude level at that point which sounds like an annoying pop. If you steadily change the frequency over time the side effects are even worse and more confusing, with wild pitch changes resulting. Programs generating sine waves should instead maintain a domain variable which is incremented by 2*pi*frequency/framerate every frame. The amplitude of the synth for any given moment can be found by taking sin(domain). In practice, the precision of floating point numbers decreases steadily as the value contained increases. If your domain variable simply continues to grow slowly over time, the quality of the tone will get worse and worse. To avoid this, you will need to find a way to lower the domain variable every once and a while without causing a pop.
Useful waves:
Saw, ramp, triangle, and square waves can also be synthesized. The formulas for these periodic functions are relatively easy to figure out. Many of the tips that apply to sine wave synthesis apply to these waves.
Additive synthesis:
Add waves together, see what happens. Add harmonics to change the voice of an instrument.
AM synthesis:
Multiply one wave by another. Can be interesting!
FM synthesis:
Modulate the frequency of one wave slightly (or a lot) with another wave. If the frequency of the second wave is low this sounds like vibrato. If it is high, this can make new and interesting noises.
Bells, Dings, Xylophones, Bips, etc:
Similar to sine wave synthesis. Use a cosine wave instead. At the beginning of the sound, initialize the domain to 0. Initialize a volume variable to 1. Every frame, multiply the volume by a number just slightly less than one (like .9999) and store the result back into volume, causing exponential decay in the volume over time. The amplitude of the sound at any time can be found with cos(domain)*volume. To choose a half life for the decay (in seconds, assuming your framerate is measured in fps), the number you multiply the volume by should be (1/(framerate*halflife))^(1/2).
Filters:
Wikipedia has good articles on high and low pass filters. Low pass filters try to remove frequencies higher than the cutoff frequency from a signal while high pass filters do the opposite. Band pass filters try to eliminate all frequencies but those in a certain range, and can be made by running the output of a high pass filter through a low pass filter or visa versa. Adding the outputs of high and low pass filters will render a band reject filter which eliminates frequencies in a certain range. By modulating the cutoff frequency of a low pass filter with a very low frequency sine wave and running a deep bass wave through it you can get started making your own dubstep!
Goertzel algorithm:
The Goertzel Algorithm is a way to find the amplitude of a given frequency in an audio sample. This can be used for many things, most of which are not at all related to music. Still, it's good to know about. Read more on Wikipedia.
Envelope filter:
An envelope filter tries to outline the peaks of an audio signal to give a general idea of its volume throughout the signal.
Vocoder:
A vocoder can be used to make voices sound strange or robotic. Kraftwerk made extensive use of vocoders. ELO's Mr Blue Sky also has vocals that have been run through a vocoder. Vocoders are also used extensively in Sci-Fi movies. The basic idea is to find the envelopes for several (usually evenly spaced) frequencies in an audio track then use the envelopes to modulate filtered samples with corresponding frequency (bandpass) of a carrier wave. The Goertzel Algorithm or a Fast Fourier Transform will directly give these envelopes, but band pass filters and envelope filters can be used together to achieve the same end. In fact, because of the frequency response of some of the other algorithms, band pass filters are usually preferred.
White noise:
Simple random samples. Completely random samples. Very annoying.
Brown noise:
Every frame an amplitude variable (initialized to 0) is incremented or decremented by a small, random quantity. This variable will give you your brown noise. In practice, audio programs need to keep their values in a small range, like -1 to 1. In this case, the amplitude can simply be multiplied by a number slightly less than one every frame, pulling it in towards 0 as it jitters up and down, producing the static. Just to be sure, the amplitude should be tested every frame to ensure it still lies in an acceptable range. If not, it should be moved in. Numbers very close to one will give brown noise with more low frequency content. Numbers that are much less than one (depending on your framerate, maybe something like .99) will begin to filter out the low frequency content. An easy way to make ocean noises is to instead multiply the amplitude by a very very low frequency sine wave (like .1hz or less). When the sine wave is at 1 it sounds like a wave is crashing in. As it retreats to 0 the surf is running along the beach. As it falls below 0 the water is retreating, pulling in the sand and making that hissing noise.
Making sound in practice:
Sounds can be generated in .NET languages using DirectX (or so I hear, I've never done it myself). The Wave module can be used to write .wav files in Python as this language is too slow to write audio samples fast enough to be played directly through the speakers. Either SDL or PortAudio can be used with C (or C++?).
Soon I will talk about the Fourier Transform since the Wikipedia article is far too confusing for most people.