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 <cassert>
12#include <memory>
13
14namespace openmsx {
15
16#if defined(_WIN32)
17static constexpr int defaultSamples = 2048;
18#else
19static constexpr int defaultSamples = 1024;
20#endif
21
22static EnumSetting<Mixer::SoundDriverType>::Map getSoundDriverMap()
23{
25 { "null", Mixer::SND_NULL },
26 { "sdl", Mixer::SND_SDL } };
27 return soundDriverMap;
28}
29
30Mixer::Mixer(Reactor& reactor_, CommandController& commandController_)
31 : reactor(reactor_)
32 , commandController(commandController_)
33 , soundDriverSetting(
34 commandController, "sound_driver",
35 "select the sound output driver",
36 Mixer::SND_SDL, getSoundDriverMap())
37 , muteSetting(
38 commandController, "mute",
39 "(un)mute the emulation sound", false, Setting::DONT_SAVE)
40 , masterVolume(
41 commandController, "master_volume",
42 "master volume", 75, 0, 100)
43 , frequencySetting(
44 commandController, "frequency",
45 "mixer frequency", 44100, 11025, 48000)
46 , samplesSetting(
47 commandController, "samples",
48 "mixer samples", defaultSamples, 64, 8192)
49{
50 muteSetting .attach(*this);
51 frequencySetting .attach(*this);
52 samplesSetting .attach(*this);
53 soundDriverSetting.attach(*this);
54
55 // Set correct initial mute state.
56 if (muteSetting.getBoolean()) ++muteCount;
57
58 reloadDriver();
59}
60
62{
63 assert(msxMixers.empty());
64 driver.reset();
65
66 soundDriverSetting.detach(*this);
67 samplesSetting .detach(*this);
68 frequencySetting .detach(*this);
69 muteSetting .detach(*this);
70}
71
72void Mixer::reloadDriver()
73{
74 // Destroy old driver before attempting to create a new one. Though
75 // this means we end up without driver if creating the new one failed
76 // for some reason.
77
78 driver = std::make_unique<NullSoundDriver>();
79
80 try {
81 switch (soundDriverSetting.getEnum()) {
82 case SND_NULL:
83 driver = std::make_unique<NullSoundDriver>();
84 break;
85 case SND_SDL:
86 driver = std::make_unique<SDLSoundDriver>(
87 reactor,
88 frequencySetting.getInt(),
89 samplesSetting.getInt());
90 break;
91 default:
93 }
94 } catch (MSXException& e) {
95 commandController.getCliComm().printWarning(e.getMessage());
96 }
97
98 muteHelper();
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 bool isMuted = muteCount || msxMixers.empty();
133 unsigned samples = isMuted ? 0 : driver->getSamples();
134 unsigned frequency = driver->getFrequency();
135 for (auto& m : msxMixers) {
136 m->setMixerParams(samples, frequency);
137 }
138
139 if (isMuted) {
140 driver->mute();
141 } else {
142 driver->unmute();
143 }
144}
145
146void Mixer::uploadBuffer(MSXMixer& /*msxMixer*/, std::span<const StereoFloat> buffer)
147{
148 // can only handle one MSXMixer ATM
149 assert(!msxMixers.empty());
150
151 driver->uploadBuffer(buffer);
152}
153
154void Mixer::update(const Setting& setting) noexcept
155{
156 if (&setting == &muteSetting) {
157 if (muteSetting.getBoolean()) {
158 mute();
159 } else {
160 unmute();
161 }
162 } else if (&setting == one_of(&samplesSetting, &soundDriverSetting, &frequencySetting)) {
163 reloadDriver();
164 } else {
166 }
167}
168
169} // 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: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:30
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:146
Contains the main loop of openMSX.
Definition Reactor.hh:72
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: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