Hi! Hope you're enjoying this blog. I have a new home at www.goldsborough.me. Be sure to also check by there for new posts <3

Sunday, February 2, 2014

Developing a digital synthesizer in C++: Part 1 - Generating a sine wave

In this first part of my series "Developing a digital synthesizer in C++", I'll show you how to generate a sine wave and store it into a buffer. With "generating", I only mean calculating the actual values, storing them into an audio file such as .wav is a totally different subject and will be discussed in my following post.

Below you can find the code. I commented on almost everything and also the variable names should more or less tell you what's going on. 

#include <cmath>
#include <stdint.h>

#define twoPI 6.28318530717958 // 2*pi = 360˚ = one full cycle

// Using standard typedefs for portability, you can change them to normal data types if you like

// @param dur: I was indecisive about whether the duration
// should be 32 or 16 bits aka 130 years or 18 hours, but then
// again you never know what sound installations people come up with

int16_t* gen(float freq, uint32_t dur, float vol=1.0);

int main(int argc, const char * argv[])
{
    int16_t* buff = gen(440,3);
    
    /* Do something with it */
    
    delete [] buff;
}

int16_t* gen(float freq, uint32_t dur, float vol)
{
    uint32_t samplerate = 44100;    // samples per second
    
    // initial phase, you could offset it, but then again you could not
    double phase = 0;
    
    // The phase increment is the phase value the phasor increases by
    // per sample.
    double phaseincr = twoPI/samplerate * freq;
    
    // The amount of samples the buffer must hold
    uint32_t total_samples = samplerate * dur;
    
    int16_t *buffer = new int16_t [total_samples]; // grab a new array with size for the entire buffer
    
    for (int i = 0; i < total_samples; i++) // fill the buffer
    {
        // the factor 32767 comes from the fact that .wav files store samples
        // as 16 bit signed integers, before this the values are normalized
        // between -1 and + 1 (the sine values). If you want to do something
        // else with these values before storing them somewhere I recommend leaving        // the factor away.
        buffer[i] = 32767*(sin(phase) * vol);
        phase += phaseincr;
        
        // when the phasor hits 2Pi/360˚/full circle we have to reset the phase
        if (phase >= twoPI) phase -= twoPI;
    }
    
    return buffer;
}

You could change the values for the sample rate, initial phase or volume, but especially changing the samplerate is not recommended as 44.1 kHz is really quite standard. I actually wanted to write a bit about the code, but there's nothing that's not already explained in the comments. If you do have any issues/questions or the code doesn't build for you, feel free to comment.

No comments :

Post a Comment