xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp (revision e92593f46aca8652d1d24decb9d7b9ac4fa83aa7)
12e9d6607Sbeveloper #include <Buffer.h>
27b0daf5cSbeveloper #include <string.h>
38d28117fSbeveloper #include <TimeSource.h> // XXX debug only
4678c2017Sbeveloper #include "MixerInput.h"
5678c2017Sbeveloper #include "MixerCore.h"
6e6c7c99fSbeveloper #include "MixerUtils.h"
77b0daf5cSbeveloper #include "Resampler.h"
888777023Sbeveloper #include "ByteSwap.h"
9e6c7c99fSbeveloper #include "debug.h"
10678c2017Sbeveloper 
118d28117fSbeveloper MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount)
12e6c7c99fSbeveloper  :	fCore(core),
132e9d6607Sbeveloper  	fInput(input),
1488777023Sbeveloper 	fInputByteSwap(0),
151c237c18Sbeveloper 	fEnabled(true),
162e9d6607Sbeveloper 	fInputChannelInfo(0),
172e9d6607Sbeveloper 	fInputChannelCount(0),
182e9d6607Sbeveloper 	fInputChannelMask(0),
192e9d6607Sbeveloper 	fMixerChannelInfo(0),
202e9d6607Sbeveloper 	fMixerChannelCount(0),
212e9d6607Sbeveloper 	fMixBuffer(0),
227b0daf5cSbeveloper 	fMixBufferFrameRate(0),
237b0daf5cSbeveloper 	fMixBufferFrameCount(0),
24*e92593f4Sbeveloper 	fLastDataFrameWritten(-1),
25af8d0a4dSbeveloper 	fLastDataAvailableTime(-1),
26*e92593f4Sbeveloper 	fFractionalFrames(0.0),
277b0daf5cSbeveloper 	fResampler(0),
28356855c3Sbeveloper 	fRtmPool(0),
299c3be6a5Sbeveloper 	fUserOverridesChannelDestinations(false)
30678c2017Sbeveloper {
31e6c7c99fSbeveloper 	fix_multiaudio_format(&fInput.format.u.raw_audio);
32e6c7c99fSbeveloper 	PRINT_INPUT("MixerInput::MixerInput", fInput);
33e6c7c99fSbeveloper 	PRINT_CHANNEL_MASK(fInput.format);
342e9d6607Sbeveloper 
352e9d6607Sbeveloper 	ASSERT(fInput.format.u.raw_audio.channel_count > 0);
362e9d6607Sbeveloper 
379c3be6a5Sbeveloper 	for (int i = 0; i <	MAX_CHANNEL_TYPES; i++)
389c3be6a5Sbeveloper 		fChannelTypeGain[i] = 1.0f;
399c3be6a5Sbeveloper 
402e9d6607Sbeveloper 	fInputChannelCount = fInput.format.u.raw_audio.channel_count;
412e9d6607Sbeveloper 	fInputChannelMask = fInput.format.u.raw_audio.channel_mask;
422e9d6607Sbeveloper 	fInputChannelInfo = new input_chan_info[fInputChannelCount];
432e9d6607Sbeveloper 
4488777023Sbeveloper 	// perhaps we need byte swapping
4588777023Sbeveloper 	if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
4688777023Sbeveloper 		if (	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
4788777023Sbeveloper 			 ||	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT
4888777023Sbeveloper 			 ||	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
4988777023Sbeveloper 			fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format);
5088777023Sbeveloper 		}
5188777023Sbeveloper 	}
5288777023Sbeveloper 
532e9d6607Sbeveloper 	// initialize fInputChannelInfo
542e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++) {
552e9d6607Sbeveloper 		fInputChannelInfo[i].buffer_base = 0;	// will be set by SetMixBufferFormat()
569c3be6a5Sbeveloper 		fInputChannelInfo[i].destination_mask = 0;	// will be set by UpdateInputChannelDestinationMask()
572e9d6607Sbeveloper 		fInputChannelInfo[i].gain = 1.0;
582e9d6607Sbeveloper 	}
592e9d6607Sbeveloper 
607b0daf5cSbeveloper 	// create resamplers
617b0daf5cSbeveloper 	fResampler = new Resampler * [fInputChannelCount];
627b0daf5cSbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
637b0daf5cSbeveloper 		fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT);
647b0daf5cSbeveloper 
659c3be6a5Sbeveloper 	// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations()
662e9d6607Sbeveloper 
678d28117fSbeveloper 	SetMixBufferFormat(mixFrameRate, mixFrameCount);
68678c2017Sbeveloper }
69678c2017Sbeveloper 
70678c2017Sbeveloper MixerInput::~MixerInput()
71678c2017Sbeveloper {
722e9d6607Sbeveloper 	if (fMixBuffer)
732e9d6607Sbeveloper 		rtm_free(fMixBuffer);
74356855c3Sbeveloper 	if (fRtmPool)
75356855c3Sbeveloper 		rtm_delete_pool(fRtmPool);
762e9d6607Sbeveloper 	delete [] fInputChannelInfo;
772e9d6607Sbeveloper 	delete [] fMixerChannelInfo;
787b0daf5cSbeveloper 
797b0daf5cSbeveloper 	// delete resamplers
807b0daf5cSbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
817b0daf5cSbeveloper 		delete fResampler[i];
827b0daf5cSbeveloper 	delete [] fResampler;
83678c2017Sbeveloper }
84678c2017Sbeveloper 
85678c2017Sbeveloper void
86678c2017Sbeveloper MixerInput::BufferReceived(BBuffer *buffer)
87678c2017Sbeveloper {
8888777023Sbeveloper 	void *data;
8988777023Sbeveloper 	size_t size;
9088777023Sbeveloper 	bigtime_t start;
91*e92593f4Sbeveloper 	bigtime_t buffer_duration;
9288777023Sbeveloper 
93d5848e21Sbeveloper 	if (!fMixBuffer) {
94a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n");
95d5848e21Sbeveloper 		return;
96d5848e21Sbeveloper 	}
972e9d6607Sbeveloper 
9888777023Sbeveloper 	data = buffer->Data();
9988777023Sbeveloper 	size = buffer->SizeUsed();
10088777023Sbeveloper 	start = buffer->Header()->start_time;
101*e92593f4Sbeveloper 	buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate, size / bytes_per_frame(fInput.format.u.raw_audio));
1028d28117fSbeveloper 	if (start < 0) {
103a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: buffer with negative start time of %Ld dropped\n", start);
1048d28117fSbeveloper 		return;
1058d28117fSbeveloper 	}
10688777023Sbeveloper 
10788777023Sbeveloper 	// swap the byte order of this buffer, if necessary
10888777023Sbeveloper 	if (fInputByteSwap)
10988777023Sbeveloper 		fInputByteSwap->Swap(data, size);
11088777023Sbeveloper 
111d91580cdSbeveloper 	int offset = frames_for_duration(fMixBufferFrameRate, start) % fMixBufferFrameCount;
1128d28117fSbeveloper 
113191033efSbeveloper 	PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", start, offset);
1147b0daf5cSbeveloper 
115191033efSbeveloper 	int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio);
116*e92593f4Sbeveloper 	double frames = double(in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate;
117*e92593f4Sbeveloper 	int out_frames = int(frames);
118*e92593f4Sbeveloper 	fFractionalFrames += frames - double(out_frames);
119*e92593f4Sbeveloper 	if (fFractionalFrames >= 1.0) {
120*e92593f4Sbeveloper 		fFractionalFrames -= 1.0;
1217619f562Sbeveloper 		out_frames++;
122*e92593f4Sbeveloper 	}
123*e92593f4Sbeveloper 
124*e92593f4Sbeveloper 	// if fLastDataFrameWritten != -1, then we have a valid last position
125*e92593f4Sbeveloper 	// and can do glitch compensation
126*e92593f4Sbeveloper 	if (fLastDataFrameWritten >= 0) {
127*e92593f4Sbeveloper 		int expected_frame = (fLastDataFrameWritten + 1) % fMixBufferFrameCount;
128*e92593f4Sbeveloper 		if (offset != expected_frame) {
129*e92593f4Sbeveloper 
130*e92593f4Sbeveloper 			// due to rounding and other errors, offset might be off by +/- 1
131*e92593f4Sbeveloper 			// this is not really a bad glitch, we just adjust the position
132*e92593f4Sbeveloper 
133*e92593f4Sbeveloper 			if (offset == fLastDataFrameWritten) {
134*e92593f4Sbeveloper 				//printf("MixerInput::BufferReceived: -1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
135*e92593f4Sbeveloper 				offset = expected_frame;
136*e92593f4Sbeveloper 			} else if (offset == ((fLastDataFrameWritten + 2) % fMixBufferFrameCount)) {
137*e92593f4Sbeveloper 				//printf("MixerInput::BufferReceived: +1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
138*e92593f4Sbeveloper 				offset = expected_frame;
139*e92593f4Sbeveloper 			} else {
140*e92593f4Sbeveloper 				printf("MixerInput::BufferReceived: GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset);
141*e92593f4Sbeveloper 
142*e92593f4Sbeveloper 				if (start > fLastDataAvailableTime) {
143*e92593f4Sbeveloper 					if ((start - fLastDataAvailableTime) < (buffer_duration / 10)) {
144*e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too late
145*e92593f4Sbeveloper 						printf("short glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime);
146*e92593f4Sbeveloper 						offset = expected_frame;
147*e92593f4Sbeveloper 						out_frames++;
148*e92593f4Sbeveloper 					} else {
149*e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too late
150*e92593f4Sbeveloper 						// XXX zerofill buffer
151*e92593f4Sbeveloper 						printf("MAJOR glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime);
152*e92593f4Sbeveloper 					}
153*e92593f4Sbeveloper 				} else { // start <= fLastDataAvailableTime
154*e92593f4Sbeveloper 					// the new buffer is too early
155*e92593f4Sbeveloper 					if ((fLastDataAvailableTime - start) < (buffer_duration / 10)) {
156*e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too early
157*e92593f4Sbeveloper 						printf("short glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start);
158*e92593f4Sbeveloper 						offset = expected_frame;
159*e92593f4Sbeveloper 						out_frames--;
160*e92593f4Sbeveloper 						if (out_frames < 1)
161*e92593f4Sbeveloper 							out_frames = 1;
162*e92593f4Sbeveloper 					} else {
163*e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too early
164*e92593f4Sbeveloper 						// XXX zerofill buffer
165*e92593f4Sbeveloper 						printf("MAJOR glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start);
166*e92593f4Sbeveloper 					}
167*e92593f4Sbeveloper 				}
168*e92593f4Sbeveloper 			}
169*e92593f4Sbeveloper 		}
170*e92593f4Sbeveloper 	}
1717b0daf5cSbeveloper 
1728d28117fSbeveloper 	//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);
1738df36cddSbeveloper 
1747b0daf5cSbeveloper 	if (offset + out_frames > fMixBufferFrameCount) {
1757b0daf5cSbeveloper 
1767b0daf5cSbeveloper 		int out_frames1 = fMixBufferFrameCount - offset;
1777b0daf5cSbeveloper 		int out_frames2 = out_frames - out_frames1;
1787b0daf5cSbeveloper 		int in_frames1 = (out_frames1 * in_frames) / out_frames;
1797b0daf5cSbeveloper 		int in_frames2 = in_frames - in_frames1;
1807b0daf5cSbeveloper 
181*e92593f4Sbeveloper 		//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);
1827619f562Sbeveloper 		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);
183191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d, in_frames1 %5d, out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n",
184191033efSbeveloper 			  in_frames, out_frames, in_frames1, out_frames1, in_frames2, out_frames2);
1857b0daf5cSbeveloper 
186*e92593f4Sbeveloper 		fLastDataFrameWritten = out_frames2 - 1;
187*e92593f4Sbeveloper 
1888d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
1898d28117fSbeveloper 
1907b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
19178563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
19278563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
1937b0daf5cSbeveloper 									in_frames1,
1948d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
1957b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
1967b0daf5cSbeveloper 									out_frames1,
1977b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
1987b0daf5cSbeveloper 
1997d970b31Sbeveloper 			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),
20078563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2017b0daf5cSbeveloper 									in_frames2,
2027b0daf5cSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base),
2037b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2047b0daf5cSbeveloper 									out_frames2,
2057b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
206*e92593f4Sbeveloper 
2077b0daf5cSbeveloper 		}
2087b0daf5cSbeveloper 	} else {
2097b0daf5cSbeveloper 
210*e92593f4Sbeveloper 		//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);
2117619f562Sbeveloper 		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);
212191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d\n", in_frames, out_frames);
2138d28117fSbeveloper 
214*e92593f4Sbeveloper 		fLastDataFrameWritten = offset + out_frames - 1;
215*e92593f4Sbeveloper 
2168d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
2177b0daf5cSbeveloper 
2187b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
21978563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
22078563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
2217b0daf5cSbeveloper 									in_frames,
2228d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
2237b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
2247b0daf5cSbeveloper 									out_frames,
2257b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
2267b0daf5cSbeveloper 		}
2277b0daf5cSbeveloper 	}
228*e92593f4Sbeveloper 
229*e92593f4Sbeveloper 	fLastDataAvailableTime = start + buffer_duration;
230678c2017Sbeveloper }
2317ee2c804Sbeveloper 
2327ee2c804Sbeveloper media_input &
2337ee2c804Sbeveloper MixerInput::MediaInput()
2347ee2c804Sbeveloper {
2357ee2c804Sbeveloper 	return fInput;
2367ee2c804Sbeveloper }
237e6c7c99fSbeveloper 
238e6c7c99fSbeveloper int32
239e6c7c99fSbeveloper MixerInput::ID()
240e6c7c99fSbeveloper {
241e6c7c99fSbeveloper 	return fInput.destination.id;
242e6c7c99fSbeveloper }
243e6c7c99fSbeveloper 
244d91580cdSbeveloper int
245fae6ce82Sbeveloper MixerInput::GetInputChannelCount()
246fae6ce82Sbeveloper {
247fae6ce82Sbeveloper 	return fInputChannelCount;
248fae6ce82Sbeveloper }
249fae6ce82Sbeveloper 
2502e9d6607Sbeveloper void
2519c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type)
2522e9d6607Sbeveloper {
2539c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
254e6c7c99fSbeveloper 
2552e9d6607Sbeveloper 	// test if the channel is valid
2562e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2572e9d6607Sbeveloper 		return;
2582e9d6607Sbeveloper 
2592e9d6607Sbeveloper 	// test if it is already set
2609c3be6a5Sbeveloper 	if (fInputChannelInfo[channel].destination_mask & mask)
2612e9d6607Sbeveloper 		return;
2622e9d6607Sbeveloper 
2639c3be6a5Sbeveloper 	// verify that no other channel has id
2649c3be6a5Sbeveloper 	if (-1 != GetInputChannelForDestination(destination_type)) {
2659c3be6a5Sbeveloper 		ERROR("MixerInput::AddInputChannelDestination: destination_type %d already assigned to channel %d\n", destination_type, GetInputChannelForDestination(destination_type));
2669c3be6a5Sbeveloper 		return;
2679c3be6a5Sbeveloper 	}
2682e9d6607Sbeveloper 
2692e9d6607Sbeveloper 	// add it to specified channel
2709c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask |= mask;
2712e9d6607Sbeveloper 
2729c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
2739c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
2742e9d6607Sbeveloper }
2752e9d6607Sbeveloper 
2762e9d6607Sbeveloper void
2779c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
2782e9d6607Sbeveloper {
2799c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
2802e9d6607Sbeveloper 
2812e9d6607Sbeveloper 	// test if the channel is valid
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 	// test if the channel is valid
3232e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3242e9d6607Sbeveloper 		return 0;
3259c3be6a5Sbeveloper 	return GetChannelType(channel, fInputChannelMask);
3262e9d6607Sbeveloper }
3272e9d6607Sbeveloper 
3282e9d6607Sbeveloper void
3292e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain)
3302e9d6607Sbeveloper {
3312e9d6607Sbeveloper 	// test if the channel is valid
3322e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3332e9d6607Sbeveloper 		return;
3342e9d6607Sbeveloper 	if (gain < 0.0f)
3352e9d6607Sbeveloper 		gain = 0.0f;
3362e9d6607Sbeveloper 
3372e9d6607Sbeveloper 	fInputChannelInfo[channel].gain = gain;
3382e9d6607Sbeveloper }
3392e9d6607Sbeveloper 
3402e9d6607Sbeveloper float
3412e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel)
3422e9d6607Sbeveloper {
3432e9d6607Sbeveloper 	// test if the channel is valid
3442e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3452e9d6607Sbeveloper 		return 0.0f;
3462e9d6607Sbeveloper 	return fInputChannelInfo[channel].gain;
3472e9d6607Sbeveloper }
3482e9d6607Sbeveloper 
3492e9d6607Sbeveloper void
3509c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinationMask()
3512e9d6607Sbeveloper {
3522e9d6607Sbeveloper 	// is the user already messed with the assignmens, don't do anything.
3539c3be6a5Sbeveloper 	if (fUserOverridesChannelDestinations)
3542e9d6607Sbeveloper 		return;
3552e9d6607Sbeveloper 
3569c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: enter\n");
3572e9d6607Sbeveloper 
358806cf560Sbeveloper 	// first apply a 1:1 mapping
3592e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
3609c3be6a5Sbeveloper 		fInputChannelInfo[i].destination_mask = GetChannelMask(i, fInputChannelMask);
361806cf560Sbeveloper 
362806cf560Sbeveloper 	// specialize this, depending on the available physical output channels
363643e1b2eSbeveloper 	if (fCore->OutputChannelCount() <= 2) {
364643e1b2eSbeveloper 		// less or equal two channels
365806cf560Sbeveloper 		if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
366ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
367806cf560Sbeveloper 		}
368643e1b2eSbeveloper 	} else {
369643e1b2eSbeveloper 		// more than two channel output card
370806cf560Sbeveloper 		if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
371ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
372806cf560Sbeveloper 		}
373806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) {
3749c3be6a5Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
375806cf560Sbeveloper 		}
376806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3779c3be6a5Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
378806cf560Sbeveloper 		}
379806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) {
3809c3be6a5Sbeveloper 			fInputChannelInfo[1].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
381806cf560Sbeveloper 		}
382806cf560Sbeveloper 		if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) {
3839c3be6a5Sbeveloper 			fInputChannelInfo[1].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
384806cf560Sbeveloper 		}
3852e9d6607Sbeveloper 	}
3862e9d6607Sbeveloper 
3872e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
388d91580cdSbeveloper 		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);
3892e9d6607Sbeveloper 
3909c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinationMask: leave\n");
3912e9d6607Sbeveloper }
3922e9d6607Sbeveloper 
3932e9d6607Sbeveloper void
3949c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinations()
3952e9d6607Sbeveloper {
396d91580cdSbeveloper 	int channel_count;
3972e9d6607Sbeveloper 	uint32 all_bits;
3982e9d6607Sbeveloper 	uint32 mask;
3992e9d6607Sbeveloper 
4009c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: enter\n");
4012e9d6607Sbeveloper 
4022e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
403d91580cdSbeveloper 		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);
4042e9d6607Sbeveloper 
4052e9d6607Sbeveloper 	all_bits = 0;
4062e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
4079c3be6a5Sbeveloper 		all_bits |= fInputChannelInfo[i].destination_mask;
4082e9d6607Sbeveloper 
409d91580cdSbeveloper 	TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
4102e9d6607Sbeveloper 
4112e9d6607Sbeveloper 	channel_count = count_nonzero_bits(all_bits);
4122e9d6607Sbeveloper 
413d91580cdSbeveloper 	TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer channels (%d old)\n", fInputChannelCount, channel_count, fMixerChannelCount);
4142e9d6607Sbeveloper 
4152e9d6607Sbeveloper 	if (channel_count != fMixerChannelCount) {
4169c3be6a5Sbeveloper 		delete [] fMixerChannelInfo;
4172e9d6607Sbeveloper 		fMixerChannelInfo = new mixer_chan_info[channel_count];
4182e9d6607Sbeveloper 		fMixerChannelCount = channel_count;
4192e9d6607Sbeveloper 	}
4202e9d6607Sbeveloper 
4212e9d6607Sbeveloper 	// assign each mixer channel one type
4229c3be6a5Sbeveloper 	// and the gain from the fChannelTypeGain[]
423d91580cdSbeveloper 	mask = 1;
424d91580cdSbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4252e9d6607Sbeveloper 		while (mask != 0 && (all_bits & mask) == 0)
4262e9d6607Sbeveloper 			mask <<= 1;
4279c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask);
4289c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_gain = fChannelTypeGain[fMixerChannelInfo[i].destination_type];
4292e9d6607Sbeveloper 		mask <<= 1;
4302e9d6607Sbeveloper 	}
4312e9d6607Sbeveloper 
4322e9d6607Sbeveloper 	// assign buffer_base pointer for each mixer channel
4332e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4342e9d6607Sbeveloper 		int j;
4352e9d6607Sbeveloper 		for (j = 0; j < fInputChannelCount; j++) {
4369c3be6a5Sbeveloper 			if (fInputChannelInfo[j].destination_mask & ChannelTypeToChannelMask(fMixerChannelInfo[i].destination_type)) {
437d5848e21Sbeveloper 				fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] : 0;
4382e9d6607Sbeveloper 				break;
4392e9d6607Sbeveloper 			}
4402e9d6607Sbeveloper 		}
4412e9d6607Sbeveloper 		if (j == fInputChannelCount) {
442a2ca4723Sbeveloper 			ERROR("buffer assignment failed for mixer chan %d\n", i);
4432e9d6607Sbeveloper 			fMixerChannelInfo[i].buffer_base = fMixBuffer;
4442e9d6607Sbeveloper 		}
4452e9d6607Sbeveloper 	}
4462e9d6607Sbeveloper 
4472e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++)
4489c3be6a5Sbeveloper 		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);
4492e9d6607Sbeveloper 
4509c3be6a5Sbeveloper 	TRACE("UpdateInputChannelDestinations: leave\n");
4512e9d6607Sbeveloper }
45269517c15Sbeveloper /*
4532e9d6607Sbeveloper void
4549c3be6a5Sbeveloper MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, float gain)
4552e9d6607Sbeveloper {
4569c3be6a5Sbeveloper 	TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, gain %.4f\n", channel, destination_type, gain);
4579c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
4589c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
4599c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
4602e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4612e9d6607Sbeveloper 		return;
4629c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
4639c3be6a5Sbeveloper 		return;
4642e9d6607Sbeveloper 	if (gain < 0.0f)
4652e9d6607Sbeveloper 		gain = 0.0f;
4669c3be6a5Sbeveloper 	fChannelTypeGain[destination_type] = gain;
4679c3be6a5Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
4689c3be6a5Sbeveloper 		if (fMixerChannelInfo[i].destination_type == destination_type) {
4699c3be6a5Sbeveloper 			fMixerChannelInfo[i].destination_gain = gain;
4709c3be6a5Sbeveloper 			return;
4719c3be6a5Sbeveloper 		}
4729c3be6a5Sbeveloper 	}
4732e9d6607Sbeveloper }
4742e9d6607Sbeveloper 
4752e9d6607Sbeveloper float
4769c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type)
4772e9d6607Sbeveloper {
4789c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
4799c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
4809c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
4812e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4829c3be6a5Sbeveloper 		return 0.0f;
4839c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
4849c3be6a5Sbeveloper 		return 0.0f;
4859c3be6a5Sbeveloper 	return fChannelTypeGain[destination_type];
4862e9d6607Sbeveloper }
48769517c15Sbeveloper */
48869517c15Sbeveloper 
48969517c15Sbeveloper void
49069517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain)
49169517c15Sbeveloper {
49269517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
49369517c15Sbeveloper 		return;
49469517c15Sbeveloper 	if (gain < 0.0f)
49569517c15Sbeveloper 		gain = 0.0f;
49669517c15Sbeveloper 
49769517c15Sbeveloper 	fMixerChannelInfo[mixer_channel].destination_gain = gain;
49869517c15Sbeveloper 	fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain;
49969517c15Sbeveloper }
50069517c15Sbeveloper 
50169517c15Sbeveloper float
50269517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel)
50369517c15Sbeveloper {
50469517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
50569517c15Sbeveloper 		return 0.0;
50669517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_gain;
50769517c15Sbeveloper }
50869517c15Sbeveloper 
50969517c15Sbeveloper int
51069517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel)
51169517c15Sbeveloper {
51269517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
51369517c15Sbeveloper 		return -1;
51469517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_type;
51569517c15Sbeveloper }
5162e9d6607Sbeveloper 
5172e9d6607Sbeveloper void
5181c237c18Sbeveloper MixerInput::SetEnabled(bool yesno)
5191c237c18Sbeveloper {
5201c237c18Sbeveloper 	fEnabled = yesno;
5211c237c18Sbeveloper }
5221c237c18Sbeveloper 
5231c237c18Sbeveloper bool
5241c237c18Sbeveloper MixerInput::IsEnabled()
5251c237c18Sbeveloper {
5261c237c18Sbeveloper 	return fEnabled;
5271c237c18Sbeveloper }
5281c237c18Sbeveloper 
5291c237c18Sbeveloper void
5308d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
5312e9d6607Sbeveloper {
532a2ca4723Sbeveloper 	TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
533d5848e21Sbeveloper 
5347b0daf5cSbeveloper 	fMixBufferFrameRate = framerate;
5358df36cddSbeveloper 	debugMixBufferFrames = frames;
5362e9d6607Sbeveloper 
537d5848e21Sbeveloper 	// frames and/or framerate can be 0 (if no output is connected)
538d5848e21Sbeveloper 	if (framerate == 0 || frames == 0) {
539d5848e21Sbeveloper 		if (fMixBuffer) {
540d5848e21Sbeveloper 			rtm_free(fMixBuffer);
541d5848e21Sbeveloper 			fMixBuffer = 0;
542d5848e21Sbeveloper 		}
543d5848e21Sbeveloper 		for (int i = 0; i < fInputChannelCount; i++)
544d5848e21Sbeveloper 			fInputChannelInfo[i].buffer_base = 0;
545d5848e21Sbeveloper 		fMixBufferFrameCount = 0;
546d5848e21Sbeveloper 
5479c3be6a5Sbeveloper 		UpdateInputChannelDestinationMask();
5489c3be6a5Sbeveloper 		UpdateInputChannelDestinations();
549d5848e21Sbeveloper 		return;
550d5848e21Sbeveloper 	}
5517b0daf5cSbeveloper 
5527b0daf5cSbeveloper 	// make fMixBufferFrameCount an integral multiple of frames,
5537b0daf5cSbeveloper 	// but at least 3 times duration of our input buffer
5547b0daf5cSbeveloper 	// and at least 2 times duration of the output buffer
5557b0daf5cSbeveloper 	bigtime_t inputBufferLength  = duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio));
5567b0daf5cSbeveloper 	bigtime_t outputBufferLength = duration_for_frames(framerate, frames);
5577b0daf5cSbeveloper 	bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength);
5587b0daf5cSbeveloper 	int temp = frames_for_duration(framerate, mixerBufferLength);
5597b0daf5cSbeveloper 	fMixBufferFrameCount = ((temp / frames) + 1) * frames;
5607b0daf5cSbeveloper 
561a2ca4723Sbeveloper 	TRACE("  inputBufferLength  %10Ld\n", inputBufferLength);
562a2ca4723Sbeveloper 	TRACE("  outputBufferLength %10Ld\n", outputBufferLength);
563a2ca4723Sbeveloper 	TRACE("  mixerBufferLength  %10Ld\n", mixerBufferLength);
564d91580cdSbeveloper 	TRACE("  fMixBufferFrameCount   %10d\n", fMixBufferFrameCount);
5657b0daf5cSbeveloper 
5668d28117fSbeveloper 	ASSERT((fMixBufferFrameCount % frames) == 0);
5678d28117fSbeveloper 
568*e92593f4Sbeveloper 	fLastDataFrameWritten = -1;
569*e92593f4Sbeveloper 	fFractionalFrames = 0.0;
570*e92593f4Sbeveloper 
5712e9d6607Sbeveloper 	if (fMixBuffer)
5722e9d6607Sbeveloper 		rtm_free(fMixBuffer);
573356855c3Sbeveloper 	if (fRtmPool)
574356855c3Sbeveloper 		rtm_delete_pool(fRtmPool);
5757b0daf5cSbeveloper 	int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
576356855c3Sbeveloper 	if (B_OK != rtm_create_pool(&fRtmPool, size))
577356855c3Sbeveloper 		fRtmPool = 0;
578356855c3Sbeveloper 	fMixBuffer = (float *)rtm_alloc(fRtmPool, size);
5797b0daf5cSbeveloper 	ASSERT(fMixBuffer);
5807b0daf5cSbeveloper 
5817b0daf5cSbeveloper 	memset(fMixBuffer, 0, size);
5822e9d6607Sbeveloper 
5832e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
5847b0daf5cSbeveloper 		fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
585d5848e21Sbeveloper 
5869c3be6a5Sbeveloper 	UpdateInputChannelDestinationMask();
5879c3be6a5Sbeveloper 	UpdateInputChannelDestinations();
5882e9d6607Sbeveloper }
589