Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/frontend/StarMainMixer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/frontend/StarMainMixer.cpp')
-rw-r--r--source/frontend/StarMainMixer.cpp114
1 files changed, 114 insertions, 0 deletions
diff --git a/source/frontend/StarMainMixer.cpp b/source/frontend/StarMainMixer.cpp
new file mode 100644
index 0000000..46c26cd
--- /dev/null
+++ b/source/frontend/StarMainMixer.cpp
@@ -0,0 +1,114 @@
+#include "StarMainMixer.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarRoot.hpp"
+#include "StarConfiguration.hpp"
+#include "StarUniverseClient.hpp"
+#include "StarPlayer.hpp"
+#include "StarAssets.hpp"
+#include "StarWorldClient.hpp"
+
+namespace Star {
+
+MainMixer::MainMixer(unsigned sampleRate, unsigned channels) {
+ m_mixer = make_shared<Mixer>(sampleRate, channels);
+}
+
+void MainMixer::setUniverseClient(UniverseClientPtr universeClient) {
+ m_universeClient = move(universeClient);
+}
+
+void MainMixer::update(bool muteSfx, bool muteMusic) {
+ auto assets = Root::singleton().assets();
+
+ auto updateGroupVolume = [&](MixerGroup group, bool muted, String const& settingName) {
+ if (m_mutedGroups.contains(group) != muted) {
+ if (muted) {
+ m_mutedGroups.add(group);
+ m_mixer->setGroupVolume(group, 0, 1.0f);
+ } else {
+ m_mutedGroups.remove(group);
+ m_mixer->setGroupVolume(group, m_groupVolumes[group], 1.0f);
+ }
+ } else if (!m_mutedGroups.contains(group)) {
+ float volumeSetting = Root::singleton().configuration()->get(settingName).toFloat() / 100;
+ if (!m_groupVolumes.contains(group) || volumeSetting != m_groupVolumes[group]) {
+ m_mixer->setGroupVolume(group, volumeSetting);
+ m_groupVolumes[group] = volumeSetting;
+ }
+ }
+ };
+
+ updateGroupVolume(MixerGroup::Effects, muteSfx, "sfxVol");
+ updateGroupVolume(MixerGroup::Music, muteMusic, "musicVol");
+ updateGroupVolume(MixerGroup::Cinematic, false, "sfxVol");
+
+ WorldClientPtr currentWorld;
+ if (m_universeClient)
+ currentWorld = m_universeClient->worldClient();
+
+ if (currentWorld) {
+ for (auto audioInstance : currentWorld->pullPendingAudio()) {
+ audioInstance->setMixerGroup(MixerGroup::Effects);
+ m_mixer->play(audioInstance);
+ }
+ for (auto audioInstance : currentWorld->pullPendingMusic()) {
+ audioInstance->setMixerGroup(MixerGroup::Music);
+ m_mixer->play(audioInstance);
+ }
+
+ if (m_universeClient && m_universeClient->mainPlayer()->underwater()) {
+ if (!m_mixer->hasEffect("lowpass"))
+ m_mixer->addEffect("lowpass", m_mixer->lowpass(32), 0.50f);
+ if (!m_mixer->hasEffect("echo"))
+ m_mixer->addEffect("echo", m_mixer->echo(0.2f, 0.6f, 0.4f), 0.50f);
+ } else {
+ if (m_mixer->hasEffect("lowpass"))
+ m_mixer->removeEffect("lowpass", 0.5f);
+ if (m_mixer->hasEffect("echo"))
+ m_mixer->removeEffect("echo", 0.5f);
+ }
+
+ float baseMaxDistance = assets->json("/sfx.config:baseMaxDistance").toFloat();
+ Vec2F stereoAdjustmentRange = jsonToVec2F(assets->json("/sfx.config:stereoAdjustmentRange"));
+ float attenuationGamma = assets->json("/sfx.config:attenuationGamma").toFloat();
+ auto playerPos = m_universeClient->mainPlayer()->position();
+ auto worldGeometry = currentWorld->geometry();
+
+ m_mixer->update([&](unsigned channel, Vec2F pos, float rangeMultiplier) {
+ Vec2F diff = worldGeometry.diff(pos, playerPos);
+ float diffMagnitude = diff.magnitude();
+ if (diffMagnitude == 0.0f)
+ return 0.0f;
+
+ Vec2F diffNorm = diff / diffMagnitude;
+
+ float stereoIncidence = channel == 0 ? -diffNorm[0] : diffNorm[0];
+
+ float maxDistance = baseMaxDistance * rangeMultiplier * lerp((stereoIncidence + 1.0f) / 2.0f, stereoAdjustmentRange[0], stereoAdjustmentRange[1]);
+
+ return pow(clamp(diffMagnitude / maxDistance, 0.0f, 1.0f), 1.0f / attenuationGamma);
+ });
+
+ } else {
+ if (m_mixer->hasEffect("lowpass"))
+ m_mixer->removeEffect("lowpass", 0);
+ if (m_mixer->hasEffect("echo"))
+ m_mixer->removeEffect("echo", 0);
+
+ m_mixer->update();
+ }
+}
+
+MixerPtr MainMixer::mixer() const {
+ return m_mixer;
+}
+
+void MainMixer::setVolume(float volume, float rampTime) {
+ m_mixer->setVolume(volume, rampTime);
+}
+
+void MainMixer::read(int16_t* sampleData, size_t frameCount) {
+ m_mixer->read(sampleData, frameCount);
+}
+
+}