xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp (revision 69517c1537473b9ae5a17672bed91790966dc583)
12e9d6607Sbeveloper #include <Buffer.h>
27b0daf5cSbeveloper #include <string.h>
38d28117fSbeveloper #include <TimeSource.h> // XXX debug only
4678c2017Sbeveloper #include "MixerInput.h"
5678c2017Sbeveloper #include "MixerCore.h"
6e6c7c99fSbeveloper #include "MixerUtils.h"
77b0daf5cSbeveloper #include "Resampler.h"
888777023Sbeveloper #include "ByteSwap.h"
9e6c7c99fSbeveloper #include "debug.h"
10678c2017Sbeveloper 
118d28117fSbeveloper MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount)
12e6c7c99fSbeveloper  :	fCore(core),
132e9d6607Sbeveloper  	fInput(input),
1488777023Sbeveloper 	fInputByteSwap(0),
151c237c18Sbeveloper 	fEnabled(true),
162e9d6607Sbeveloper 	fInputChannelInfo(0),
172e9d6607Sbeveloper 	fInputChannelCount(0),
182e9d6607Sbeveloper 	fInputChannelMask(0),
192e9d6607Sbeveloper 	fMixerChannelInfo(0),
202e9d6607Sbeveloper 	fMixerChannelCount(0),
212e9d6607Sbeveloper 	fMixBuffer(0),
227b0daf5cSbeveloper 	fMixBufferFrameRate(0),
237b0daf5cSbeveloper 	fMixBufferFrameCount(0),
24af8d0a4dSbeveloper 	fLastDataAvailableTime(-1),
257b0daf5cSbeveloper 	fResampler(0),
26356855c3Sbeveloper 	fRtmPool(0),
279c3be6a5Sbeveloper 	fUserOverridesChannelDestinations(false)
28678c2017Sbeveloper {
29e6c7c99fSbeveloper 	fix_multiaudio_format(&fInput.format.u.raw_audio);
30e6c7c99fSbeveloper 	PRINT_INPUT("MixerInput::MixerInput", fInput);
31e6c7c99fSbeveloper 	PRINT_CHANNEL_MASK(fInput.format);
322e9d6607Sbeveloper 
332e9d6607Sbeveloper 	ASSERT(fInput.format.u.raw_audio.channel_count > 0);
342e9d6607Sbeveloper 
359c3be6a5Sbeveloper 	for (int i = 0; i <	MAX_CHANNEL_TYPES; i++)
369c3be6a5Sbeveloper 		fChannelTypeGain[i] = 1.0f;
379c3be6a5Sbeveloper 
382e9d6607Sbeveloper 	fInputChannelCount = fInput.format.u.raw_audio.channel_count;
392e9d6607Sbeveloper 	fInputChannelMask = fInput.format.u.raw_audio.channel_mask;
402e9d6607Sbeveloper 	fInputChannelInfo = new input_chan_info[fInputChannelCount];
412e9d6607Sbeveloper 
4288777023Sbeveloper 	// perhaps we need byte swapping
4388777023Sbeveloper 	if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
4488777023Sbeveloper 		if (	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
4588777023Sbeveloper 			 ||	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT
4688777023Sbeveloper 			 ||	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
4788777023Sbeveloper 			fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format);
4888777023Sbeveloper 		}
4988777023Sbeveloper 	}
5088777023Sbeveloper 
512e9d6607Sbeveloper 	// initialize fInputChannelInfo
522e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++) {
532e9d6607Sbeveloper 		fInputChannelInfo[i].buffer_base = 0;	// will be set by SetMixBufferFormat()
549c3be6a5Sbeveloper 		fInputChannelInfo[i].destination_mask = 0;	// will be set by UpdateInputChannelDestinationMask()
552e9d6607Sbeveloper 		fInputChannelInfo[i].gain = 1.0;
562e9d6607Sbeveloper 	}
572e9d6607Sbeveloper 
587b0daf5cSbeveloper 	// create resamplers
597b0daf5cSbeveloper 	fResampler = new Resampler * [fInputChannelCount];
607b0daf5cSbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
617b0daf5cSbeveloper 		fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT);
627b0daf5cSbeveloper 
639c3be6a5Sbeveloper 	// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations()
642e9d6607Sbeveloper 
658d28117fSbeveloper 	SetMixBufferFormat(mixFrameRate, mixFrameCount);
66678c2017Sbeveloper }
67678c2017Sbeveloper 
68678c2017Sbeveloper MixerInput::~MixerInput()
69678c2017Sbeveloper {
702e9d6607Sbeveloper 	if (fMixBuffer)
712e9d6607Sbeveloper 		rtm_free(fMixBuffer);
72356855c3Sbeveloper 	if (fRtmPool)
73356855c3Sbeveloper 		rtm_delete_pool(fRtmPool);
742e9d6607Sbeveloper 	delete [] fInputChannelInfo;
752e9d6607Sbeveloper 	delete [] fMixerChannelInfo;
767b0daf5cSbeveloper 
777b0daf5cSbeveloper 	// delete resamplers
787b0daf5cSbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
797b0daf5cSbeveloper 		delete fResampler[i];
807b0daf5cSbeveloper 	delete [] fResampler;
81678c2017Sbeveloper }
82678c2017Sbeveloper 
83678c2017Sbeveloper void
84678c2017Sbeveloper MixerInput::BufferReceived(BBuffer *buffer)
85678c2017Sbeveloper {
8688777023Sbeveloper 	void *data;
8788777023Sbeveloper 	size_t size;
8888777023Sbeveloper 	bigtime_t start;
8988777023Sbeveloper 
90d5848e21Sbeveloper 	if (!fMixBuffer) {
91a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n");
92d5848e21Sbeveloper 		return;
93d5848e21Sbeveloper 	}
942e9d6607Sbeveloper 
9588777023Sbeveloper 	data = buffer->Data();
9688777023Sbeveloper 	size = buffer->SizeUsed();
9788777023Sbeveloper 	start = buffer->Header()->start_time;
988d28117fSbeveloper 	if (start < 0) {
99a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: buffer with negative start time of %Ld dropped\n", start);
1008d28117fSbeveloper 		return;
1018d28117fSbeveloper 	}
10288777023Sbeveloper 
103af8d0a4dSbeveloper 	fLastDataAvailableTime = start + buffer_duration(fInput.format.u.raw_audio);
104af8d0a4dSbeveloper 
10588777023Sbeveloper 	// swap the byte order of this buffer, if necessary
10688777023Sbeveloper 	if (fInputByteSwap)
10788777023Sbeveloper 		fInputByteSwap->Swap(data, size);
10888777023Sbeveloper 
1098d28117fSbeveloper 	int32 offset = frames_for_duration(fMixBufferFrameRate, start) % fMixBufferFrameCount;
1108d28117fSbeveloper 
111191033efSbeveloper 	PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", start, offset);
1127b0daf5cSbeveloper 
113191033efSbeveloper 	int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio);
1147619f562Sbeveloper 	int out_frames = int((in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate); // XXX losing fractions
1157619f562Sbeveloper 	// XXX we should better accumulate the fractions from previous buffers, and also check previous end offset
1167619f562Sbeveloper 	// XXX to only add an output frame if needed (but we also need to use arrival times to cope with lost buffers).
1177619f562Sbeveloper 	// XXX This workaround will very often (but not always) cause the first sample of the next buffer to overwrite
1187619f562Sbeveloper 	// XXX the last sample of the current buffer (but that's better then having some random data at that place)
1197619f562Sbeveloper 	if (fMixBufferFrameRate % int(0.5 + fInput.format.u.raw_audio.frame_rate) != 0)
1207619f562Sbeveloper 		out_frames++;
1217b0daf5cSbeveloper 
1228d28117fSbeveloper 	//printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames);
1238df36cddSbeveloper 
1247b0daf5cSbeveloper 	if (offset + out_frames > fMixBufferFrameCount) {
1257b0daf5cSbeveloper 
1267b0daf5cSbeveloper 		int out_frames1 = fMixBufferFrameCount - offset;
1277b0daf5cSbeveloper 		int out_frames2 = out_frames - out_frames1;
1287b0daf5cSbeveloper 		int in_frames1 = (out_frames1 * in_frames) / out_frames;
1297b0daf5cSbeveloper 		int in_frames2 = in_frames - in_frames1;
1307b0daf5cSbeveloper 
1317619f562Sbeveloper 		PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames1 - 1, 0, out_frames2 - 1);
1328df36cddSbeveloper 
133191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d, in_frames1 %5d, out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n",
134191033efSbeveloper 			  in_frames, out_frames, in_frames1, out_frames1, in_frames2, out_frames2);
1357b0daf5cSbeveloper 
1368d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
1378d28117fSbeveloper 
1387b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
13978563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
14078563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
1417b0daf5cSbeveloper 									in_frames1,
1428d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
1437b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
1447b0daf5cSbeveloper 									out_frames1,
1457b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
1467b0daf5cSbeveloper 
1477d970b31Sbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio) + in_frames1 * bytes_per_frame(fInput.format.u.raw_audio),
14878563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
1497b0daf5cSbeveloper 									in_frames2,
1507b0daf5cSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base),
1517b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
1527b0daf5cSbeveloper 									out_frames2,
1537b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
1547b0daf5cSbeveloper 		}
1557b0daf5cSbeveloper 	} else {
1567b0daf5cSbeveloper 
1577619f562Sbeveloper 		PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames - 1);
158191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d\n", in_frames, out_frames);
1598d28117fSbeveloper 
1608d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
1617b0daf5cSbeveloper 
1627b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
16378563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
16478563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
1657b0daf5cSbeveloper 									in_frames,
1668d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
1677b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
1687b0daf5cSbeveloper 									out_frames,
1697b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
1707b0daf5cSbeveloper 		}
1717b0daf5cSbeveloper 	}
172678c2017Sbeveloper }
1737ee2c804Sbeveloper 
1747ee2c804Sbeveloper media_input &
1757ee2c804Sbeveloper MixerInput::MediaInput()
1767ee2c804Sbeveloper {
1777ee2c804Sbeveloper 	return fInput;
1787ee2c804Sbeveloper }
179e6c7c99fSbeveloper 
180e6c7c99fSbeveloper int32
181e6c7c99fSbeveloper MixerInput::ID()
182e6c7c99fSbeveloper {
183e6c7c99fSbeveloper 	return fInput.destination.id;
184e6c7c99fSbeveloper }
185e6c7c99fSbeveloper 
186fae6ce82Sbeveloper uint32
187fae6ce82Sbeveloper MixerInput::GetInputChannelCount()
188fae6ce82Sbeveloper {
189fae6ce82Sbeveloper 	return fInputChannelCount;
190fae6ce82Sbeveloper }
191fae6ce82Sbeveloper 
1922e9d6607Sbeveloper void
1939c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type)
1942e9d6607Sbeveloper {
1959c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
196e6c7c99fSbeveloper 
1972e9d6607Sbeveloper 	// test if the channel is valid
1982e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
1992e9d6607Sbeveloper 		return;
2002e9d6607Sbeveloper 
2012e9d6607Sbeveloper 	// test if it is already set
2029c3be6a5Sbeveloper 	if (fInputChannelInfo[channel].destination_mask & mask)
2032e9d6607Sbeveloper 		return;
2042e9d6607Sbeveloper 
2059c3be6a5Sbeveloper 	// verify that no other channel has id
2069c3be6a5Sbeveloper 	if (-1 != GetInputChannelForDestination(destination_type)) {
2079c3be6a5Sbeveloper 		ERROR("MixerInput::AddInputChannelDestination: destination_type %d already assigned to channel %d\n", destination_type, GetInputChannelForDestination(destination_type));
2089c3be6a5Sbeveloper 		return;
2099c3be6a5Sbeveloper 	}
2102e9d6607Sbeveloper 
2112e9d6607Sbeveloper 	// add it to specified channel
2129c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask |= mask;
2132e9d6607Sbeveloper 
2149c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
2159c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
2162e9d6607Sbeveloper }
2172e9d6607Sbeveloper 
2182e9d6607Sbeveloper void
2199c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
2202e9d6607Sbeveloper {
2219c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
2222e9d6607Sbeveloper 
2232e9d6607Sbeveloper 	// test if the channel is valid
2242e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2252e9d6607Sbeveloper 		return;
2262e9d6607Sbeveloper 
2272e9d6607Sbeveloper 	// test if it is really set
2289c3be6a5Sbeveloper 	if ((fInputChannelInfo[channel].destination_mask & mask) == 0)
2292e9d6607Sbeveloper 		return;
2302e9d6607Sbeveloper 
2312e9d6607Sbeveloper 	// remove it from specified channel
2329c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask &= ~mask;
2332e9d6607Sbeveloper 
2349c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
2359c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
2362e9d6607Sbeveloper }
2372e9d6607Sbeveloper 
2389c3be6a5Sbeveloper bool
2399c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type)
2402e9d6607Sbeveloper {
2412e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2429c3be6a5Sbeveloper 		return false;
2439c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
2449c3be6a5Sbeveloper 		return false;
2459c3be6a5Sbeveloper 	return fInputChannelInfo[channel].destination_mask & ChannelTypeToChannelMask(destination_type);
2462e9d6607Sbeveloper }
2472e9d6607Sbeveloper 
2489c3be6a5Sbeveloper int
2499c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type)
2509c3be6a5Sbeveloper {
2519c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
2529c3be6a5Sbeveloper 		return -1;
2539c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
2549c3be6a5Sbeveloper 	for (int chan = 0; chan < fInputChannelCount; chan++) {
2559c3be6a5Sbeveloper 		if (fInputChannelInfo[chan].destination_mask & mask)
2569c3be6a5Sbeveloper 			return chan;
2579c3be6a5Sbeveloper 	}
2589c3be6a5Sbeveloper 	return -1;
2599c3be6a5Sbeveloper }
2609c3be6a5Sbeveloper 
2619c3be6a5Sbeveloper int
2622e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel)
2632e9d6607Sbeveloper {
2642e9d6607Sbeveloper 	// test if the channel is valid
2652e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2662e9d6607Sbeveloper 		return 0;
2679c3be6a5Sbeveloper 	return GetChannelType(channel, fInputChannelMask);
2682e9d6607Sbeveloper }
2692e9d6607Sbeveloper 
270*69517c15Sbeveloper /*
2712e9d6607Sbeveloper void
2722e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain)
2732e9d6607Sbeveloper {
2742e9d6607Sbeveloper 	// test if the channel is valid
2752e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2762e9d6607Sbeveloper 		return;
2772e9d6607Sbeveloper 	if (gain < 0.0f)
2782e9d6607Sbeveloper 		gain = 0.0f;
2792e9d6607Sbeveloper 
2802e9d6607Sbeveloper 	fInputChannelInfo[channel].gain = gain;
2812e9d6607Sbeveloper }
2822e9d6607Sbeveloper 
2832e9d6607Sbeveloper float
2842e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel)
2852e9d6607Sbeveloper {
2862e9d6607Sbeveloper 	// test if the channel is valid
2872e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2882e9d6607Sbeveloper 		return 0.0f;
2892e9d6607Sbeveloper 	return fInputChannelInfo[channel].gain;
2902e9d6607Sbeveloper }
291*69517c15Sbeveloper */
2922e9d6607Sbeveloper 
2932e9d6607Sbeveloper void
2949c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinationMask()
2952e9d6607Sbeveloper {
2962e9d6607Sbeveloper 	// is the user already messed with the assignmens, don't do anything.
2979c3be6a5Sbeveloper 	if (fUserOverridesChannelDestinations)
2982e9d6607Sbeveloper 		return;
2992e9d6607Sbeveloper 
3009c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: enter\n");
3012e9d6607Sbeveloper 
302806cf560Sbeveloper 	// first apply a 1:1 mapping
3032e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
3049c3be6a5Sbeveloper 		fInputChannelInfo[i].destination_mask = GetChannelMask(i, fInputChannelMask);
305806cf560Sbeveloper 
306806cf560Sbeveloper 	// specialize this, depending on the available physical output channels
307806cf560Sbeveloper 	switch (fCore->OutputChannelCount()) {
308806cf560Sbeveloper 		case 0:
309806cf560Sbeveloper 		case 1:
310806cf560Sbeveloper 			break;
311806cf560Sbeveloper 
312806cf560Sbeveloper 		case 2:
313806cf560Sbeveloper 			if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
3149c3be6a5Sbeveloper 				fInputChannelInfo[0].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
315806cf560Sbeveloper 			}
316806cf560Sbeveloper 			break;
317806cf560Sbeveloper 
318806cf560Sbeveloper 		default:
319806cf560Sbeveloper 			if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
3209c3be6a5Sbeveloper 				fInputChannelInfo[0].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT;
321806cf560Sbeveloper 			}
322806cf560Sbeveloper 			if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) {
3239c3be6a5Sbeveloper 				fInputChannelInfo[0].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
324806cf560Sbeveloper 			}
325806cf560Sbeveloper 			if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3269c3be6a5Sbeveloper 				fInputChannelInfo[0].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
327806cf560Sbeveloper 			}
328806cf560Sbeveloper 			if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) {
3299c3be6a5Sbeveloper 				fInputChannelInfo[1].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
330806cf560Sbeveloper 			}
331806cf560Sbeveloper 			if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3329c3be6a5Sbeveloper 				fInputChannelInfo[1].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
333806cf560Sbeveloper 			}
334806cf560Sbeveloper 			break;
3352e9d6607Sbeveloper 	}
3362e9d6607Sbeveloper 
3372e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
3389c3be6a5Sbeveloper 		TRACE("UpdateInputChannelDestinationMask: input channel %d, destination_mask 0x%08X, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
3392e9d6607Sbeveloper 
3409c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: leave\n");
3412e9d6607Sbeveloper }
3422e9d6607Sbeveloper 
3432e9d6607Sbeveloper void
3449c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinations()
3452e9d6607Sbeveloper {
3462e9d6607Sbeveloper 	uint32 channel_count;
3472e9d6607Sbeveloper 	uint32 all_bits;
3482e9d6607Sbeveloper 	uint32 mask;
3492e9d6607Sbeveloper 
3509c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: enter\n");
3512e9d6607Sbeveloper 
3522e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
3539c3be6a5Sbeveloper 		TRACE("UpdateInputChannelDestinations: input channel %d, destination_mask 0x%08X, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
3542e9d6607Sbeveloper 
3552e9d6607Sbeveloper 	all_bits = 0;
3562e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
3579c3be6a5Sbeveloper 		all_bits |= fInputChannelInfo[i].destination_mask;
3582e9d6607Sbeveloper 
3599c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: all_bits = %08x\n", all_bits);
3602e9d6607Sbeveloper 
3612e9d6607Sbeveloper 	channel_count = count_nonzero_bits(all_bits);
3622e9d6607Sbeveloper 
3639c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: %ld input channels, %ld mixer channels (%ld old)\n", fInputChannelCount, channel_count, fMixerChannelCount);
3642e9d6607Sbeveloper 
3652e9d6607Sbeveloper 	if (channel_count != fMixerChannelCount) {
3669c3be6a5Sbeveloper 		delete [] fMixerChannelInfo;
3672e9d6607Sbeveloper 		fMixerChannelInfo = new mixer_chan_info[channel_count];
3682e9d6607Sbeveloper 		fMixerChannelCount = channel_count;
3692e9d6607Sbeveloper 	}
3702e9d6607Sbeveloper 
3712e9d6607Sbeveloper 	// assign each mixer channel one type
3729c3be6a5Sbeveloper 	// and the gain from the fChannelTypeGain[]
3732e9d6607Sbeveloper 	for (int i  = 0, mask = 1; i < fMixerChannelCount; i++) {
3742e9d6607Sbeveloper 		while (mask != 0 && (all_bits & mask) == 0)
3752e9d6607Sbeveloper 			mask <<= 1;
3769c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask);
3779c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_gain = fChannelTypeGain[fMixerChannelInfo[i].destination_type];
3782e9d6607Sbeveloper 		mask <<= 1;
3792e9d6607Sbeveloper 	}
3802e9d6607Sbeveloper 
3812e9d6607Sbeveloper 	// assign buffer_base pointer for each mixer channel
3822e9d6607Sbeveloper 	for (int i  = 0; i < fMixerChannelCount; i++) {
3832e9d6607Sbeveloper 		int j;
3842e9d6607Sbeveloper 		for (j = 0; j < fInputChannelCount; j++) {
3859c3be6a5Sbeveloper 			if (fInputChannelInfo[j].destination_mask & ChannelTypeToChannelMask(fMixerChannelInfo[i].destination_type)) {
386d5848e21Sbeveloper 				fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] : 0;
3872e9d6607Sbeveloper 				break;
3882e9d6607Sbeveloper 			}
3892e9d6607Sbeveloper 		}
3902e9d6607Sbeveloper 		if (j == fInputChannelCount) {
391a2ca4723Sbeveloper 			ERROR("buffer assignment failed for mixer chan %d\n", i);
3922e9d6607Sbeveloper 			fMixerChannelInfo[i].buffer_base = fMixBuffer;
3932e9d6607Sbeveloper 		}
3942e9d6607Sbeveloper 	}
3952e9d6607Sbeveloper 
3962e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++)
3979c3be6a5Sbeveloper 		TRACE("UpdateInputChannelDestinations: mixer channel %d, type %2d, base %p, gain %.3f\n", i, fMixerChannelInfo[i].destination_type, fMixerChannelInfo[i].buffer_base, fMixerChannelInfo[i].destination_gain);
3982e9d6607Sbeveloper 
3999c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: leave\n");
4002e9d6607Sbeveloper }
401*69517c15Sbeveloper /*
4022e9d6607Sbeveloper void
4039c3be6a5Sbeveloper MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, float gain)
4042e9d6607Sbeveloper {
4059c3be6a5Sbeveloper 	TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, gain %.4f\n", channel, destination_type, gain);
4069c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
4079c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
4089c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
4092e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4102e9d6607Sbeveloper 		return;
4119c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
4129c3be6a5Sbeveloper 		return;
4132e9d6607Sbeveloper 	if (gain < 0.0f)
4142e9d6607Sbeveloper 		gain = 0.0f;
4159c3be6a5Sbeveloper 	fChannelTypeGain[destination_type] = gain;
4169c3be6a5Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4179c3be6a5Sbeveloper 		if (fMixerChannelInfo[i].destination_type == destination_type) {
4189c3be6a5Sbeveloper 			fMixerChannelInfo[i].destination_gain = gain;
4199c3be6a5Sbeveloper 			return;
4209c3be6a5Sbeveloper 		}
4219c3be6a5Sbeveloper 	}
4222e9d6607Sbeveloper }
4232e9d6607Sbeveloper 
4242e9d6607Sbeveloper float
4259c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type)
4262e9d6607Sbeveloper {
4279c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
4289c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
4299c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
4302e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4319c3be6a5Sbeveloper 		return 0.0f;
4329c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
4339c3be6a5Sbeveloper 		return 0.0f;
4349c3be6a5Sbeveloper 	return fChannelTypeGain[destination_type];
4352e9d6607Sbeveloper }
436*69517c15Sbeveloper */
437*69517c15Sbeveloper 
438*69517c15Sbeveloper void
439*69517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain)
440*69517c15Sbeveloper {
441*69517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
442*69517c15Sbeveloper 		return;
443*69517c15Sbeveloper 	if (gain < 0.0f)
444*69517c15Sbeveloper 		gain = 0.0f;
445*69517c15Sbeveloper 
446*69517c15Sbeveloper 	fMixerChannelInfo[mixer_channel].destination_gain = gain;
447*69517c15Sbeveloper 	fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain;
448*69517c15Sbeveloper }
449*69517c15Sbeveloper 
450*69517c15Sbeveloper float
451*69517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel)
452*69517c15Sbeveloper {
453*69517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
454*69517c15Sbeveloper 		return 0.0;
455*69517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_gain;
456*69517c15Sbeveloper }
457*69517c15Sbeveloper 
458*69517c15Sbeveloper int
459*69517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel)
460*69517c15Sbeveloper {
461*69517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
462*69517c15Sbeveloper 		return -1;
463*69517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_type;
464*69517c15Sbeveloper }
4652e9d6607Sbeveloper 
4662e9d6607Sbeveloper void
4671c237c18Sbeveloper MixerInput::SetEnabled(bool yesno)
4681c237c18Sbeveloper {
4691c237c18Sbeveloper 	fEnabled = yesno;
4701c237c18Sbeveloper }
4711c237c18Sbeveloper 
4721c237c18Sbeveloper bool
4731c237c18Sbeveloper MixerInput::IsEnabled()
4741c237c18Sbeveloper {
4751c237c18Sbeveloper 	return fEnabled;
4761c237c18Sbeveloper }
4771c237c18Sbeveloper 
4781c237c18Sbeveloper void
4798d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
4802e9d6607Sbeveloper {
481a2ca4723Sbeveloper 	TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
482d5848e21Sbeveloper 
4837b0daf5cSbeveloper 	fMixBufferFrameRate = framerate;
4848df36cddSbeveloper 	debugMixBufferFrames = frames;
4852e9d6607Sbeveloper 
486d5848e21Sbeveloper 	// frames and/or framerate can be 0 (if no output is connected)
487d5848e21Sbeveloper 	if (framerate == 0 || frames == 0) {
488d5848e21Sbeveloper 		if (fMixBuffer) {
489d5848e21Sbeveloper 			rtm_free(fMixBuffer);
490d5848e21Sbeveloper 			fMixBuffer = 0;
491d5848e21Sbeveloper 		}
492d5848e21Sbeveloper 		for (int i = 0; i < fInputChannelCount; i++)
493d5848e21Sbeveloper 			fInputChannelInfo[i].buffer_base = 0;
494d5848e21Sbeveloper 		fMixBufferFrameCount = 0;
495d5848e21Sbeveloper 
4969c3be6a5Sbeveloper 		UpdateInputChannelDestinationMask();
4979c3be6a5Sbeveloper 		UpdateInputChannelDestinations();
498d5848e21Sbeveloper 		return;
499d5848e21Sbeveloper 	}
5007b0daf5cSbeveloper 
5017b0daf5cSbeveloper 	// make fMixBufferFrameCount an integral multiple of frames,
5027b0daf5cSbeveloper 	// but at least 3 times duration of our input buffer
5037b0daf5cSbeveloper 	// and at least 2 times duration of the output buffer
5047b0daf5cSbeveloper 	bigtime_t inputBufferLength  = duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio));
5057b0daf5cSbeveloper 	bigtime_t outputBufferLength = duration_for_frames(framerate, frames);
5067b0daf5cSbeveloper 	bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength);
5077b0daf5cSbeveloper 	int temp = frames_for_duration(framerate, mixerBufferLength);
5087b0daf5cSbeveloper 	fMixBufferFrameCount = ((temp / frames) + 1) * frames;
5097b0daf5cSbeveloper 
510a2ca4723Sbeveloper 	TRACE("  inputBufferLength  %10Ld\n", inputBufferLength);
511a2ca4723Sbeveloper 	TRACE("  outputBufferLength %10Ld\n", outputBufferLength);
512a2ca4723Sbeveloper 	TRACE("  mixerBufferLength  %10Ld\n", mixerBufferLength);
513a2ca4723Sbeveloper 	TRACE("  fMixBufferFrameCount   %10ld\n", fMixBufferFrameCount);
5147b0daf5cSbeveloper 
5158d28117fSbeveloper 	ASSERT((fMixBufferFrameCount % frames) == 0);
5168d28117fSbeveloper 
5172e9d6607Sbeveloper 	if (fMixBuffer)
5182e9d6607Sbeveloper 		rtm_free(fMixBuffer);
519356855c3Sbeveloper 	if (fRtmPool)
520356855c3Sbeveloper 		rtm_delete_pool(fRtmPool);
5217b0daf5cSbeveloper 	int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
522356855c3Sbeveloper 	if (B_OK != rtm_create_pool(&fRtmPool, size))
523356855c3Sbeveloper 		fRtmPool = 0;
524356855c3Sbeveloper 	fMixBuffer = (float *)rtm_alloc(fRtmPool, size);
5257b0daf5cSbeveloper 	ASSERT(fMixBuffer);
5267b0daf5cSbeveloper 
5277b0daf5cSbeveloper 	memset(fMixBuffer, 0, size);
5282e9d6607Sbeveloper 
5292e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
5307b0daf5cSbeveloper 		fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
531d5848e21Sbeveloper 
5329c3be6a5Sbeveloper 	UpdateInputChannelDestinationMask();
5339c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
5342e9d6607Sbeveloper }
535