Hey everyone, I\'m currently trying to figure out how to play back a tone I have generated using a sinusoidal wave.
Here\'s my code:
#include
You will need to go through the OS to play back sounds. It's not as straightforward as you would think. In OSX, you will need to go through CoreAudio.
A better approach would be to use a wrapper library like PortAudio (http://www.portaudio.com/) which will make your code more portable and save you some of the boilerplate needed to get sound out of your program.
I've written an example exactly for this. Runs fine with OpenAL under MacOSX and plays smooth sines. Take a look here: http://ioctl.eu/blog/2011/03/16/openal-sine-synth/
Code is quite short, i guess i can add it here as well for sake of completeness:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#define CASE_RETURN(err) case (err): return "##err"
const char* al_err_str(ALenum err) {
switch(err) {
CASE_RETURN(AL_NO_ERROR);
CASE_RETURN(AL_INVALID_NAME);
CASE_RETURN(AL_INVALID_ENUM);
CASE_RETURN(AL_INVALID_VALUE);
CASE_RETURN(AL_INVALID_OPERATION);
CASE_RETURN(AL_OUT_OF_MEMORY);
}
return "unknown";
}
#undef CASE_RETURN
#define __al_check_error(file,line) \
do { \
ALenum err = alGetError(); \
for(; err!=AL_NO_ERROR; err=alGetError()) { \
std::cerr << "AL Error " << al_err_str(err) << " at " << file << ":" << line << std::endl; \
} \
}while(0)
#define al_check_error() \
__al_check_error(__FILE__, __LINE__)
void init_al() {
ALCdevice *dev = NULL;
ALCcontext *ctx = NULL;
const char *defname = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
std::cout << "Default device: " << defname << std::endl;
dev = alcOpenDevice(defname);
ctx = alcCreateContext(dev, NULL);
alcMakeContextCurrent(ctx);
}
void exit_al() {
ALCdevice *dev = NULL;
ALCcontext *ctx = NULL;
ctx = alcGetCurrentContext();
dev = alcGetContextsDevice(ctx);
alcMakeContextCurrent(NULL);
alcDestroyContext(ctx);
alcCloseDevice(dev);
}
int main(int argc, char* argv[]) {
/* initialize OpenAL */
init_al();
/* Create buffer to store samples */
ALuint buf;
alGenBuffers(1, &buf);
al_check_error();
/* Fill buffer with Sine-Wave */
float freq = 440.f;
int seconds = 4;
unsigned sample_rate = 22050;
size_t buf_size = seconds * sample_rate;
short *samples;
samples = new short[buf_size];
for(int i=0; i<buf_size; ++i) {
samples[i] = 32760 * sin( (2.f*float(M_PI)*freq)/sample_rate * i );
}
/* Download buffer to OpenAL */
alBufferData(buf, AL_FORMAT_MONO16, samples, buf_size, sample_rate);
al_check_error();
/* Set-up sound source and play buffer */
ALuint src = 0;
alGenSources(1, &src);
alSourcei(src, AL_BUFFER, buf);
alSourcePlay(src);
/* While sound is playing, sleep */
al_check_error();
sleep(seconds);
/* Dealloc OpenAL */
exit_al();
al_check_error();
return 0;
}
Update: I've found OpenAL a bit too limiting for my needs, like I have some problems with low-latency playback as this appears to be not the primary domain of OpenAL. Instead, I've found the very convincing PortAudio: http://www.portaudio.com/ It supports all major platforms (Mac,Win,Unix/ALSA) and looks very good. There is an example for sine playback which is far more sophisticated, yet quite simple. Just download the latest release and find the sine-playback sample at test/patest_sine.c
Try this (this program uses Z transform concept, a complete example that generates dtmf tones using ALSA and compilable on LINUX are available here):
/*
* Cosine Samples Generator
*
* Autor: Volnei Klehm
* Data: 04/01/2014
*/
#include <math.h>
#include <stdio.h>
#define S_FREQ 8000 /*Sample frequency, should be greater thar 2*sineFrequency
If using audio output it has to be the same saple frequency
Used there*/
const float frequency_in_Hertz = 697; /*set output frequency*/
const float generatorContant1 = cosf(2*M_PI*(frequency_in_Hertz/S_FREQ));
const float generatorContant2 = sinf(2*M_PI*(frequency_in_Hertz/S_FREQ));
float GenerateSignal(){
static float Register[2]={1,0};
static float FeedBack;
FeedBack=2*generatorContant1*Register[0]-Register[1];
Register[1]=Register[0];
Register[0]=FeedBack;
return (generatorContant2*Register[1]);
}
int main(void) {
/*generate 300 samples*/
for (int NumberOfSamples = 300; NumberOfSamples > 0; NumberOfSamples--)
printf("\n%f", GenerateSignal());
return 0;
}