xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp (revision a9cf57cff5dfe040f74a96705d98d6711b6b1b50)
1bf7ab50dSStephan Aßmus /*
2*a9cf57cfSAxel 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:
6bf7ab50dSStephan Aßmus  *		Marcus Overhagen
7bf7ab50dSStephan Aßmus  */
8*a9cf57cfSAxel Dörfler 
9*a9cf57cfSAxel Dörfler 
10bf7ab50dSStephan Aßmus #include "MixerCore.h"
11*a9cf57cfSAxel Dörfler 
12*a9cf57cfSAxel Dörfler #include <Buffer.h>
13*a9cf57cfSAxel Dörfler #include <string.h>
14*a9cf57cfSAxel Dörfler #include <TimeSource.h> // TODO: debug only
15*a9cf57cfSAxel Dörfler 
16*a9cf57cfSAxel Dörfler #include "ByteSwap.h"
17bf7ab50dSStephan Aßmus #include "MixerInput.h"
18bf7ab50dSStephan Aßmus #include "MixerUtils.h"
19bf7ab50dSStephan Aßmus #include "Resampler.h"
20bf7ab50dSStephan Aßmus 
21678c2017Sbeveloper 
22*a9cf57cfSAxel Dörfler MixerInput::MixerInput(MixerCore *core, const media_input &input,
23*a9cf57cfSAxel Dörfler 	float mixFrameRate, int32 mixFrameCount)
24*a9cf57cfSAxel Dörfler 	:
25*a9cf57cfSAxel Dörfler 	fCore(core),
262e9d6607Sbeveloper  	fInput(input),
2788777023Sbeveloper 	fInputByteSwap(0),
281c237c18Sbeveloper 	fEnabled(true),
292e9d6607Sbeveloper 	fInputChannelInfo(0),
302e9d6607Sbeveloper 	fInputChannelCount(0),
312e9d6607Sbeveloper 	fInputChannelMask(0),
322e9d6607Sbeveloper 	fMixerChannelInfo(0),
332e9d6607Sbeveloper 	fMixerChannelCount(0),
342e9d6607Sbeveloper 	fMixBuffer(0),
357b0daf5cSbeveloper 	fMixBufferFrameRate(0),
367b0daf5cSbeveloper 	fMixBufferFrameCount(0),
37e92593f4Sbeveloper 	fLastDataFrameWritten(-1),
38af8d0a4dSbeveloper 	fLastDataAvailableTime(-1),
39e92593f4Sbeveloper 	fFractionalFrames(0.0),
407b0daf5cSbeveloper 	fResampler(0),
41356855c3Sbeveloper 	fRtmPool(0),
429c3be6a5Sbeveloper 	fUserOverridesChannelDestinations(false)
43678c2017Sbeveloper {
44e6c7c99fSbeveloper 	fix_multiaudio_format(&fInput.format.u.raw_audio);
45e6c7c99fSbeveloper 	PRINT_INPUT("MixerInput::MixerInput", fInput);
46e6c7c99fSbeveloper 	PRINT_CHANNEL_MASK(fInput.format);
472e9d6607Sbeveloper 
482e9d6607Sbeveloper 	ASSERT(fInput.format.u.raw_audio.channel_count > 0);
492e9d6607Sbeveloper 
509c3be6a5Sbeveloper 	for (int i = 0; i <	MAX_CHANNEL_TYPES; i++)
519c3be6a5Sbeveloper 		fChannelTypeGain[i] = 1.0f;
529c3be6a5Sbeveloper 
532e9d6607Sbeveloper 	fInputChannelCount = fInput.format.u.raw_audio.channel_count;
542e9d6607Sbeveloper 	fInputChannelMask = fInput.format.u.raw_audio.channel_mask;
552e9d6607Sbeveloper 	fInputChannelInfo = new input_chan_info[fInputChannelCount];
562e9d6607Sbeveloper 
5788777023Sbeveloper 	// perhaps we need byte swapping
5888777023Sbeveloper 	if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
59*a9cf57cfSAxel Dörfler 		if (fInput.format.u.raw_audio.format
60*a9cf57cfSAxel Dörfler 				== media_raw_audio_format::B_AUDIO_FLOAT
61*a9cf57cfSAxel Dörfler 			|| fInput.format.u.raw_audio.format
62*a9cf57cfSAxel Dörfler 				== media_raw_audio_format::B_AUDIO_INT
63*a9cf57cfSAxel Dörfler 			|| fInput.format.u.raw_audio.format
64*a9cf57cfSAxel Dörfler 				== media_raw_audio_format::B_AUDIO_SHORT) {
6588777023Sbeveloper 			fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format);
6688777023Sbeveloper 		}
6788777023Sbeveloper 	}
6888777023Sbeveloper 
692e9d6607Sbeveloper 	// initialize fInputChannelInfo
702e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++) {
712e9d6607Sbeveloper 		fInputChannelInfo[i].buffer_base = 0;	// will be set by SetMixBufferFormat()
729c3be6a5Sbeveloper 		fInputChannelInfo[i].destination_mask = 0;	// will be set by UpdateInputChannelDestinationMask()
732e9d6607Sbeveloper 		fInputChannelInfo[i].gain = 1.0;
742e9d6607Sbeveloper 	}
752e9d6607Sbeveloper 
767b0daf5cSbeveloper 	// create resamplers
777b0daf5cSbeveloper 	fResampler = new Resampler * [fInputChannelCount];
787b0daf5cSbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
79f0a85f97SJérôme Duval 		fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT);
807b0daf5cSbeveloper 
819c3be6a5Sbeveloper 	// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations()
82bf7ab50dSStephan Aßmus 	SetMixBufferFormat((int32)mixFrameRate, mixFrameCount);
83678c2017Sbeveloper }
84678c2017Sbeveloper 
85*a9cf57cfSAxel Dörfler 
86678c2017Sbeveloper MixerInput::~MixerInput()
87678c2017Sbeveloper {
882e9d6607Sbeveloper 	if (fMixBuffer)
892e9d6607Sbeveloper 		rtm_free(fMixBuffer);
90356855c3Sbeveloper 	if (fRtmPool)
91356855c3Sbeveloper 		rtm_delete_pool(fRtmPool);
922e9d6607Sbeveloper 	delete [] fInputChannelInfo;
932e9d6607Sbeveloper 	delete [] fMixerChannelInfo;
947b0daf5cSbeveloper 
957b0daf5cSbeveloper 	// delete resamplers
967b0daf5cSbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
977b0daf5cSbeveloper 		delete fResampler[i];
987b0daf5cSbeveloper 	delete [] fResampler;
99678c2017Sbeveloper }
100678c2017Sbeveloper 
101*a9cf57cfSAxel Dörfler 
102678c2017Sbeveloper void
103678c2017Sbeveloper MixerInput::BufferReceived(BBuffer *buffer)
104678c2017Sbeveloper {
10588777023Sbeveloper 	void *data;
10688777023Sbeveloper 	size_t size;
10788777023Sbeveloper 	bigtime_t start;
108e92593f4Sbeveloper 	bigtime_t buffer_duration;
10988777023Sbeveloper 
110d5848e21Sbeveloper 	if (!fMixBuffer) {
111a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n");
112d5848e21Sbeveloper 		return;
113d5848e21Sbeveloper 	}
1142e9d6607Sbeveloper 
11588777023Sbeveloper 	data = buffer->Data();
11688777023Sbeveloper 	size = buffer->SizeUsed();
11788777023Sbeveloper 	start = buffer->Header()->start_time;
118e92593f4Sbeveloper 	buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate, size / bytes_per_frame(fInput.format.u.raw_audio));
1198d28117fSbeveloper 	if (start < 0) {
120a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: buffer with negative start time of %Ld dropped\n", start);
1218d28117fSbeveloper 		return;
1228d28117fSbeveloper 	}
12388777023Sbeveloper 
12488777023Sbeveloper 	// swap the byte order of this buffer, if necessary
12588777023Sbeveloper 	if (fInputByteSwap)
12688777023Sbeveloper 		fInputByteSwap->Swap(data, size);
12788777023Sbeveloper 
128d91580cdSbeveloper 	int offset = frames_for_duration(fMixBufferFrameRate, start) % fMixBufferFrameCount;
1298d28117fSbeveloper 
130191033efSbeveloper 	PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", start, offset);
1317b0daf5cSbeveloper 
132191033efSbeveloper 	int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio);
133e92593f4Sbeveloper 	double frames = double(in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate;
134e92593f4Sbeveloper 	int out_frames = int(frames);
135e92593f4Sbeveloper 	fFractionalFrames += frames - double(out_frames);
136e92593f4Sbeveloper 	if (fFractionalFrames >= 1.0) {
137e92593f4Sbeveloper 		fFractionalFrames -= 1.0;
1387619f562Sbeveloper 		out_frames++;
139e92593f4Sbeveloper 	}
140e92593f4Sbeveloper 
141e92593f4Sbeveloper 	// if fLastDataFrameWritten != -1, then we have a valid last position
142e92593f4Sbeveloper 	// and can do glitch compensation
143e92593f4Sbeveloper 	if (fLastDataFrameWritten >= 0) {
144e92593f4Sbeveloper 		int expected_frame = (fLastDataFrameWritten + 1) % fMixBufferFrameCount;
145e92593f4Sbeveloper 		if (offset != expected_frame) {
146e92593f4Sbeveloper 			// due to rounding and other errors, offset might be off by +/- 1
147e92593f4Sbeveloper 			// this is not really a bad glitch, we just adjust the position
148e92593f4Sbeveloper 			if (offset == fLastDataFrameWritten) {
149e92593f4Sbeveloper 				//printf("MixerInput::BufferReceived: -1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
150e92593f4Sbeveloper 				offset = expected_frame;
151e92593f4Sbeveloper 			} else if (offset == ((fLastDataFrameWritten + 2) % fMixBufferFrameCount)) {
152e92593f4Sbeveloper 				//printf("MixerInput::BufferReceived: +1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
153e92593f4Sbeveloper 				offset = expected_frame;
154e92593f4Sbeveloper 			} else {
155dbaf884cSbeveloper 				printf("MixerInput::BufferReceived: GLITCH! last frame was %4ld, expected frame was %4d, new frame is %4d\n", fLastDataFrameWritten, expected_frame, offset);
156e92593f4Sbeveloper 
157e92593f4Sbeveloper 				if (start > fLastDataAvailableTime) {
158e92593f4Sbeveloper 					if ((start - fLastDataAvailableTime) < (buffer_duration / 10)) {
159e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too late
160e92593f4Sbeveloper 						printf("short glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime);
161e92593f4Sbeveloper 						offset = expected_frame;
162e92593f4Sbeveloper 						out_frames++;
163e92593f4Sbeveloper 					} else {
164e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too late
165e92593f4Sbeveloper 						// XXX zerofill buffer
166e92593f4Sbeveloper 						printf("MAJOR glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime);
167e92593f4Sbeveloper 					}
168e92593f4Sbeveloper 				} else { // start <= fLastDataAvailableTime
169e92593f4Sbeveloper 					// the new buffer is too early
170e92593f4Sbeveloper 					if ((fLastDataAvailableTime - start) < (buffer_duration / 10)) {
171e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too early
172e92593f4Sbeveloper 						printf("short glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start);
173e92593f4Sbeveloper 						offset = expected_frame;
174e92593f4Sbeveloper 						out_frames--;
175e92593f4Sbeveloper 						if (out_frames < 1)
176e92593f4Sbeveloper 							out_frames = 1;
177e92593f4Sbeveloper 					} else {
178e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too early
179e92593f4Sbeveloper 						// XXX zerofill buffer
180e92593f4Sbeveloper 						printf("MAJOR glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start);
181e92593f4Sbeveloper 					}
182e92593f4Sbeveloper 				}
183e92593f4Sbeveloper 			}
184e92593f4Sbeveloper 		}
185e92593f4Sbeveloper 	}
1867b0daf5cSbeveloper 
1878d28117fSbeveloper 	//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);
1887b0daf5cSbeveloper 	if (offset + out_frames > fMixBufferFrameCount) {
1897b0daf5cSbeveloper 		int out_frames1 = fMixBufferFrameCount - offset;
1907b0daf5cSbeveloper 		int out_frames2 = out_frames - out_frames1;
1917b0daf5cSbeveloper 		int in_frames1 = (out_frames1 * in_frames) / out_frames;
1927b0daf5cSbeveloper 		int in_frames2 = in_frames - in_frames1;
1937b0daf5cSbeveloper 
194e92593f4Sbeveloper 		//printf("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);
1957619f562Sbeveloper 		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);
196191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d, in_frames1 %5d, out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n",
197191033efSbeveloper 			  in_frames, out_frames, in_frames1, out_frames1, in_frames2, out_frames2);
1987b0daf5cSbeveloper 
199e92593f4Sbeveloper 		fLastDataFrameWritten = out_frames2 - 1;
200e92593f4Sbeveloper 
2018d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
2028d28117fSbeveloper 
2037b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
20478563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
20578563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2067b0daf5cSbeveloper 									in_frames1,
2078d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
2087b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2097b0daf5cSbeveloper 									out_frames1,
2107b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
2117b0daf5cSbeveloper 
2127d970b31Sbeveloper 			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),
21378563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2147b0daf5cSbeveloper 									in_frames2,
2157b0daf5cSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base),
2167b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2177b0daf5cSbeveloper 									out_frames2,
2187b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
219e92593f4Sbeveloper 
2207b0daf5cSbeveloper 		}
2217b0daf5cSbeveloper 	} else {
222e92593f4Sbeveloper 		//printf("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);
2237619f562Sbeveloper 		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);
224191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d\n", in_frames, out_frames);
2258d28117fSbeveloper 
226e92593f4Sbeveloper 		fLastDataFrameWritten = offset + out_frames - 1;
2278d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
2287b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
22978563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
23078563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2317b0daf5cSbeveloper 									in_frames,
2328d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
2337b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2347b0daf5cSbeveloper 									out_frames,
2357b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
2367b0daf5cSbeveloper 		}
2377b0daf5cSbeveloper 	}
238e92593f4Sbeveloper 	fLastDataAvailableTime = start + buffer_duration;
239678c2017Sbeveloper }
2407ee2c804Sbeveloper 
241bf7ab50dSStephan Aßmus 
2427ee2c804Sbeveloper media_input &
2437ee2c804Sbeveloper MixerInput::MediaInput()
2447ee2c804Sbeveloper {
2457ee2c804Sbeveloper 	return fInput;
2467ee2c804Sbeveloper }
247e6c7c99fSbeveloper 
248bf7ab50dSStephan Aßmus 
249e6c7c99fSbeveloper int32
250e6c7c99fSbeveloper MixerInput::ID()
251e6c7c99fSbeveloper {
252e6c7c99fSbeveloper 	return fInput.destination.id;
253e6c7c99fSbeveloper }
254e6c7c99fSbeveloper 
255bf7ab50dSStephan Aßmus 
256d91580cdSbeveloper int
257fae6ce82Sbeveloper MixerInput::GetInputChannelCount()
258fae6ce82Sbeveloper {
259fae6ce82Sbeveloper 	return fInputChannelCount;
260fae6ce82Sbeveloper }
261fae6ce82Sbeveloper 
262bf7ab50dSStephan Aßmus 
2632e9d6607Sbeveloper void
2649c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type)
2652e9d6607Sbeveloper {
2669c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
267e6c7c99fSbeveloper 
2682e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2692e9d6607Sbeveloper 		return;
2702e9d6607Sbeveloper 
2712e9d6607Sbeveloper 	// test if it is already set
2729c3be6a5Sbeveloper 	if (fInputChannelInfo[channel].destination_mask & mask)
2732e9d6607Sbeveloper 		return;
2742e9d6607Sbeveloper 
2759c3be6a5Sbeveloper 	// verify that no other channel has id
2769c3be6a5Sbeveloper 	if (-1 != GetInputChannelForDestination(destination_type)) {
2779c3be6a5Sbeveloper 		ERROR("MixerInput::AddInputChannelDestination: destination_type %d already assigned to channel %d\n", destination_type, GetInputChannelForDestination(destination_type));
2789c3be6a5Sbeveloper 		return;
2799c3be6a5Sbeveloper 	}
2802e9d6607Sbeveloper 
2812e9d6607Sbeveloper 	// add it to specified channel
2829c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask |= mask;
2832e9d6607Sbeveloper 
2849c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
2859c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
2862e9d6607Sbeveloper }
2872e9d6607Sbeveloper 
288*a9cf57cfSAxel Dörfler 
2892e9d6607Sbeveloper void
2909c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
2912e9d6607Sbeveloper {
2929c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
2932e9d6607Sbeveloper 
2942e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2952e9d6607Sbeveloper 		return;
2962e9d6607Sbeveloper 
2972e9d6607Sbeveloper 	// test if it is really set
2989c3be6a5Sbeveloper 	if ((fInputChannelInfo[channel].destination_mask & mask) == 0)
2992e9d6607Sbeveloper 		return;
3002e9d6607Sbeveloper 
3012e9d6607Sbeveloper 	// remove it from specified channel
3029c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask &= ~mask;
3032e9d6607Sbeveloper 
3049c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
3059c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
3062e9d6607Sbeveloper }
3072e9d6607Sbeveloper 
308*a9cf57cfSAxel Dörfler 
3099c3be6a5Sbeveloper bool
3109c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type)
3112e9d6607Sbeveloper {
3122e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3139c3be6a5Sbeveloper 		return false;
3149c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
3159c3be6a5Sbeveloper 		return false;
3169c3be6a5Sbeveloper 	return fInputChannelInfo[channel].destination_mask & ChannelTypeToChannelMask(destination_type);
3172e9d6607Sbeveloper }
3182e9d6607Sbeveloper 
319*a9cf57cfSAxel Dörfler 
3209c3be6a5Sbeveloper int
3219c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type)
3229c3be6a5Sbeveloper {
3239c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
3249c3be6a5Sbeveloper 		return -1;
3259c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
3269c3be6a5Sbeveloper 	for (int chan = 0; chan < fInputChannelCount; chan++) {
3279c3be6a5Sbeveloper 		if (fInputChannelInfo[chan].destination_mask & mask)
3289c3be6a5Sbeveloper 			return chan;
3299c3be6a5Sbeveloper 	}
3309c3be6a5Sbeveloper 	return -1;
3319c3be6a5Sbeveloper }
3329c3be6a5Sbeveloper 
333*a9cf57cfSAxel Dörfler 
3349c3be6a5Sbeveloper int
3352e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel)
3362e9d6607Sbeveloper {
3372e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3382e9d6607Sbeveloper 		return 0;
3399c3be6a5Sbeveloper 	return GetChannelType(channel, fInputChannelMask);
3402e9d6607Sbeveloper }
3412e9d6607Sbeveloper 
342*a9cf57cfSAxel Dörfler 
3432e9d6607Sbeveloper void
3442e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain)
3452e9d6607Sbeveloper {
3462e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3472e9d6607Sbeveloper 		return;
3482e9d6607Sbeveloper 	if (gain < 0.0f)
3492e9d6607Sbeveloper 		gain = 0.0f;
3502e9d6607Sbeveloper 
3512e9d6607Sbeveloper 	fInputChannelInfo[channel].gain = gain;
3522e9d6607Sbeveloper }
3532e9d6607Sbeveloper 
354*a9cf57cfSAxel Dörfler 
3552e9d6607Sbeveloper float
3562e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel)
3572e9d6607Sbeveloper {
3582e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3592e9d6607Sbeveloper 		return 0.0f;
3602e9d6607Sbeveloper 	return fInputChannelInfo[channel].gain;
3612e9d6607Sbeveloper }
3622e9d6607Sbeveloper 
363*a9cf57cfSAxel Dörfler 
3642e9d6607Sbeveloper void
3659c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinationMask()
3662e9d6607Sbeveloper {
3672e9d6607Sbeveloper 	// is the user already messed with the assignmens, don't do anything.
3689c3be6a5Sbeveloper 	if (fUserOverridesChannelDestinations)
3692e9d6607Sbeveloper 		return;
3702e9d6607Sbeveloper 
3719c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: enter\n");
3722e9d6607Sbeveloper 
373806cf560Sbeveloper 	// first apply a 1:1 mapping
3742e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
3759c3be6a5Sbeveloper 		fInputChannelInfo[i].destination_mask = GetChannelMask(i, fInputChannelMask);
376806cf560Sbeveloper 
377806cf560Sbeveloper 	// specialize this, depending on the available physical output channels
378643e1b2eSbeveloper 	if (fCore->OutputChannelCount() <= 2) {
379643e1b2eSbeveloper 		// less or equal two channels
380806cf560Sbeveloper 		if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
381ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
382806cf560Sbeveloper 		}
383643e1b2eSbeveloper 	} else {
384643e1b2eSbeveloper 		// more than two channel output card
385806cf560Sbeveloper 		if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
386ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
387806cf560Sbeveloper 		}
388806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) {
3899c3be6a5Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
390806cf560Sbeveloper 		}
391806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3929c3be6a5Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
393806cf560Sbeveloper 		}
394806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) {
3959c3be6a5Sbeveloper 			fInputChannelInfo[1].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
396806cf560Sbeveloper 		}
397806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3989c3be6a5Sbeveloper 			fInputChannelInfo[1].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
399806cf560Sbeveloper 		}
4002e9d6607Sbeveloper 	}
4012e9d6607Sbeveloper 
4022e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
403d91580cdSbeveloper 		TRACE("UpdateInputChannelDestinationMask: input channel %d, destination_mask 0x%08lX, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
4049c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: leave\n");
4052e9d6607Sbeveloper }
4062e9d6607Sbeveloper 
407*a9cf57cfSAxel Dörfler 
4082e9d6607Sbeveloper void
4099c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinations()
4102e9d6607Sbeveloper {
411d91580cdSbeveloper 	int channel_count;
4122e9d6607Sbeveloper 	uint32 all_bits;
4132e9d6607Sbeveloper 	uint32 mask;
4142e9d6607Sbeveloper 
4159c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: enter\n");
4162e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
417d91580cdSbeveloper 		TRACE("UpdateInputChannelDestinations: input channel %d, destination_mask 0x%08lX, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
4182e9d6607Sbeveloper 
4192e9d6607Sbeveloper 	all_bits = 0;
4202e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
4219c3be6a5Sbeveloper 		all_bits |= fInputChannelInfo[i].destination_mask;
4222e9d6607Sbeveloper 
423d91580cdSbeveloper 	TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
4242e9d6607Sbeveloper 
4252e9d6607Sbeveloper 	channel_count = count_nonzero_bits(all_bits);
426d91580cdSbeveloper 	TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer channels (%d old)\n", fInputChannelCount, channel_count, fMixerChannelCount);
4272e9d6607Sbeveloper 	if (channel_count != fMixerChannelCount) {
4289c3be6a5Sbeveloper 		delete [] fMixerChannelInfo;
4292e9d6607Sbeveloper 		fMixerChannelInfo = new mixer_chan_info[channel_count];
4302e9d6607Sbeveloper 		fMixerChannelCount = channel_count;
4312e9d6607Sbeveloper 	}
4322e9d6607Sbeveloper 
4332e9d6607Sbeveloper 	// assign each mixer channel one type
4349c3be6a5Sbeveloper 	// and the gain from the fChannelTypeGain[]
435d91580cdSbeveloper 	mask = 1;
436d91580cdSbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4372e9d6607Sbeveloper 		while (mask != 0 && (all_bits & mask) == 0)
4382e9d6607Sbeveloper 			mask <<= 1;
4399c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask);
4409c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_gain = fChannelTypeGain[fMixerChannelInfo[i].destination_type];
4412e9d6607Sbeveloper 		mask <<= 1;
4422e9d6607Sbeveloper 	}
4432e9d6607Sbeveloper 
4442e9d6607Sbeveloper 	// assign buffer_base pointer for each mixer channel
4452e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4462e9d6607Sbeveloper 		int j;
4472e9d6607Sbeveloper 		for (j = 0; j < fInputChannelCount; j++) {
4489c3be6a5Sbeveloper 			if (fInputChannelInfo[j].destination_mask & ChannelTypeToChannelMask(fMixerChannelInfo[i].destination_type)) {
449d5848e21Sbeveloper 				fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] : 0;
4502e9d6607Sbeveloper 				break;
4512e9d6607Sbeveloper 			}
4522e9d6607Sbeveloper 		}
4532e9d6607Sbeveloper 		if (j == fInputChannelCount) {
454a2ca4723Sbeveloper 			ERROR("buffer assignment failed for mixer chan %d\n", i);
4552e9d6607Sbeveloper 			fMixerChannelInfo[i].buffer_base = fMixBuffer;
4562e9d6607Sbeveloper 		}
4572e9d6607Sbeveloper 	}
4582e9d6607Sbeveloper 
4592e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++)
4609c3be6a5Sbeveloper 		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);
4612e9d6607Sbeveloper 
4629c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: leave\n");
4632e9d6607Sbeveloper }
464bf7ab50dSStephan Aßmus 
465*a9cf57cfSAxel Dörfler 
466bf7ab50dSStephan Aßmus // Note: The following code is outcommented on purpose
467bf7ab50dSStephan Aßmus // and is about to be modified at a later point
46869517c15Sbeveloper /*
4692e9d6607Sbeveloper void
4709c3be6a5Sbeveloper MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, float gain)
4712e9d6607Sbeveloper {
4729c3be6a5Sbeveloper 	TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, gain %.4f\n", channel, destination_type, gain);
4739c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
4749c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
4759c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
4762e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4772e9d6607Sbeveloper 		return;
4789c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
4799c3be6a5Sbeveloper 		return;
4802e9d6607Sbeveloper 	if (gain < 0.0f)
4812e9d6607Sbeveloper 		gain = 0.0f;
4829c3be6a5Sbeveloper 	fChannelTypeGain[destination_type] = gain;
4839c3be6a5Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4849c3be6a5Sbeveloper 		if (fMixerChannelInfo[i].destination_type == destination_type) {
4859c3be6a5Sbeveloper 			fMixerChannelInfo[i].destination_gain = gain;
4869c3be6a5Sbeveloper 			return;
4879c3be6a5Sbeveloper 		}
4889c3be6a5Sbeveloper 	}
4892e9d6607Sbeveloper }
4902e9d6607Sbeveloper 
491*a9cf57cfSAxel Dörfler 
4922e9d6607Sbeveloper float
4939c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type)
4942e9d6607Sbeveloper {
4959c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
4969c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
4979c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
4982e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4999c3be6a5Sbeveloper 		return 0.0f;
5009c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
5019c3be6a5Sbeveloper 		return 0.0f;
5029c3be6a5Sbeveloper 	return fChannelTypeGain[destination_type];
5032e9d6607Sbeveloper }
50469517c15Sbeveloper */
50569517c15Sbeveloper 
506*a9cf57cfSAxel Dörfler 
50769517c15Sbeveloper void
50869517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain)
50969517c15Sbeveloper {
51069517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
51169517c15Sbeveloper 		return;
51269517c15Sbeveloper 	if (gain < 0.0f)
51369517c15Sbeveloper 		gain = 0.0f;
51469517c15Sbeveloper 
51569517c15Sbeveloper 	fMixerChannelInfo[mixer_channel].destination_gain = gain;
51669517c15Sbeveloper 	fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain;
51769517c15Sbeveloper }
51869517c15Sbeveloper 
519*a9cf57cfSAxel Dörfler 
52069517c15Sbeveloper float
52169517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel)
52269517c15Sbeveloper {
52369517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
52469517c15Sbeveloper 		return 0.0;
52569517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_gain;
52669517c15Sbeveloper }
52769517c15Sbeveloper 
528*a9cf57cfSAxel Dörfler 
52969517c15Sbeveloper int
53069517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel)
53169517c15Sbeveloper {
53269517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
53369517c15Sbeveloper 		return -1;
53469517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_type;
53569517c15Sbeveloper }
5362e9d6607Sbeveloper 
537*a9cf57cfSAxel Dörfler 
5382e9d6607Sbeveloper void
5391c237c18Sbeveloper MixerInput::SetEnabled(bool yesno)
5401c237c18Sbeveloper {
5411c237c18Sbeveloper 	fEnabled = yesno;
5421c237c18Sbeveloper }
5431c237c18Sbeveloper 
544*a9cf57cfSAxel Dörfler 
5451c237c18Sbeveloper bool
5461c237c18Sbeveloper MixerInput::IsEnabled()
5471c237c18Sbeveloper {
5481c237c18Sbeveloper 	return fEnabled;
5491c237c18Sbeveloper }
5501c237c18Sbeveloper 
551*a9cf57cfSAxel Dörfler 
5521c237c18Sbeveloper void
5538d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
5542e9d6607Sbeveloper {
555*a9cf57cfSAxel Dörfler 	TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n",
556*a9cf57cfSAxel Dörfler 		framerate, frames);
557d5848e21Sbeveloper 
5587b0daf5cSbeveloper 	fMixBufferFrameRate = framerate;
559*a9cf57cfSAxel Dörfler 	fDebugMixBufferFrames = frames;
5602e9d6607Sbeveloper 
561d5848e21Sbeveloper 	// frames and/or framerate can be 0 (if no output is connected)
562d5848e21Sbeveloper 	if (framerate == 0 || frames == 0) {
563*a9cf57cfSAxel Dörfler 		if (fMixBuffer != NULL) {
564d5848e21Sbeveloper 			rtm_free(fMixBuffer);
565*a9cf57cfSAxel Dörfler 			fMixBuffer = NULL;
566d5848e21Sbeveloper 		}
567d5848e21Sbeveloper 		for (int i = 0; i < fInputChannelCount; i++)
568d5848e21Sbeveloper 			fInputChannelInfo[i].buffer_base = 0;
569d5848e21Sbeveloper 		fMixBufferFrameCount = 0;
570d5848e21Sbeveloper 
5719c3be6a5Sbeveloper 		UpdateInputChannelDestinationMask();
5729c3be6a5Sbeveloper 		UpdateInputChannelDestinations();
573d5848e21Sbeveloper 		return;
574d5848e21Sbeveloper 	}
5757b0daf5cSbeveloper 
5767b0daf5cSbeveloper 	// make fMixBufferFrameCount an integral multiple of frames,
5777b0daf5cSbeveloper 	// but at least 3 times duration of our input buffer
5787b0daf5cSbeveloper 	// and at least 2 times duration of the output buffer
5797b0daf5cSbeveloper 	bigtime_t inputBufferLength  = duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio));
5807b0daf5cSbeveloper 	bigtime_t outputBufferLength = duration_for_frames(framerate, frames);
5817b0daf5cSbeveloper 	bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength);
5827b0daf5cSbeveloper 	int temp = frames_for_duration(framerate, mixerBufferLength);
5837b0daf5cSbeveloper 	fMixBufferFrameCount = ((temp / frames) + 1) * frames;
5847b0daf5cSbeveloper 
585a2ca4723Sbeveloper 	TRACE("  inputBufferLength  %10Ld\n", inputBufferLength);
586a2ca4723Sbeveloper 	TRACE("  outputBufferLength %10Ld\n", outputBufferLength);
587a2ca4723Sbeveloper 	TRACE("  mixerBufferLength  %10Ld\n", mixerBufferLength);
588d91580cdSbeveloper 	TRACE("  fMixBufferFrameCount   %10d\n", fMixBufferFrameCount);
5897b0daf5cSbeveloper 
5908d28117fSbeveloper 	ASSERT((fMixBufferFrameCount % frames) == 0);
5918d28117fSbeveloper 
592e92593f4Sbeveloper 	fLastDataFrameWritten = -1;
593e92593f4Sbeveloper 	fFractionalFrames = 0.0;
594e92593f4Sbeveloper 
5952e9d6607Sbeveloper 	rtm_free(fMixBuffer);
596356855c3Sbeveloper 	rtm_delete_pool(fRtmPool);
597*a9cf57cfSAxel Dörfler 
5987b0daf5cSbeveloper 	int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
599*a9cf57cfSAxel Dörfler 	if (rtm_create_pool(&fRtmPool, size) != B_OK)
600*a9cf57cfSAxel Dörfler 		fRtmPool = NULL;
601*a9cf57cfSAxel Dörfler 
602356855c3Sbeveloper 	fMixBuffer = (float *)rtm_alloc(fRtmPool, size);
603*a9cf57cfSAxel Dörfler 	if (fMixBuffer == NULL)
604*a9cf57cfSAxel Dörfler 		return;
6057b0daf5cSbeveloper 
6067b0daf5cSbeveloper 	memset(fMixBuffer, 0, size);
6072e9d6607Sbeveloper 
6082e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
6097b0daf5cSbeveloper 		fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
610d5848e21Sbeveloper 
6119c3be6a5Sbeveloper 	UpdateInputChannelDestinationMask();
6129c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
6132e9d6607Sbeveloper }
614