audio: channels

This commit is contained in:
MihailRis
2024-03-04 02:35:22 +03:00
parent 5657457edb
commit 75ee269db3
8 changed files with 259 additions and 73 deletions
+8 -6
View File
@@ -162,7 +162,7 @@ bool assetload::sound(
std::shared_ptr<AssetCfg> config std::shared_ptr<AssetCfg> config
) { ) {
auto cfg = dynamic_cast<SoundCfg*>(config.get()); auto cfg = dynamic_cast<SoundCfg*>(config.get());
auto sound = audio::loadSound(paths->find(file), cfg->keepPCM); auto sound = audio::load_sound(paths->find(file), cfg->keepPCM);
if (sound == nullptr) { if (sound == nullptr) {
std::cerr << "failed to load sound '" << name << "' from '"; std::cerr << "failed to load sound '" << name << "' from '";
std::cerr << file << "'" << std::endl; std::cerr << file << "'" << std::endl;
@@ -172,11 +172,13 @@ bool assetload::sound(
return true; return true;
} }
bool assetload::animation(Assets* assets, bool assetload::animation(
const ResPaths* paths, Assets* assets,
const std::string directory, const ResPaths* paths,
const std::string name, const std::string directory,
Atlas* dstAtlas) { const std::string name,
Atlas* dstAtlas
) {
std::string animsDir = directory + "/animations"; std::string animsDir = directory + "/animations";
std::string blocksDir = directory + "/blocks"; std::string blocksDir = directory + "/blocks";
+29 -13
View File
@@ -19,13 +19,13 @@ ALSound::~ALSound() {
buffer = 0; buffer = 0;
} }
Speaker* ALSound::newInstance(int priority) const { Speaker* ALSound::newInstance(int priority, int channel) const {
uint source = al->getFreeSource(); uint source = al->getFreeSource();
if (source == 0) { if (source == 0) {
return nullptr; return nullptr;
} }
AL_CHECK(alSourcei(source, AL_BUFFER, buffer)); AL_CHECK(alSourcei(source, AL_BUFFER, buffer));
return new ALSpeaker(al, source, priority); return new ALSpeaker(al, source, priority, channel);
} }
ALStream::ALStream(ALAudio* al, std::shared_ptr<PCMStream> source, bool keepSource) ALStream::ALStream(ALAudio* al, std::shared_ptr<PCMStream> source, bool keepSource)
@@ -54,7 +54,7 @@ bool ALStream::preloadBuffer(uint buffer, bool loop) {
return true; return true;
} }
Speaker* ALStream::createSpeaker(bool loop) { Speaker* ALStream::createSpeaker(bool loop, int channel) {
this->loop = loop; this->loop = loop;
uint source = al->getFreeSource(); uint source = al->getFreeSource();
if (source == 0) { if (source == 0) {
@@ -67,7 +67,7 @@ Speaker* ALStream::createSpeaker(bool loop) {
} }
AL_CHECK(alSourceQueueBuffers(source, 1, &buffer)); AL_CHECK(alSourceQueueBuffers(source, 1, &buffer));
} }
return new ALSpeaker(al, source, PRIORITY_HIGH); return new ALSpeaker(al, source, PRIORITY_HIGH, channel);
} }
@@ -111,7 +111,7 @@ void ALStream::update(double delta) {
AL_CHECK(alSourceQueueBuffers(source, 1, &buffer)); AL_CHECK(alSourceQueueBuffers(source, 1, &buffer));
} }
} }
if (speaker->isStopped() && !speaker->isStoppedManually()) { if (speaker->isStopped() && !alspeaker->stopped) {
if (preloaded) { if (preloaded) {
speaker->play(); speaker->play();
} else { } else {
@@ -124,7 +124,8 @@ void ALStream::setTime(duration_t time) {
// TODO: implement // TODO: implement
} }
ALSpeaker::ALSpeaker(ALAudio* al, uint source, int priority) : al(al), priority(priority), source(source) { ALSpeaker::ALSpeaker(ALAudio* al, uint source, int priority, int channel)
: al(al), priority(priority), channel(channel), source(source) {
} }
ALSpeaker::~ALSpeaker() { ALSpeaker::~ALSpeaker() {
@@ -133,6 +134,23 @@ ALSpeaker::~ALSpeaker() {
} }
} }
void ALSpeaker::update(const Channel* channel, float masterVolume) {
float gain = this->volume * channel->getVolume()*masterVolume;
AL_CHECK(alSourcef(source, AL_GAIN, gain));
if (!paused) {
if (isPaused() && !channel->isPaused()) {
play();
} else if (isPlaying() && channel->isPaused()) {
AL_CHECK(alSourcePause(source));
}
}
}
int ALSpeaker::getChannel() const {
return channel;
}
State ALSpeaker::getState() const { State ALSpeaker::getState() const {
int state = AL::getSourcei(source, AL_SOURCE_STATE, AL_STOPPED); int state = AL::getSourcei(source, AL_SOURCE_STATE, AL_STOPPED);
switch (state) { switch (state) {
@@ -147,7 +165,7 @@ float ALSpeaker::getVolume() const {
} }
void ALSpeaker::setVolume(float volume) { void ALSpeaker::setVolume(float volume) {
AL_CHECK(alSourcef(source, AL_GAIN, volume)); this->volume = volume;
} }
float ALSpeaker::getPitch() const { float ALSpeaker::getPitch() const {
@@ -167,16 +185,18 @@ void ALSpeaker::setLoop(bool loop) {
} }
void ALSpeaker::play() { void ALSpeaker::play() {
stoppedManually = false; paused = false;
stopped = false;
AL_CHECK(alSourcePlay(source)); AL_CHECK(alSourcePlay(source));
} }
void ALSpeaker::pause() { void ALSpeaker::pause() {
paused = true;
AL_CHECK(alSourcePause(source)); AL_CHECK(alSourcePause(source));
} }
void ALSpeaker::stop() { void ALSpeaker::stop() {
stoppedManually = true; stopped = true;
if (source) { if (source) {
AL_CHECK(alSourceStop(source)); AL_CHECK(alSourceStop(source));
al->freeSource(source); al->freeSource(source);
@@ -184,10 +204,6 @@ void ALSpeaker::stop() {
} }
} }
bool ALSpeaker::isStoppedManually() const {
return stoppedManually;
}
duration_t ALSpeaker::getTime() const { duration_t ALSpeaker::getTime() const {
return static_cast<duration_t>(AL::getSourcef(source, AL_SEC_OFFSET)); return static_cast<duration_t>(AL::getSourcef(source, AL_SEC_OFFSET));
} }
+10 -5
View File
@@ -40,7 +40,7 @@ namespace audio {
return pcm; return pcm;
} }
Speaker* newInstance(int priority) const override; Speaker* newInstance(int priority, int channel) const override;
}; };
class ALStream : public Stream { class ALStream : public Stream {
@@ -61,7 +61,7 @@ namespace audio {
std::shared_ptr<PCMStream> getSource() const override; std::shared_ptr<PCMStream> getSource() const override;
void bindSpeaker(speakerid_t speaker) override; void bindSpeaker(speakerid_t speaker) override;
Speaker* createSpeaker(bool loop) override; Speaker* createSpeaker(bool loop, int channel) override;
speakerid_t getSpeaker() const override; speakerid_t getSpeaker() const override;
void update(double delta) override; void update(double delta) override;
void setTime(duration_t time) override; void setTime(duration_t time) override;
@@ -73,13 +73,19 @@ namespace audio {
class ALSpeaker : public Speaker { class ALSpeaker : public Speaker {
ALAudio* al; ALAudio* al;
int priority; int priority;
bool stoppedManually = false; int channel;
float volume = 0.0f;
public: public:
bool stopped = true;
bool paused = false;
uint source; uint source;
ALSpeaker(ALAudio* al, uint source, int priority); ALSpeaker(ALAudio* al, uint source, int priority, int channel);
~ALSpeaker(); ~ALSpeaker();
void update(const Channel* channel, float masterVolume) override;
int getChannel() const override;
State getState() const override; State getState() const override;
float getVolume() const override; float getVolume() const override;
@@ -94,7 +100,6 @@ namespace audio {
void play() override; void play() override;
void pause() override; void pause() override;
void stop() override; void stop() override;
bool isStoppedManually() const override;
duration_t getTime() const override; duration_t getTime() const override;
void setTime(duration_t time) override; void setTime(duration_t time) override;
+2 -2
View File
@@ -19,7 +19,7 @@ namespace audio {
return pcm; return pcm;
} }
Speaker* newInstance(int priority) const override { Speaker* newInstance(int priority, int channel) const override {
return nullptr; return nullptr;
} }
}; };
@@ -42,7 +42,7 @@ namespace audio {
void bindSpeaker(speakerid_t speaker) override { void bindSpeaker(speakerid_t speaker) override {
} }
Speaker* createSpeaker(bool loop) override{ Speaker* createSpeaker(bool loop, int channel) override{
return nullptr; return nullptr;
} }
+118 -26
View File
@@ -14,20 +14,50 @@ namespace audio {
static Backend* backend; static Backend* backend;
static std::unordered_map<speakerid_t, std::unique_ptr<Speaker>> speakers; static std::unordered_map<speakerid_t, std::unique_ptr<Speaker>> speakers;
static std::unordered_map<speakerid_t, std::shared_ptr<Stream>> streams; static std::unordered_map<speakerid_t, std::shared_ptr<Stream>> streams;
static std::vector<std::unique_ptr<Channel>> channels;
} }
using namespace audio; using namespace audio;
Channel::Channel(std::string name) : name(name) {
}
float Channel::getVolume() const {
return volume;
}
void Channel::setVolume(float volume) {
this->volume = std::max(0.0f, std::min(volume, 1.0f));
}
const std::string& Channel::getName() const {
return name;
}
// see pause logic in audio::update
void Channel::pause() {
paused = true;
}
// see pause logic in audio::update
void Channel::resume() {
paused = false;
}
bool Channel::isPaused() const {
return paused;
}
size_t PCMStream::readFully(char* buffer, size_t bufferSize, bool loop) { size_t PCMStream::readFully(char* buffer, size_t bufferSize, bool loop) {
if (!isOpen()) { if (!isOpen()) {
return 0; return 0;
} }
long bytes = 0;
size_t size = 0; size_t size = 0;
do { do {
size_t bytes = 0;
do { do {
bytes = read(buffer, bufferSize); bytes = read(buffer, bufferSize);
if (bytes < 0) { if (bytes == PCMStream::ERROR) {
return size; return size;
} }
size += bytes; size += bytes;
@@ -126,9 +156,14 @@ void audio::initialize(bool enabled) {
std::cerr << "could not to initialize audio" << std::endl; std::cerr << "could not to initialize audio" << std::endl;
backend = NoAudio::create(); backend = NoAudio::create();
} }
create_channel("master");
create_channel("regular");
create_channel("music");
create_channel("ambient");
create_channel("ui");
} }
PCM* audio::loadPCM(const fs::path& file, bool headerOnly) { PCM* audio::load_PCM(const fs::path& file, bool headerOnly) {
if (!fs::exists(file)) { if (!fs::exists(file)) {
throw std::runtime_error("file not found '"+file.u8string()+"'"); throw std::runtime_error("file not found '"+file.u8string()+"'");
} }
@@ -141,16 +176,16 @@ PCM* audio::loadPCM(const fs::path& file, bool headerOnly) {
throw std::runtime_error("unsupported audio format"); throw std::runtime_error("unsupported audio format");
} }
Sound* audio::loadSound(const fs::path& file, bool keepPCM) { Sound* audio::load_sound(const fs::path& file, bool keepPCM) {
std::shared_ptr<PCM> pcm(loadPCM(file, !keepPCM && backend->isDummy())); std::shared_ptr<PCM> pcm(load_PCM(file, !keepPCM && backend->isDummy()));
return createSound(pcm, keepPCM); return create_sound(pcm, keepPCM);
} }
Sound* audio::createSound(std::shared_ptr<PCM> pcm, bool keepPCM) { Sound* audio::create_sound(std::shared_ptr<PCM> pcm, bool keepPCM) {
return backend->createSound(pcm, keepPCM); return backend->createSound(pcm, keepPCM);
} }
PCMStream* audio::openPCMStream(const fs::path& file) { PCMStream* audio::open_PCM_stream(const fs::path& file) {
std::string ext = file.extension().u8string(); std::string ext = file.extension().u8string();
if (ext == ".wav" || ext == ".WAV") { if (ext == ".wav" || ext == ".WAV") {
return wav::create_stream(file); return wav::create_stream(file);
@@ -160,27 +195,27 @@ PCMStream* audio::openPCMStream(const fs::path& file) {
throw std::runtime_error("unsupported audio stream format"); throw std::runtime_error("unsupported audio stream format");
} }
Stream* audio::openStream(const fs::path& file, bool keepSource) { Stream* audio::open_stream(const fs::path& file, bool keepSource) {
if (!keepSource && backend->isDummy()) { if (!keepSource && backend->isDummy()) {
auto header = loadPCM(file, true); auto header = load_PCM(file, true);
// using void source sized as audio instead of actual audio file // using void source sized as audio instead of actual audio file
return openStream( return open_stream(
std::make_shared<PCMVoidSource>(header->totalSamples, header->sampleRate, header->seekable), std::make_shared<PCMVoidSource>(header->totalSamples, header->sampleRate, header->seekable),
keepSource keepSource
); );
} }
return openStream( return open_stream(
std::shared_ptr<PCMStream>(openPCMStream(file)), std::shared_ptr<PCMStream>(open_PCM_stream(file)),
keepSource keepSource
); );
} }
Stream* audio::openStream(std::shared_ptr<PCMStream> stream, bool keepSource) { Stream* audio::open_stream(std::shared_ptr<PCMStream> stream, bool keepSource) {
return backend->openStream(stream, keepSource); return backend->openStream(stream, keepSource);
} }
void audio::setListener( void audio::set_listener(
glm::vec3 position, glm::vec3 position,
glm::vec3 velocity, glm::vec3 velocity,
glm::vec3 lookAt, glm::vec3 lookAt,
@@ -215,12 +250,13 @@ speakerid_t audio::play(
float volume, float volume,
float pitch, float pitch,
bool loop, bool loop,
int priority int priority,
int channel
) { ) {
Speaker* speaker = sound->newInstance(priority); Speaker* speaker = sound->newInstance(priority, channel);
if (speaker == nullptr) { if (speaker == nullptr) {
remove_lower_priority_speaker(priority); remove_lower_priority_speaker(priority);
speaker = sound->newInstance(priority); speaker = sound->newInstance(priority, channel);
} }
if (speaker == nullptr) { if (speaker == nullptr) {
return 0; return 0;
@@ -242,12 +278,13 @@ speakerid_t audio::play(
bool relative, bool relative,
float volume, float volume,
float pitch, float pitch,
bool loop bool loop,
int channel
) { ) {
Speaker* speaker = stream->createSpeaker(loop); Speaker* speaker = stream->createSpeaker(loop, channel);
if (speaker == nullptr) { if (speaker == nullptr) {
remove_lower_priority_speaker(PRIORITY_HIGH); remove_lower_priority_speaker(PRIORITY_HIGH);
speaker = stream->createSpeaker(loop); speaker = stream->createSpeaker(loop, channel);
} }
if (speaker == nullptr) { if (speaker == nullptr) {
return 0; return 0;
@@ -266,16 +303,17 @@ speakerid_t audio::play(
return id; return id;
} }
speakerid_t audio::playStream( speakerid_t audio::play_stream(
const fs::path& file, const fs::path& file,
glm::vec3 position, glm::vec3 position,
bool relative, bool relative,
float volume, float volume,
float pitch, float pitch,
bool loop bool loop,
int channel
) { ) {
std::shared_ptr<Stream> stream (openStream(file, false)); std::shared_ptr<Stream> stream (open_stream(file, false));
return play(stream, position, relative, volume, pitch, loop); return play(stream, position, relative, volume, pitch, loop, channel);
} }
Speaker* audio::get(speakerid_t id) { Speaker* audio::get(speakerid_t id) {
@@ -286,6 +324,37 @@ Speaker* audio::get(speakerid_t id) {
return found->second.get(); return found->second.get();
} }
int audio::create_channel(const std::string& name) {
int index = get_channel_index(name);
if (index != -1) {
return index;
}
channels.emplace_back(new Channel(name));
return channels.size()-1;
}
int audio::get_channel_index(const std::string& name) {
int index = 0;
for (auto& channel : channels) {
if (channel->getName() == name) {
return index;
}
index++;
}
return -1;
}
Channel* audio::get_channel(int index) {
if (index < 0 || index >= int(channels.size())) {
return nullptr;
}
return channels.at(index).get();
}
float audio::get_master_volume() {
return channels.at(0)->getVolume();
}
void audio::update(double delta) { void audio::update(double delta) {
backend->update(delta); backend->update(delta);
@@ -293,8 +362,15 @@ void audio::update(double delta) {
entry.second->update(delta); entry.second->update(delta);
} }
float masterVolume = get_master_volume();
for (auto it = speakers.begin(); it != speakers.end();) { for (auto it = speakers.begin(); it != speakers.end();) {
if (it->second->isStoppedManually()) { auto speaker = it->second.get();
int speakerChannel = speaker->getChannel();
auto channel = get_channel(speakerChannel);
if (channel != nullptr) {
speaker->update(channel, speakerChannel == 0 ? 1.0f : masterVolume);
}
if (speaker->isStopped()) {
streams.erase(it->first); streams.erase(it->first);
it = speakers.erase(it); it = speakers.erase(it);
} else { } else {
@@ -303,6 +379,22 @@ void audio::update(double delta) {
} }
} }
void audio::reset() {
for (auto& entry : speakers) {
entry.second->stop();
}
for (auto& entry : streams) {
entry.second->update(0.0f);
}
for (auto& channel : channels) {
if (channel->isPaused()) {
channel->resume();
}
}
streams.clear();
speakers.clear();
}
void audio::close() { void audio::close() {
speakers.clear(); speakers.clear();
delete backend; delete backend;
+89 -18
View File
@@ -34,6 +34,37 @@ namespace audio {
stopped stopped
}; };
/// @brief Mixer channel controls speakers volume and effects
/// There is main channel 'master' and sub-channels like 'regular', 'music', 'ambient'...
class Channel {
/// @brief Channel name
std::string name;
/// @brief Channel volume setting
float volume = 1.0f;
bool paused = false;
public:
Channel(std::string name);
/// @brief Get channel volume
float getVolume() const;
/// @brief Set channel volume
/// @param volume value in range [0.0, 1.0]
void setVolume(float volume);
/// @brief Get channel name
const std::string& getName() const;
/// @brief Pause all speakers in channel
void pause();
/// @brief Unpause all speakers paused by this channel
void resume();
/// @brief Check if the channel is paused
bool isPaused() const;
};
/// @brief Pulse-code modulation data /// @brief Pulse-code modulation data
struct PCM { struct PCM {
/// @brief May contain 8 bit and 16 bit PCM data /// @brief May contain 8 bit and 16 bit PCM data
@@ -64,6 +95,8 @@ namespace audio {
sampleRate(sampleRate), sampleRate(sampleRate),
seekable(seekable) {} seekable(seekable) {}
/// @brief Get total audio duration
/// @return duration in seconds
inline duration_t getDuration() const { inline duration_t getDuration() const {
return static_cast<duration_t>(totalSamples) / return static_cast<duration_t>(totalSamples) /
static_cast<duration_t>(sampleRate); static_cast<duration_t>(sampleRate);
@@ -115,6 +148,9 @@ namespace audio {
/// @brief Move playhead to the selected sample number /// @brief Move playhead to the selected sample number
/// @param position selected sample number /// @param position selected sample number
virtual void seek(size_t position) = 0; virtual void seek(size_t position) = 0;
/// @brief Value returning by read(...) in case of error
static const size_t ERROR = -1;
}; };
/// @brief Audio streaming interface /// @brief Audio streaming interface
@@ -130,8 +166,9 @@ namespace audio {
/// @brief Create new speaker bound to the Stream /// @brief Create new speaker bound to the Stream
/// and having high priority /// and having high priority
/// @param loop is stream looped (required for correct buffers preload) /// @param loop is stream looped (required for correct buffers preload)
/// @param channel channel index
/// @return speaker id or 0 /// @return speaker id or 0
virtual Speaker* createSpeaker(bool loop) = 0; virtual Speaker* createSpeaker(bool loop, int channel) = 0;
/// @brief Unbind previous speaker and bind new speaker to the stream /// @brief Unbind previous speaker and bind new speaker to the stream
/// @param speaker speaker id or 0 if all you need is unbind speaker /// @param speaker speaker id or 0 if all you need is unbind speaker
@@ -168,16 +205,26 @@ namespace audio {
/// @brief Create new sound instance /// @brief Create new sound instance
/// @param priority instance priority. High priority instance can /// @param priority instance priority. High priority instance can
/// take out speaker from low priority instance /// take out speaker from low priority instance
/// @param channel channel index
/// @return new speaker with sound bound or nullptr /// @return new speaker with sound bound or nullptr
/// if all speakers are in use /// if all speakers are in use
virtual Speaker* newInstance(int priority) const = 0; virtual Speaker* newInstance(int priority, int channel) const = 0;
}; };
/// @brief Audio source controller interface /// @brief Audio source controller interface.
/// @attention Speaker is not supposed to be reused
class Speaker { class Speaker {
public: public:
virtual ~Speaker() {} virtual ~Speaker() {}
/// @brief Synchronize the speaker with channel settings
/// @param channel speaker channel
/// @param masterVolume volume of the master channel
virtual void update(const Channel* channel, float masterVolume) = 0;
/// @brief Check speaker channel index
virtual int getChannel() const = 0;
/// @brief Get current speaker state /// @brief Get current speaker state
/// @return speaker state /// @return speaker state
virtual State getState() const = 0; virtual State getState() const = 0;
@@ -215,9 +262,6 @@ namespace audio {
/// @brief Stop and destroy speaker /// @brief Stop and destroy speaker
virtual void stop() = 0; virtual void stop() = 0;
/// @brief Check if the speaker has stopped by calling stop()
virtual bool isStoppedManually() const = 0;
/// @brief Get current time position of playing audio /// @brief Get current time position of playing audio
/// @return time position in seconds /// @return time position in seconds
virtual duration_t getTime() const = 0; virtual duration_t getTime() const = 0;
@@ -297,45 +341,45 @@ namespace audio {
/// @param headerOnly read header only /// @param headerOnly read header only
/// @throws std::runtime_error if I/O error ocurred or format is unknown /// @throws std::runtime_error if I/O error ocurred or format is unknown
/// @return PCM audio data /// @return PCM audio data
extern PCM* loadPCM(const fs::path& file, bool headerOnly); extern PCM* load_PCM(const fs::path& file, bool headerOnly);
/// @brief Load sound from file /// @brief Load sound from file
/// @param file audio file path /// @param file audio file path
/// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM /// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM
/// @throws std::runtime_error if I/O error ocurred or format is unknown /// @throws std::runtime_error if I/O error ocurred or format is unknown
/// @return new Sound instance /// @return new Sound instance
extern Sound* loadSound(const fs::path& file, bool keepPCM); extern Sound* load_sound(const fs::path& file, bool keepPCM);
/// @brief Create new sound from PCM data /// @brief Create new sound from PCM data
/// @param pcm PCM data /// @param pcm PCM data
/// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM /// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM
/// @return new Sound instance /// @return new Sound instance
extern Sound* createSound(std::shared_ptr<PCM> pcm, bool keepPCM); extern Sound* create_sound(std::shared_ptr<PCM> pcm, bool keepPCM);
/// @brief Open new PCM stream from file /// @brief Open new PCM stream from file
/// @param file audio file path /// @param file audio file path
/// @throws std::runtime_error if I/O error ocurred or format is unknown /// @throws std::runtime_error if I/O error ocurred or format is unknown
/// @return new PCMStream instance /// @return new PCMStream instance
extern PCMStream* openPCMStream(const fs::path& file); extern PCMStream* open_PCM_stream(const fs::path& file);
/// @brief Open new audio stream from file /// @brief Open new audio stream from file
/// @param file audio file path /// @param file audio file path
/// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource /// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource
/// @return new Stream instance /// @return new Stream instance
extern Stream* openStream(const fs::path& file, bool keepSource); extern Stream* open_stream(const fs::path& file, bool keepSource);
/// @brief Open new audio stream from source /// @brief Open new audio stream from source
/// @param stream PCM data source /// @param stream PCM data source
/// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource /// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource
/// @return new Stream instance /// @return new Stream instance
extern Stream* openStream(std::shared_ptr<PCMStream> stream, bool keepSource); extern Stream* open_stream(std::shared_ptr<PCMStream> stream, bool keepSource);
/// @brief Configure 3D listener /// @brief Configure 3D listener
/// @param position listener position /// @param position listener position
/// @param velocity listener velocity (used for Doppler effect) /// @param velocity listener velocity (used for Doppler effect)
/// @param lookAt point the listener look at /// @param lookAt point the listener look at
/// @param up camera up vector /// @param up camera up vector
extern void setListener( extern void set_listener(
glm::vec3 position, glm::vec3 position,
glm::vec3 velocity, glm::vec3 velocity,
glm::vec3 lookAt, glm::vec3 lookAt,
@@ -351,6 +395,7 @@ namespace audio {
/// @param loop loop sound /// @param loop loop sound
/// @param priority sound priority /// @param priority sound priority
/// (PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH) /// (PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH)
/// @param channel channel index
/// @return speaker id or 0 /// @return speaker id or 0
extern speakerid_t play( extern speakerid_t play(
Sound* sound, Sound* sound,
@@ -359,7 +404,8 @@ namespace audio {
float volume, float volume,
float pitch, float pitch,
bool loop, bool loop,
int priority int priority,
int channel
); );
/// @brief Play stream /// @brief Play stream
@@ -369,6 +415,7 @@ namespace audio {
/// @param volume stream volume [0.0-1.0] /// @param volume stream volume [0.0-1.0]
/// @param pitch stream pitch multiplier [0.0-...] /// @param pitch stream pitch multiplier [0.0-...]
/// @param loop loop stream /// @param loop loop stream
/// @param channel channel index
/// @return speaker id or 0 /// @return speaker id or 0
extern speakerid_t play( extern speakerid_t play(
std::shared_ptr<Stream> stream, std::shared_ptr<Stream> stream,
@@ -376,7 +423,8 @@ namespace audio {
bool relative, bool relative,
float volume, float volume,
float pitch, float pitch,
bool loop bool loop,
int channel
); );
/// @brief Play stream from file /// @brief Play stream from file
@@ -386,15 +434,16 @@ namespace audio {
/// @param volume stream volume [0.0-1.0] /// @param volume stream volume [0.0-1.0]
/// @param pitch stream pitch multiplier [0.0-...] /// @param pitch stream pitch multiplier [0.0-...]
/// @param loop loop stream /// @param loop loop stream
/// @param channel channel index
/// @return speaker id or 0 /// @return speaker id or 0
/// @return extern speakerid_t play_stream(
extern speakerid_t playStream(
const fs::path& file, const fs::path& file,
glm::vec3 position, glm::vec3 position,
bool relative, bool relative,
float volume, float volume,
float pitch, float pitch,
bool loop bool loop,
int channel
); );
/// @brief Get speaker by id /// @brief Get speaker by id
@@ -402,10 +451,32 @@ namespace audio {
/// @return speaker or nullptr /// @return speaker or nullptr
extern Speaker* get(speakerid_t id); extern Speaker* get(speakerid_t id);
/// @brief Create new channel.
/// All non-builtin channels will be destroyed on audio::reset() call
/// @param name channel name
/// @return new channel index
extern int create_channel(const std::string& name);
/// @brief Get channel index by name
/// @param name channel name
/// @return channel index or -1
extern int get_channel_index(const std::string& name);
/// @brief Get channel by index. 0 - is master channel
/// @param name channel index
/// @return channel or nullptr
extern Channel* get_channel(int index);
/// @brief Get volume of the master channel
extern float get_master_volume();
/// @brief Update audio streams and sound instanced /// @brief Update audio streams and sound instanced
/// @param delta time elapsed since the last update (seconds) /// @param delta time elapsed since the last update (seconds)
extern void update(double delta); extern void update(double delta);
/// @brief Stop all playing audio, destroy all non-builtin channels
extern void reset();
/// @brief Finalize audio system /// @brief Finalize audio system
extern void close(); extern void close();
}; };
+1 -1
View File
@@ -91,7 +91,7 @@ public:
long bytes = ov_read(&vf, buffer, bufferSize, 0, 2, true, &bitstream); long bytes = ov_read(&vf, buffer, bufferSize, 0, 2, true, &bitstream);
if (bytes < 0) { if (bytes < 0) {
std::cerr << "ogg::load_pcm: " << vorbis_error_message(bytes) << " " << bytes << std::endl; std::cerr << "ogg::load_pcm: " << vorbis_error_message(bytes) << " " << bytes << std::endl;
return 0; return PCMStream::ERROR;
} }
return bytes; return bytes;
} }
+1 -1
View File
@@ -153,7 +153,7 @@ void LevelScreen::update(float delta) {
auto player = controller->getPlayer(); auto player = controller->getPlayer();
auto camera = player->camera; auto camera = player->camera;
audio::setListener( audio::set_listener(
camera->position, camera->position,
player->hitbox->velocity, player->hitbox->velocity,
camera->position+camera->dir, camera->position+camera->dir,