Static and Buzzing when Generating and Playing Sine Waves with SFML - c++

I am writing a program that needs to play a lot of synthesized sine waves in rapid succession. I am using C++ and SFML to write this program. I have created a class to represent a synthesizer. It is responsible for generating the sine wave and playing it down a single audio stream. However, whenever I use the app, I get a lot of crackling and popping sounds that get intermixed in. I am not sure if this is a library issue or I am generating and feeding in the sine wave wrong. Here is my code:
synth.h
#pragma once
#include <SFML/Audio.hpp>
#include <vector>
#include <mutex>
class Synth : public sf::SoundStream {
std::vector<sf::Int16> m_AudioData;
std::mutex m_Lock;
bool m_ClearData, m_Loaded, m_Started;
int m_Amplitude;
const float TAU = 6.28318;
public:
Synth(int);
Synth(const Synth&);
~Synth();
bool onGetData(sf::SoundStream::Chunk&) override;
void onSeek(sf::Time) override;
void makeSound(float, int);
bool busy();
};
synth.cpp
#include "synth.h"
Synth::Synth(int amplitude)
: m_Amplitude(amplitude)
, m_Loaded(false)
, m_ClearData(false)
, m_Started(false)
{
initialize(1, 44100);
}
Synth::Synth(const Synth& other)
: m_Amplitude(other.m_Amplitude)
, m_Loaded(false)
, m_ClearData(false)
, m_Started(false)
{
initialize(1, 44100);
}
Synth::~Synth() {
stop();
}
bool Synth::onGetData(Chunk &chunk) {
static const sf::Int16 empty[10] = { 0 };
m_Lock.lock();
if (m_Loaded) {
chunk.sampleCount = m_AudioData.size();
chunk.samples = m_AudioData.data();
m_ClearData = true;
m_Loaded = false;
}
else {
if (m_ClearData) {
m_AudioData.clear();
m_ClearData = false;
}
chunk.sampleCount = 10;
chunk.samples = empty;
}
m_Lock.unlock();
return true;
}
void Synth::onSeek(sf::Time) {}
void Synth::makeSound(float freq, int duration) {
m_Lock.lock();
m_ClearData = false;
m_Loaded = true;
m_AudioData.clear();
int sampleCount = duration * 44;
int amplitude = m_Amplitude;
for (int i = 0; i < sampleCount; i++) {
if (i < sampleCount / 5)
amplitude = floor(m_Amplitude * (i / (double)sampleCount) * 5);
else if (i > sampleCount / 2)
amplitude = floor(m_Amplitude * ((sampleCount - i) / (double)sampleCount));
else
amplitude = m_Amplitude;
m_AudioData.push_back(amplitude * sin(TAU * (freq / 44100) * i));
}
m_Lock.unlock();
if (!m_Started) {
play();
m_Started = true;
}
}
bool Synth::busy() {
bool isBusy = false;
if (m_Lock.try_lock()) {
isBusy = m_Loaded || m_ClearData;
m_Lock.unlock();
}
return isBusy;
}
For context, these synthesizers are stored in a vector owned by a parent class. They are used to represent available channels for playing audio. There are 50 stored in the parent class in total, however the number can vary. I doubt that this has any relevance to my problem, but I wanted to inform everyone to the best of my ability.
Thanks a million, open to any other side criticisms of my code.

Related

How do I generate a tone using SDL_audio?

