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::DONT_SAVE)
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 reloadDriver();
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<NullSoundDriver>();
88 break;
90 driver = std::make_unique<SDLSoundDriver>(
91 reactor,
92 frequencySetting.getInt(),
93 samplesSetting.getInt());
94 break;
95 default:
97 }
98 } catch (MSXException& e) {
99 commandController.getCliComm().printWarning(e.getMessage());
100 }
101
102 muteHelper();
103}
104
106{
107 assert(!contains(msxMixers, &mixer));
108 msxMixers.push_back(&mixer);
109 muteHelper();
110}
111
113{
114 move_pop_back(msxMixers, rfind_unguarded(msxMixers, &mixer));
115 muteHelper();
116}
117
118
120{
121 if (muteCount++ == 0) {
122 muteHelper();
123 }
124}
125
127{
128 assert(muteCount);
129 if (--muteCount == 0) {
130 muteHelper();
131 }
132}
133
134void Mixer::muteHelper()
135{
136 bool isMuted = muteCount || msxMixers.empty();
137 unsigned samples = isMuted ? 0 : driver->getSamples();
138 unsigned frequency = driver->getFrequency();
139 for (auto& m : msxMixers) {
140 m->setMixerParams(samples, frequency);
141 }
142
143 if (isMuted) {
144 driver->mute();
145 } else {
146 driver->unmute();
147 }
148}
149
150void Mixer::uploadBuffer(MSXMixer& /*msxMixer*/, std::span<const StereoFloat> buffer)
151{
152 // can only handle one MSXMixer ATM
153 assert(!msxMixers.empty());
154
155 driver->uploadBuffer(buffer);
156}
157
158void Mixer::update(const Setting& setting) noexcept
159{
160 if (&setting == &muteSetting) {
161 if (muteSetting.getBoolean()) {
162 mute();
163 } else {
164 unmute();
165 }
166 } else if (&setting == one_of(&samplesSetting, &soundDriverSetting, &frequencySetting)) {
167 reloadDriver();
168 } else {
170 }
171}
172
173} // namespace openmsx
BaseSetting * setting
bool getBoolean() const noexcept
void printWarning(std::string_view message)
Definition CliComm.cc:10
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:105
void mute()
This methods (un)mute the sound.
Definition Mixer.cc:119
void unmute()
Definition Mixer.cc:126
Mixer(Reactor &reactor, CommandController &commandController)
Definition Mixer.cc:34
void unregisterMixer(MSXMixer &mixer)
Unregister per-machine mixer.
Definition Mixer.cc:112
void uploadBuffer(MSXMixer &msxMixer, std::span< const StereoFloat > buffer)
Upload new sample data.
Definition Mixer.cc:150
Contains the main loop of openMSX.
Definition Reactor.hh:74
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:134
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:109
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition stl.hh:32
#define UNREACHABLE