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 "CommandController.hh"
7 #include "CliComm.hh"
8 #include "IntegerSetting.hh"
9 #include "BooleanSetting.hh"
10 #include "EnumSetting.hh"
11 #include "MSXException.hh"
12 #include "memory.hh"
13 #include "stl.hh"
14 #include "unreachable.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  soundDriverSetting = make_unique<EnumSetting<SoundDriverType>>(
55  commandController, "sound_driver",
56  "select the sound output driver",
57  defaultSoundDriver, soundDriverMap);
58 
59  muteSetting->attach(*this);
60  frequencySetting->attach(*this);
61  samplesSetting->attach(*this);
62  soundDriverSetting->attach(*this);
63 
64  // Set correct initial mute state.
65  if (muteSetting->getBoolean()) ++muteCount;
66 
67  reloadDriver();
68 }
69 
71 {
72  assert(msxMixers.empty());
73  driver.reset();
74 
75  soundDriverSetting->detach(*this);
76  samplesSetting->detach(*this);
77  frequencySetting->detach(*this);
78  muteSetting->detach(*this);
79 }
80 
81 void Mixer::reloadDriver()
82 {
83  driver = make_unique<NullSoundDriver>();
84 
85  try {
86  switch (soundDriverSetting->getEnum()) {
87  case SND_NULL:
88  driver = make_unique<NullSoundDriver>();
89  break;
90  case SND_SDL:
91  driver = make_unique<SDLSoundDriver>(
92  reactor,
93  frequencySetting->getInt(),
94  samplesSetting->getInt());
95  break;
96 #ifdef _WIN32
97  case SND_DIRECTX:
98  driver = make_unique<DirectXSoundDriver>(
99  frequencySetting->getInt(),
100  samplesSetting->getInt());
101  break;
102 #endif
103  default:
104  UNREACHABLE;
105  }
106  } catch (MSXException& e) {
107  commandController.getCliComm().printWarning(e.getMessage());
108  }
109 
110  muteHelper();
111 }
112 
114 {
115  assert(!contains(msxMixers, &mixer));
116  msxMixers.push_back(&mixer);
117  muteHelper();
118 }
119 
121 {
122  msxMixers.erase(find_unguarded(msxMixers, &mixer));
123  muteHelper();
124 }
125 
126 
128 {
129  if (muteCount++ == 0) {
130  muteHelper();
131  }
132 }
133 
135 {
136  assert(muteCount);
137  if (--muteCount == 0) {
138  muteHelper();
139  }
140 }
141 
142 void Mixer::muteHelper()
143 {
144  bool mute = muteCount || msxMixers.empty();
145  unsigned samples = mute ? 0 : driver->getSamples();
146  unsigned frequency = driver->getFrequency();
147  for (auto& m : msxMixers) {
148  m->setMixerParams(samples, frequency);
149  }
150 
151  if (mute) {
152  driver->mute();
153  } else {
154  driver->unmute();
155  }
156 }
157 
158 void Mixer::uploadBuffer(MSXMixer& /*msxMixer*/, short* buffer, unsigned len)
159 {
160  // can only handle one MSXMixer ATM
161  assert(!msxMixers.empty());
162 
163  driver->uploadBuffer(buffer, len);
164 }
165 
166 void Mixer::update(const Setting& setting)
167 {
168  if (&setting == muteSetting.get()) {
169  if (muteSetting->getBoolean()) {
170  mute();
171  } else {
172  unmute();
173  }
174  } else if ((&setting == samplesSetting.get()) ||
175  (&setting == soundDriverSetting.get()) ||
176  (&setting == frequencySetting.get())) {
177  reloadDriver();
178  } else {
179  UNREACHABLE;
180  }
181 }
182 
183 } // namespace openmsx
Contains the main loop of openMSX.
Definition: Reactor.hh:62
ITER find_unguarded(ITER first, ITER last, const VAL &val)
Faster alternative to 'find' when it's guaranteed that the value will be found (if not the behavior i...
Definition: stl.hh:114
void uploadBuffer(MSXMixer &msxMixer, short *buffer, unsigned len)
Upload new sample data.
Definition: Mixer.cc:158
void printWarning(string_ref message)
Definition: CliComm.cc:28
bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:95
Mixer(Reactor &reactor, CommandController &commandController)
Definition: Mixer.cc:29
virtual ~Mixer()
Definition: Mixer.cc:70
A Setting with an integer value.
void mute()
This methods (un)mute the sound.
Definition: Mixer.cc:127
void unregisterMixer(MSXMixer &mixer)
Unregister per-machine mixer.
Definition: Mixer.cc:120
commandController(commandController_)
virtual CliComm & getCliComm()=0
void registerMixer(MSXMixer &mixer)
Register per-machine mixer.
Definition: Mixer.cc:113
std::unique_ptr< T > make_unique()
Definition: memory.hh:27
void unmute()
Definition: Mixer.cc:134
#define UNREACHABLE
Definition: unreachable.hh:56