I am trying to generate a simple, constant sine tone using SDL_audio. I have a small helper class that can be called to turn the tone on/off, change the frequency, and change the wave shape. I have followed some examples I could find on the web and got the following:
beeper.h
#pragma once
#include <SDL.h>
#include <SDL_audio.h>
#include <cmath>
#include "logger.h"
class Beeper {
private:
//Should there be sound right now
bool soundOn = true;
//Type of wave that should be generated
int waveType = 0;
//Tone that the wave will produce (may or may not be applicable based on wave type)
float waveTone = 440;
//Running index for sampling
float samplingIndex = 0;
//These are useful variables that cannot be changed outside of this file:
//Volume
const Sint16 amplitude = 32000;
//Sampling rate
const int samplingRate = 44100;
//Buffer size
const int bufferSize = 1024;
//Samples a sine wave at a given index
float sampleSine(float index);
//Samples a square wave at a given index
float sampleSquare(float index);
public:
//Initializes SDL audio, audio device, and audio specs
void initializeAudio();
//Function called by SDL audio_callback that fills stream with samples
void generateSamples(short* stream, int length);
//Turn sound on or off
void setSoundOn(bool soundOnOrOff);
//Set timbre of tone produced by beeper
void setWaveType(int waveTypeID);
//Set tone (in Hz) produced by beeper
void setWaveTone(int waveHz);
};
beeper.cpp
#include <beeper.h>
void fillBuffer(void* userdata, Uint8* _stream, int len) {
short * stream = reinterpret_cast<short*>(_stream);
int length = len;
Beeper* beeper = (Beeper*)userdata;
beeper->generateSamples(stream, length);
}
void Beeper::initializeAudio() {
SDL_AudioSpec desired, returned;
SDL_AudioDeviceID devID;
SDL_zero(desired);
desired.freq = samplingRate;
desired.format = AUDIO_S16SYS; //16-bit audio
desired.channels = 1;
desired.samples = bufferSize;
desired.callback = &fillBuffer;
desired.userdata = this;
devID = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(0,0), 0, &desired, &returned, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
SDL_PauseAudioDevice(devID, 0);
}
void Beeper::generateSamples(short *stream, int length) {
int samplesToWrite = length / sizeof(short);
for (int i = 0; i < samplesToWrite; i++) {
if (soundOn) {
if (waveType == 0) {
stream[i] = (short)(amplitude * sampleSine(samplingIndex));
}
else if (waveType == 1) {
stream[i] = (short)(amplitude * 0.8 * sampleSquare(samplingIndex));
}
}
else {
stream[i] = 0;
}
//INFO << "Sampling index: " << samplingIndex;
samplingIndex += (waveTone * M_PI * 2) / samplingRate;
//INFO << "Stream input: " << stream[i];
if (samplingIndex >= (M_PI*2)) {
samplingIndex -= M_PI * 2;
}
}
}
void Beeper::setSoundOn(bool soundOnOrOff) {
soundOn = soundOnOrOff;
//if (soundOnOrOff) {
// samplingIndex = 0;
//}
}
void Beeper::setWaveType(int waveTypeID) {
waveType = waveTypeID;
//samplingIndex = 0;
}
void Beeper::setWaveTone(int waveHz) {
waveTone = waveHz;
//samplingIndex = 0;
}
float Beeper::sampleSine(float index) {
double result = sin((index));
//INFO << "Sine result: " << result;
return result;
}
float Beeper::sampleSquare(float index)
{
int unSquaredSin = sin((index));
if (unSquaredSin >= 0) {
return 1;
}
else {
return -1;
}
}
The callback function is being called and the generateSamples function is loading data into the stream, but I cannot hear anything but a very slight click at irregular periods. I have had a look at the data inside the stream and it follows a pattern that I would expect for a scaled sine wave with a 440 Hz frequency. Is there something obvious that I am missing? I did notice that the size of the stream is double what I put when declaring the SDL_AudioSpec and calling SDL_OpenAudioDevice. Why is that?
Answered my own question! When opening the audio device I used the flag SDL_AUDIO_ALLOW_FORMAT_CHANGE which meant that SDL was actually using a float buffer instead of the short buffer that I expected. This was causing issues in a couple of places that were hard to detect (the stream being double the amount of bytes I was expecting should have tipped me off). I changed that parameter in SDL_OpenAudioDevice() to 0 and it worked as expected!

Qt input audio measuring

