Hi, I was working recently on a project that required me to play variations of the same audio sample multiple times in rapid succession. I have set up a Player class that will handle this for me.
My ApproachMy player class creates a single sf::SoundBuffer representing the source sample. It then stores a queue for various sf::Sound objects that all use the same base sound buffer. They all have pitches changes and volume adjustments applied and are pushed on the queue and played from the queue. Before each play call, the player automatically pops all stopped sounds from the queue to save memory.
The ErrorsIn doing this I have come across a couple strange OpenAL errors. Error Batch 1 happened at runtime and Error Batch 2 happened when the program was closing. (I am assuming they are caused be something gone awry in the destructor). All of them seem to refer to invalid referencing or deleting of audio resources, but I am not sure.
Error Batch 1:
An internal OpenAL call failed in SoundSource.cpp(45).
Expression:
alGenSources(1, &m_source)
Error description:
AL_INVALID_VALUE
A numeric argument is out of range.
An internal OpenAL call failed in SoundSource.cpp(46).
Expression:
alSourcei(m_source, AL_BUFFER, 0)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in SoundSource.cpp(68).
Expression:
alSourcef(m_source, AL_PITCH, pitch)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in SoundSource.cpp(75).
Expression:
alSourcef(m_source, AL_GAIN, volume * 0.01f)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in SoundSource.cpp(82).
Expression:
alSource3f(m_source, AL_POSITION, x, y, z)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in SoundSource.cpp(96).
Expression:
alSourcei(m_source, AL_SOURCE_RELATIVE, relative)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in SoundSource.cpp(103).
Expression:
alSourcef(m_source, AL_REFERENCE_DISTANCE, distance)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in SoundSource.cpp(110).
Expression:
alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in Sound.cpp(104).
Expression:
alSourcei(m_source, AL_BUFFER, m_buffer->m_buffer)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in Sound.cpp(111).
Expression:
alSourcei(m_source, AL_LOOPING, loop)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in Sound.cpp(73).
Expression:
alSourcePlay(m_source)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
Error Batch 2:
An internal OpenAL call failed in SoundSource.cpp(60).
Expression:
alSourcei(m_source, AL_BUFFER, 0)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in SoundSource.cpp(61).
Expression:
alDeleteSources(1, &m_source)
Error description:
AL_INVALID_OPERATION
The specified operation is not allowed in the current state.
An internal OpenAL call failed in Sound.cpp(87).
Expression:
alSourceStop(m_source)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
An internal OpenAL call failed in Sound.cpp(87).
Expression:
alSourceStop(m_source)
Error description:
AL_INVALID_NAME
A bad name (ID) has been specified.
My CodeBelow is the full implementation of my player class. There is nothing more to it.
Player.h:
#pragma once
#include <SFML/Audio.hpp>
#include <queue>
class Player {
sf::SoundBuffer m_Sample;
std::queue<sf::Sound> m_Sounds;
int m_Max;
float convertToPitch(int);
public:
Player(int);
~Player();
void playValue(int);
};
Player.cpp:
#include "player.h"
Player::Player(int max)
: m_Max(max + 1)
{
m_Sample.loadFromFile("data/sample.wav");
}
Player::~Player() {
while (m_Sounds.size() > 0) {
m_Sounds.front().stop();
m_Sounds.pop();
}
}
float Player::convertToPitch(int value) {
return 2.0 * (value / (float)m_Max) + 0.01;
}
void Player::playValue(int value) {
while (m_Sounds.size() > 0 && m_Sounds.front().getStatus() == sf::Sound::Stopped)
m_Sounds.pop();
float pitch = convertToPitch(value);
sf::Sound sound;
sound.setBuffer(m_Sample);
sound.setPitch(pitch);
sound.setVolume(20);
m_Sounds.push(sound);
m_Sounds.back().play();
}
Please get back to me as soon as possible and don't hesitate to let me know of anything else you need to see.
Thanks again!