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