xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp (revision bf7ab50d4ced3f1735551c8f6d9032a42e548f7e)
1*bf7ab50dSStephan Aßmus /*
2*bf7ab50dSStephan Aßmus  * Copyright 2007 Haiku Inc. All rights reserved.
3*bf7ab50dSStephan Aßmus  * Distributed under the terms of the MIT License.
4*bf7ab50dSStephan Aßmus  *
5*bf7ab50dSStephan Aßmus  * Authors:
6*bf7ab50dSStephan Aßmus  *              Marcus Overhagen
7*bf7ab50dSStephan Aßmus  */
8*bf7ab50dSStephan Aßmus #include "ByteSwap.h"
9*bf7ab50dSStephan Aßmus #include "MixerCore.h"
10*bf7ab50dSStephan Aßmus #include "MixerInput.h"
11*bf7ab50dSStephan Aßmus #include "MixerUtils.h"
12*bf7ab50dSStephan Aßmus #include "Resampler.h"
13*bf7ab50dSStephan Aßmus 
142e9d6607Sbeveloper #include <Buffer.h>
157b0daf5cSbeveloper #include <string.h>
168d28117fSbeveloper #include <TimeSource.h> // XXX debug only
17678c2017Sbeveloper 
188d28117fSbeveloper MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount)
19e6c7c99fSbeveloper  :	fCore(core),
202e9d6607Sbeveloper  	fInput(input),
2188777023Sbeveloper 	fInputByteSwap(0),
221c237c18Sbeveloper 	fEnabled(true),
232e9d6607Sbeveloper 	fInputChannelInfo(0),
242e9d6607Sbeveloper 	fInputChannelCount(0),
252e9d6607Sbeveloper 	fInputChannelMask(0),
262e9d6607Sbeveloper 	fMixerChannelInfo(0),
272e9d6607Sbeveloper 	fMixerChannelCount(0),
282e9d6607Sbeveloper 	fMixBuffer(0),
297b0daf5cSbeveloper 	fMixBufferFrameRate(0),
307b0daf5cSbeveloper 	fMixBufferFrameCount(0),
31e92593f4Sbeveloper 	fLastDataFrameWritten(-1),
32af8d0a4dSbeveloper 	fLastDataAvailableTime(-1),
33e92593f4Sbeveloper 	fFractionalFrames(0.0),
347b0daf5cSbeveloper 	fResampler(0),
35356855c3Sbeveloper 	fRtmPool(0),
369c3be6a5Sbeveloper 	fUserOverridesChannelDestinations(false)
37678c2017Sbeveloper {
38e6c7c99fSbeveloper 	fix_multiaudio_format(&fInput.format.u.raw_audio);
39e6c7c99fSbeveloper 	PRINT_INPUT("MixerInput::MixerInput", fInput);
40e6c7c99fSbeveloper 	PRINT_CHANNEL_MASK(fInput.format);
412e9d6607Sbeveloper 
422e9d6607Sbeveloper 	ASSERT(fInput.format.u.raw_audio.channel_count > 0);
432e9d6607Sbeveloper 
449c3be6a5Sbeveloper 	for (int i = 0; i <	MAX_CHANNEL_TYPES; i++)
459c3be6a5Sbeveloper 		fChannelTypeGain[i] = 1.0f;
469c3be6a5Sbeveloper 
472e9d6607Sbeveloper 	fInputChannelCount = fInput.format.u.raw_audio.channel_count;
482e9d6607Sbeveloper 	fInputChannelMask = fInput.format.u.raw_audio.channel_mask;
492e9d6607Sbeveloper 	fInputChannelInfo = new input_chan_info[fInputChannelCount];
502e9d6607Sbeveloper 
5188777023Sbeveloper 	// perhaps we need byte swapping
5288777023Sbeveloper 	if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
5388777023Sbeveloper 		if (	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
5488777023Sbeveloper 			 ||	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT
5588777023Sbeveloper 			 ||	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
5688777023Sbeveloper 			fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format);
5788777023Sbeveloper 		}
5888777023Sbeveloper 	}
5988777023Sbeveloper 
602e9d6607Sbeveloper 	// initialize fInputChannelInfo
612e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++) {
622e9d6607Sbeveloper 		fInputChannelInfo[i].buffer_base = 0;	// will be set by SetMixBufferFormat()
639c3be6a5Sbeveloper 		fInputChannelInfo[i].destination_mask = 0;	// will be set by UpdateInputChannelDestinationMask()
642e9d6607Sbeveloper 		fInputChannelInfo[i].gain = 1.0;
652e9d6607Sbeveloper 	}
662e9d6607Sbeveloper 
677b0daf5cSbeveloper 	// create resamplers
687b0daf5cSbeveloper 	fResampler = new Resampler * [fInputChannelCount];
697b0daf5cSbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
70ff14d245SJérôme Duval 		fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT, 0);
717b0daf5cSbeveloper 
729c3be6a5Sbeveloper 	// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations()
73*bf7ab50dSStephan Aßmus 	SetMixBufferFormat((int32)mixFrameRate, mixFrameCount);
74678c2017Sbeveloper }
75678c2017Sbeveloper 
76678c2017Sbeveloper MixerInput::~MixerInput()
77678c2017Sbeveloper {
782e9d6607Sbeveloper 	if (fMixBuffer)
792e9d6607Sbeveloper 		rtm_free(fMixBuffer);
80356855c3Sbeveloper 	if (fRtmPool)
81356855c3Sbeveloper 		rtm_delete_pool(fRtmPool);
822e9d6607Sbeveloper 	delete [] fInputChannelInfo;
832e9d6607Sbeveloper 	delete [] fMixerChannelInfo;
847b0daf5cSbeveloper 
857b0daf5cSbeveloper 	// delete resamplers
867b0daf5cSbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
877b0daf5cSbeveloper 		delete fResampler[i];
887b0daf5cSbeveloper 	delete [] fResampler;
89678c2017Sbeveloper }
90678c2017Sbeveloper 
91678c2017Sbeveloper void
92678c2017Sbeveloper MixerInput::BufferReceived(BBuffer *buffer)
93678c2017Sbeveloper {
9488777023Sbeveloper 	void *data;
9588777023Sbeveloper 	size_t size;
9688777023Sbeveloper 	bigtime_t start;
97e92593f4Sbeveloper 	bigtime_t buffer_duration;
9888777023Sbeveloper 
99d5848e21Sbeveloper 	if (!fMixBuffer) {
100a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n");
101d5848e21Sbeveloper 		return;
102d5848e21Sbeveloper 	}
1032e9d6607Sbeveloper 
10488777023Sbeveloper 	data = buffer->Data();
10588777023Sbeveloper 	size = buffer->SizeUsed();
10688777023Sbeveloper 	start = buffer->Header()->start_time;
107e92593f4Sbeveloper 	buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate, size / bytes_per_frame(fInput.format.u.raw_audio));
1088d28117fSbeveloper 	if (start < 0) {
109a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: buffer with negative start time of %Ld dropped\n", start);
1108d28117fSbeveloper 		return;
1118d28117fSbeveloper 	}
11288777023Sbeveloper 
11388777023Sbeveloper 	// swap the byte order of this buffer, if necessary
11488777023Sbeveloper 	if (fInputByteSwap)
11588777023Sbeveloper 		fInputByteSwap->Swap(data, size);
11688777023Sbeveloper 
117d91580cdSbeveloper 	int offset = frames_for_duration(fMixBufferFrameRate, start) % fMixBufferFrameCount;
1188d28117fSbeveloper 
119191033efSbeveloper 	PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", start, offset);
1207b0daf5cSbeveloper 
121191033efSbeveloper 	int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio);
122e92593f4Sbeveloper 	double frames = double(in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate;
123e92593f4Sbeveloper 	int out_frames = int(frames);
124e92593f4Sbeveloper 	fFractionalFrames += frames - double(out_frames);
125e92593f4Sbeveloper 	if (fFractionalFrames >= 1.0) {
126e92593f4Sbeveloper 		fFractionalFrames -= 1.0;
1277619f562Sbeveloper 		out_frames++;
128e92593f4Sbeveloper 	}
129e92593f4Sbeveloper 
130e92593f4Sbeveloper 	// if fLastDataFrameWritten != -1, then we have a valid last position
131e92593f4Sbeveloper 	// and can do glitch compensation
132e92593f4Sbeveloper 	if (fLastDataFrameWritten >= 0) {
133e92593f4Sbeveloper 		int expected_frame = (fLastDataFrameWritten + 1) % fMixBufferFrameCount;
134e92593f4Sbeveloper 		if (offset != expected_frame) {
135e92593f4Sbeveloper 			// due to rounding and other errors, offset might be off by +/- 1
136e92593f4Sbeveloper 			// this is not really a bad glitch, we just adjust the position
137e92593f4Sbeveloper 			if (offset == fLastDataFrameWritten) {
138e92593f4Sbeveloper 				//printf("MixerInput::BufferReceived: -1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
139e92593f4Sbeveloper 				offset = expected_frame;
140e92593f4Sbeveloper 			} else if (offset == ((fLastDataFrameWritten + 2) % fMixBufferFrameCount)) {
141e92593f4Sbeveloper 				//printf("MixerInput::BufferReceived: +1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
142e92593f4Sbeveloper 				offset = expected_frame;
143e92593f4Sbeveloper 			} else {
144dbaf884cSbeveloper 				printf("MixerInput::BufferReceived: GLITCH! last frame was %4ld, expected frame was %4d, new frame is %4d\n", fLastDataFrameWritten, expected_frame, offset);
145e92593f4Sbeveloper 
146e92593f4Sbeveloper 				if (start > fLastDataAvailableTime) {
147e92593f4Sbeveloper 					if ((start - fLastDataAvailableTime) < (buffer_duration / 10)) {
148e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too late
149e92593f4Sbeveloper 						printf("short glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime);
150e92593f4Sbeveloper 						offset = expected_frame;
151e92593f4Sbeveloper 						out_frames++;
152e92593f4Sbeveloper 					} else {
153e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too late
154e92593f4Sbeveloper 						// XXX zerofill buffer
155e92593f4Sbeveloper 						printf("MAJOR glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime);
156e92593f4Sbeveloper 					}
157e92593f4Sbeveloper 				} else { // start <= fLastDataAvailableTime
158e92593f4Sbeveloper 					// the new buffer is too early
159e92593f4Sbeveloper 					if ((fLastDataAvailableTime - start) < (buffer_duration / 10)) {
160e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too early
161e92593f4Sbeveloper 						printf("short glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start);
162e92593f4Sbeveloper 						offset = expected_frame;
163e92593f4Sbeveloper 						out_frames--;
164e92593f4Sbeveloper 						if (out_frames < 1)
165e92593f4Sbeveloper 							out_frames = 1;
166e92593f4Sbeveloper 					} else {
167e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too early
168e92593f4Sbeveloper 						// XXX zerofill buffer
169e92593f4Sbeveloper 						printf("MAJOR glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start);
170e92593f4Sbeveloper 					}
171e92593f4Sbeveloper 				}
172e92593f4Sbeveloper 			}
173e92593f4Sbeveloper 		}
174e92593f4Sbeveloper 	}
1757b0daf5cSbeveloper 
1768d28117fSbeveloper 	//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);
1777b0daf5cSbeveloper 	if (offset + out_frames > fMixBufferFrameCount) {
1787b0daf5cSbeveloper 		int out_frames1 = fMixBufferFrameCount - offset;
1797b0daf5cSbeveloper 		int out_frames2 = out_frames - out_frames1;
1807b0daf5cSbeveloper 		int in_frames1 = (out_frames1 * in_frames) / out_frames;
1817b0daf5cSbeveloper 		int in_frames2 = in_frames - in_frames1;
1827b0daf5cSbeveloper 
183e92593f4Sbeveloper 		//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);
1847619f562Sbeveloper 		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);
185191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d, in_frames1 %5d, out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n",
186191033efSbeveloper 			  in_frames, out_frames, in_frames1, out_frames1, in_frames2, out_frames2);
1877b0daf5cSbeveloper 
188e92593f4Sbeveloper 		fLastDataFrameWritten = out_frames2 - 1;
189e92593f4Sbeveloper 
1908d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
1918d28117fSbeveloper 
1927b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
19378563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
19478563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
1957b0daf5cSbeveloper 									in_frames1,
1968d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
1977b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
1987b0daf5cSbeveloper 									out_frames1,
1997b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
2007b0daf5cSbeveloper 
2017d970b31Sbeveloper 			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),
20278563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2037b0daf5cSbeveloper 									in_frames2,
2047b0daf5cSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base),
2057b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2067b0daf5cSbeveloper 									out_frames2,
2077b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
208e92593f4Sbeveloper 
2097b0daf5cSbeveloper 		}
2107b0daf5cSbeveloper 	} else {
211e92593f4Sbeveloper 		//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);
2127619f562Sbeveloper 		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);
213191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d\n", in_frames, out_frames);
2148d28117fSbeveloper 
215e92593f4Sbeveloper 		fLastDataFrameWritten = offset + out_frames - 1;
2168d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
2177b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
21878563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
21978563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2207b0daf5cSbeveloper 									in_frames,
2218d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
2227b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2237b0daf5cSbeveloper 									out_frames,
2247b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
2257b0daf5cSbeveloper 		}
2267b0daf5cSbeveloper 	}
227e92593f4Sbeveloper 	fLastDataAvailableTime = start + buffer_duration;
228678c2017Sbeveloper }
2297ee2c804Sbeveloper 
230*bf7ab50dSStephan Aßmus 
2317ee2c804Sbeveloper media_input &
2327ee2c804Sbeveloper MixerInput::MediaInput()
2337ee2c804Sbeveloper {
2347ee2c804Sbeveloper 	return fInput;
2357ee2c804Sbeveloper }
236e6c7c99fSbeveloper 
237*bf7ab50dSStephan Aßmus 
238e6c7c99fSbeveloper int32
239e6c7c99fSbeveloper MixerInput::ID()
240e6c7c99fSbeveloper {
241e6c7c99fSbeveloper 	return fInput.destination.id;
242e6c7c99fSbeveloper }
243e6c7c99fSbeveloper 
244*bf7ab50dSStephan Aßmus 
245d91580cdSbeveloper int
246fae6ce82Sbeveloper MixerInput::GetInputChannelCount()
247fae6ce82Sbeveloper {
248fae6ce82Sbeveloper 	return fInputChannelCount;
249fae6ce82Sbeveloper }
250fae6ce82Sbeveloper 
251*bf7ab50dSStephan Aßmus 
2522e9d6607Sbeveloper void
2539c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type)
2542e9d6607Sbeveloper {
2559c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
256e6c7c99fSbeveloper 
2572e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2582e9d6607Sbeveloper 		return;
2592e9d6607Sbeveloper 
2602e9d6607Sbeveloper 	// test if it is already set
2619c3be6a5Sbeveloper 	if (fInputChannelInfo[channel].destination_mask & mask)
2622e9d6607Sbeveloper 		return;
2632e9d6607Sbeveloper 
2649c3be6a5Sbeveloper 	// verify that no other channel has id
2659c3be6a5Sbeveloper 	if (-1 != GetInputChannelForDestination(destination_type)) {
2669c3be6a5Sbeveloper 		ERROR("MixerInput::AddInputChannelDestination: destination_type %d already assigned to channel %d\n", destination_type, GetInputChannelForDestination(destination_type));
2679c3be6a5Sbeveloper 		return;
2689c3be6a5Sbeveloper 	}
2692e9d6607Sbeveloper 
2702e9d6607Sbeveloper 	// add it to specified channel
2719c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask |= mask;
2722e9d6607Sbeveloper 
2739c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
2749c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
2752e9d6607Sbeveloper }
2762e9d6607Sbeveloper 
2772e9d6607Sbeveloper void
2789c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
2792e9d6607Sbeveloper {
2809c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
2812e9d6607Sbeveloper 
2822e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2832e9d6607Sbeveloper 		return;
2842e9d6607Sbeveloper 
2852e9d6607Sbeveloper 	// test if it is really set
2869c3be6a5Sbeveloper 	if ((fInputChannelInfo[channel].destination_mask & mask) == 0)
2872e9d6607Sbeveloper 		return;
2882e9d6607Sbeveloper 
2892e9d6607Sbeveloper 	// remove it from specified channel
2909c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask &= ~mask;
2912e9d6607Sbeveloper 
2929c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
2939c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
2942e9d6607Sbeveloper }
2952e9d6607Sbeveloper 
2969c3be6a5Sbeveloper bool
2979c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type)
2982e9d6607Sbeveloper {
2992e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3009c3be6a5Sbeveloper 		return false;
3019c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
3029c3be6a5Sbeveloper 		return false;
3039c3be6a5Sbeveloper 	return fInputChannelInfo[channel].destination_mask & ChannelTypeToChannelMask(destination_type);
3042e9d6607Sbeveloper }
3052e9d6607Sbeveloper 
3069c3be6a5Sbeveloper int
3079c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type)
3089c3be6a5Sbeveloper {
3099c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
3109c3be6a5Sbeveloper 		return -1;
3119c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
3129c3be6a5Sbeveloper 	for (int chan = 0; chan < fInputChannelCount; chan++) {
3139c3be6a5Sbeveloper 		if (fInputChannelInfo[chan].destination_mask & mask)
3149c3be6a5Sbeveloper 			return chan;
3159c3be6a5Sbeveloper 	}
3169c3be6a5Sbeveloper 	return -1;
3179c3be6a5Sbeveloper }
3189c3be6a5Sbeveloper 
3199c3be6a5Sbeveloper int
3202e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel)
3212e9d6607Sbeveloper {
3222e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3232e9d6607Sbeveloper 		return 0;
3249c3be6a5Sbeveloper 	return GetChannelType(channel, fInputChannelMask);
3252e9d6607Sbeveloper }
3262e9d6607Sbeveloper 
3272e9d6607Sbeveloper void
3282e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain)
3292e9d6607Sbeveloper {
3302e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3312e9d6607Sbeveloper 		return;
3322e9d6607Sbeveloper 	if (gain < 0.0f)
3332e9d6607Sbeveloper 		gain = 0.0f;
3342e9d6607Sbeveloper 
3352e9d6607Sbeveloper 	fInputChannelInfo[channel].gain = gain;
3362e9d6607Sbeveloper }
3372e9d6607Sbeveloper 
3382e9d6607Sbeveloper float
3392e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel)
3402e9d6607Sbeveloper {
3412e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3422e9d6607Sbeveloper 		return 0.0f;
3432e9d6607Sbeveloper 	return fInputChannelInfo[channel].gain;
3442e9d6607Sbeveloper }
3452e9d6607Sbeveloper 
3462e9d6607Sbeveloper void
3479c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinationMask()
3482e9d6607Sbeveloper {
3492e9d6607Sbeveloper 	// is the user already messed with the assignmens, don't do anything.
3509c3be6a5Sbeveloper 	if (fUserOverridesChannelDestinations)
3512e9d6607Sbeveloper 		return;
3522e9d6607Sbeveloper 
3539c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: enter\n");
3542e9d6607Sbeveloper 
355806cf560Sbeveloper 	// first apply a 1:1 mapping
3562e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
3579c3be6a5Sbeveloper 		fInputChannelInfo[i].destination_mask = GetChannelMask(i, fInputChannelMask);
358806cf560Sbeveloper 
359806cf560Sbeveloper 	// specialize this, depending on the available physical output channels
360643e1b2eSbeveloper 	if (fCore->OutputChannelCount() <= 2) {
361643e1b2eSbeveloper 		// less or equal two channels
362806cf560Sbeveloper 		if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
363ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
364806cf560Sbeveloper 		}
365643e1b2eSbeveloper 	} else {
366643e1b2eSbeveloper 		// more than two channel output card
367806cf560Sbeveloper 		if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
368ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
369806cf560Sbeveloper 		}
370806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) {
3719c3be6a5Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
372806cf560Sbeveloper 		}
373806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3749c3be6a5Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
375806cf560Sbeveloper 		}
376806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) {
3779c3be6a5Sbeveloper 			fInputChannelInfo[1].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
378806cf560Sbeveloper 		}
379806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3809c3be6a5Sbeveloper 			fInputChannelInfo[1].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
381806cf560Sbeveloper 		}
3822e9d6607Sbeveloper 	}
3832e9d6607Sbeveloper 
3842e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
385d91580cdSbeveloper 		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);
3869c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: leave\n");
3872e9d6607Sbeveloper }
3882e9d6607Sbeveloper 
3892e9d6607Sbeveloper void
3909c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinations()
3912e9d6607Sbeveloper {
392d91580cdSbeveloper 	int channel_count;
3932e9d6607Sbeveloper 	uint32 all_bits;
3942e9d6607Sbeveloper 	uint32 mask;
3952e9d6607Sbeveloper 
3969c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: enter\n");
3972e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
398d91580cdSbeveloper 		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);
3992e9d6607Sbeveloper 
4002e9d6607Sbeveloper 	all_bits = 0;
4012e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
4029c3be6a5Sbeveloper 		all_bits |= fInputChannelInfo[i].destination_mask;
4032e9d6607Sbeveloper 
404d91580cdSbeveloper 	TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
4052e9d6607Sbeveloper 
4062e9d6607Sbeveloper 	channel_count = count_nonzero_bits(all_bits);
407d91580cdSbeveloper 	TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer channels (%d old)\n", fInputChannelCount, channel_count, fMixerChannelCount);
4082e9d6607Sbeveloper 	if (channel_count != fMixerChannelCount) {
4099c3be6a5Sbeveloper 		delete [] fMixerChannelInfo;
4102e9d6607Sbeveloper 		fMixerChannelInfo = new mixer_chan_info[channel_count];
4112e9d6607Sbeveloper 		fMixerChannelCount = channel_count;
4122e9d6607Sbeveloper 	}
4132e9d6607Sbeveloper 
4142e9d6607Sbeveloper 	// assign each mixer channel one type
4159c3be6a5Sbeveloper 	// and the gain from the fChannelTypeGain[]
416d91580cdSbeveloper 	mask = 1;
417d91580cdSbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4182e9d6607Sbeveloper 		while (mask != 0 && (all_bits & mask) == 0)
4192e9d6607Sbeveloper 			mask <<= 1;
4209c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask);
4219c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_gain = fChannelTypeGain[fMixerChannelInfo[i].destination_type];
4222e9d6607Sbeveloper 		mask <<= 1;
4232e9d6607Sbeveloper 	}
4242e9d6607Sbeveloper 
4252e9d6607Sbeveloper 	// assign buffer_base pointer for each mixer channel
4262e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4272e9d6607Sbeveloper 		int j;
4282e9d6607Sbeveloper 		for (j = 0; j < fInputChannelCount; j++) {
4299c3be6a5Sbeveloper 			if (fInputChannelInfo[j].destination_mask & ChannelTypeToChannelMask(fMixerChannelInfo[i].destination_type)) {
430d5848e21Sbeveloper 				fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] : 0;
4312e9d6607Sbeveloper 				break;
4322e9d6607Sbeveloper 			}
4332e9d6607Sbeveloper 		}
4342e9d6607Sbeveloper 		if (j == fInputChannelCount) {
435a2ca4723Sbeveloper 			ERROR("buffer assignment failed for mixer chan %d\n", i);
4362e9d6607Sbeveloper 			fMixerChannelInfo[i].buffer_base = fMixBuffer;
4372e9d6607Sbeveloper 		}
4382e9d6607Sbeveloper 	}
4392e9d6607Sbeveloper 
4402e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++)
4419c3be6a5Sbeveloper 		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);
4422e9d6607Sbeveloper 
4439c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: leave\n");
4442e9d6607Sbeveloper }
445*bf7ab50dSStephan Aßmus 
446*bf7ab50dSStephan Aßmus // Note: The following code is outcommented on purpose
447*bf7ab50dSStephan Aßmus // and is about to be modified at a later point
44869517c15Sbeveloper /*
4492e9d6607Sbeveloper void
4509c3be6a5Sbeveloper MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, float gain)
4512e9d6607Sbeveloper {
4529c3be6a5Sbeveloper 	TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, gain %.4f\n", channel, destination_type, gain);
4539c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
4549c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
4559c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
4562e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4572e9d6607Sbeveloper 		return;
4589c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
4599c3be6a5Sbeveloper 		return;
4602e9d6607Sbeveloper 	if (gain < 0.0f)
4612e9d6607Sbeveloper 		gain = 0.0f;
4629c3be6a5Sbeveloper 	fChannelTypeGain[destination_type] = gain;
4639c3be6a5Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4649c3be6a5Sbeveloper 		if (fMixerChannelInfo[i].destination_type == destination_type) {
4659c3be6a5Sbeveloper 			fMixerChannelInfo[i].destination_gain = gain;
4669c3be6a5Sbeveloper 			return;
4679c3be6a5Sbeveloper 		}
4689c3be6a5Sbeveloper 	}
4692e9d6607Sbeveloper }
4702e9d6607Sbeveloper 
4712e9d6607Sbeveloper float
4729c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type)
4732e9d6607Sbeveloper {
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)
4789c3be6a5Sbeveloper 		return 0.0f;
4799c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
4809c3be6a5Sbeveloper 		return 0.0f;
4819c3be6a5Sbeveloper 	return fChannelTypeGain[destination_type];
4822e9d6607Sbeveloper }
48369517c15Sbeveloper */
48469517c15Sbeveloper 
48569517c15Sbeveloper void
48669517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain)
48769517c15Sbeveloper {
48869517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
48969517c15Sbeveloper 		return;
49069517c15Sbeveloper 	if (gain < 0.0f)
49169517c15Sbeveloper 		gain = 0.0f;
49269517c15Sbeveloper 
49369517c15Sbeveloper 	fMixerChannelInfo[mixer_channel].destination_gain = gain;
49469517c15Sbeveloper 	fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain;
49569517c15Sbeveloper }
49669517c15Sbeveloper 
49769517c15Sbeveloper float
49869517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel)
49969517c15Sbeveloper {
50069517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
50169517c15Sbeveloper 		return 0.0;
50269517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_gain;
50369517c15Sbeveloper }
50469517c15Sbeveloper 
50569517c15Sbeveloper int
50669517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel)
50769517c15Sbeveloper {
50869517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
50969517c15Sbeveloper 		return -1;
51069517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_type;
51169517c15Sbeveloper }
5122e9d6607Sbeveloper 
5132e9d6607Sbeveloper void
5141c237c18Sbeveloper MixerInput::SetEnabled(bool yesno)
5151c237c18Sbeveloper {
5161c237c18Sbeveloper 	fEnabled = yesno;
5171c237c18Sbeveloper }
5181c237c18Sbeveloper 
5191c237c18Sbeveloper bool
5201c237c18Sbeveloper MixerInput::IsEnabled()
5211c237c18Sbeveloper {
5221c237c18Sbeveloper 	return fEnabled;
5231c237c18Sbeveloper }
5241c237c18Sbeveloper 
5251c237c18Sbeveloper void
5268d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
5272e9d6607Sbeveloper {
528a2ca4723Sbeveloper 	TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
529d5848e21Sbeveloper 
5307b0daf5cSbeveloper 	fMixBufferFrameRate = framerate;
5318df36cddSbeveloper 	debugMixBufferFrames = frames;
5322e9d6607Sbeveloper 
533d5848e21Sbeveloper 	// frames and/or framerate can be 0 (if no output is connected)
534d5848e21Sbeveloper 	if (framerate == 0 || frames == 0) {
535d5848e21Sbeveloper 		if (fMixBuffer) {
536d5848e21Sbeveloper 			rtm_free(fMixBuffer);
537d5848e21Sbeveloper 			fMixBuffer = 0;
538d5848e21Sbeveloper 		}
539d5848e21Sbeveloper 		for (int i = 0; i < fInputChannelCount; i++)
540d5848e21Sbeveloper 			fInputChannelInfo[i].buffer_base = 0;
541d5848e21Sbeveloper 		fMixBufferFrameCount = 0;
542d5848e21Sbeveloper 
5439c3be6a5Sbeveloper 		UpdateInputChannelDestinationMask();
5449c3be6a5Sbeveloper 		UpdateInputChannelDestinations();
545d5848e21Sbeveloper 		return;
546d5848e21Sbeveloper 	}
5477b0daf5cSbeveloper 
5487b0daf5cSbeveloper 	// make fMixBufferFrameCount an integral multiple of frames,
5497b0daf5cSbeveloper 	// but at least 3 times duration of our input buffer
5507b0daf5cSbeveloper 	// and at least 2 times duration of the output buffer
5517b0daf5cSbeveloper 	bigtime_t inputBufferLength  = duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio));
5527b0daf5cSbeveloper 	bigtime_t outputBufferLength = duration_for_frames(framerate, frames);
5537b0daf5cSbeveloper 	bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength);
5547b0daf5cSbeveloper 	int temp = frames_for_duration(framerate, mixerBufferLength);
5557b0daf5cSbeveloper 	fMixBufferFrameCount = ((temp / frames) + 1) * frames;
5567b0daf5cSbeveloper 
557a2ca4723Sbeveloper 	TRACE("  inputBufferLength  %10Ld\n", inputBufferLength);
558a2ca4723Sbeveloper 	TRACE("  outputBufferLength %10Ld\n", outputBufferLength);
559a2ca4723Sbeveloper 	TRACE("  mixerBufferLength  %10Ld\n", mixerBufferLength);
560d91580cdSbeveloper 	TRACE("  fMixBufferFrameCount   %10d\n", fMixBufferFrameCount);
5617b0daf5cSbeveloper 
5628d28117fSbeveloper 	ASSERT((fMixBufferFrameCount % frames) == 0);
5638d28117fSbeveloper 
564e92593f4Sbeveloper 	fLastDataFrameWritten = -1;
565e92593f4Sbeveloper 	fFractionalFrames = 0.0;
566e92593f4Sbeveloper 
5672e9d6607Sbeveloper 	if (fMixBuffer)
5682e9d6607Sbeveloper 		rtm_free(fMixBuffer);
569356855c3Sbeveloper 	if (fRtmPool)
570356855c3Sbeveloper 		rtm_delete_pool(fRtmPool);
5717b0daf5cSbeveloper 	int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
572356855c3Sbeveloper 	if (B_OK != rtm_create_pool(&fRtmPool, size))
573356855c3Sbeveloper 		fRtmPool = 0;
574356855c3Sbeveloper 	fMixBuffer = (float *)rtm_alloc(fRtmPool, size);
5757b0daf5cSbeveloper 	ASSERT(fMixBuffer);
5767b0daf5cSbeveloper 
5777b0daf5cSbeveloper 	memset(fMixBuffer, 0, size);
5782e9d6607Sbeveloper 
5792e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
5807b0daf5cSbeveloper 		fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
581d5848e21Sbeveloper 
5829c3be6a5Sbeveloper 	UpdateInputChannelDestinationMask();
5839c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
5842e9d6607Sbeveloper }
585