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