OXYGENHUB
◆ main openmsx / src / sound / Mixer.cc
3.7 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "Mixer.hh"
2
3
#include "MSXMixer.hh"
4
#include "NullSoundDriver.hh"
5
#include "SDLSoundDriver.hh"
6
7
#include "CliComm.hh"
8
#include "CommandController.hh"
9
#include "MSXException.hh"
10
11
#include "one_of.hh"
12
#include "stl.hh"
13
#include "unreachable.hh"
14
15
#include <cassert>
16
#include <memory>
17
18
namespace openmsx {
19
20
#ifdef _WIN32
21
static constexpr int defaultSamples = 2048;
22
#else
23
static constexpr int defaultSamples = 1024;
24
#endif
25
26
static EnumSetting<Mixer::SoundDriverType>::Map getSoundDriverMap()
27
{
28
	EnumSetting<Mixer::SoundDriverType>::Map soundDriverMap = {
29
		{ "null", Mixer::SoundDriverType::NONE },
30
		{ "sdl",  Mixer::SoundDriverType::SDL } };
31
	return soundDriverMap;
32
}
33
34
Mixer::Mixer(Reactor& reactor_, CommandController& commandController_)
35
	: reactor(reactor_)
36
	, commandController(commandController_)
37
	, soundDriverSetting(
38
		commandController, "sound_driver",
39
		"select the sound output driver",
40
		Mixer::SoundDriverType::SDL, getSoundDriverMap())
41
	, muteSetting(
42
		commandController, "mute",
43
		"(un)mute the emulation sound", false, Setting::Save::NO)
44
	, masterVolume(
45
		commandController, "master_volume",
46
		"master volume", 75, 0, 100)
47
	, frequencySetting(
48
		commandController, "frequency",
49
		"mixer frequency", 44100, 11025, 48000)
50
	, samplesSetting(
51
		commandController, "samples",
52
		"mixer samples", defaultSamples, 64, 8192)
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
	assert(!driver);
63
}
64
65
Mixer::~Mixer()
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 SoundDriverType::SDL:
87
			driver = std::make_unique<SDLSoundDriver>(
88
				reactor,
89
				frequencySetting.getInt(),
90
				samplesSetting.getInt());
91
			break;
92
		default:
93
			// nothing, NullSoundDriver already created
94
			break;
95
		}
96
	} catch (MSXException& e) {
97
		commandController.getCliComm().printWarning(e.getMessage());
98
	}
99
}
100
101
void Mixer::registerMixer(MSXMixer& mixer)
102
{
103
	assert(!contains(msxMixers, &mixer));
104
	msxMixers.push_back(&mixer);
105
	muteHelper();
106
}
107
108
void Mixer::unregisterMixer(MSXMixer& mixer)
109
{
110
	move_pop_back(msxMixers, rfind_unguarded(msxMixers, &mixer));
111
	muteHelper();
112
}
113
114
115
void Mixer::mute()
116
{
117
	if (muteCount++ == 0) {
118
		muteHelper();
119
	}
120
}
121
122
void Mixer::unmute()
123
{
124
	assert(muteCount);
125
	if (--muteCount == 0) {
126
		muteHelper();
127
	}
128
}
129
130
void Mixer::muteHelper()
131
{
132
	if (!driver) reloadDriver();
133
134
	bool isMuted = muteCount || msxMixers.empty();
135
	unsigned samples = isMuted ? 0 : driver->getSamples();
136
	unsigned frequency = driver->getFrequency();
137
	for (auto& m : msxMixers) {
138
		m->setMixerParams(samples, frequency);
139
	}
140
141
	if (isMuted) {
142
		driver->mute();
143
	} else {
144
		driver->unmute();
145
	}
146
}
147
148
void Mixer::uploadBuffer(MSXMixer& /*msxMixer*/, std::span<const StereoFloat> buffer)
149
{
150
	if (!driver) {
151
		reloadDriver();
152
		muteHelper();
153
	}
154
155
	// can only handle one MSXMixer ATM
156
	assert(!msxMixers.empty());
157
158
	driver->uploadBuffer(buffer);
159
}
160
161
void Mixer::update(const Setting& setting) noexcept
162
{
163
	if (&setting == &muteSetting) {
164
		if (muteSetting.getBoolean()) {
165
			mute();
166
		} else {
167
			unmute();
168
		}
169
	} else if (&setting == one_of(&samplesSetting, &soundDriverSetting, &frequencySetting)) {
170
		reloadDriver();
171
		muteHelper();
172
	} else {
173
		UNREACHABLE;
174
	}
175
}
176
177
} // namespace openmsx