openMSX
Mixer.cc
Go to the documentation of this file.
1#include "Mixer.hh"
2#include "MSXMixer.hh"
3#include "NullSoundDriver.hh"
4#include "SDLSoundDriver.hh"
6#include "CliComm.hh"
7#include "MSXException.hh"
8#include "one_of.hh"
9#include "stl.hh"
10#include "unreachable.hh"
11#include "build-info.hh"
12#include <cassert>
13#include <memory>
14
15namespace openmsx {
16
17#if defined(_WIN32)
18static constexpr int defaultSamples = 2048;
19#else
20static constexpr int defaultSamples = 1024;
21#endif
22
23static EnumSetting<Mixer::SoundDriverType>::Map getSoundDriverMap()
24{
26 { "null", Mixer::SND_NULL },
27 { "sdl", Mixer::SND_SDL } };
28 return soundDriverMap;
29}
30
31Mixer::Mixer(Reactor& reactor_, CommandController& commandController_)
32 : reactor(reactor_)
33 , commandController(commandController_)
34 , soundDriverSetting(
35 commandController, "sound_driver",
36 "select the sound output driver",
37 Mixer::SND_SDL, getSoundDriverMap())
38 , muteSetting(
39 commandController, "mute",
40 "(un)mute the emulation sound", false, Setting::DONT_SAVE)
41 , masterVolume(
42 commandController, "master_volume",
43 "master volume", 75, 0, 100)
44 , frequencySetting(
45 commandController, "frequency",
46 "mixer frequency", 44100, 11025, 48000)
47 , samplesSetting(
48 commandController, "samples",
49 "mixer samples", defaultSamples, 64, 8192)
50{
51 muteSetting .attach(*this);
52 frequencySetting .attach(*this);
53 samplesSetting .attach(*this);
54 soundDriverSetting.attach(*this);
55
56 // Set correct initial mute state.
57 if (muteSetting.getBoolean()) ++muteCount;
58
59 reloadDriver();
60}
61
63{
64 assert(msxMixers.empty());
65 driver.reset();
66
67 soundDriverSetting.detach(*this);
68 samplesSetting .detach(*this);
69 frequencySetting .detach(*this);
70 muteSetting .detach(*this);
71}
72
73void Mixer::reloadDriver()
74{
75 // Destroy old driver before attempting to create a new one. Though
76 // this means we end up without driver if creating the new one failed
77 // for some reason.
78
79 driver = std::make_unique<NullSoundDriver>();
80
81 try {
82 switch (soundDriverSetting.getEnum()) {
83 case SND_NULL:
84 driver = std::make_unique<NullSoundDriver>();
85 break;
86 case SND_SDL:
87 driver = std::make_unique<SDLSoundDriver>(
88 reactor,
89 frequencySetting.getInt(),
90 samplesSetting.getInt());
91 break;
92 default:
94 }
95 } catch (MSXException& e) {
96 commandController.getCliComm().printWarning(e.getMessage());
97 }
98
99 muteHelper();
100}
101
103{
104 assert(!contains(msxMixers, &mixer));
105 msxMixers.push_back(&mixer);
106 muteHelper();
107}
108
110{
111 move_pop_back(msxMixers, rfind_unguarded(msxMixers, &mixer));
112 muteHelper();
113}
114
115
117{
118 if (muteCount++ == 0) {
119 muteHelper();
120 }
121}
122
124{
125 assert(muteCount);
126 if (--muteCount == 0) {
127 muteHelper();
128 }
129}
130
131void Mixer::muteHelper()
132{
133 bool isMuted = muteCount || msxMixers.empty();
134 unsigned samples = isMuted ? 0 : driver->getSamples();
135 unsigned frequency = driver->getFrequency();
136 for (auto& m : msxMixers) {
137 m->setMixerParams(samples, frequency);
138 }
139
140 if (isMuted) {
141 driver->mute();
142 } else {
143 driver->unmute();
144 }
145}
146
147void Mixer::uploadBuffer(MSXMixer& /*msxMixer*/, std::span<const StereoFloat> buffer)
148{
149 // can only handle one MSXMixer ATM
150 assert(!msxMixers.empty());
151
152 driver->uploadBuffer(buffer);
153}
154
155void Mixer::update(const Setting& setting) noexcept
156{
157 if (&setting == &muteSetting) {
158 if (muteSetting.getBoolean()) {
159 mute();
160 } else {
161 unmute();
162 }
163 } else if (&setting == one_of(&samplesSetting, &soundDriverSetting, &frequencySetting)) {
164 reloadDriver();
165 } else {
167 }
168}
169
170} // namespace openmsx
BaseSetting * setting
Definition: Interpreter.cc:28
Definition: one_of.hh:7
bool getBoolean() const noexcept
void printWarning(std::string_view message)
Definition: CliComm.cc:10
virtual CliComm & getCliComm()=0
EnumSettingBase::Map Map
Definition: EnumSetting.hh:56
T getEnum() const noexcept
Definition: EnumSetting.hh:112
int getInt() const noexcept
void registerMixer(MSXMixer &mixer)
Register per-machine mixer.
Definition: Mixer.cc:102
void mute()
This methods (un)mute the sound.
Definition: Mixer.cc:116
void unmute()
Definition: Mixer.cc:123
Mixer(Reactor &reactor, CommandController &commandController)
Definition: Mixer.cc:31
void unregisterMixer(MSXMixer &mixer)
Unregister per-machine mixer.
Definition: Mixer.cc:109
void uploadBuffer(MSXMixer &msxMixer, std::span< const StereoFloat > buffer)
Upload new sample data.
Definition: Mixer.cc:147
Contains the main loop of openMSX.
Definition: Reactor.hh:68
void detach(Observer< T > &observer)
Definition: Subject.hh:56
void attach(Observer< T > &observer)
Definition: Subject.hh:50
constexpr double e
Definition: Math.hh:21
This file implemented 3 utility functions:
Definition: Autofire.cc:9
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
Definition: stl.hh:125
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
Definition: stl.hh:100
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:23
#define UNREACHABLE
Definition: unreachable.hh:38