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 "DirectXSoundDriver.hh"
6 #include "LibAOSoundDriver.hh"
7 #include "CommandController.hh"
8 #include "CliComm.hh"
9 #include "IntegerSetting.hh"
10 #include "BooleanSetting.hh"
11 #include "EnumSetting.hh"
12 #include "MSXException.hh"
13 #include "unreachable.hh"
14 #include "memory.hh"
15 #include "components.hh"
16 #include "build-info.hh"
17 #include <cassert>
18 
19 namespace openmsx {
20 
21 #if defined(_WIN32)
22 static const int defaultsamples = 2048;
23 #elif PLATFORM_ANDROID
24 static const int defaultsamples = 2560;
25 #else
26 static const int defaultsamples = 1024;
27 #endif
28 
29 Mixer::Mixer(Reactor& reactor_, CommandController& commandController_)
30  : reactor(reactor_)
31  , commandController(commandController_)
32  , muteSetting(make_unique<BooleanSetting>(
33  commandController, "mute",
34  "(un)mute the emulation sound", false, Setting::DONT_SAVE))
35  , masterVolume(make_unique<IntegerSetting>(
36  commandController, "master_volume",
37  "master volume", 75, 0, 100))
38  , frequencySetting(make_unique<IntegerSetting>(
39  commandController, "frequency",
40  "mixer frequency", 44100, 11025, 48000))
41  , samplesSetting(make_unique<IntegerSetting>(
42  commandController, "samples",
43  "mixer samples", defaultsamples, 64, 8192))
44  , muteCount(0)
45 {
46  EnumSetting<SoundDriverType>::Map soundDriverMap;
47  soundDriverMap["null"] = SND_NULL;
48  soundDriverMap["sdl"] = SND_SDL;
49  SoundDriverType defaultSoundDriver = SND_SDL;
50 
51 #ifdef _WIN32
52  soundDriverMap["directx"] = SND_DIRECTX;
53  defaultSoundDriver = SND_DIRECTX;
54 #endif
55 #if COMPONENT_AO
56  soundDriverMap["libao"] = SND_LIBAO;
57 #endif
58 
59  soundDriverSetting = make_unique<EnumSetting<SoundDriverType>>(
60  commandController, "sound_driver",
61  "select the sound output driver",
62  defaultSoundDriver, soundDriverMap);
63 
64  muteSetting->attach(*this);
65  frequencySetting->attach(*this);
66  samplesSetting->attach(*this);
67  soundDriverSetting->attach(*this);
68 
69  // Set correct initial mute state.
70  if (muteSetting->getValue()) ++muteCount;
71 
72  reloadDriver();
73 }
74 
76 {
77  assert(msxMixers.empty());
78  driver.reset();
79 
80  soundDriverSetting->detach(*this);
81  samplesSetting->detach(*this);
82  frequencySetting->detach(*this);
83  muteSetting->detach(*this);
84 }
85 
86 void Mixer::reloadDriver()
87 {
88  driver = make_unique<NullSoundDriver>();
89 
90  try {
91  switch (soundDriverSetting->getValue()) {
92  case SND_NULL:
93  driver = make_unique<NullSoundDriver>();
94  break;
95  case SND_SDL:
96  driver = make_unique<SDLSoundDriver>(
97  reactor,
98  frequencySetting->getValue(),
99  samplesSetting->getValue());
100  break;
101 #ifdef _WIN32
102  case SND_DIRECTX:
103  driver = make_unique<DirectXSoundDriver>(
104  frequencySetting->getValue(),
105  samplesSetting->getValue());
106  break;
107 #endif
108 #if COMPONENT_AO
109  case SND_LIBAO:
110  driver = make_unique<LibAOSoundDriver>(
111  frequencySetting->getValue(),
112  samplesSetting->getValue());
113  break;
114 #endif
115  default:
116  UNREACHABLE;
117  }
118  } catch (MSXException& e) {
119  commandController.getCliComm().printWarning(e.getMessage());
120  }
121 
122  muteHelper();
123 }
124 
126 {
127  assert(count(msxMixers.begin(), msxMixers.end(), &mixer) == 0);
128  msxMixers.push_back(&mixer);
129 
130  muteHelper();
131 }
132 
134 {
135  assert(count(msxMixers.begin(), msxMixers.end(), &mixer) == 1);
136  msxMixers.erase(find(msxMixers.begin(), msxMixers.end(), &mixer));
137 
138  muteHelper();
139 }
140 
141 
143 {
144  if (muteCount++ == 0) {
145  muteHelper();
146  }
147 }
148 
150 {
151  assert(muteCount);
152  if (--muteCount == 0) {
153  muteHelper();
154  }
155 }
156 
157 void Mixer::muteHelper()
158 {
159  bool mute = muteCount || msxMixers.empty();
160  unsigned samples = mute ? 0 : driver->getSamples();
161  unsigned frequency = driver->getFrequency();
162  for (auto& m : msxMixers) {
163  m->setMixerParams(samples, frequency);
164  }
165 
166  if (mute) {
167  driver->mute();
168  } else {
169  driver->unmute();
170  }
171 }
172 
174 {
175  return *masterVolume;
176 }
177 
178 void Mixer::uploadBuffer(MSXMixer& /*msxMixer*/, short* buffer, unsigned len)
179 {
180  // can only handle one MSXMixer ATM
181  assert(!msxMixers.empty());
182 
183  driver->uploadBuffer(buffer, len);
184 }
185 
186 void Mixer::update(const Setting& setting)
187 {
188  if (&setting == muteSetting.get()) {
189  if (muteSetting->getValue()) {
190  mute();
191  } else {
192  unmute();
193  }
194  } else if ((&setting == samplesSetting.get()) ||
195  (&setting == soundDriverSetting.get()) ||
196  (&setting == frequencySetting.get())) {
197  reloadDriver();
198  } else {
199  UNREACHABLE;
200  }
201 }
202 
203 } // namespace openmsx