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"
5 #include "CommandController.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 
15 namespace openmsx {
16 
17 #if defined(_WIN32)
18 constexpr int defaultsamples = 2048;
19 #elif PLATFORM_ANDROID
20 constexpr int defaultsamples = 2560;
21 #else
22 constexpr int defaultsamples = 1024;
23 #endif
24 
25 static EnumSetting<Mixer::SoundDriverType>::Map getSoundDriverMap()
26 {
28  { "null", Mixer::SND_NULL },
29  { "sdl", Mixer::SND_SDL } };
30  return soundDriverMap;
31 }
32 
33 Mixer::Mixer(Reactor& reactor_, CommandController& commandController_)
34  : reactor(reactor_)
35  , commandController(commandController_)
36  , soundDriverSetting(
37  commandController, "sound_driver",
38  "select the sound output driver",
39  Mixer::SND_SDL, getSoundDriverMap())
40  , muteSetting(
41  commandController, "mute",
42  "(un)mute the emulation sound", false, Setting::DONT_SAVE)
43  , masterVolume(
44  commandController, "master_volume",
45  "master volume", 75, 0, 100)
46  , frequencySetting(
47  commandController, "frequency",
48  "mixer frequency", 44100, 11025, 48000)
49  , samplesSetting(
50  commandController, "samples",
51  "mixer samples", defaultsamples, 64, 8192)
52  , muteCount(0)
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 
76 void 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()) {
86  case SND_NULL:
87  driver = std::make_unique<NullSoundDriver>();
88  break;
89  case SND_SDL:
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 
134 void 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 
150 void Mixer::uploadBuffer(MSXMixer& /*msxMixer*/, float* buffer, unsigned len)
151 {
152  // can only handle one MSXMixer ATM
153  assert(!msxMixers.empty());
154 
155  driver->uploadBuffer(buffer, len);
156 }
157 
158 void Mixer::update(const Setting& setting)
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 {
169  UNREACHABLE;
170  }
171 }
172 
173 } // namespace openmsx
openmsx::MSXMixer
Definition: MSXMixer.hh:30
one_of.hh
openmsx::Mixer::registerMixer
void registerMixer(MSXMixer &mixer)
Register per-machine mixer.
Definition: Mixer.cc:105
openmsx::Mixer::SND_NULL
@ SND_NULL
Definition: Mixer.hh:21
SDLSoundDriver.hh
openmsx::Subject::detach
void detach(Observer< T > &observer)
Definition: Subject.hh:56
openmsx::Mixer::uploadBuffer
void uploadBuffer(MSXMixer &msxMixer, float *buffer, unsigned len)
Upload new sample data.
Definition: Mixer.cc:150
openmsx::CommandController
Definition: CommandController.hh:18
openmsx::defaultsamples
constexpr int defaultsamples
Definition: Mixer.cc:22
contains
bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:92
openmsx::Mixer::~Mixer
~Mixer()
Definition: Mixer.cc:65
MSXException.hh
openmsx::EnumSetting::getEnum
T getEnum() const noexcept
Definition: EnumSetting.hh:92
openmsx::Subject::attach
void attach(Observer< T > &observer)
Definition: Subject.hh:50
openmsx::Setting
Definition: Setting.hh:120
openmsx::Reactor
Contains the main loop of openMSX.
Definition: Reactor.hh:67
openmsx::Mixer::unmute
void unmute()
Definition: Mixer.cc:126
openmsx::Mixer::SND_SDL
@ SND_SDL
Definition: Mixer.hh:21
openmsx::IntegerSetting::getInt
int getInt() const noexcept
Definition: IntegerSetting.hh:21
CommandController.hh
move_pop_back
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
Definition: stl.hh:177
openmsx::CliComm::printWarning
void printWarning(std::string_view message)
Definition: CliComm.cc:10
UNREACHABLE
#define UNREACHABLE
Definition: unreachable.hh:38
Mixer.hh
openmsx::Mixer::mute
void mute()
This methods (un)mute the sound.
Definition: Mixer.cc:119
openmsx::CommandController::getCliComm
virtual CliComm & getCliComm()=0
openmsx::Mixer::unregisterMixer
void unregisterMixer(MSXMixer &mixer)
Unregister per-machine mixer.
Definition: Mixer.cc:112
one_of
Definition: one_of.hh:7
openmsx::Mixer
Definition: Mixer.hh:19
build-info.hh
openmsx::EnumSetting::Map
std::vector< std::pair< std::string, T > > Map
Definition: EnumSetting.hh:35
stl.hh
NullSoundDriver.hh
unreachable.hh
CliComm.hh
MSXMixer.hh
rfind_unguarded
auto rfind_unguarded(RANGE &range, const VAL &val)
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
Definition: stl.hh:152
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::Mixer::Mixer
Mixer(Reactor &reactor, CommandController &commandController)
Definition: Mixer.cc:33
openmsx::BooleanSetting::getBoolean
bool getBoolean() const noexcept
Definition: BooleanSetting.hh:17