Download: siren.wav
Complete Source Code:
Main.cpp
#include <al.h>
#include <alc.h>
#include <iostream>
#include <chrono>
#include <thread>
#include "SoundFile_WAV.h"
using namespace std;
using namespace chrono;
/* like in OpenGL, errors are queried in a for-loop */
#define CheckForALError CheckForALError__(__FILE__, __LINE__);
void CheckForALError__(const char* filename, unsigned int line)
{
for (ALenum error; (error = alGetError()) != AL_NO_ERROR;)
{
cout << "AL_ERROR: " << filename << " line " << line << ": \t";
if (error == AL_INVALID_NAME)
cout << "AL_INVALID_NAME";
if (error == AL_INVALID_ENUM)
cout << "AL_INVALID_ENUM";
if (error == AL_INVALID_VALUE)
cout << "AL_INVALID_VALUE";
if (error == AL_INVALID_OPERATION)
cout << "AL_INVALID_OPERATION";
if (error == AL_OUT_OF_MEMORY)
cout << "AL_OUT_OF_MEMORY";
cout << (char)7 << endl; /*play sound*/
cin.get();
}
}
/* get sound format of .wav file */
ALenum SoundFormat(const CSoundFile_WAV& wav)
{
if (wav.NumberOfChannels() == 1)
{
if (wav.BitsPerSample() == 8)
return AL_FORMAT_MONO8;
if (wav.BitsPerSample() == 16)
return AL_FORMAT_MONO16;
}
if (wav.NumberOfChannels() == 2)
{
if (wav.BitsPerSample() == 8)
return AL_FORMAT_STEREO8;
if (wav.BitsPerSample() == 16)
return AL_FORMAT_STEREO16;
}
/* unknown sound format */
cout << "WARNING: cant get sound format from file " << wav.FileName() << endl;
return 0;
}
double Time()
{
static high_resolution_clock::time_point tstart = high_resolution_clock::now();
high_resolution_clock::time_point tnow = high_resolution_clock::now();
return duration_cast<duration<double>>(tnow - tstart).count();
}
int main(int argc, char* argv[])
{
/* read .wav file */
/************************************************************************/
CSoundFile_WAV wav;
if (!CSoundFile_WAV::Load("siren.wav", wav))
{
cout << "ERROR: cant read .wav file" << wav.FileName() << endl;
cin.get();
return 1;
}
cout << "\t---> " << wav.FileName() << endl;
cout << "AudioFormat " << wav.AudioFormat() << endl;
cout << "NumberOfChannels " << wav.NumberOfChannels() << endl;
cout << "SampleRate " << wav.SampleRate() << endl;
cout << "ByteRate " << wav.ByteRate() << endl;
cout << "BlockAlign " << wav.BlockAlign() << endl;
cout << "BitsPerSample " << wav.BitsPerSample() << endl;
cout << "AudioSize in KiloBytes " << wav.AudioSize() / 1000 << endl;
cout << endl;
/* open device, create context */
/************************************************************************/
ALCdevice* device = alcOpenDevice(nullptr);
if (!device)
{
cout << "ERROR: cant open audio device" << endl;
cin.get();
return 1;
}
ALCcontext* context = alcCreateContext(device, nullptr);
if (!context)
{
cout << "ERROR: cant create audio context" << endl;
alcCloseDevice(device);
cin.get();
return 1;
}
/* there can be multiple contexts doing separate things, but
only 1 at a time can be "played" by OpenAL (the "current" one),
the others are either run in background or are suspended */
alcMakeContextCurrent(context);
/* query some context infos */
/************************************************************************/
cout << "OpenAL Version: " << alGetString(AL_VERSION) << endl;
cout << "Renderer: \t" << alGetString(AL_RENDERER) << endl;
cout << "Vendor: \t" << alGetString(AL_VENDOR) << endl;
cout << "Extensions: \t" << alGetString(AL_EXTENSIONS) << endl;
cout << endl;
/* create a buffer, fill it with sound data */
/************************************************************************/
ALenum format = SoundFormat(wav);
const ALvoid* data = wav.AudioData();
ALsizei size = wav.AudioSize();
ALsizei frequency = wav.SampleRate();
ALuint buffer = 0;
alGenBuffers(1, &buffer);
alBufferData(
buffer, /* which buffer */
format, /* what format (mono / stereo, 8bit or 16bit) */
data, /* what sound data */
size, /* how many bytes to copy */
frequency); /* what sample rate */
/* create a source, tell it which buffer(s) to play */
/************************************************************************/
ALuint source = 0;
alGenSources(1, &source);
alSourcei(source, AL_BUFFER, buffer); /* which buffer */
alSourcei(source, AL_LOOPING, AL_TRUE); /* repeat when finished */
alSourcePlay(source); /* start playing ... */
/* check if everything went right */
/************************************************************************/
CheckForALError
/* ... do nothing (or something else), just let OpenAL do its thing ... */
/************************************************************************/
float x_velocity = 10;
float position[] = { -100, 0, 2 }; /* 3D position */
float velocity[] = { x_velocity, 0, 0 }; /* 3D velocity */
/* for 15 seconds, update source location */
double time_start = Time();
while (Time() < time_start + 15)
{
/* update source position */
position[0] += x_velocity * 0.1f; /* 0.1 = timestep between 2 frames / loop executions */
alSourcefv(source, AL_POSITION, position);
alSourcefv(source, AL_VELOCITY, velocity);
this_thread::sleep_for(milliseconds(100)); /* wait 0.1 seconds */
}
/* release resources */
/************************************************************************/
alDeleteSources(1, &source);
alDeleteBuffers(1, &buffer);
/* destroy context, close device */
/************************************************************************/
alcMakeContextCurrent(nullptr);
alcDestroyContext(context);
alcCloseDevice(device);
return 0;
}