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
+118 -26
View File
@@ -14,20 +14,50 @@ namespace audio {
static Backend* backend;
static std::unordered_map<speakerid_t, std::unique_ptr<Speaker>> speakers;
static std::unordered_map<speakerid_t, std::shared_ptr<Stream>> streams;
static std::vector<std::unique_ptr<Channel>> channels;
}
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) {
if (!isOpen()) {
return 0;
}
long bytes = 0;
size_t size = 0;
do {
size_t bytes = 0;
do {
bytes = read(buffer, bufferSize);
if (bytes < 0) {
if (bytes == PCMStream::ERROR) {
return size;
}
size += bytes;
@@ -126,9 +156,14 @@ void audio::initialize(bool enabled) {
std::cerr << "could not to initialize audio" << std::endl;
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)) {
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");
}
Sound* audio::loadSound(const fs::path& file, bool keepPCM) {
std::shared_ptr<PCM> pcm(loadPCM(file, !keepPCM && backend->isDummy()));
return createSound(pcm, keepPCM);
Sound* audio::load_sound(const fs::path& file, bool keepPCM) {
std::shared_ptr<PCM> pcm(load_PCM(file, !keepPCM && backend->isDummy()));
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);
}
PCMStream* audio::openPCMStream(const fs::path& file) {
PCMStream* audio::open_PCM_stream(const fs::path& file) {
std::string ext = file.extension().u8string();
if (ext == ".wav" || ext == ".WAV") {
return wav::create_stream(file);
@@ -160,27 +195,27 @@ PCMStream* audio::openPCMStream(const fs::path& file) {
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()) {
auto header = loadPCM(file, true);
auto header = load_PCM(file, true);
// 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),
keepSource
);
}
return openStream(
std::shared_ptr<PCMStream>(openPCMStream(file)),
return open_stream(
std::shared_ptr<PCMStream>(open_PCM_stream(file)),
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);
}
void audio::setListener(
void audio::set_listener(
glm::vec3 position,
glm::vec3 velocity,
glm::vec3 lookAt,
@@ -215,12 +250,13 @@ speakerid_t audio::play(
float volume,
float pitch,
bool loop,
int priority
int priority,
int channel
) {
Speaker* speaker = sound->newInstance(priority);
Speaker* speaker = sound->newInstance(priority, channel);
if (speaker == nullptr) {
remove_lower_priority_speaker(priority);
speaker = sound->newInstance(priority);
speaker = sound->newInstance(priority, channel);
}
if (speaker == nullptr) {
return 0;
@@ -242,12 +278,13 @@ speakerid_t audio::play(
bool relative,
float volume,
float pitch,
bool loop
bool loop,
int channel
) {
Speaker* speaker = stream->createSpeaker(loop);
Speaker* speaker = stream->createSpeaker(loop, channel);
if (speaker == nullptr) {
remove_lower_priority_speaker(PRIORITY_HIGH);
speaker = stream->createSpeaker(loop);
speaker = stream->createSpeaker(loop, channel);
}
if (speaker == nullptr) {
return 0;
@@ -266,16 +303,17 @@ speakerid_t audio::play(
return id;
}
speakerid_t audio::playStream(
speakerid_t audio::play_stream(
const fs::path& file,
glm::vec3 position,
bool relative,
float volume,
float pitch,
bool loop
bool loop,
int channel
) {
std::shared_ptr<Stream> stream (openStream(file, false));
return play(stream, position, relative, volume, pitch, loop);
std::shared_ptr<Stream> stream (open_stream(file, false));
return play(stream, position, relative, volume, pitch, loop, channel);
}
Speaker* audio::get(speakerid_t id) {
@@ -286,6 +324,37 @@ Speaker* audio::get(speakerid_t id) {
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) {
backend->update(delta);
@@ -293,8 +362,15 @@ void audio::update(double delta) {
entry.second->update(delta);
}
float masterVolume = get_master_volume();
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);
it = speakers.erase(it);
} 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() {
speakers.clear();
delete backend;