I want to measure the level of input volume in peak or decibel or other things.I just want to measure it and detect the loudness.I have this code but it does not detect continuously.It just detect the level at the beginning and after, the level begins to reduce.
Related parts of header file:
Q_INVOKABLE void start();
Q_INVOKABLE void stop();
std::shared_ptr<QAudioInput> source;
QIODevice *device;
QAudioFormat format;
int peak = 0, n;
int16_t v;
C++ file:
#include "Bot.h"
void Bot::start() {
format.setByteOrder(QAudioFormat::LittleEndian);
format.setChannelCount(2);
format.setCodec("audio/pcm");
format.setSampleRate(8000);
format.setSampleSize(16);
format.setSampleType(QAudioFormat::SignedInt);
source = std::shared_ptr<QAudioInput>(new QAudioInput(format));
device = source->start();
connect(device, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
}
void Bot::stop() {
source = nullptr;
device = nullptr;
peak = 0;
emit volumeChanged(peak);
}
void Bot::onReadyRead() {
peak = 0;
n = source->bytesReady();
n /= 2;
if (n >= 80) {
for (int i = 0; i < n; i++) {
v = 0;
device->read((char *)&v, 2);
if (v < 0) {
v = -v;
}
if (peak < v) {
peak = v;
}
}
peak = peak * 100 / 32768;
if (peak < 0) {
peak = 0;
}
emit volumeChanged(peak);
}
}

Sound playback not working when using QueueAudio on C++

I am trying to play a sin wave sound with SDL2 by using the audio queue on C++. In order to do that, I have created a class "Speaker", which has a pushBeep function that is called every time a beep needs to be generated. I have created an AudioDevice successfully, and it is also successful when I do the QueueAudio to the device (I have checked on the debugger) but I can't seem to get any sound out of it.
I have tried changing the way I generate the samples in numerous ways, also, as I said previously, I have checked that the device is properly opened and the QueueAudio returns 0 for success.
This is the class
Speaker::Speaker()
{
SDL_AudioSpec ds;
ds.freq = Speaker::SPEAKER_FREQUENCY;
ds.format = AUDIO_F32;
ds.channels = 1;
ds.samples = 4096;
ds.callback = NULL;
ds.userdata = this;
SDL_AudioSpec os;
this->dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, NULL);
std::cout << "DEVICE: " << this->dev << std::endl;
SDL_PauseAudioDevice(this->dev, 0);
}
Speaker::~Speaker()
{
SDL_CloseAudioDevice(this->dev);
}
void Speaker::pushBeep(double freq, int duration) {
int nSamples = duration * Speaker::SPEAKER_FREQUENCY / 1000;
float* samples = new float[nSamples];
double v = 0.0;
for (int idx = 0; idx < nSamples; idx++) {
//float value = (float)Speaker::SPEAKER_AMPLITUDE * std::sin(v * 2 * M_PI / Speaker::SPEAKER_FREQUENCY);
float value = 440.0;
samples[idx] = value;
v += freq;
}
int a = SDL_QueueAudio(this->dev, (void*)samples, nSamples * sizeof(float));
std::cout << a << std::endl;
delete[] samples;
samples = NULL;
}
And this is how I call it
Speaker s;
s.pushBeep(440.0, 1000);
When I try with the sin wave generation code (commented) it gives me a "double to float loss of precision" error. When I use the fixed value (not commented) it does not give the error, but it still does not work.
I expect the program to output the sound.
Couple of things you are missing, or maybe you didn't add to your code snippet. You didn't specify an audio callback so when you call SDL_QueueAudio(); it didn't know what to do with the data I'm pretty sure. And you weren't calling SDL_PauseAudioDevice() in your example with the delay.
#include <math.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#include <iostream>
namespace AudioGen
{
const int AMPLITUDE = 1;
const int SAMPLE_RATE = 44000;
// Globals
float *in_buffer;
SDL_atomic_t callback_sample_pos;
SDL_Event event;
SDL_bool running = SDL_TRUE;
/**
* Structure for holding audio metadata such as frequency
*/
struct AudioData
{
int sampleNum;
float frequency;
};
void audio_callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
float *buffer = (float*)raw_buffer;
AudioData &audio_data(*static_cast<AudioData*>(user_data));
int nSamples = bytes / 4; // For F32
std::cout << nSamples << std::endl;
for(int i = 0; i < nSamples; i++, audio_data.sampleNum++)
{
double time = (double)audio_data.sampleNum / (double)SAMPLE_RATE;
buffer[i] = (float)(AMPLITUDE * sin(2.0f * M_PI * audio_data.frequency * time));
}
}
int buffer_length;
void callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
float *buffer = (float*)raw_buffer;
int nSamples = bytes/4;
auto local_sample_pos = SDL_AtomicGet(&callback_sample_pos);
for(int i = 0; i < nSamples; ++i)
{
// Stop running audio if all samples are finished playing
if(buffer_length == local_sample_pos)
{
running = SDL_FALSE;
break;
}
buffer[i] = in_buffer[local_sample_pos];
++local_sample_pos;
}
SDL_AtomicSet(&callback_sample_pos, local_sample_pos);
}
class Speaker
{
public:
Speaker()
{
SDL_Init(SDL_INIT_AUDIO);
SDL_AudioSpec ds;
ds.freq = SAMPLE_RATE;
ds.format = AUDIO_F32;
ds.channels = 1;
ds.samples = 4096;
ds.callback = callback;
ds.userdata = &ad; // metadata for frequency
SDL_AudioSpec os;
dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
}
~Speaker()
{
SDL_CloseAudioDevice(dev);
SDL_Quit();
}
void pushBeep(float frequency, int duration)
{
ad.frequency = frequency; // set the frequency for the beep
SDL_PauseAudioDevice(dev, 0);
SDL_Delay(duration); // wait while sound is playing
SDL_PauseAudioDevice(dev, 1);
}
void pushBeep2(float frequency, int duration )
{
int nSamples = duration * SAMPLE_RATE / 1000;
in_buffer = new float[nSamples];
buffer_length = nSamples;
for (int idx = 0; idx < nSamples; idx++) {
double time = (double)idx / (double)SAMPLE_RATE;
in_buffer[idx] = (float)(AMPLITUDE * std::sin(2.0f * M_PI * frequency * time));
}
SDL_QueueAudio(dev, in_buffer, nSamples * sizeof(float));
SDL_PauseAudioDevice(dev, 0);
while(running){
while(SDL_PollEvent(&event)!=0);
}
delete[] in_buffer;
}
private:
SDL_AudioDeviceID dev;
AudioData ad;
int sampleNum = 0;
};
} // End of namespace AudioGen
int main(int argc, char *argv[])
{
AudioGen::Speaker speaker;
//speaker.pushBeep(440, 1000);
speaker.pushBeep2(440.0f, 1000);
return 0;
}

