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  { "null", SND_NULL },
48  { "sdl", SND_SDL } };
49  SoundDriverType defaultSoundDriver = SND_SDL;
50 #ifdef _WIN32
51  soundDriverMap.emplace_back("directx", SND_DIRECTX);
52  defaultSoundDriver = SND_DIRECTX;
53 #endif
54 #if COMPONENT_AO
55  soundDriverMap.emplace_back("libao", SND_LIBAO);
56 #endif
57  soundDriverSetting = make_unique<EnumSetting<SoundDriverType>>(
58  commandController, "sound_driver",
59  "select the sound output driver",
60  defaultSoundDriver, soundDriverMap);
61 
62  muteSetting->attach(*this);
63  frequencySetting->attach(*this);
64  samplesSetting->attach(*this);
65  soundDriverSetting->attach(*this);
66 
67  // Set correct initial mute state.
68  if (muteSetting->getBoolean()) ++muteCount;
69 
70  reloadDriver();
71 }
72 
74 {
75  assert(msxMixers.empty());
76  driver.reset();
77 
78  soundDriverSetting->detach(*this);
79  samplesSetting->detach(*this);
80  frequencySetting->detach(*this);
81  muteSetting->detach(*this);
82 }
83 
84 void Mixer::reloadDriver()
85 {
86  driver = make_unique<NullSoundDriver>();
87 
88  try {
89  switch (soundDriverSetting->getEnum()) {
90  case SND_NULL:
91  driver = make_unique<NullSoundDriver>();
92  break;
93  case SND_SDL:
94  driver = make_unique<SDLSoundDriver>(
95  reactor,
96  frequencySetting->getInt(),
97  samplesSetting->getInt());
98  break;
99 #ifdef _WIN32
100  case SND_DIRECTX:
101  driver = make_unique<DirectXSoundDriver>(
102  frequencySetting->getInt(),
103  samplesSetting->getInt());
104  break;
105 #endif
106 #if COMPONENT_AO
107  case SND_LIBAO:
108  driver = make_unique<LibAOSoundDriver>(
109  frequencySetting->getInt(),
110  samplesSetting->getInt());
111  break;
112 #endif
113  default:
114  UNREACHABLE;
115  }
116  } catch (MSXException& e) {
117  commandController.getCliComm().printWarning(e.getMessage());
118  }
119 
120  muteHelper();
121 }
122 
124 {
125  assert(count(msxMixers.begin(), msxMixers.end(), &mixer) == 0);
126  msxMixers.push_back(&mixer);
127 
128  muteHelper();
129 }
130 
132 {
133  assert(count(msxMixers.begin(), msxMixers.end(), &mixer) == 1);
134  msxMixers.erase(find(msxMixers.begin(), msxMixers.end(), &mixer));
135 
136  muteHelper();
137 }
138 
139 
141 {
142  if (muteCount++ == 0) {
143  muteHelper();
144  }
145 }
146 
148 {
149  assert(muteCount);
150  if (--muteCount == 0) {
151  muteHelper();
152  }
153 }
154 
155 void Mixer::muteHelper()
156 {
157  bool mute = muteCount || msxMixers.empty();
158  unsigned samples = mute ? 0 : driver->getSamples();
159  unsigned frequency = driver->getFrequency();
160  for (auto& m : msxMixers) {
161  m->setMixerParams(samples, frequency);
162  }
163 
164  if (mute) {
165  driver->mute();
166  } else {
167  driver->unmute();
168  }
169 }
170 
172 {
173  return *masterVolume;
174 }
175 
176 void Mixer::uploadBuffer(MSXMixer& /*msxMixer*/, short* buffer, unsigned len)
177 {
178  // can only handle one MSXMixer ATM
179  assert(!msxMixers.empty());
180 
181  driver->uploadBuffer(buffer, len);
182 }
183 
184 void Mixer::update(const Setting& setting)
185 {
186  if (&setting == muteSetting.get()) {
187  if (muteSetting->getBoolean()) {
188  mute();
189  } else {
190  unmute();
191  }
192  } else if ((&setting == samplesSetting.get()) ||
193  (&setting == soundDriverSetting.get()) ||
194  (&setting == frequencySetting.get())) {
195  reloadDriver();
196  } else {
197  UNREACHABLE;
198  }
199 }
200 
201 } // namespace openmsx
Contains the main loop of openMSX.
Definition: Reactor.hh:61
IntegerSetting & getMasterVolume() const
Definition: Mixer.cc:171
void uploadBuffer(MSXMixer &msxMixer, short *buffer, unsigned len)
Upload new sample data.
Definition: Mixer.cc:176
void printWarning(string_ref message)
Definition: CliComm.cc:28
Mixer(Reactor &reactor, CommandController &commandController)
Definition: Mixer.cc:29
virtual ~Mixer()
Definition: Mixer.cc:73
A Setting with an integer value.
void mute()
This methods (un)mute the sound.
Definition: Mixer.cc:140
void unregisterMixer(MSXMixer &mixer)
Unregister per-machine mixer.
Definition: Mixer.cc:131
virtual CliComm & getCliComm()=0
void registerMixer(MSXMixer &mixer)
Register per-machine mixer.
Definition: Mixer.cc:123
std::unique_ptr< T > make_unique()
Definition: memory.hh:27
void unmute()
Definition: Mixer.cc:147
#define UNREACHABLE
Definition: unreachable.hh:56