xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp (revision db6f1135a66869d6cf3e5b05211b4d584139c458)
1bf7ab50dSStephan Aßmus /*
2a9cf57cfSAxel Dörfler  * Copyright 2003-2009 Haiku Inc. All rights reserved.
3bf7ab50dSStephan Aßmus  * Distributed under the terms of the MIT License.
4bf7ab50dSStephan Aßmus  *
5bf7ab50dSStephan Aßmus  * Authors:
6bf7ab50dSStephan Aßmus  *		Marcus Overhagen
7bf7ab50dSStephan Aßmus  */
8a9cf57cfSAxel Dörfler 
9a9cf57cfSAxel Dörfler 
10bf7ab50dSStephan Aßmus #include "MixerCore.h"
11a9cf57cfSAxel Dörfler 
12a9cf57cfSAxel Dörfler #include <Buffer.h>
13a9cf57cfSAxel Dörfler #include <string.h>
14a9cf57cfSAxel Dörfler #include <TimeSource.h> // TODO: debug only
15a9cf57cfSAxel Dörfler 
16a9cf57cfSAxel 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 
22a9cf57cfSAxel Dörfler MixerInput::MixerInput(MixerCore *core, const media_input &input,
23a9cf57cfSAxel Dörfler 	float mixFrameRate, int32 mixFrameCount)
24a9cf57cfSAxel Dörfler 	:
25a9cf57cfSAxel 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) {
59a9cf57cfSAxel Dörfler 		if (fInput.format.u.raw_audio.format
60a9cf57cfSAxel Dörfler 				== media_raw_audio_format::B_AUDIO_FLOAT
61a9cf57cfSAxel Dörfler 			|| fInput.format.u.raw_audio.format
62a9cf57cfSAxel Dörfler 				== media_raw_audio_format::B_AUDIO_INT
63a9cf57cfSAxel Dörfler 			|| fInput.format.u.raw_audio.format
64a9cf57cfSAxel 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 
85a9cf57cfSAxel 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;
99*db6f1135SJérôme Duval 	delete fInputByteSwap;
100678c2017Sbeveloper }
101678c2017Sbeveloper 
102a9cf57cfSAxel Dörfler 
103678c2017Sbeveloper void
104678c2017Sbeveloper MixerInput::BufferReceived(BBuffer *buffer)
105678c2017Sbeveloper {
10688777023Sbeveloper 	void *data;
10788777023Sbeveloper 	size_t size;
10888777023Sbeveloper 	bigtime_t start;
109e92593f4Sbeveloper 	bigtime_t buffer_duration;
11088777023Sbeveloper 
111d5848e21Sbeveloper 	if (!fMixBuffer) {
112a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n");
113d5848e21Sbeveloper 		return;
114d5848e21Sbeveloper 	}
1152e9d6607Sbeveloper 
11688777023Sbeveloper 	data = buffer->Data();
11788777023Sbeveloper 	size = buffer->SizeUsed();
11888777023Sbeveloper 	start = buffer->Header()->start_time;
119e92593f4Sbeveloper 	buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate, size / bytes_per_frame(fInput.format.u.raw_audio));
1208d28117fSbeveloper 	if (start < 0) {
121a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: buffer with negative start time of %Ld dropped\n", start);
1228d28117fSbeveloper 		return;
1238d28117fSbeveloper 	}
12488777023Sbeveloper 
12588777023Sbeveloper 	// swap the byte order of this buffer, if necessary
12688777023Sbeveloper 	if (fInputByteSwap)
12788777023Sbeveloper 		fInputByteSwap->Swap(data, size);
12888777023Sbeveloper 
129d91580cdSbeveloper 	int offset = frames_for_duration(fMixBufferFrameRate, start) % fMixBufferFrameCount;
1308d28117fSbeveloper 
131191033efSbeveloper 	PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", start, offset);
1327b0daf5cSbeveloper 
133191033efSbeveloper 	int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio);
134e92593f4Sbeveloper 	double frames = double(in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate;
135e92593f4Sbeveloper 	int out_frames = int(frames);
136e92593f4Sbeveloper 	fFractionalFrames += frames - double(out_frames);
137e92593f4Sbeveloper 	if (fFractionalFrames >= 1.0) {
138e92593f4Sbeveloper 		fFractionalFrames -= 1.0;
1397619f562Sbeveloper 		out_frames++;
140e92593f4Sbeveloper 	}
141e92593f4Sbeveloper 
142e92593f4Sbeveloper 	// if fLastDataFrameWritten != -1, then we have a valid last position
143e92593f4Sbeveloper 	// and can do glitch compensation
144e92593f4Sbeveloper 	if (fLastDataFrameWritten >= 0) {
145e92593f4Sbeveloper 		int expected_frame = (fLastDataFrameWritten + 1) % fMixBufferFrameCount;
146e92593f4Sbeveloper 		if (offset != expected_frame) {
147e92593f4Sbeveloper 			// due to rounding and other errors, offset might be off by +/- 1
148e92593f4Sbeveloper 			// this is not really a bad glitch, we just adjust the position
149e92593f4Sbeveloper 			if (offset == fLastDataFrameWritten) {
150e92593f4Sbeveloper 				//printf("MixerInput::BufferReceived: -1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
151e92593f4Sbeveloper 				offset = expected_frame;
152e92593f4Sbeveloper 			} else if (offset == ((fLastDataFrameWritten + 2) % fMixBufferFrameCount)) {
153e92593f4Sbeveloper 				//printf("MixerInput::BufferReceived: +1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
154e92593f4Sbeveloper 				offset = expected_frame;
155e92593f4Sbeveloper 			} else {
156dbaf884cSbeveloper 				printf("MixerInput::BufferReceived: GLITCH! last frame was %4ld, expected frame was %4d, new frame is %4d\n", fLastDataFrameWritten, expected_frame, offset);
157e92593f4Sbeveloper 
158e92593f4Sbeveloper 				if (start > fLastDataAvailableTime) {
159e92593f4Sbeveloper 					if ((start - fLastDataAvailableTime) < (buffer_duration / 10)) {
160e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too late
161e92593f4Sbeveloper 						printf("short glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime);
162e92593f4Sbeveloper 						offset = expected_frame;
163e92593f4Sbeveloper 						out_frames++;
164e92593f4Sbeveloper 					} else {
165e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too late
166e92593f4Sbeveloper 						// XXX zerofill buffer
167e92593f4Sbeveloper 						printf("MAJOR glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime);
168e92593f4Sbeveloper 					}
169e92593f4Sbeveloper 				} else { // start <= fLastDataAvailableTime
170e92593f4Sbeveloper 					// the new buffer is too early
171e92593f4Sbeveloper 					if ((fLastDataAvailableTime - start) < (buffer_duration / 10)) {
172e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too early
173e92593f4Sbeveloper 						printf("short glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start);
174e92593f4Sbeveloper 						offset = expected_frame;
175e92593f4Sbeveloper 						out_frames--;
176e92593f4Sbeveloper 						if (out_frames < 1)
177e92593f4Sbeveloper 							out_frames = 1;
178e92593f4Sbeveloper 					} else {
179e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too early
180e92593f4Sbeveloper 						// XXX zerofill buffer
181e92593f4Sbeveloper 						printf("MAJOR glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start);
182e92593f4Sbeveloper 					}
183e92593f4Sbeveloper 				}
184e92593f4Sbeveloper 			}
185e92593f4Sbeveloper 		}
186e92593f4Sbeveloper 	}
1877b0daf5cSbeveloper 
1888d28117fSbeveloper 	//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);
1897b0daf5cSbeveloper 	if (offset + out_frames > fMixBufferFrameCount) {
1907b0daf5cSbeveloper 		int out_frames1 = fMixBufferFrameCount - offset;
1917b0daf5cSbeveloper 		int out_frames2 = out_frames - out_frames1;
1927b0daf5cSbeveloper 		int in_frames1 = (out_frames1 * in_frames) / out_frames;
1937b0daf5cSbeveloper 		int in_frames2 = in_frames - in_frames1;
1947b0daf5cSbeveloper 
195e92593f4Sbeveloper 		//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);
1967619f562Sbeveloper 		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);
197191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d, in_frames1 %5d, out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n",
198191033efSbeveloper 			  in_frames, out_frames, in_frames1, out_frames1, in_frames2, out_frames2);
1997b0daf5cSbeveloper 
200e92593f4Sbeveloper 		fLastDataFrameWritten = out_frames2 - 1;
201e92593f4Sbeveloper 
2028d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
2038d28117fSbeveloper 
2047b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
20578563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
20678563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2077b0daf5cSbeveloper 									in_frames1,
2088d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
2097b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2107b0daf5cSbeveloper 									out_frames1,
2117b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
2127b0daf5cSbeveloper 
2137d970b31Sbeveloper 			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),
21478563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2157b0daf5cSbeveloper 									in_frames2,
2167b0daf5cSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base),
2177b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2187b0daf5cSbeveloper 									out_frames2,
2197b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
220e92593f4Sbeveloper 
2217b0daf5cSbeveloper 		}
2227b0daf5cSbeveloper 	} else {
223e92593f4Sbeveloper 		//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);
2247619f562Sbeveloper 		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);
225191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d\n", in_frames, out_frames);
2268d28117fSbeveloper 
227e92593f4Sbeveloper 		fLastDataFrameWritten = offset + out_frames - 1;
2288d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
2297b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
23078563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
23178563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2327b0daf5cSbeveloper 									in_frames,
2338d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
2347b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2357b0daf5cSbeveloper 									out_frames,
2367b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
2377b0daf5cSbeveloper 		}
2387b0daf5cSbeveloper 	}
239e92593f4Sbeveloper 	fLastDataAvailableTime = start + buffer_duration;
240678c2017Sbeveloper }
2417ee2c804Sbeveloper 
242bf7ab50dSStephan Aßmus 
2437ee2c804Sbeveloper media_input &
2447ee2c804Sbeveloper MixerInput::MediaInput()
2457ee2c804Sbeveloper {
2467ee2c804Sbeveloper 	return fInput;
2477ee2c804Sbeveloper }
248e6c7c99fSbeveloper 
249bf7ab50dSStephan Aßmus 
250e6c7c99fSbeveloper int32
251e6c7c99fSbeveloper MixerInput::ID()
252e6c7c99fSbeveloper {
253e6c7c99fSbeveloper 	return fInput.destination.id;
254e6c7c99fSbeveloper }
255e6c7c99fSbeveloper 
256bf7ab50dSStephan Aßmus 
257d91580cdSbeveloper int
258fae6ce82Sbeveloper MixerInput::GetInputChannelCount()
259fae6ce82Sbeveloper {
260fae6ce82Sbeveloper 	return fInputChannelCount;
261fae6ce82Sbeveloper }
262fae6ce82Sbeveloper 
263bf7ab50dSStephan Aßmus 
2642e9d6607Sbeveloper void
2659c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type)
2662e9d6607Sbeveloper {
2679c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
268e6c7c99fSbeveloper 
2692e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2702e9d6607Sbeveloper 		return;
2712e9d6607Sbeveloper 
2722e9d6607Sbeveloper 	// test if it is already set
2739c3be6a5Sbeveloper 	if (fInputChannelInfo[channel].destination_mask & mask)
2742e9d6607Sbeveloper 		return;
2752e9d6607Sbeveloper 
2769c3be6a5Sbeveloper 	// verify that no other channel has id
2779c3be6a5Sbeveloper 	if (-1 != GetInputChannelForDestination(destination_type)) {
2789c3be6a5Sbeveloper 		ERROR("MixerInput::AddInputChannelDestination: destination_type %d already assigned to channel %d\n", destination_type, GetInputChannelForDestination(destination_type));
2799c3be6a5Sbeveloper 		return;
2809c3be6a5Sbeveloper 	}
2812e9d6607Sbeveloper 
2822e9d6607Sbeveloper 	// add it to specified channel
2839c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask |= mask;
2842e9d6607Sbeveloper 
2859c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
2869c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
2872e9d6607Sbeveloper }
2882e9d6607Sbeveloper 
289a9cf57cfSAxel Dörfler 
2902e9d6607Sbeveloper void
2919c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
2922e9d6607Sbeveloper {
2939c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
2942e9d6607Sbeveloper 
2952e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2962e9d6607Sbeveloper 		return;
2972e9d6607Sbeveloper 
2982e9d6607Sbeveloper 	// test if it is really set
2999c3be6a5Sbeveloper 	if ((fInputChannelInfo[channel].destination_mask & mask) == 0)
3002e9d6607Sbeveloper 		return;
3012e9d6607Sbeveloper 
3022e9d6607Sbeveloper 	// remove it from specified channel
3039c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask &= ~mask;
3042e9d6607Sbeveloper 
3059c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
3069c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
3072e9d6607Sbeveloper }
3082e9d6607Sbeveloper 
309a9cf57cfSAxel Dörfler 
3109c3be6a5Sbeveloper bool
3119c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type)
3122e9d6607Sbeveloper {
3132e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3149c3be6a5Sbeveloper 		return false;
3159c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
3169c3be6a5Sbeveloper 		return false;
3179c3be6a5Sbeveloper 	return fInputChannelInfo[channel].destination_mask & ChannelTypeToChannelMask(destination_type);
3182e9d6607Sbeveloper }
3192e9d6607Sbeveloper 
320a9cf57cfSAxel Dörfler 
3219c3be6a5Sbeveloper int
3229c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type)
3239c3be6a5Sbeveloper {
3249c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
3259c3be6a5Sbeveloper 		return -1;
3269c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
3279c3be6a5Sbeveloper 	for (int chan = 0; chan < fInputChannelCount; chan++) {
3289c3be6a5Sbeveloper 		if (fInputChannelInfo[chan].destination_mask & mask)
3299c3be6a5Sbeveloper 			return chan;
3309c3be6a5Sbeveloper 	}
3319c3be6a5Sbeveloper 	return -1;
3329c3be6a5Sbeveloper }
3339c3be6a5Sbeveloper 
334a9cf57cfSAxel Dörfler 
3359c3be6a5Sbeveloper int
3362e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel)
3372e9d6607Sbeveloper {
3382e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3392e9d6607Sbeveloper 		return 0;
3409c3be6a5Sbeveloper 	return GetChannelType(channel, fInputChannelMask);
3412e9d6607Sbeveloper }
3422e9d6607Sbeveloper 
343a9cf57cfSAxel Dörfler 
3442e9d6607Sbeveloper void
3452e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain)
3462e9d6607Sbeveloper {
3472e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3482e9d6607Sbeveloper 		return;
3492e9d6607Sbeveloper 	if (gain < 0.0f)
3502e9d6607Sbeveloper 		gain = 0.0f;
3512e9d6607Sbeveloper 
3522e9d6607Sbeveloper 	fInputChannelInfo[channel].gain = gain;
3532e9d6607Sbeveloper }
3542e9d6607Sbeveloper 
355a9cf57cfSAxel Dörfler 
3562e9d6607Sbeveloper float
3572e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel)
3582e9d6607Sbeveloper {
3592e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3602e9d6607Sbeveloper 		return 0.0f;
3612e9d6607Sbeveloper 	return fInputChannelInfo[channel].gain;
3622e9d6607Sbeveloper }
3632e9d6607Sbeveloper 
364a9cf57cfSAxel Dörfler 
3652e9d6607Sbeveloper void
3669c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinationMask()
3672e9d6607Sbeveloper {
3682e9d6607Sbeveloper 	// is the user already messed with the assignmens, don't do anything.
3699c3be6a5Sbeveloper 	if (fUserOverridesChannelDestinations)
3702e9d6607Sbeveloper 		return;
3712e9d6607Sbeveloper 
3729c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: enter\n");
3732e9d6607Sbeveloper 
374806cf560Sbeveloper 	// first apply a 1:1 mapping
3752e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
3769c3be6a5Sbeveloper 		fInputChannelInfo[i].destination_mask = GetChannelMask(i, fInputChannelMask);
377806cf560Sbeveloper 
378806cf560Sbeveloper 	// specialize this, depending on the available physical output channels
379643e1b2eSbeveloper 	if (fCore->OutputChannelCount() <= 2) {
380643e1b2eSbeveloper 		// less or equal two channels
381806cf560Sbeveloper 		if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
382ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
383806cf560Sbeveloper 		}
384643e1b2eSbeveloper 	} else {
385643e1b2eSbeveloper 		// more than two channel output card
386806cf560Sbeveloper 		if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
387ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
388806cf560Sbeveloper 		}
389806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) {
3909c3be6a5Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
391806cf560Sbeveloper 		}
392806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3939c3be6a5Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
394806cf560Sbeveloper 		}
395806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) {
3969c3be6a5Sbeveloper 			fInputChannelInfo[1].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
397806cf560Sbeveloper 		}
398806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3999c3be6a5Sbeveloper 			fInputChannelInfo[1].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
400806cf560Sbeveloper 		}
4012e9d6607Sbeveloper 	}
4022e9d6607Sbeveloper 
4032e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
404d91580cdSbeveloper 		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);
4059c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: leave\n");
4062e9d6607Sbeveloper }
4072e9d6607Sbeveloper 
408a9cf57cfSAxel Dörfler 
4092e9d6607Sbeveloper void
4109c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinations()
4112e9d6607Sbeveloper {
412d91580cdSbeveloper 	int channel_count;
4132e9d6607Sbeveloper 	uint32 all_bits;
4142e9d6607Sbeveloper 	uint32 mask;
4152e9d6607Sbeveloper 
4169c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: enter\n");
4172e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
418d91580cdSbeveloper 		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);
4192e9d6607Sbeveloper 
4202e9d6607Sbeveloper 	all_bits = 0;
4212e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
4229c3be6a5Sbeveloper 		all_bits |= fInputChannelInfo[i].destination_mask;
4232e9d6607Sbeveloper 
424d91580cdSbeveloper 	TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
4252e9d6607Sbeveloper 
4262e9d6607Sbeveloper 	channel_count = count_nonzero_bits(all_bits);
427d91580cdSbeveloper 	TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer channels (%d old)\n", fInputChannelCount, channel_count, fMixerChannelCount);
4282e9d6607Sbeveloper 	if (channel_count != fMixerChannelCount) {
4299c3be6a5Sbeveloper 		delete [] fMixerChannelInfo;
4302e9d6607Sbeveloper 		fMixerChannelInfo = new mixer_chan_info[channel_count];
4312e9d6607Sbeveloper 		fMixerChannelCount = channel_count;
4322e9d6607Sbeveloper 	}
4332e9d6607Sbeveloper 
4342e9d6607Sbeveloper 	// assign each mixer channel one type
4359c3be6a5Sbeveloper 	// and the gain from the fChannelTypeGain[]
436d91580cdSbeveloper 	mask = 1;
437d91580cdSbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4382e9d6607Sbeveloper 		while (mask != 0 && (all_bits & mask) == 0)
4392e9d6607Sbeveloper 			mask <<= 1;
4409c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask);
4419c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_gain = fChannelTypeGain[fMixerChannelInfo[i].destination_type];
4422e9d6607Sbeveloper 		mask <<= 1;
4432e9d6607Sbeveloper 	}
4442e9d6607Sbeveloper 
4452e9d6607Sbeveloper 	// assign buffer_base pointer for each mixer channel
4462e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4472e9d6607Sbeveloper 		int j;
4482e9d6607Sbeveloper 		for (j = 0; j < fInputChannelCount; j++) {
4499c3be6a5Sbeveloper 			if (fInputChannelInfo[j].destination_mask & ChannelTypeToChannelMask(fMixerChannelInfo[i].destination_type)) {
450d5848e21Sbeveloper 				fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] : 0;
4512e9d6607Sbeveloper 				break;
4522e9d6607Sbeveloper 			}
4532e9d6607Sbeveloper 		}
4542e9d6607Sbeveloper 		if (j == fInputChannelCount) {
455a2ca4723Sbeveloper 			ERROR("buffer assignment failed for mixer chan %d\n", i);
4562e9d6607Sbeveloper 			fMixerChannelInfo[i].buffer_base = fMixBuffer;
4572e9d6607Sbeveloper 		}
4582e9d6607Sbeveloper 	}
4592e9d6607Sbeveloper 
4602e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++)
4619c3be6a5Sbeveloper 		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);
4622e9d6607Sbeveloper 
4639c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: leave\n");
4642e9d6607Sbeveloper }
465bf7ab50dSStephan Aßmus 
466a9cf57cfSAxel Dörfler 
467bf7ab50dSStephan Aßmus // Note: The following code is outcommented on purpose
468bf7ab50dSStephan Aßmus // and is about to be modified at a later point
46969517c15Sbeveloper /*
4702e9d6607Sbeveloper void
4719c3be6a5Sbeveloper MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, float gain)
4722e9d6607Sbeveloper {
4739c3be6a5Sbeveloper 	TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, gain %.4f\n", channel, destination_type, gain);
4749c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
4759c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
4769c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
4772e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4782e9d6607Sbeveloper 		return;
4799c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
4809c3be6a5Sbeveloper 		return;
4812e9d6607Sbeveloper 	if (gain < 0.0f)
4822e9d6607Sbeveloper 		gain = 0.0f;
4839c3be6a5Sbeveloper 	fChannelTypeGain[destination_type] = gain;
4849c3be6a5Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4859c3be6a5Sbeveloper 		if (fMixerChannelInfo[i].destination_type == destination_type) {
4869c3be6a5Sbeveloper 			fMixerChannelInfo[i].destination_gain = gain;
4879c3be6a5Sbeveloper 			return;
4889c3be6a5Sbeveloper 		}
4899c3be6a5Sbeveloper 	}
4902e9d6607Sbeveloper }
4912e9d6607Sbeveloper 
492a9cf57cfSAxel Dörfler 
4932e9d6607Sbeveloper float
4949c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type)
4952e9d6607Sbeveloper {
4969c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
4979c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
4989c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
4992e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
5009c3be6a5Sbeveloper 		return 0.0f;
5019c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
5029c3be6a5Sbeveloper 		return 0.0f;
5039c3be6a5Sbeveloper 	return fChannelTypeGain[destination_type];
5042e9d6607Sbeveloper }
50569517c15Sbeveloper */
50669517c15Sbeveloper 
507a9cf57cfSAxel Dörfler 
50869517c15Sbeveloper void
50969517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain)
51069517c15Sbeveloper {
51169517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
51269517c15Sbeveloper 		return;
51369517c15Sbeveloper 	if (gain < 0.0f)
51469517c15Sbeveloper 		gain = 0.0f;
51569517c15Sbeveloper 
51669517c15Sbeveloper 	fMixerChannelInfo[mixer_channel].destination_gain = gain;
51769517c15Sbeveloper 	fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain;
51869517c15Sbeveloper }
51969517c15Sbeveloper 
520a9cf57cfSAxel Dörfler 
52169517c15Sbeveloper float
52269517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel)
52369517c15Sbeveloper {
52469517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
52569517c15Sbeveloper 		return 0.0;
52669517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_gain;
52769517c15Sbeveloper }
52869517c15Sbeveloper 
529a9cf57cfSAxel Dörfler 
53069517c15Sbeveloper int
53169517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel)
53269517c15Sbeveloper {
53369517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
53469517c15Sbeveloper 		return -1;
53569517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_type;
53669517c15Sbeveloper }
5372e9d6607Sbeveloper 
538a9cf57cfSAxel Dörfler 
5392e9d6607Sbeveloper void
5401c237c18Sbeveloper MixerInput::SetEnabled(bool yesno)
5411c237c18Sbeveloper {
5421c237c18Sbeveloper 	fEnabled = yesno;
5431c237c18Sbeveloper }
5441c237c18Sbeveloper 
545a9cf57cfSAxel Dörfler 
5461c237c18Sbeveloper bool
5471c237c18Sbeveloper MixerInput::IsEnabled()
5481c237c18Sbeveloper {
5491c237c18Sbeveloper 	return fEnabled;
5501c237c18Sbeveloper }
5511c237c18Sbeveloper 
552a9cf57cfSAxel Dörfler 
5531c237c18Sbeveloper void
5548d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
5552e9d6607Sbeveloper {
556a9cf57cfSAxel Dörfler 	TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n",
557a9cf57cfSAxel Dörfler 		framerate, frames);
558d5848e21Sbeveloper 
5597b0daf5cSbeveloper 	fMixBufferFrameRate = framerate;
560a9cf57cfSAxel Dörfler 	fDebugMixBufferFrames = frames;
5612e9d6607Sbeveloper 
562d5848e21Sbeveloper 	// frames and/or framerate can be 0 (if no output is connected)
563d5848e21Sbeveloper 	if (framerate == 0 || frames == 0) {
564a9cf57cfSAxel Dörfler 		if (fMixBuffer != NULL) {
565d5848e21Sbeveloper 			rtm_free(fMixBuffer);
566a9cf57cfSAxel Dörfler 			fMixBuffer = NULL;
567d5848e21Sbeveloper 		}
568d5848e21Sbeveloper 		for (int i = 0; i < fInputChannelCount; i++)
569d5848e21Sbeveloper 			fInputChannelInfo[i].buffer_base = 0;
570d5848e21Sbeveloper 		fMixBufferFrameCount = 0;
571d5848e21Sbeveloper 
5729c3be6a5Sbeveloper 		UpdateInputChannelDestinationMask();
5739c3be6a5Sbeveloper 		UpdateInputChannelDestinations();
574d5848e21Sbeveloper 		return;
575d5848e21Sbeveloper 	}
5767b0daf5cSbeveloper 
5777b0daf5cSbeveloper 	// make fMixBufferFrameCount an integral multiple of frames,
5787b0daf5cSbeveloper 	// but at least 3 times duration of our input buffer
5797b0daf5cSbeveloper 	// and at least 2 times duration of the output buffer
5807b0daf5cSbeveloper 	bigtime_t inputBufferLength  = duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio));
5817b0daf5cSbeveloper 	bigtime_t outputBufferLength = duration_for_frames(framerate, frames);
5827b0daf5cSbeveloper 	bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength);
5837b0daf5cSbeveloper 	int temp = frames_for_duration(framerate, mixerBufferLength);
5847b0daf5cSbeveloper 	fMixBufferFrameCount = ((temp / frames) + 1) * frames;
5857b0daf5cSbeveloper 
586a2ca4723Sbeveloper 	TRACE("  inputBufferLength  %10Ld\n", inputBufferLength);
587a2ca4723Sbeveloper 	TRACE("  outputBufferLength %10Ld\n", outputBufferLength);
588a2ca4723Sbeveloper 	TRACE("  mixerBufferLength  %10Ld\n", mixerBufferLength);
589d91580cdSbeveloper 	TRACE("  fMixBufferFrameCount   %10d\n", fMixBufferFrameCount);
5907b0daf5cSbeveloper 
5918d28117fSbeveloper 	ASSERT((fMixBufferFrameCount % frames) == 0);
5928d28117fSbeveloper 
593e92593f4Sbeveloper 	fLastDataFrameWritten = -1;
594e92593f4Sbeveloper 	fFractionalFrames = 0.0;
595e92593f4Sbeveloper 
5962e9d6607Sbeveloper 	rtm_free(fMixBuffer);
597356855c3Sbeveloper 	rtm_delete_pool(fRtmPool);
598a9cf57cfSAxel Dörfler 
5997b0daf5cSbeveloper 	int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
600a9cf57cfSAxel Dörfler 	if (rtm_create_pool(&fRtmPool, size) != B_OK)
601a9cf57cfSAxel Dörfler 		fRtmPool = NULL;
602a9cf57cfSAxel Dörfler 
603356855c3Sbeveloper 	fMixBuffer = (float *)rtm_alloc(fRtmPool, size);
604a9cf57cfSAxel Dörfler 	if (fMixBuffer == NULL)
605a9cf57cfSAxel Dörfler 		return;
6067b0daf5cSbeveloper 
6077b0daf5cSbeveloper 	memset(fMixBuffer, 0, size);
6082e9d6607Sbeveloper 
6092e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
6107b0daf5cSbeveloper 		fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
611d5848e21Sbeveloper 
6129c3be6a5Sbeveloper 	UpdateInputChannelDestinationMask();
6139c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
6142e9d6607Sbeveloper }
615