audio: channels
This commit is contained in:
+118
-26
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user