1
votes

How might one generate audio at runtime using C++? I'm just looking for a starting point. Someone on a forum suggested I try to make a program play a square wave of a given frequency and amplitude.

I've heard that modern computers encode audio using PCM samples: At a give rate for a specific unit of time (eg. 48 kHz), the amplitude of a sound is recorded at a given resolution (eg. 16-bits). If I generate such a sample, how do I get my speakers to play it? I'm currently using windows. I'd prefer to avoid any additional libraries if at all possible but I'd settle for a very light one.

Here is my attempt to generate a square wave sample using this principal:

signed short* Generate_Square_Wave(
    signed short a_amplitude , 
    signed short a_frequency ,
    signed short a_sample_rate )
{
    signed short* sample = new signed short[a_sample_rate];

    for( signed short c = 0; c == a_sample_rate; c++ )
    {
        if( c % a_frequency < a_frequency / 2 )
            sample[c] = a_amplitude;
        else
            sample[c] = -a_amplitude;
    }

    return sample;
}

Am I doing this correctly? If so, what do I do with the generated sample to get my speakers to play it?

2
You should check out PortAudio. It will handle audio io for you and it has plenty of sample code.Bjorn Roche

2 Answers

1
votes

Your loop has to use c < a_sample_rate to avoid a buffer overrun.

To output the sound you call waveOutOpen and other waveOut... functions. They are all listed here:

http://msdn.microsoft.com/en-us/library/windows/desktop/dd743834(v=vs.85).aspx

0
votes

The code you are using generates a wave that is truly square, binary kind of square, in short the type of waveform that does not exist in real life. In reality most (pretty sure all) of the sounds you hear are a combination of sine waves at different frequencies.

Because your samples are created the way they are they will produce aliasing, where a higher frequency masquerades as a lower frequency causing audio artefacts. To demonstrate this to yourself write a little program which sweeps the frequency of your code from 20-20,000hz. You will hear that the sound does not go up smoothly as it raises in frequency. You will hear artefacts.

Wikipedia has an excellent article on square waves: https://en.m.wikipedia.org/wiki/Square_wave

One way to generate a square wave is to perform an inverse Fast Fourier Transform which transforms a series of frequency measurements into a series of time based samples. Then generating a square wave is a matter of supplying the routine with a collection of the measurements of sin waves at different frequencies that make up a square wave and the output is a buffer with a single cycle of the waveform.

To generate audio waves is computationally expensive so what is often done is to generate arrays of audio samples and play them back at varying speeds to play different frequencies. This is called wave table synthesis.

Have a look at the following link:

https://www.earlevel.com/main/2012/05/04/a-wavetable-oscillator%E2%80%94part-1/

And some more about band limiting a signal and why it’s necessary:

https://dsp.stackexchange.com/questions/22652/why-band-limit-a-signal