xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
1 #include <MediaNode.h>
2 #include "MixerOutput.h"
3 #include "MixerCore.h"
4 #include "MixerUtils.h"
5 #include "debug.h"
6 
7 MixerOutput::MixerOutput(MixerCore *core, const media_output &output)
8  :	fCore(core),
9 	fOutput(output),
10 	fOutputChannelCount(0),
11 	fOutputChannelInfo(0),
12 	fOutputByteSwap(0),
13 	fMuted(false)
14 {
15 	fix_multiaudio_format(&fOutput.format.u.raw_audio);
16 	PRINT_OUTPUT("MixerOutput::MixerOutput", fOutput);
17 	PRINT_CHANNEL_MASK(fOutput.format);
18 
19 	UpdateOutputChannels();
20 	UpdateByteOrderSwap();
21 }
22 
23 MixerOutput::~MixerOutput()
24 {
25 	delete fOutputChannelInfo;
26 	delete fOutputByteSwap;
27 }
28 
29 media_output &
30 MixerOutput::MediaOutput()
31 {
32 	return fOutput;
33 }
34 
35 void
36 MixerOutput::ChangeFormat(const media_multi_audio_format &format)
37 {
38 	fOutput.format.u.raw_audio = format;
39 	fix_multiaudio_format(&fOutput.format.u.raw_audio);
40 
41 	PRINT_OUTPUT("MixerOutput::ChangeFormat", fOutput);
42 	PRINT_CHANNEL_MASK(fOutput.format);
43 
44 	UpdateOutputChannels();
45 	UpdateByteOrderSwap();
46 }
47 
48 void
49 MixerOutput::UpdateByteOrderSwap()
50 {
51 	delete fOutputByteSwap;
52 	fOutputByteSwap = 0;
53 
54 	// perhaps we need byte swapping
55 	if (fOutput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
56 		if (	fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
57 			 ||	fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT
58 			 ||	fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
59 			fOutputByteSwap = new ByteSwap(fOutput.format.u.raw_audio.format);
60 		}
61 	}
62 }
63 
64 void
65 MixerOutput::UpdateOutputChannels()
66 {
67 	output_chan_info *oldInfo = fOutputChannelInfo;
68 	int oldCount = fOutputChannelCount;
69 
70 	fOutputChannelCount = fOutput.format.u.raw_audio.channel_count;
71 	fOutputChannelInfo = new output_chan_info[fOutputChannelCount];
72 	for (int i = 0; i < fOutputChannelCount; i++) {
73 		fOutputChannelInfo[i].channel_type = GetChannelType(i, fOutput.format.u.raw_audio.channel_mask);
74 		fOutputChannelInfo[i].channel_gain = 1.0;
75 		fOutputChannelInfo[i].source_count = 1;
76 		fOutputChannelInfo[i].source_gain[0] = 1.0;
77 		fOutputChannelInfo[i].source_type[0] = fOutputChannelInfo[i].channel_type;
78 		// all the cached values are 0.0 for a new channel
79 		for (int j = 0; j < MAX_CHANNEL_TYPES; j++)
80 			fOutputChannelInfo[i].source_gain_cache[j] = 0.0;
81 	}
82 
83 	AssignDefaultSources();
84 
85 	// apply old gains and sources, overriding the 1.0 gain defaults for the old channels
86 	if (oldInfo != 0 && oldCount != 0) {
87 		for (int i = 0; i < fOutputChannelCount; i++) {
88 			for (int j = 0; j < oldCount; j++) {
89 				if (fOutputChannelInfo[i].channel_type == oldInfo[j].channel_type) {
90 					fOutputChannelInfo[i].channel_gain = oldInfo[j].channel_gain;
91 					fOutputChannelInfo[i].source_count = oldInfo[j].source_count;
92 					for (int k = 0; k < fOutputChannelInfo[i].source_count; k++) {
93 						fOutputChannelInfo[i].source_gain[k] = oldInfo[j].source_gain[k];
94 						fOutputChannelInfo[i].source_type[k] = oldInfo[j].source_type[k];
95 					}
96 					// also copy the old gain cache
97 					for (int k = 0; k < MAX_CHANNEL_TYPES; k++)
98 						fOutputChannelInfo[i].source_gain_cache[k] = oldInfo[j].source_gain_cache[k];
99 					break;
100 				}
101 			}
102 		}
103 		// also delete the old info array
104 		delete [] oldInfo;
105 	}
106 	for (int i = 0; i < fOutputChannelCount; i++)
107 		TRACE("UpdateOutputChannels: output channel %d, type %2d, gain %.3f\n", i, fOutputChannelInfo[i].channel_type, fOutputChannelInfo[i].channel_gain);
108 }
109 
110 void
111 MixerOutput::AssignDefaultSources()
112 {
113 	uint32 mask = fOutput.format.u.raw_audio.channel_mask;
114 	int count = fOutputChannelCount;
115 
116 	// assign default sources for a few known setups,
117 	// everything else is left unchanged (it already is 1:1)
118 
119 	if (count == 1 && mask & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
120 		// we have only one phycial output channel, and use it as a mix of
121 		// left, right, rear-left, rear-right, center and sub
122 		TRACE("AssignDefaultSources: 1 channel setup\n");
123 		fOutputChannelInfo[0].source_count = 9;
124 		fOutputChannelInfo[0].source_gain[0] = 1.0;
125 		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
126 		fOutputChannelInfo[0].source_gain[1] = 1.0;
127 		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
128 		fOutputChannelInfo[0].source_gain[2] = 0.8;
129 		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
130 		fOutputChannelInfo[0].source_gain[3] = 0.8;
131 		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
132 		fOutputChannelInfo[0].source_gain[4] = 0.7;
133 		fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
134 		fOutputChannelInfo[0].source_gain[5] = 0.6;
135 		fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SUB);
136 		fOutputChannelInfo[0].source_gain[6] = 1.0;
137 		fOutputChannelInfo[0].source_type[6] = ChannelMaskToChannelType(B_CHANNEL_MONO);
138 		fOutputChannelInfo[0].source_gain[7] = 0.7;
139 		fOutputChannelInfo[0].source_type[7] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
140 		fOutputChannelInfo[0].source_gain[8] = 0.7;
141 		fOutputChannelInfo[0].source_type[8] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
142 	} else if (count == 2 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
143 		// we have have two phycial output channels
144 		TRACE("AssignDefaultSources: 2 channel setup\n");
145 		// left channel:
146 		fOutputChannelInfo[0].source_count = 6;
147 		fOutputChannelInfo[0].source_gain[0] = 1.0;
148 		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
149 		fOutputChannelInfo[0].source_gain[1] = 0.8;
150 		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
151 		fOutputChannelInfo[0].source_gain[2] = 0.7;
152 		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
153 		fOutputChannelInfo[0].source_gain[3] = 0.6;
154 		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB);
155 		fOutputChannelInfo[0].source_gain[4] = 1.0;
156 		fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO);
157 		fOutputChannelInfo[0].source_gain[5] = 0.7;
158 		fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
159 		// right channel:
160 		fOutputChannelInfo[1].source_count = 6;
161 		fOutputChannelInfo[1].source_gain[0] = 1.0;
162 		fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
163 		fOutputChannelInfo[1].source_gain[1] = 0.8;
164 		fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
165 		fOutputChannelInfo[1].source_gain[2] = 0.7;
166 		fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
167 		fOutputChannelInfo[1].source_gain[3] = 0.6;
168 		fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB);
169 		fOutputChannelInfo[1].source_gain[4] = 1.0;
170 		fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO);
171 		fOutputChannelInfo[1].source_gain[5] = 0.7;
172 		fOutputChannelInfo[1].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
173 	} else if (count == 4 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT)) {
174 		TRACE("AssignDefaultSources: 4 channel setup\n");
175 		// left channel:
176 		fOutputChannelInfo[0].source_count = 5;
177 		fOutputChannelInfo[0].source_gain[0] = 1.0;
178 		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
179 		fOutputChannelInfo[0].source_gain[1] = 0.7;
180 		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
181 		fOutputChannelInfo[0].source_gain[2] = 0.6;
182 		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB);
183 		fOutputChannelInfo[0].source_gain[3] = 1.0;
184 		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO);
185 		fOutputChannelInfo[0].source_gain[4] = 0.6;
186 		fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
187 		// right channel:
188 		fOutputChannelInfo[1].source_count = 5;
189 		fOutputChannelInfo[1].source_gain[0] = 1.0;
190 		fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
191 		fOutputChannelInfo[1].source_gain[1] = 0.7;
192 		fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
193 		fOutputChannelInfo[1].source_gain[2] = 0.6;
194 		fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB);
195 		fOutputChannelInfo[1].source_gain[3] = 1.0;
196 		fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO);
197 		fOutputChannelInfo[1].source_gain[4] = 0.6;
198 		fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
199 		// rear-left channel:
200 		fOutputChannelInfo[2].source_count = 4;
201 		fOutputChannelInfo[2].source_gain[0] = 1.0;
202 		fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
203 		fOutputChannelInfo[2].source_gain[1] = 0.6;
204 		fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
205 		fOutputChannelInfo[2].source_gain[2] = 0.9;
206 		fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
207 		fOutputChannelInfo[2].source_gain[3] = 0.6;
208 		fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
209 		// rear-right channel:
210 		fOutputChannelInfo[3].source_count = 4;
211 		fOutputChannelInfo[3].source_gain[0] = 1.0;
212 		fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
213 		fOutputChannelInfo[3].source_gain[1] = 0.6;
214 		fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
215 		fOutputChannelInfo[3].source_gain[2] = 0.9;
216 		fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
217 		fOutputChannelInfo[3].source_gain[3] = 0.6;
218 		fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
219 	} else if (count == 5 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT | B_CHANNEL_CENTER)) {
220 		TRACE("AssignDefaultSources: 5 channel setup\n");
221 		// left channel:
222 		fOutputChannelInfo[0].source_count = 4;
223 		fOutputChannelInfo[0].source_gain[0] = 1.0;
224 		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
225 		fOutputChannelInfo[0].source_gain[1] = 0.6;
226 		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
227 		fOutputChannelInfo[0].source_gain[2] = 1.0;
228 		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
229 		fOutputChannelInfo[0].source_gain[3] = 0.6;
230 		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
231 		// right channel:
232 		fOutputChannelInfo[1].source_count = 4;
233 		fOutputChannelInfo[1].source_gain[0] = 1.0;
234 		fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
235 		fOutputChannelInfo[1].source_gain[1] = 0.6;
236 		fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
237 		fOutputChannelInfo[1].source_gain[2] = 1.0;
238 		fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
239 		fOutputChannelInfo[1].source_gain[3] = 0.6;
240 		fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
241 		// rear-left channel:
242 		fOutputChannelInfo[2].source_count = 4;
243 		fOutputChannelInfo[2].source_gain[0] = 1.0;
244 		fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
245 		fOutputChannelInfo[2].source_gain[1] = 0.6;
246 		fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
247 		fOutputChannelInfo[2].source_gain[2] = 0.9;
248 		fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
249 		fOutputChannelInfo[2].source_gain[3] = 0.6;
250 		fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
251 		// rear-right channel:
252 		fOutputChannelInfo[3].source_count = 4;
253 		fOutputChannelInfo[3].source_gain[0] = 1.0;
254 		fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
255 		fOutputChannelInfo[3].source_gain[1] = 0.6;
256 		fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
257 		fOutputChannelInfo[3].source_gain[2] = 0.9;
258 		fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
259 		fOutputChannelInfo[3].source_gain[3] = 0.6;
260 		fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
261 		// center channel:
262 		fOutputChannelInfo[4].source_count = 3;
263 		fOutputChannelInfo[4].source_gain[0] = 1.0;
264 		fOutputChannelInfo[4].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
265 		fOutputChannelInfo[4].source_gain[1] = 0.5;
266 		fOutputChannelInfo[4].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
267 		fOutputChannelInfo[4].source_gain[2] = 0.8;
268 		fOutputChannelInfo[4].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
269 	} else {
270 		TRACE("AssignDefaultSources: no default setup, adding mono channel to first two channels\n");
271 		if (count >= 1) {
272 			// this is not a left channel, but we add the mono channel anyway
273 			fOutputChannelInfo[0].source_gain[fOutputChannelInfo[0].source_count] = 1.0;
274 			fOutputChannelInfo[0].source_type[fOutputChannelInfo[0].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO);
275 			fOutputChannelInfo[0].source_count++;
276 		}
277 		if (count >= 2) {
278 			// this is not a right channel, but we add the mono channel anyway
279 			fOutputChannelInfo[1].source_gain[fOutputChannelInfo[1].source_count] = 1.0;
280 			fOutputChannelInfo[1].source_type[fOutputChannelInfo[1].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO);
281 			fOutputChannelInfo[1].source_count++;
282 		}
283 	}
284 
285 	for (int i = 0; i < fOutputChannelCount; i++) {
286 		for (int j = 0; j < fOutputChannelInfo[i].source_count; j++) {
287 			TRACE("AssignDefaultSources: output channel %d, source index %d: source_type %2d, source_gain %.3f\n", i, j, fOutputChannelInfo[i].source_type[j], fOutputChannelInfo[i].source_gain[j]);
288 		}
289 	}
290 }
291 
292 int
293 MixerOutput::GetOutputChannelType(int channel)
294 {
295 	if (channel < 0 || channel >= fOutputChannelCount)
296 		return 0;
297 	return fOutputChannelInfo[channel].channel_type;
298 }
299 
300 void
301 MixerOutput::SetOutputChannelGain(int channel, float gain)
302 {
303 	TRACE("SetOutputChannelGain chan %d, gain %.5f\n", channel, gain);
304 	if (channel < 0 || channel >= fOutputChannelCount)
305 		return;
306 	fOutputChannelInfo[channel].channel_gain = gain;
307 }
308 
309 void
310 MixerOutput::AddOutputChannelSource(int channel, int source_type)
311 {
312 	if (channel < 0 || channel >= fOutputChannelCount)
313 		return;
314 	if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
315 		return;
316 	if (fOutputChannelInfo[channel].source_count == MAX_SOURCE_ENTRIES)
317 		return;
318 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
319 		if (fOutputChannelInfo[channel].source_type[i] == source_type)
320 			return;
321 	}
322 	// when adding a new source, use the current gain value from cache
323 	float source_gain = fOutputChannelInfo[channel].source_gain_cache[source_type];
324 	fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count] = source_type;
325 	fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count] = source_gain;
326 	fOutputChannelInfo[channel].source_count++;
327 }
328 
329 void
330 MixerOutput::RemoveOutputChannelSource(int channel, int source_type)
331 {
332 	if (channel < 0 || channel >= fOutputChannelCount)
333 		return;
334 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
335 		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
336 			// when removing a source, save the current gain value into the cache
337 			fOutputChannelInfo[channel].source_gain_cache[source_type] = fOutputChannelInfo[channel].source_gain[i];
338 			// remove the entry
339 			fOutputChannelInfo[channel].source_type[i] = fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count - 1];
340 			fOutputChannelInfo[channel].source_gain[i] = fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count - 1];
341 			fOutputChannelInfo[channel].source_count--;
342 			return;
343 		}
344 	}
345 }
346 
347 void
348 MixerOutput::SetOutputChannelSourceGain(int channel, int source_type, float source_gain)
349 {
350 	if (channel < 0 || channel >= fOutputChannelCount)
351 		return;
352 	// set gain for active source
353 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
354 		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
355 			fOutputChannelInfo[channel].source_gain[i] = source_gain;
356 			return;
357 		}
358 	}
359 	// we don't have an active source of that type, save gain in cache
360 	if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
361 		return;
362 	fOutputChannelInfo[channel].source_gain_cache[source_type] = source_gain;
363 }
364 
365 float
366 MixerOutput::GetOutputChannelSourceGain(int channel, int source_type)
367 {
368 	if (channel < 0 || channel >= fOutputChannelCount)
369 		return 0.0;
370 	// get gain for active source
371 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
372 		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
373 			return fOutputChannelInfo[channel].source_gain[i];
374 		}
375 	}
376 	// we don't have an active source of that type, get gain from cache
377 	if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
378 		return 0.0;
379 	return fOutputChannelInfo[channel].source_gain_cache[source_type];
380 }
381 
382 bool
383 MixerOutput::HasOutputChannelSource(int channel, int source_type)
384 {
385 	if (channel < 0 || channel >= fOutputChannelCount)
386 		return false;
387 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
388 		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
389 			return true;
390 		}
391 	}
392 	return false;
393 }
394 
395 void
396 MixerOutput::SetMuted(bool yesno)
397 {
398 	fMuted = yesno;
399 }
400