Simple sound wave generator with SDL in c++

i am having problems understanding how the audio part of the sdl library works
now, i know that when you initialize it, you have to specify the frequency and a >>callback<< function, which i think is then called automatically at the given frequency.
can anyone who worked with the sdl library write a simple example that would use sdl_audio to generate a 440 hz square wave (since it is the simplest waveform) at a sampling frequency of 44000 hz?
The Introduction to SDL (2011 cached version: 2) has got a neat example of using SDL Sound library that should get you started: http://www.libsdl.org/intro.en/usingsound.html
EDIT: Here is a working program that does what you asked for. I modified a bit the code found here: http://www.dgames.org/beep-sound-with-sdl/
#include <SDL/SDL.h>
#include <SDL/SDL_audio.h>
#include <queue>
#include <cmath>
const int AMPLITUDE = 28000;
const int FREQUENCY = 44100;
struct BeepObject
{
double freq;
int samplesLeft;
};
class Beeper
{
private:
double v;
std::queue<BeepObject> beeps;
public:
Beeper();
~Beeper();
void beep(double freq, int duration);
void generateSamples(Sint16 *stream, int length);
void wait();
};
void audio_callback(void*, Uint8*, int);
Beeper::Beeper()
{
SDL_AudioSpec desiredSpec;
desiredSpec.freq = FREQUENCY;
desiredSpec.format = AUDIO_S16SYS;
desiredSpec.channels = 1;
desiredSpec.samples = 2048;
desiredSpec.callback = audio_callback;
desiredSpec.userdata = this;
SDL_AudioSpec obtainedSpec;
// you might want to look for errors here
SDL_OpenAudio(&desiredSpec, &obtainedSpec);
// start play audio
SDL_PauseAudio(0);
}
Beeper::~Beeper()
{
SDL_CloseAudio();
}
void Beeper::generateSamples(Sint16 *stream, int length)
{
int i = 0;
while (i < length) {
if (beeps.empty()) {
while (i < length) {
stream[i] = 0;
i++;
}
return;
}
BeepObject& bo = beeps.front();
int samplesToDo = std::min(i + bo.samplesLeft, length);
bo.samplesLeft -= samplesToDo - i;
while (i < samplesToDo) {
stream[i] = AMPLITUDE * std::sin(v * 2 * M_PI / FREQUENCY);
i++;
v += bo.freq;
}
if (bo.samplesLeft == 0) {
beeps.pop();
}
}
}
void Beeper::beep(double freq, int duration)
{
BeepObject bo;
bo.freq = freq;
bo.samplesLeft = duration * FREQUENCY / 1000;
SDL_LockAudio();
beeps.push(bo);
SDL_UnlockAudio();
}
void Beeper::wait()
{
int size;
do {
SDL_Delay(20);
SDL_LockAudio();
size = beeps.size();
SDL_UnlockAudio();
} while (size > 0);
}
void audio_callback(void *_beeper, Uint8 *_stream, int _length)
{
Sint16 *stream = (Sint16*) _stream;
int length = _length / 2;
Beeper* beeper = (Beeper*) _beeper;
beeper->generateSamples(stream, length);
}
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_AUDIO);
int duration = 1000;
double Hz = 440;
Beeper b;
b.beep(Hz, duration);
b.wait();
return 0;
}
Good luck.
A boiled-down variant of the beeper-example, reduced to the bare minimum (with error-handling).
#include <math.h>
#include <SDL.h>
#include <SDL_audio.h>
const int AMPLITUDE = 28000;
const int SAMPLE_RATE = 44100;
void audio_callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
Sint16 *buffer = (Sint16*)raw_buffer;
int length = bytes / 2; // 2 bytes per sample for AUDIO_S16SYS
int &sample_nr(*(int*)user_data);
for(int i = 0; i < length; i++, sample_nr++)
{
double time = (double)sample_nr / (double)SAMPLE_RATE;
buffer[i] = (Sint16)(AMPLITUDE * sin(2.0f * M_PI * 441.0f * time)); // render 441 HZ sine wave
}
}
int main(int argc, char *argv[])
{
if(SDL_Init(SDL_INIT_AUDIO) != 0) SDL_Log("Failed to initialize SDL: %s", SDL_GetError());
int sample_nr = 0;
SDL_AudioSpec want;
want.freq = SAMPLE_RATE; // number of samples per second
want.format = AUDIO_S16SYS; // sample type (here: signed short i.e. 16 bit)
want.channels = 1; // only one channel
want.samples = 2048; // buffer-size
want.callback = audio_callback; // function SDL calls periodically to refill the buffer
want.userdata = &sample_nr; // counter, keeping track of current sample number
SDL_AudioSpec have;
if(SDL_OpenAudio(&want, &have) != 0) SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Failed to open audio: %s", SDL_GetError());
if(want.format != have.format) SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Failed to get the desired AudioSpec");
SDL_PauseAudio(0); // start playing sound
SDL_Delay(1000); // wait while sound is playing
SDL_PauseAudio(1); // stop playing sound
SDL_CloseAudio();
return 0;
}
SDL 2 C example
The following code produces a sinusoidal sound, it is adapted from: https://codereview.stackexchange.com/questions/41086/play-some-sine-waves-with-sdl2
main.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <SDL2/SDL.h>
const double ChromaticRatio = 1.059463094359295264562;
const double Tao = 6.283185307179586476925;
Uint32 sampleRate = 48000;
Uint32 frameRate = 60;
Uint32 floatStreamLength = 1024;
Uint32 samplesPerFrame;
Uint32 msPerFrame;
double practicallySilent = 0.001;
Uint32 audioBufferLength = 48000;
float *audioBuffer;
SDL_atomic_t audioCallbackLeftOff;
Sint32 audioMainLeftOff;
Uint8 audioMainAccumulator;
SDL_AudioDeviceID AudioDevice;
SDL_AudioSpec audioSpec;
SDL_Event event;
SDL_bool running = SDL_TRUE;
typedef struct {
float *waveform;
Uint32 waveformLength;
double volume;
double pan;
double frequency;
double phase;
} voice;
void speak(voice *v) {
float sample;
Uint32 sourceIndex;
double phaseIncrement = v->frequency/sampleRate;
Uint32 i;
if (v->volume > practicallySilent) {
for (i = 0; (i + 1) < samplesPerFrame; i += 2) {
v->phase += phaseIncrement;
if (v->phase > 1)
v->phase -= 1;
sourceIndex = v->phase*v->waveformLength;
sample = v->waveform[sourceIndex]*v->volume;
audioBuffer[audioMainLeftOff+i] += sample*(1-v->pan);
audioBuffer[audioMainLeftOff+i+1] += sample*v->pan;
}
}
else {
for (i=0; i<samplesPerFrame; i+=1)
audioBuffer[audioMainLeftOff+i] = 0;
}
audioMainAccumulator++;
}
double getFrequency(double pitch) {
return pow(ChromaticRatio, pitch-57)*440;
}
int getWaveformLength(double pitch) {
return sampleRate / getFrequency(pitch)+0.5f;
}
void buildSineWave(float *data, Uint32 length) {
Uint32 i;
for (i=0; i < length; i++)
data[i] = sin(i*(Tao/length));
}
void logSpec(SDL_AudioSpec *as) {
printf(
" freq______%5d\n"
" format____%5d\n"
" channels__%5d\n"
" silence___%5d\n"
" samples___%5d\n"
" size______%5d\n\n",
(int) as->freq,
(int) as->format,
(int) as->channels,
(int) as->silence,
(int) as->samples,
(int) as->size
);
}
void logVoice(voice *v) {
printf(
" waveformLength__%d\n"
" volume__________%f\n"
" pan_____________%f\n"
" frequency_______%f\n"
" phase___________%f\n",
v->waveformLength,
v->volume,
v->pan,
v->frequency,
v->phase
);
}
void logWavedata(float *floatStream, Uint32 floatStreamLength, Uint32 increment) {
printf("\n\nwaveform data:\n\n");
Uint32 i=0;
for (i = 0; i < floatStreamLength; i += increment)
printf("%4d:%2.16f\n", i, floatStream[i]);
printf("\n\n");
}
void audioCallback(void *unused, Uint8 *byteStream, int byteStreamLength) {
float* floatStream = (float*) byteStream;
Sint32 localAudioCallbackLeftOff = SDL_AtomicGet(&audioCallbackLeftOff);
Uint32 i;
for (i = 0; i < floatStreamLength; i++) {
floatStream[i] = audioBuffer[localAudioCallbackLeftOff];
localAudioCallbackLeftOff++;
if (localAudioCallbackLeftOff == audioBufferLength)
localAudioCallbackLeftOff = 0;
}
SDL_AtomicSet(&audioCallbackLeftOff, localAudioCallbackLeftOff);
}
int init(void) {
SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER);
SDL_AudioSpec want;
SDL_zero(want);
want.freq = sampleRate;
want.format = AUDIO_F32;
want.channels = 2;
want.samples = floatStreamLength;
want.callback = audioCallback;
AudioDevice = SDL_OpenAudioDevice(NULL, 0, &want, &audioSpec, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
if (AudioDevice == 0) {
printf("\nFailed to open audio: %s\n", SDL_GetError());
return 1;
}
printf("want:\n");
logSpec(&want);
printf("audioSpec:\n");
logSpec(&audioSpec);
if (audioSpec.format != want.format) {
printf("\nCouldn't get Float32 audio format.\n");
return 2;
}
sampleRate = audioSpec.freq;
floatStreamLength = audioSpec.size / 4;
samplesPerFrame = sampleRate / frameRate;
msPerFrame = 1000 / frameRate;
audioMainLeftOff = samplesPerFrame * 8;
SDL_AtomicSet(&audioCallbackLeftOff, 0);
if (audioBufferLength % samplesPerFrame)
audioBufferLength += samplesPerFrame - (audioBufferLength % samplesPerFrame);
audioBuffer = malloc(sizeof(float) * audioBufferLength);
return 0;
}
int onExit(void) {
SDL_CloseAudioDevice(AudioDevice);
SDL_Quit();
return 0;
}
int main(int argc, char *argv[]) {
float syncCompensationFactor = 0.0016;
Sint32 mainAudioLead;
Uint32 i;
voice testVoiceA;
voice testVoiceB;
voice testVoiceC;
testVoiceA.volume = 1;
testVoiceB.volume = 1;
testVoiceC.volume = 1;
testVoiceA.pan = 0.5;
testVoiceB.pan = 0;
testVoiceC.pan = 1;
testVoiceA.phase = 0;
testVoiceB.phase = 0;
testVoiceC.phase = 0;
testVoiceA.frequency = getFrequency(45);
testVoiceB.frequency = getFrequency(49);
testVoiceC.frequency = getFrequency(52);
Uint16 C0waveformLength = getWaveformLength(0);
testVoiceA.waveformLength = C0waveformLength;
testVoiceB.waveformLength = C0waveformLength;
testVoiceC.waveformLength = C0waveformLength;
float sineWave[C0waveformLength];
buildSineWave(sineWave, C0waveformLength);
testVoiceA.waveform = sineWave;
testVoiceB.waveform = sineWave;
testVoiceC.waveform = sineWave;
if (init())
return 1;
SDL_Delay(42);
SDL_PauseAudioDevice(AudioDevice, 0);
while (running) {
while (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_QUIT) {
running = SDL_FALSE;
}
}
for (i = 0; i < samplesPerFrame; i++)
audioBuffer[audioMainLeftOff+i] = 0;
speak(&testVoiceA);
speak(&testVoiceB);
speak(&testVoiceC);
if (audioMainAccumulator > 1) {
for (i=0; i<samplesPerFrame; i++) {
audioBuffer[audioMainLeftOff+i] /= audioMainAccumulator;
}
}
audioMainAccumulator = 0;
audioMainLeftOff += samplesPerFrame;
if (audioMainLeftOff == audioBufferLength)
audioMainLeftOff = 0;
mainAudioLead = audioMainLeftOff - SDL_AtomicGet(&audioCallbackLeftOff);
if (mainAudioLead < 0)
mainAudioLead += audioBufferLength;
if (mainAudioLead < floatStreamLength)
printf("An audio collision may have occured!\n");
SDL_Delay(mainAudioLead * syncCompensationFactor);
}
onExit();
return 0;
}
Compile and run:
gcc -ggdb3 -O3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c -lSDL2 -lm
./main.out
Should be easy to turn this into a simple piano with: https://github.com/cirosantilli/cpp-cheat/blob/f734a2e76fbcfc67f707ae06be7a2a2ef5db47d1/c/interactive/audio_gen.c#L44
For wav manipulation, also check the official examples:
http://hg.libsdl.org/SDL/file/e12c38730512/test/testresample.c
http://hg.libsdl.org/SDL/file/e12c38730512/test/loopwave.c
Tested on Ubuntu 19.10, SDL 2.0.10.
This is a minimal example of how to play a sine wave in SDL2.
Make sure to call SDL_Init(SDL_INIT_AUDIO) before creating an instance of Sound.
Sound.h
#include <cstdint>
#include <SDL2/SDL.h>
class Sound
{
public:
Sound();
~Sound();
void play();
void stop();
const double m_sineFreq;
const double m_sampleFreq;
const double m_samplesPerSine;
uint32_t m_samplePos;
private:
static void SDLAudioCallback(void *data, Uint8 *buffer, int length);
SDL_AudioDeviceID m_device;
};
Sound.cpp
#include "Sound.h"
#include <cmath>
#include <iostream>
Sound::Sound()
: m_sineFreq(1000),
m_sampleFreq(44100),
m_samplesPerSine(m_sampleFreq / m_sineFreq),
m_samplePos(0)
{
SDL_AudioSpec wantSpec, haveSpec;
SDL_zero(wantSpec);
wantSpec.freq = m_sampleFreq;
wantSpec.format = AUDIO_U8;
wantSpec.channels = 1;
wantSpec.samples = 2048;
wantSpec.callback = SDLAudioCallback;
wantSpec.userdata = this;
m_device = SDL_OpenAudioDevice(NULL, 0, &wantSpec, &haveSpec, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
if (m_device == 0)
{
std::cout << "Failed to open audio: " << SDL_GetError() << std::endl;
}
}
Sound::~Sound()
{
SDL_CloseAudioDevice(m_device);
}
void Sound::play()
{
SDL_PauseAudioDevice(m_device, 0);
}
void Sound::stop()
{
SDL_PauseAudioDevice(m_device, 1);
}
void Sound::SDLAudioCallback(void *data, Uint8 *buffer, int length)
{
Sound *sound = reinterpret_cast<Sound*>(data);
for(int i = 0; i < length; ++i)
{
buffer[i] = (std::sin(sound->m_samplePos / sound->m_samplesPerSine * M_PI * 2) + 1) * 127.5;
++sound->m_samplePos;
}
}

FMOD - Unhandled Exception with no source code avaiable

I'm trying to get my audio track to play using FMOD but I keep getting an unhandled exception and then it says there's no source code available, and shows me disassembly code.
main.cpp
bool AudioProject::initAudio()
{
// Audio code
fmSound = new Sound();
fmSound->initialise();
fmSound->load("Music/Rocky_Theme_Tune.mp3");
fmSound->play();
return true;
}
I put break points in the see where it stopped, which was in the initialise function. It even goes into the initialise function and then just randomly breaks. I think I have every include file for fmod as I used it last year no problem.
I'll post my sound.h/.cpp files too.
.h
#include "stdafx.h"
#pragma once
#include "fmod.hpp"
#include "fmod.h"
class Sound
{
private:
bool on; //is sound on?
bool possible; //is it possible to play sound?
char * currentSound; //currently played sound
//FMOD-specific stuff
FMOD_RESULT result;
FMOD_SYSTEM * fmodsystem;
FMOD_SOUND * sound;
FMOD_CHANNEL * channel;
public:
Sound();
~Sound();
void initialise (void);
void setVolume (float v);
void load (const char * filename);
void unload (void);
void play (bool pause = false);
bool getSound (void);
void setPause (bool pause);
void setSound (bool sound);
void toggleSound (void);
void togglePause (void);
};
.cpp
#include "stdafx.h"
#include "Sound.h"
#include "fmod.h"
#include "fmod.hpp"
Sound::Sound()
{
on = true; //is sound on?
possible = true; //is it possible to play sound?
currentSound=""; //currently played sound
sound=0;
}
Sound::~Sound()
{
}
//initialises sound
void Sound::initialise (void)
{
//create the sound system. If fails, sound is set to impossible
result = FMOD_System_Create(&fmodsystem);
if (result != FMOD_OK)
possible = false;
//if initialise the sound system. If fails, sound is set to impossible
if (possible)
result = FMOD_System_Init(fmodsystem,2, FMOD_INIT_NORMAL, 0);
if (result != FMOD_OK)
possible = false;
//sets initial sound volume (mute)
if (possible)
FMOD_Channel_SetVolume(channel,1.0f);
}
//sets the actual playing sound's volume
void Sound::setVolume (float v)
{
if (possible && on && v >= 0.0f && v <= 1.0f)
{
FMOD_Channel_SetVolume(channel,v);
}
}
//loads a soundfile
void Sound::load (const char * filename)
{
currentSound = (char *)filename;
if (possible && on)
{
result = FMOD_Sound_Release(sound);
result = FMOD_System_CreateStream(fmodsystem,currentSound, FMOD_SOFTWARE, 0, &sound);
if (result != FMOD_OK)
possible = false;
}
}
//frees the sound object
void Sound::unload (void)
{
if (possible)
{
result = FMOD_Sound_Release(sound);
}
}
//plays a sound (no argument to leave pause as dafault)
void Sound::play (bool pause)
{
if (possible && on)
{
result = FMOD_System_PlaySound(fmodsystem,FMOD_CHANNEL_FREE, sound, pause, &channel);
FMOD_Channel_SetMode(channel,FMOD_LOOP_NORMAL);
}
}
//toggles sound on and off
void Sound::toggleSound (void)
{
on = !on;
if (on == true)
{
load(currentSound);
play();
}
if (on == false)
{
unload();
}
}
//pause or unpause the sound
void Sound::setPause (bool pause)
{
FMOD_Channel_SetPaused (channel, pause);
}
//turn sound on or off
void Sound::setSound (bool s)
{
on = s;
}
//toggle pause on and off
void Sound::togglePause (void)
{
FMOD_BOOL p;
FMOD_Channel_GetPaused(channel,&p);
FMOD_Channel_SetPaused (channel,!p);
}
//tells whether the sound is on or off
bool Sound::getSound (void)
{
return on;
}
Hit a brick wall here, anyone have any ideas?
You are calling FMOD_Channel_SetVolume(channel,1.0f) in initialise, but the channel variable isn't hasn't been initialized yet, it gets initialized by the FMOD_System_PlaySound(fmodsystem,FMOD_CHANNEL_FREE, sound, pause, &channel); in Sound::play