## Sound Synthesis (1/ Oscillators)

By Vermeille on Monday 25 March 2013, 23:42 - C++ - Permalink

## Introduction

### Motivation

Yesterday, I was at BeMyApp contest, where we had to develop something about music. After a stupid lyrics generators using markov chains and an uninteresting game in html5, I decided to code a synthesizer (A dream I had for many years, since I'm really interested in sound synthesis).

## Theory

### Reminders

Okay, let's start with some sound theory.

Sound is mechanical wave propagating in the air. If those waves are periodic, it's a note. Taking a fundamental frequency (mostly 440 Hz, we can define our notes with the following formula:

As Fourier tells us, every periodic wave can be described in terms of a sum of sinus functions.

The wave with the lowest is named "fundamental", and multiples of this frequency are called "harmonics".

Let's see our 5 primitive waveforms:

### Sinus

The simplest wave is then a sinus: pure signal, without any harmonics. The formula is:

### Square

A square waveform, in sense of Fourier is an infinite serie summing all odd frequencies multiple of the harmonic.

Hopefully, we won't need to code such a formula. Electrically, we do this by commutating a DC generator, and we will do almost the same programatically.

### Sawtooth

A sawtooth is defined as a sum of all even harmonics

Electrically, I think that this is achieved with some RLC circuits (please, if you know, confirm it). Programatically, we don't need to code such a formula.

### Triangle

A triangle is the sum of odd harmonics, multiplying every th harmonic by and rolling off the harmonics by the inverse square of their relative frequency to the fundamental (thx Wikipedia :D)

### Whitenoise

It's just random numbers guys.

### Recap

## Synthesis systems

### Additive synthesis

This system is directly inspired from Fourier's series: take a lot of sinus, and add them to make a complex sound.

### Substractive synthesis

Take complex sounds (like the 5 ones defined above), and then apply some filters to treat them.

### FM synthesis

This kind of synthesis has almost an unpredictable result, and works like radio does: the timbre of a simple waveform is changed by frequency modulating it with a modulating frequency that is also in the audio range, resulting in a more complex waveform and a different-sounding tone.

### Wavetable synthesis

This one may be though like a combinations of others: take some sounds, and play them each for few milliseconds. The result can really be crazy. This is the one we will implement, because it allows killing acid sounds without efforts.

## We are in a digital world

### A word about your sound card

Since we're using a computer, we're dealing with discrete values. We will send our sound to the sound card in the form of many `int16`

, so we have to be able to give the amplitude of our signal considering sampling rate and the frequency. In most systems, the default sampling rate is 44100 Hz, it means that you have to feed your sound card with 44100 "values" per second (for each channel, that's why, assuming stereo, I'll duplicate each value).

### Generating waveforms

Enter the world of algorithms. Since I wrote my synthesizer both in Haskell and C++, I'll show, for each part, the language which is the easier to understand. If you never read haskell, list are constructed with `:`

, don't bother about infinite lists and recursions (allowed by laziness), and everything should be okay.

I need to introduce two magic numbers widely used in the code: 44100 is the default sampling rate we target, (-32767, 32768) are `short_min`

and `short_max`

```
-- takes a frequency and returns the number of data needed to fill a period
getPeriod :: Float -> Int
getPeriod freq = freq * 2 * pi / 44100
-- takes a number of milliseconds and returns the corresponding number of data
msToDatas :: Int -> Int
msToDatas ms = truncate $ 44100.0 / (1000.0 / fromIntegral ms)
```

#### Sine

It's really straigthforward, generate the ith value using the period, and recurse on the (i+1)th value.

```
sinW :: Float -> Int -> [Int16]
sinW freq i = sinW' i (getPeriod freq)
sinW' :: Int -> Float -> [Int16]
sinW' i period =
let new = (round $ (* 32767.0) $ sin (fromIntegral i * period)) in
new:new:sinW' (i + 1) period
```

#### Square

The square waveform is .

```
squareW :: Float -> Int -> [Int16]
squareW freq i = squareW' i (getPeriod freq)
squareW' :: Int -> Float -> [Int16]
squareW' i period = let new = (round . (* 32767.0) . fromIntegral . sign
$ sin (fromIntegral i * period)) in
new:new:squareW' (i + 1) period
sign x | x < 0 = -1
| otherwise = 1
```

#### Sawtooth

Algorithmically, this is simple : `samplesPerWavelength`

is the number of data to play during one period, `ampStep`

is the "amount of amplitude" to add between each step. Start at `int16_min`

, add `ampStep`

until we reach `int16_max`

, then restart.

```
sawW :: Int -> Float -> [Int16]
sawW i period = sawW' i period (-32767)
sawW' :: Int -> Float -> Int -> [Int16]
sawW' i period tempSample
| i < samplesPerWavelength =
let new = fromIntegral tempSample in
new:new:sawW' (i + 1) period (tempSample + ampStep period)
| otherwise = (-32767):(-32767):sawW' 0 period (-32767 + ampStep period)
where
samplesPerWavelength :: Int
samplesPerWavelength = truncate $ 44100.0 / period
ampStep :: Int
ampStep = (44100 * 2) `div` samplesPerWavelength period
```

#### Triangle

This looks like the sawtooth: `samplesPerWavelength`

is the number of data to play during one period, `ampStep`

is the "amount of amplitude" to add or substract between each step. Start at `int16_min`

, add `ampStep`

until we reach `int16_max`

, then substract `ampStep`

until we reach `int16_min`

etc...

```
triW :: Float -> Int-> [Int16]
triW period i = triW' period (-32766)
$ (44100 * 3)
`div` (samplesPerWavelength period)
where
samplesPerWavelength :: Float -> Int
samplesPerWavelength freq = truncate $ 44100.0 / freq
triW' :: Float -> Int -> Int -> [Int16]
triW' period tempSample ampStep
| abs tempSample > 32767 =
let new = fromIntegral $ tempSample + ampStep in
new:new:triW' period (tempSample - ampStep) (-ampStep)
| otherwise =
fromIntegral tempSample
:fromIntegral tempSample:triW' period (tempSample + ampStep) ampStep
```

### Playing notes

Okay, now you can play frequencies. You should create a simple array which allows a note number to be converted to a frequency, and you'll be able to play notes.

### Wavetable Synthesis

As I promised, here, we do some wavetable synthesis: just play some waveforms a few milliseconds.

```
int main()
{
double freqs[] = {
#define X(A) A,
# include "freqs.def"
#undef X
};
srand(time(nullptr));
// One theme I composed for Subliminal AEon
int note = 0;
int song[] = {
48, 55, 56, 48, 51, 55, 50, 53,
48, 55, 56, 48, 51, 55, 50, 53,
47, 50, 51, 55, 51, 50, 51, 48,
47, 50, 51, 55, 51, 50, 51, 48
};
while (true)
{
for (size_t i = 0; i < 5; ++i)
{
// Second parameter is the number or milliseconds to play
Sinus(freqs[song[note]], 6);
Square(freqs[song[note]], 5);
Sinus(freqs[song[note]], 7);
Saw(freqs[song[note]], 3);
Triangle(freqs[song[note]], 3);
Sinus(freqs[song[note]], 7);
White(2);
Sinus(freqs[song[note]], 7);
}
note = (note + 1) % (sizeof (song) / sizeof (song[0]));
}
return (0);
}
```

And just play that using

`./a.out | aplay -c 2 -f U16_LE -r 44100`

You may have to adjust parameters of `aplay`

depending on your architectures

## Going further

### New waves

As an example, you can now merge waveforms by adding or multiplying them to create additionnal waveforms. Feel free to create whatever you want when merging.

```
triPlusSquare :: Float -> [Int16]
triPlusSquareW freq = zipWith addW (triW freq) (squareW (freq * 2))
addW :: Int16 -> Int16 -> Int16
addW x y = (x `div` 2 + y `div` 2)
```

### Filters

It sounds really acid. We will give us the possibility (in the next article :D) to use Fourier's transform to use {low,high}-pass filters.

## Conclusion

I was really proud to create my own synthesizer, you should do it too :D !

## Comments

I love the simple random white noise one. You can make a few NES and Atari 2600 effects easily with it.

One piece of advice: if you generate waveforms using floating-point, use double if you can, especially if you are doing a for loop.

If some one needs to be updated with most

up-to-date technologies afterward he must be pay a quick visit this web page and be up to date every day.

Veгy nice pоst. I just stumbled upon your blog aand wanted to say

that I've truly enjoyed bгowsing your bloǥ pߋsts.

Ateг all I'll bbe subscribing to yοur rss feed aand I

hope you write again soon!

At the end of the study, participants lost, on average, 17 pounds resulting in a 10.

If you also suffer from high blood pressure, Svetol branded Coffee

Bean at about 200mg a day have shown to help reduce the effects of hypertension. More clinical trials is required to verify this, but it really is optimistic now.

You will find 16 tracks with which to build your musical

masterpiece so it is possible to have drums on a person monitor,

keyboard on one more and so on, and many others.

I'm using Step Filter for mine, here are the settings:.

A disadvantage is that a variable file, unlike a fixed-size file, may become

fragmented and cause even more hard drive activity.

Check out tour dates and tickets at IRON MAIDEN's website or LIVE NATION.

Also there are two additional unit types of dark and light

which simply just good against the other. I had offered to be one of the drivers, as not every member going

on the trip was a licensed driver.

It's awesome for me to have a site, which is beneficial designed for my knowledge.

thanks admin

This post will assist the internet people for building up new

weblog or even a weblog from start to end.

biggest loser diet plan and exercise

grams to troy ounces

I do not drop manby comments, but i did some searching and wounbd up here Sound Synthesis (1/ Oscillators) - Vermeille's blog.

Andd I do have some questions for youu if you don't mind.

Is it just me or does it look like a few of these respones look as

if they are left by brainn dead folks? :-P And, if you are writing at other places, I would like

to kedep up with everything new you have tto post. Would you

maoe a list oof all of all your publc sites like your linjkedin profile, Facebook page or twitter feed?