1bf7ab50dSStephan Aßmus/*
2a9cf57cfSAxel Dörfler * Copyright 2003-2009 Haiku Inc. All rights reserved.
3bf7ab50dSStephan Aßmus * Distributed under the terms of the MIT License.
4bf7ab50dSStephan Aßmus *
5bf7ab50dSStephan Aßmus * Authors:
6a9cf57cfSAxel Dörfler *		Marcus Overhagen
7bf7ab50dSStephan Aßmus */
8a9cf57cfSAxel Dörfler
9a9cf57cfSAxel Dörfler
10a9cf57cfSAxel Dörfler#include "MixerOutput.h"
11a9cf57cfSAxel Dörfler
12a9cf57cfSAxel Dörfler#include <MediaNode.h>
13a9cf57cfSAxel Dörfler
14678c2017Sbeveloper#include "MixerCore.h"
15f916862cSMarcus Overhagen#include "MixerDebug.h"
16bf7ab50dSStephan Aßmus#include "MixerUtils.h"
17bf7ab50dSStephan Aßmus
18678c2017Sbeveloper
19e6c7c99fSbeveloperMixerOutput::MixerOutput(MixerCore *core, const media_output &output)
20a9cf57cfSAxel Dörfler	:
21a9cf57cfSAxel Dörfler	fCore(core),
22fae6ce82Sbeveloper	fOutput(output),
23fae6ce82Sbeveloper	fOutputChannelCount(0),
241081d7ceSbeveloper	fOutputChannelInfo(0),
25b326a30eSbeveloper	fOutputByteSwap(0),
26b326a30eSbeveloper	fMuted(false)
27678c2017Sbeveloper{
28e6c7c99fSbeveloper	fix_multiaudio_format(&fOutput.format.u.raw_audio);
29e6c7c99fSbeveloper	PRINT_OUTPUT("MixerOutput::MixerOutput", fOutput);
30e6c7c99fSbeveloper	PRINT_CHANNEL_MASK(fOutput.format);
31fae6ce82Sbeveloper
32fae6ce82Sbeveloper	UpdateOutputChannels();
331081d7ceSbeveloper	UpdateByteOrderSwap();
34678c2017Sbeveloper}
35678c2017Sbeveloper
36a9cf57cfSAxel Dörfler
37678c2017SbeveloperMixerOutput::~MixerOutput()
38678c2017Sbeveloper{
39fae6ce82Sbeveloper	delete fOutputChannelInfo;
401081d7ceSbeveloper	delete fOutputByteSwap;
41678c2017Sbeveloper}
42678c2017Sbeveloper
43a9cf57cfSAxel Dörfler
447ee2c804Sbevelopermedia_output &
457ee2c804SbeveloperMixerOutput::MediaOutput()
467ee2c804Sbeveloper{
477ee2c804Sbeveloper	return fOutput;
487ee2c804Sbeveloper}
49c47e5a5aSbeveloper
50a9cf57cfSAxel Dörfler
51c47e5a5aSbevelopervoid
52c47e5a5aSbeveloperMixerOutput::ChangeFormat(const media_multi_audio_format &format)
53c47e5a5aSbeveloper{
54c47e5a5aSbeveloper	fOutput.format.u.raw_audio = format;
55c47e5a5aSbeveloper	fix_multiaudio_format(&fOutput.format.u.raw_audio);
56a9cf57cfSAxel Dörfler
57c47e5a5aSbeveloper	PRINT_OUTPUT("MixerOutput::ChangeFormat", fOutput);
58c47e5a5aSbeveloper	PRINT_CHANNEL_MASK(fOutput.format);
59fae6ce82Sbeveloper
60fae6ce82Sbeveloper	UpdateOutputChannels();
611081d7ceSbeveloper	UpdateByteOrderSwap();
621081d7ceSbeveloper}
631081d7ceSbeveloper
64a9cf57cfSAxel Dörfler
651081d7ceSbevelopervoid
661081d7ceSbeveloperMixerOutput::UpdateByteOrderSwap()
671081d7ceSbeveloper{
681081d7ceSbeveloper	delete fOutputByteSwap;
691081d7ceSbeveloper	fOutputByteSwap = 0;
701081d7ceSbeveloper
711081d7ceSbeveloper	// perhaps we need byte swapping
721081d7ceSbeveloper	if (fOutput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
731081d7ceSbeveloper		if (	fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
741081d7ceSbeveloper			 ||	fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT
751081d7ceSbeveloper			 ||	fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
761081d7ceSbeveloper			fOutputByteSwap = new ByteSwap(fOutput.format.u.raw_audio.format);
771081d7ceSbeveloper		}
781081d7ceSbeveloper	}
79fae6ce82Sbeveloper}
80fae6ce82Sbeveloper
81a9cf57cfSAxel Dörfler
82fae6ce82Sbevelopervoid
83fae6ce82SbeveloperMixerOutput::UpdateOutputChannels()
84fae6ce82Sbeveloper{
85fae6ce82Sbeveloper	output_chan_info *oldInfo = fOutputChannelInfo;
86d91580cdSbeveloper	int oldCount = fOutputChannelCount;
87fae6ce82Sbeveloper
88fae6ce82Sbeveloper	fOutputChannelCount = fOutput.format.u.raw_audio.channel_count;
89fae6ce82Sbeveloper	fOutputChannelInfo = new output_chan_info[fOutputChannelCount];
90fae6ce82Sbeveloper	for (int i = 0; i < fOutputChannelCount; i++) {
91b6270d60Sbeveloper		fOutputChannelInfo[i].channel_type = GetChannelType(i, fOutput.format.u.raw_audio.channel_mask);
92b6270d60Sbeveloper		fOutputChannelInfo[i].channel_gain = 1.0;
93fae6ce82Sbeveloper		fOutputChannelInfo[i].source_count = 1;
94fae6ce82Sbeveloper		fOutputChannelInfo[i].source_gain[0] = 1.0;
95b6270d60Sbeveloper		fOutputChannelInfo[i].source_type[0] = fOutputChannelInfo[i].channel_type;
96e0dc5b6dSbeveloper		// all the cached values are 0.0 for a new channel
97e0dc5b6dSbeveloper		for (int j = 0; j < MAX_CHANNEL_TYPES; j++)
98e0dc5b6dSbeveloper			fOutputChannelInfo[i].source_gain_cache[j] = 0.0;
99fae6ce82Sbeveloper	}
100e0dc5b6dSbeveloper
101fae6ce82Sbeveloper	AssignDefaultSources();
102bf7ab50dSStephan Aßmus
103fae6ce82Sbeveloper	// apply old gains and sources, overriding the 1.0 gain defaults for the old channels
104fae6ce82Sbeveloper	if (oldInfo != 0 && oldCount != 0) {
105fae6ce82Sbeveloper		for (int i = 0; i < fOutputChannelCount; i++) {
106fae6ce82Sbeveloper			for (int j = 0; j < oldCount; j++) {
107b6270d60Sbeveloper				if (fOutputChannelInfo[i].channel_type == oldInfo[j].channel_type) {
108d91580cdSbeveloper					fOutputChannelInfo[i].channel_gain = oldInfo[j].channel_gain;
109d91580cdSbeveloper					fOutputChannelInfo[i].source_count = oldInfo[j].source_count;
110fae6ce82Sbeveloper					for (int k = 0; k < fOutputChannelInfo[i].source_count; k++) {
111d91580cdSbeveloper						fOutputChannelInfo[i].source_gain[k] = oldInfo[j].source_gain[k];
112d91580cdSbeveloper						fOutputChannelInfo[i].source_type[k] = oldInfo[j].source_type[k];
113fae6ce82Sbeveloper					}
114e0dc5b6dSbeveloper					// also copy the old gain cache
115e0dc5b6dSbeveloper					for (int k = 0; k < MAX_CHANNEL_TYPES; k++)
116e0dc5b6dSbeveloper						fOutputChannelInfo[i].source_gain_cache[k] = oldInfo[j].source_gain_cache[k];
117fae6ce82Sbeveloper					break;
118fae6ce82Sbeveloper				}
119fae6ce82Sbeveloper			}
120fae6ce82Sbeveloper		}
121fae6ce82Sbeveloper		// also delete the old info array
122fae6ce82Sbeveloper		delete [] oldInfo;
123fae6ce82Sbeveloper	}
124fae6ce82Sbeveloper	for (int i = 0; i < fOutputChannelCount; i++)
1259c3be6a5Sbeveloper		TRACE("UpdateOutputChannels: output channel %d, type %2d, gain %.3f\n", i, fOutputChannelInfo[i].channel_type, fOutputChannelInfo[i].channel_gain);
126fae6ce82Sbeveloper}
127fae6ce82Sbeveloper
128a9cf57cfSAxel Dörfler
129fae6ce82Sbevelopervoid
130fae6ce82SbeveloperMixerOutput::AssignDefaultSources()
131fae6ce82Sbeveloper{
132806cf560Sbeveloper	uint32 mask = fOutput.format.u.raw_audio.channel_mask;
133d91580cdSbeveloper	int count = fOutputChannelCount;
134a9cf57cfSAxel Dörfler
135806cf560Sbeveloper	// assign default sources for a few known setups,
136806cf560Sbeveloper	// everything else is left unchanged (it already is 1:1)
137806cf560Sbeveloper	if (count == 1 && mask & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
138806cf560Sbeveloper		// we have only one phycial output channel, and use it as a mix of
139806cf560Sbeveloper		// left, right, rear-left, rear-right, center and sub
140a2ca4723Sbeveloper		TRACE("AssignDefaultSources: 1 channel setup\n");
14169316791Sbeveloper		fOutputChannelInfo[0].source_count = 9;
142806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[0] = 1.0;
143806cf560Sbeveloper		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
144806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[1] = 1.0;
145806cf560Sbeveloper		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
146806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[2] = 0.8;
147806cf560Sbeveloper		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
148806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[3] = 0.8;
149806cf560Sbeveloper		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
150806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[4] = 0.7;
151806cf560Sbeveloper		fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
152806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[5] = 0.6;
153806cf560Sbeveloper		fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SUB);
154ab276ac8Sbeveloper		fOutputChannelInfo[0].source_gain[6] = 1.0;
155ab276ac8Sbeveloper		fOutputChannelInfo[0].source_type[6] = ChannelMaskToChannelType(B_CHANNEL_MONO);
15669316791Sbeveloper		fOutputChannelInfo[0].source_gain[7] = 0.7;
15769316791Sbeveloper		fOutputChannelInfo[0].source_type[7] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
15869316791Sbeveloper		fOutputChannelInfo[0].source_gain[8] = 0.7;
15969316791Sbeveloper		fOutputChannelInfo[0].source_type[8] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
160806cf560Sbeveloper	} else if (count == 2 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
161806cf560Sbeveloper		// we have have two phycial output channels
162a2ca4723Sbeveloper		TRACE("AssignDefaultSources: 2 channel setup\n");
163806cf560Sbeveloper		// left channel:
16469316791Sbeveloper		fOutputChannelInfo[0].source_count = 6;
165806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[0] = 1.0;
166806cf560Sbeveloper		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
167806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[1] = 0.8;
168806cf560Sbeveloper		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
169806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[2] = 0.7;
170806cf560Sbeveloper		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
171806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[3] = 0.6;
172806cf560Sbeveloper		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB);
173ab276ac8Sbeveloper		fOutputChannelInfo[0].source_gain[4] = 1.0;
174ab276ac8Sbeveloper		fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO);
17569316791Sbeveloper		fOutputChannelInfo[0].source_gain[5] = 0.7;
17669316791Sbeveloper		fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
177806cf560Sbeveloper		// right channel:
17869316791Sbeveloper		fOutputChannelInfo[1].source_count = 6;
179806cf560Sbeveloper		fOutputChannelInfo[1].source_gain[0] = 1.0;
180806cf560Sbeveloper		fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
181806cf560Sbeveloper		fOutputChannelInfo[1].source_gain[1] = 0.8;
182806cf560Sbeveloper		fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
183806cf560Sbeveloper		fOutputChannelInfo[1].source_gain[2] = 0.7;
184806cf560Sbeveloper		fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
185806cf560Sbeveloper		fOutputChannelInfo[1].source_gain[3] = 0.6;
186806cf560Sbeveloper		fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB);
187ab276ac8Sbeveloper		fOutputChannelInfo[1].source_gain[4] = 1.0;
188ab276ac8Sbeveloper		fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO);
18969316791Sbeveloper		fOutputChannelInfo[1].source_gain[5] = 0.7;
19069316791Sbeveloper		fOutputChannelInfo[1].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
191806cf560Sbeveloper	} else if (count == 4 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT)) {
192a2ca4723Sbeveloper		TRACE("AssignDefaultSources: 4 channel setup\n");
193806cf560Sbeveloper		// left channel:
19469316791Sbeveloper		fOutputChannelInfo[0].source_count = 5;
195806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[0] = 1.0;
196806cf560Sbeveloper		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
197806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[1] = 0.7;
198806cf560Sbeveloper		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
199806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[2] = 0.6;
200806cf560Sbeveloper		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB);
201ab276ac8Sbeveloper		fOutputChannelInfo[0].source_gain[3] = 1.0;
202ab276ac8Sbeveloper		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO);
20369316791Sbeveloper		fOutputChannelInfo[0].source_gain[4] = 0.6;
20469316791Sbeveloper		fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
205806cf560Sbeveloper		// right channel:
20669316791Sbeveloper		fOutputChannelInfo[1].source_count = 5;
207806cf560Sbeveloper		fOutputChannelInfo[1].source_gain[0] = 1.0;
208806cf560Sbeveloper		fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
209806cf560Sbeveloper		fOutputChannelInfo[1].source_gain[1] = 0.7;
210806cf560Sbeveloper		fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
211806cf560Sbeveloper		fOutputChannelInfo[1].source_gain[2] = 0.6;
212806cf560Sbeveloper		fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB);
213ab276ac8Sbeveloper		fOutputChannelInfo[1].source_gain[3] = 1.0;
214ab276ac8Sbeveloper		fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO);
21569316791Sbeveloper		fOutputChannelInfo[1].source_gain[4] = 0.6;
21669316791Sbeveloper		fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
217806cf560Sbeveloper		// rear-left channel:
21869316791Sbeveloper		fOutputChannelInfo[2].source_count = 4;
219806cf560Sbeveloper		fOutputChannelInfo[2].source_gain[0] = 1.0;
220806cf560Sbeveloper		fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
221806cf560Sbeveloper		fOutputChannelInfo[2].source_gain[1] = 0.6;
222806cf560Sbeveloper		fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
223ab276ac8Sbeveloper		fOutputChannelInfo[2].source_gain[2] = 0.9;
224ab276ac8Sbeveloper		fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
22569316791Sbeveloper		fOutputChannelInfo[2].source_gain[3] = 0.6;
22669316791Sbeveloper		fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
227806cf560Sbeveloper		// rear-right channel:
22869316791Sbeveloper		fOutputChannelInfo[3].source_count = 4;
229806cf560Sbeveloper		fOutputChannelInfo[3].source_gain[0] = 1.0;
230806cf560Sbeveloper		fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
231806cf560Sbeveloper		fOutputChannelInfo[3].source_gain[1] = 0.6;
232806cf560Sbeveloper		fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
233ab276ac8Sbeveloper		fOutputChannelInfo[3].source_gain[2] = 0.9;
234ab276ac8Sbeveloper		fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
23569316791Sbeveloper		fOutputChannelInfo[3].source_gain[3] = 0.6;
23669316791Sbeveloper		fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
237806cf560Sbeveloper	} else if (count == 5 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT | B_CHANNEL_CENTER)) {
238a2ca4723Sbeveloper		TRACE("AssignDefaultSources: 5 channel setup\n");
239806cf560Sbeveloper		// left channel:
24069316791Sbeveloper		fOutputChannelInfo[0].source_count = 4;
241806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[0] = 1.0;
242806cf560Sbeveloper		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
243806cf560Sbeveloper		fOutputChannelInfo[0].source_gain[1] = 0.6;
244806cf560Sbeveloper		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
245ab276ac8Sbeveloper		fOutputChannelInfo[0].source_gain[2] = 1.0;
246ab276ac8Sbeveloper		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
24769316791Sbeveloper		fOutputChannelInfo[0].source_gain[3] = 0.6;
24869316791Sbeveloper		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
249806cf560Sbeveloper		// right channel:
25069316791Sbeveloper		fOutputChannelInfo[1].source_count = 4;
251806cf560Sbeveloper		fOutputChannelInfo[1].source_gain[0] = 1.0;
252806cf560Sbeveloper		fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
253806cf560Sbeveloper		fOutputChannelInfo[1].source_gain[1] = 0.6;
254806cf560Sbeveloper		fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
255ab276ac8Sbeveloper		fOutputChannelInfo[1].source_gain[2] = 1.0;
256ab276ac8Sbeveloper		fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
25769316791Sbeveloper		fOutputChannelInfo[1].source_gain[3] = 0.6;
25869316791Sbeveloper		fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
259806cf560Sbeveloper		// rear-left channel:
26069316791Sbeveloper		fOutputChannelInfo[2].source_count = 4;
261806cf560Sbeveloper		fOutputChannelInfo[2].source_gain[0] = 1.0;
262806cf560Sbeveloper		fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
263806cf560Sbeveloper		fOutputChannelInfo[2].source_gain[1] = 0.6;
264806cf560Sbeveloper		fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
265ab276ac8Sbeveloper		fOutputChannelInfo[2].source_gain[2] = 0.9;
266ab276ac8Sbeveloper		fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
26769316791Sbeveloper		fOutputChannelInfo[2].source_gain[3] = 0.6;
26869316791Sbeveloper		fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
269806cf560Sbeveloper		// rear-right channel:
27069316791Sbeveloper		fOutputChannelInfo[3].source_count = 4;
271806cf560Sbeveloper		fOutputChannelInfo[3].source_gain[0] = 1.0;
272806cf560Sbeveloper		fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
273806cf560Sbeveloper		fOutputChannelInfo[3].source_gain[1] = 0.6;
274806cf560Sbeveloper		fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
275ab276ac8Sbeveloper		fOutputChannelInfo[3].source_gain[2] = 0.9;
276ab276ac8Sbeveloper		fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
27769316791Sbeveloper		fOutputChannelInfo[3].source_gain[3] = 0.6;
27869316791Sbeveloper		fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
279806cf560Sbeveloper		// center channel:
280ab276ac8Sbeveloper		fOutputChannelInfo[4].source_count = 3;
281806cf560Sbeveloper		fOutputChannelInfo[4].source_gain[0] = 1.0;
282806cf560Sbeveloper		fOutputChannelInfo[4].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
283806cf560Sbeveloper		fOutputChannelInfo[4].source_gain[1] = 0.5;
284806cf560Sbeveloper		fOutputChannelInfo[4].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
285ab276ac8Sbeveloper		fOutputChannelInfo[4].source_gain[2] = 0.8;
286ab276ac8Sbeveloper		fOutputChannelInfo[4].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
287806cf560Sbeveloper	} else {
288ab276ac8Sbeveloper		TRACE("AssignDefaultSources: no default setup, adding mono channel to first two channels\n");
289ab276ac8Sbeveloper		if (count >= 1) {
290ab276ac8Sbeveloper			// this is not a left channel, but we add the mono channel anyway
291ab276ac8Sbeveloper			fOutputChannelInfo[0].source_gain[fOutputChannelInfo[0].source_count] = 1.0;
292ab276ac8Sbeveloper			fOutputChannelInfo[0].source_type[fOutputChannelInfo[0].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO);
293ab276ac8Sbeveloper			fOutputChannelInfo[0].source_count++;
294ab276ac8Sbeveloper		}
295ab276ac8Sbeveloper		if (count >= 2) {
296ab276ac8Sbeveloper			// this is not a right channel, but we add the mono channel anyway
297ab276ac8Sbeveloper			fOutputChannelInfo[1].source_gain[fOutputChannelInfo[1].source_count] = 1.0;
298ab276ac8Sbeveloper			fOutputChannelInfo[1].source_type[fOutputChannelInfo[1].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO);
299ab276ac8Sbeveloper			fOutputChannelInfo[1].source_count++;
300ab276ac8Sbeveloper		}
301806cf560Sbeveloper	}
302806cf560Sbeveloper
303fae6ce82Sbeveloper	for (int i = 0; i < fOutputChannelCount; i++) {
304fae6ce82Sbeveloper		for (int j = 0; j < fOutputChannelInfo[i].source_count; j++) {
305b6270d60Sbeveloper			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]);
306fae6ce82Sbeveloper		}
307fae6ce82Sbeveloper	}
308fae6ce82Sbeveloper}
309fae6ce82Sbeveloper
310a9cf57cfSAxel Dörfler
3119c3be6a5Sbeveloperint
3120c63c7d0SbeveloperMixerOutput::GetOutputChannelType(int channel)
313fae6ce82Sbeveloper{
314fae6ce82Sbeveloper	if (channel < 0 || channel >= fOutputChannelCount)
315fae6ce82Sbeveloper		return 0;
316b6270d60Sbeveloper	return fOutputChannelInfo[channel].channel_type;
317fae6ce82Sbeveloper}
318fae6ce82Sbeveloper
319a9cf57cfSAxel Dörfler
320fae6ce82Sbevelopervoid
321fae6ce82SbeveloperMixerOutput::SetOutputChannelGain(int channel, float gain)
322fae6ce82Sbeveloper{
3239391f0a5Sbeveloper	TRACE("SetOutputChannelGain chan %d, gain %.5f\n", channel, gain);
324fae6ce82Sbeveloper	if (channel < 0 || channel >= fOutputChannelCount)
325fae6ce82Sbeveloper		return;
326b6270d60Sbeveloper	fOutputChannelInfo[channel].channel_gain = gain;
327fae6ce82Sbeveloper}
328fae6ce82Sbeveloper
329a9cf57cfSAxel Dörfler
330fae6ce82Sbevelopervoid
331e0dc5b6dSbeveloperMixerOutput::AddOutputChannelSource(int channel, int source_type)
332fae6ce82Sbeveloper{
333fae6ce82Sbeveloper	if (channel < 0 || channel >= fOutputChannelCount)
334fae6ce82Sbeveloper		return;
335e0dc5b6dSbeveloper	if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
336e0dc5b6dSbeveloper		return;
337b6270d60Sbeveloper	if (fOutputChannelInfo[channel].source_count == MAX_SOURCE_ENTRIES)
338fae6ce82Sbeveloper		return;
339fae6ce82Sbeveloper	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
340fae6ce82Sbeveloper		if (fOutputChannelInfo[channel].source_type[i] == source_type)
341fae6ce82Sbeveloper			return;
342fae6ce82Sbeveloper	}
343e0dc5b6dSbeveloper	// when adding a new source, use the current gain value from cache
344e0dc5b6dSbeveloper	float source_gain = fOutputChannelInfo[channel].source_gain_cache[source_type];
345fae6ce82Sbeveloper	fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count] = source_type;
346fae6ce82Sbeveloper	fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count] = source_gain;
347fae6ce82Sbeveloper	fOutputChannelInfo[channel].source_count++;
348fae6ce82Sbeveloper}
349fae6ce82Sbeveloper
350a9cf57cfSAxel Dörfler
351fae6ce82Sbevelopervoid
352b6270d60SbeveloperMixerOutput::RemoveOutputChannelSource(int channel, int source_type)
353fae6ce82Sbeveloper{
354fae6ce82Sbeveloper	if (channel < 0 || channel >= fOutputChannelCount)
355fae6ce82Sbeveloper		return;
356fae6ce82Sbeveloper	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
357fae6ce82Sbeveloper		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
358e0dc5b6dSbeveloper			// when removing a source, save the current gain value into the cache
359e0dc5b6dSbeveloper			fOutputChannelInfo[channel].source_gain_cache[source_type] = fOutputChannelInfo[channel].source_gain[i];
360e0dc5b6dSbeveloper			// remove the entry
361fae6ce82Sbeveloper			fOutputChannelInfo[channel].source_type[i] = fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count - 1];
362fae6ce82Sbeveloper			fOutputChannelInfo[channel].source_gain[i] = fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count - 1];
363fae6ce82Sbeveloper			fOutputChannelInfo[channel].source_count--;
364fae6ce82Sbeveloper			return;
365fae6ce82Sbeveloper		}
366fae6ce82Sbeveloper	}
367fae6ce82Sbeveloper}
368fae6ce82Sbeveloper
369a9cf57cfSAxel Dörfler
370e0dc5b6dSbevelopervoid
371b6270d60SbeveloperMixerOutput::SetOutputChannelSourceGain(int channel, int source_type, float source_gain)
372fae6ce82Sbeveloper{
373fae6ce82Sbeveloper	if (channel < 0 || channel >= fOutputChannelCount)
374e0dc5b6dSbeveloper		return;
375e0dc5b6dSbeveloper	// set gain for active source
376fae6ce82Sbeveloper	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
377fae6ce82Sbeveloper		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
378fae6ce82Sbeveloper			fOutputChannelInfo[channel].source_gain[i] = source_gain;
379e0dc5b6dSbeveloper			return;
380fae6ce82Sbeveloper		}
381fae6ce82Sbeveloper	}
382e0dc5b6dSbeveloper	// we don't have an active source of that type, save gain in cache
383e0dc5b6dSbeveloper	if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
384e0dc5b6dSbeveloper		return;
385e0dc5b6dSbeveloper	fOutputChannelInfo[channel].source_gain_cache[source_type] = source_gain;
386fae6ce82Sbeveloper}
387fae6ce82Sbeveloper
388a9cf57cfSAxel Dörfler
389fae6ce82Sbeveloperfloat
390b6270d60SbeveloperMixerOutput::GetOutputChannelSourceGain(int channel, int source_type)
391fae6ce82Sbeveloper{
392fae6ce82Sbeveloper	if (channel < 0 || channel >= fOutputChannelCount)
393b6270d60Sbeveloper		return 0.0;
394e0dc5b6dSbeveloper	// get gain for active source
395fae6ce82Sbeveloper	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
396fae6ce82Sbeveloper		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
397fae6ce82Sbeveloper			return fOutputChannelInfo[channel].source_gain[i];
398fae6ce82Sbeveloper		}
399fae6ce82Sbeveloper	}
400e0dc5b6dSbeveloper	// we don't have an active source of that type, get gain from cache
401e0dc5b6dSbeveloper	if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
402e0dc5b6dSbeveloper		return 0.0;
403e0dc5b6dSbeveloper	return fOutputChannelInfo[channel].source_gain_cache[source_type];
404fae6ce82Sbeveloper}
405fae6ce82Sbeveloper
406a9cf57cfSAxel Dörfler
407b6270d60Sbeveloperbool
408b6270d60SbeveloperMixerOutput::HasOutputChannelSource(int channel, int source_type)
409fae6ce82Sbeveloper{
410fae6ce82Sbeveloper	if (channel < 0 || channel >= fOutputChannelCount)
411b6270d60Sbeveloper		return false;
412b6270d60Sbeveloper	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
413b6270d60Sbeveloper		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
414b6270d60Sbeveloper			return true;
415b6270d60Sbeveloper		}
416fae6ce82Sbeveloper	}
417b6270d60Sbeveloper	return false;
418c47e5a5aSbeveloper}
419b326a30eSbeveloper
420a9cf57cfSAxel Dörfler
421b326a30eSbevelopervoid
422b326a30eSbeveloperMixerOutput::SetMuted(bool yesno)
423b326a30eSbeveloper{
424b326a30eSbeveloper	fMuted = yesno;
42557b75f14Sbeveloper}
426