fishbowl/engine/src/mixer.cc
2026-05-28 14:29:58 +09:00

143 lines
2.9 KiB
C++

#include <fishbone/foundation.h>
fishbone::Mixer::Mixer() {
this->mutex = new fishbone::Mutex();
#define LOADER(X) this->loaders.push_back(new fishbone::X##SoundLoader());
FB_SOUND_LOADERS
#undef LOADER
this->position[0] = 0;
this->position[1] = 0;
this->position[2] = 0;
}
fishbone::Mixer::~Mixer() {
for(int i = 0; i < this->sounds.size(); i++) {
delete this->sounds[i];
}
for(int i = 0; i < this->loaders.size(); i++) {
delete this->loaders[i];
}
delete this->mutex;
}
void fishbone::Mixer::read(short* buffer, size_t frames) {
float* tmp = new float[frames * 2];
for(int i = 0; i < frames * 2; i++) tmp[i] = 0;
this->lock();
for(int i = 0; i < this->sounds.size(); i++) {
size_t ask;
short* req;
size_t got;
float la = 1, ra = 1;
if(this->sounds[i]->isPaused()) continue;
if(this->sounds[i]->is3d) {
float r[3];
float angle, v;
float d;
float lf, rf;
for(int j = 0; j < 3; j++) r[j] = this->position[i] - this->sounds[i]->position[j];
angle = atan2(r[2], r[0]);
v = cos(angle);
d = sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2]);
lf = 1.0 - v;
rf = 1.0 + v;
la = 1.0 / (1.0 + lf + d * d);
ra = 1.0 / (1.0 + rf + d * d);
}
ask = frames * this->sounds[i]->rate / fishbone::Mixer::rate;
req = new short[ask * this->sounds[i]->channels];
got = this->sounds[i]->read(req, ask) * fishbone::Mixer::rate / this->sounds[i]->rate;
if(got <= 0) {
delete[] req;
if(this->sounds[i]->isLoop()) {
this->sounds[i]->seek(0);
} else {
this->sounds[i]->pauseNoLock();
}
continue;
}
for(int j = 0; j < got; j++) {
short l, r;
if(this->sounds[i]->channels == 1) {
l = r = req[j * this->sounds[i]->rate / fishbone::Mixer::rate];
} else if(this->sounds[i]->channels == 2) {
l = req[(j * this->sounds[i]->rate / fishbone::Mixer::rate) * 2 + 0];
r = req[(j * this->sounds[i]->rate / fishbone::Mixer::rate) * 2 + 1];
}
if(this->sounds[i]->is3d){
l = (l + r) / 2;
r = l;
}
tmp[2 * j + 0] += l / 32767.0 * la * this->sounds[i]->volume;
tmp[2 * j + 1] += r / 32767.0 * ra * this->sounds[i]->volume;
}
delete[] req;
}
this->unlock();
for(int i = 0; i < frames * 2; i++) buffer[i] = tmp[i] * 32767;
delete[] tmp;
}
fishbone::Sound* fishbone::Mixer::open(const char* path) {
fishbone::File f(path, "r");
unsigned char* buffer;
fishbone::Sound* snd;
if(!f.good) return nullptr;
buffer = new unsigned char[f.size];
f.read(buffer, f.size);
for(int i = 0; i < this->loaders.size(); i++) {
snd = this->loaders[i]->open(this, buffer, f.size);
if(snd != nullptr) break;
}
delete[] buffer;
if(snd != nullptr) {
if(snd->channels != 1 && snd->channels != 2) {
delete snd;
return nullptr;
}
this->lock();
this->sounds.push_back(snd);
this->unlock();
}
return snd;
}
void fishbone::Mixer::lock() {
this->mutex->lock();
}
void fishbone::Mixer::unlock() {
this->mutex->unlock();
}