2 * Copyright 2003-2009 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
10 #include "MixerOutput.h"
12 #include <MediaNode.h>
14 #include "MixerCore.h"
15 #include "MixerDebug.h"
16 #include "MixerUtils.h"
19 MixerOutput::MixerOutput(MixerCore
*core
, const media_output
&output
)
23 fOutputChannelCount(0),
24 fOutputChannelInfo(0),
28 fix_multiaudio_format(&fOutput
.format
.u
.raw_audio
);
29 PRINT_OUTPUT("MixerOutput::MixerOutput", fOutput
);
30 PRINT_CHANNEL_MASK(fOutput
.format
);
32 UpdateOutputChannels();
33 UpdateByteOrderSwap();
37 MixerOutput::~MixerOutput()
39 delete fOutputChannelInfo
;
40 delete fOutputByteSwap
;
45 MixerOutput::MediaOutput()
52 MixerOutput::ChangeFormat(const media_multi_audio_format
&format
)
54 fOutput
.format
.u
.raw_audio
= format
;
55 fix_multiaudio_format(&fOutput
.format
.u
.raw_audio
);
57 PRINT_OUTPUT("MixerOutput::ChangeFormat", fOutput
);
58 PRINT_CHANNEL_MASK(fOutput
.format
);
60 UpdateOutputChannels();
61 UpdateByteOrderSwap();
66 MixerOutput::UpdateByteOrderSwap()
68 delete fOutputByteSwap
;
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
);
83 MixerOutput::UpdateOutputChannels()
85 output_chan_info
*oldInfo
= fOutputChannelInfo
;
86 int oldCount
= fOutputChannelCount
;
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;
101 AssignDefaultSources();
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
];
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
];
121 // also delete the old info array
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
);
130 MixerOutput::AssignDefaultSources()
132 uint32 mask
= fOutput
.format
.u
.raw_audio
.channel_mask
;
133 int count
= fOutputChannelCount
;
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");
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
);
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");
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
);
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");
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
);
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
);
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
);
288 TRACE("AssignDefaultSources: no default setup, adding mono channel to first two channels\n");
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
++;
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
++;
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
]);
312 MixerOutput::GetOutputChannelType(int channel
)
314 if (channel
< 0 || channel
>= fOutputChannelCount
)
316 return fOutputChannelInfo
[channel
].channel_type
;
321 MixerOutput::SetOutputChannelGain(int channel
, float gain
)
323 TRACE("SetOutputChannelGain chan %d, gain %.5f\n", channel
, gain
);
324 if (channel
< 0 || channel
>= fOutputChannelCount
)
326 fOutputChannelInfo
[channel
].channel_gain
= gain
;
331 MixerOutput::AddOutputChannelSource(int channel
, int source_type
)
333 if (channel
< 0 || channel
>= fOutputChannelCount
)
335 if (source_type
< 0 || source_type
>= MAX_CHANNEL_TYPES
)
337 if (fOutputChannelInfo
[channel
].source_count
== MAX_SOURCE_ENTRIES
)
339 for (int i
= 0; i
< fOutputChannelInfo
[channel
].source_count
; i
++) {
340 if (fOutputChannelInfo
[channel
].source_type
[i
] == source_type
)
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
++;
352 MixerOutput::RemoveOutputChannelSource(int channel
, int source_type
)
354 if (channel
< 0 || channel
>= fOutputChannelCount
)
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
];
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
--;
371 MixerOutput::SetOutputChannelSourceGain(int channel
, int source_type
, float source_gain
)
373 if (channel
< 0 || channel
>= fOutputChannelCount
)
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
;
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
)
385 fOutputChannelInfo
[channel
].source_gain_cache
[source_type
] = source_gain
;
390 MixerOutput::GetOutputChannelSourceGain(int channel
, int source_type
)
392 if (channel
< 0 || channel
>= fOutputChannelCount
)
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
];
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
)
403 return fOutputChannelInfo
[channel
].source_gain_cache
[source_type
];
408 MixerOutput::HasOutputChannelSource(int channel
, int source_type
)
410 if (channel
< 0 || channel
>= fOutputChannelCount
)
412 for (int i
= 0; i
< fOutputChannelInfo
[channel
].source_count
; i
++) {
413 if (fOutputChannelInfo
[channel
].source_type
[i
] == source_type
) {
422 MixerOutput::SetMuted(bool yesno
)