C++ - Play back a tone generated from a sinusoidal wave
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
Moonlight293
Updated on September 08, 2020Comments
-
Moonlight293 over 3 years
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 <iostream> #include <OpenAL/al.h> #include <OpenAL/alc.h> #include <Math.h> using namespace std; int main (int argc, char * const argv[]) { int number = 0; int i, size; double const Pi=4*atan(1); cout << "Enter number of seconds:" << endl; scanf("%d", &number); size = 44100*number; unsigned char buffer [size]; //buffer array for(i = 0; i < size; i++){ buffer[i] = (char)sin((2*Pi*440)/(44100*i))*127; } return 0; }
Obviously it doesn't do anything at the moment, since I have no idea how to play the buffer. I don't want to generate a wav file, nor do I want to load one in. I just want to play back the buffer I have generated.
I am currently working on Mac OS X, and have tried using OpenAL methods - however I have found that alut and alu are not part of it anymore and if I try to use it then it turns out that it's all depredated anyway. I have also tried to include QAudioOutput, but for some reason it does not appear to be anywhere on my Mac.
I just want a simple playback of the tone I've created. Does anyone have anything they can point me to?
Thanks heaps!!!
-
Moonlight293 about 13 yearsThank you!! That's exactly what I needed :)
-
Moonlight293 about 13 yearsThis nearly worked until I got a bunch of linking errors! But I think that's my own programming skill that did it, so this option pretty much worked too.
-
Moonlight293 about 13 yearsJust a quick question - what is the 32760 for when making the samples? Thanks heaps!
-
zerm about 13 years@Moonlight293: audio format is MONO16, i.e. 16 bits per sample. sine generated is float, thus from -1 to 1. To map it to 16 bits, i.e. from -32767 to 32768, i multiply with that number. A bit less just for..uhm..lazyness
-
Minimus Heximus over 8 yearsI tested no sounds produced.
-
Minimus Heximus over 8 yearsFor me
#include <AL/alut.h>
works instead of#include <OpenAL/al.h>
. probably your code is outdated, -
Minimus Heximus over 8 yearsalso instead of
sleep
function you should usealutSleep
.sleep
may not work in some OS's. -
Minimus Heximus over 8 yearsand it seems you should
delete samples;
. -
Minimus Heximus over 8 yearsAlso you do not delete buffer and resources. I wonder if upvoters were familiar with openal.
-
Elvis Rock Code over 8 yearsThis version just generate the values, for full DTMF follow the link on the description.