xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp (revision 425ac1b60a56f4df7a0e88bd784545c0ec4fa01f)
1bf7ab50dSStephan Aßmus /*
2b543dbc2SStephan Aßmus  * Copyright 2003-2010 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"
17a79b30c3SStephan Aßmus #include "Interpolate.h"
18bf7ab50dSStephan Aßmus #include "MixerInput.h"
19bf7ab50dSStephan Aßmus #include "MixerUtils.h"
20bf7ab50dSStephan Aßmus #include "Resampler.h"
21bf7ab50dSStephan Aßmus 
22678c2017Sbeveloper 
MixerInput(MixerCore * core,const media_input & input,float mixFrameRate,int32 mixFrameCount)23a9cf57cfSAxel Dörfler MixerInput::MixerInput(MixerCore* core, const media_input& input,
24b006bbe1SStephan Aßmus 	float mixFrameRate, int32 mixFrameCount)
25a9cf57cfSAxel Dörfler 	:
26a9cf57cfSAxel Dörfler 	fCore(core),
272e9d6607Sbeveloper  	fInput(input),
28b006bbe1SStephan Aßmus 	fInputByteSwap(NULL),
291c237c18Sbeveloper 	fEnabled(true),
30b006bbe1SStephan Aßmus 	fInputChannelInfo(NULL),
312e9d6607Sbeveloper 	fInputChannelCount(0),
322e9d6607Sbeveloper 	fInputChannelMask(0),
332e9d6607Sbeveloper 	fMixerChannelInfo(0),
342e9d6607Sbeveloper 	fMixerChannelCount(0),
35b006bbe1SStephan Aßmus 	fMixBuffer(NULL),
367b0daf5cSbeveloper 	fMixBufferFrameRate(0),
377b0daf5cSbeveloper 	fMixBufferFrameCount(0),
38e92593f4Sbeveloper 	fLastDataFrameWritten(-1),
39af8d0a4dSbeveloper 	fLastDataAvailableTime(-1),
40e92593f4Sbeveloper 	fFractionalFrames(0.0),
41b006bbe1SStephan Aßmus 	fResampler(NULL),
42b006bbe1SStephan Aßmus 	fRtmPool(NULL),
439c3be6a5Sbeveloper 	fUserOverridesChannelDestinations(false)
44678c2017Sbeveloper {
45e6c7c99fSbeveloper 	fix_multiaudio_format(&fInput.format.u.raw_audio);
46e6c7c99fSbeveloper 	PRINT_INPUT("MixerInput::MixerInput", fInput);
47e6c7c99fSbeveloper 	PRINT_CHANNEL_MASK(fInput.format);
482e9d6607Sbeveloper 
492e9d6607Sbeveloper 	ASSERT(fInput.format.u.raw_audio.channel_count > 0);
502e9d6607Sbeveloper 
519c3be6a5Sbeveloper 	for (int i = 0; i <	MAX_CHANNEL_TYPES; i++)
529c3be6a5Sbeveloper 		fChannelTypeGain[i] = 1.0f;
539c3be6a5Sbeveloper 
542e9d6607Sbeveloper 	fInputChannelCount = fInput.format.u.raw_audio.channel_count;
552e9d6607Sbeveloper 	fInputChannelMask = fInput.format.u.raw_audio.channel_mask;
562e9d6607Sbeveloper 	fInputChannelInfo = new input_chan_info[fInputChannelCount];
572e9d6607Sbeveloper 
5888777023Sbeveloper 	// perhaps we need byte swapping
5988777023Sbeveloper 	if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
60a9cf57cfSAxel Dörfler 		if (fInput.format.u.raw_audio.format
61a9cf57cfSAxel Dörfler 				== media_raw_audio_format::B_AUDIO_FLOAT
62a9cf57cfSAxel Dörfler 			|| fInput.format.u.raw_audio.format
63a9cf57cfSAxel Dörfler 				== media_raw_audio_format::B_AUDIO_INT
64a9cf57cfSAxel Dörfler 			|| fInput.format.u.raw_audio.format
65a9cf57cfSAxel Dörfler 				== media_raw_audio_format::B_AUDIO_SHORT) {
6688777023Sbeveloper 			fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format);
6788777023Sbeveloper 		}
6888777023Sbeveloper 	}
6988777023Sbeveloper 
702e9d6607Sbeveloper 	// initialize fInputChannelInfo
712e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++) {
72b543dbc2SStephan Aßmus 		fInputChannelInfo[i].buffer_base = 0;
73b543dbc2SStephan Aßmus 			// will be set by SetMixBufferFormat()
74b543dbc2SStephan Aßmus 		fInputChannelInfo[i].destination_mask = 0;
75b006bbe1SStephan Aßmus 			// will be set by _UpdateInputChannelDestinationMask()
762e9d6607Sbeveloper 		fInputChannelInfo[i].gain = 1.0;
772e9d6607Sbeveloper 	}
782e9d6607Sbeveloper 
79b006bbe1SStephan Aßmus 	UpdateResamplingAlgorithm();
807b0daf5cSbeveloper 
81b543dbc2SStephan Aßmus 	// fMixerChannelInfo and fMixerChannelCount will be initialized by
82b006bbe1SStephan Aßmus 	// _UpdateInputChannelDestinations()
83bf7ab50dSStephan Aßmus 	SetMixBufferFormat((int32)mixFrameRate, mixFrameCount);
84678c2017Sbeveloper }
85678c2017Sbeveloper 
86a9cf57cfSAxel Dörfler 
~MixerInput()87678c2017Sbeveloper MixerInput::~MixerInput()
88678c2017Sbeveloper {
892e9d6607Sbeveloper 	if (fMixBuffer)
902e9d6607Sbeveloper 		rtm_free(fMixBuffer);
91356855c3Sbeveloper 	if (fRtmPool)
92356855c3Sbeveloper 		rtm_delete_pool(fRtmPool);
932e9d6607Sbeveloper 	delete[] fInputChannelInfo;
942e9d6607Sbeveloper 	delete[] fMixerChannelInfo;
957b0daf5cSbeveloper 
967b0daf5cSbeveloper 	// delete resamplers
97b006bbe1SStephan Aßmus 	if (fResampler != NULL) {
987b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++)
997b0daf5cSbeveloper 			delete fResampler[i];
1007b0daf5cSbeveloper 		delete[] fResampler;
101b006bbe1SStephan Aßmus 	}
102db6f1135SJérôme Duval 	delete fInputByteSwap;
103678c2017Sbeveloper }
104678c2017Sbeveloper 
105a9cf57cfSAxel Dörfler 
106b006bbe1SStephan Aßmus int32
ID()107b006bbe1SStephan Aßmus MixerInput::ID()
108b006bbe1SStephan Aßmus {
109b006bbe1SStephan Aßmus 	return fInput.destination.id;
110b006bbe1SStephan Aßmus }
111b006bbe1SStephan Aßmus 
112b006bbe1SStephan Aßmus 
113b006bbe1SStephan Aßmus media_input&
MediaInput()114b006bbe1SStephan Aßmus MixerInput::MediaInput()
115b006bbe1SStephan Aßmus {
116b006bbe1SStephan Aßmus 	return fInput;
117b006bbe1SStephan Aßmus }
118b006bbe1SStephan Aßmus 
119b006bbe1SStephan Aßmus 
120678c2017Sbeveloper void
BufferReceived(BBuffer * buffer)121678c2017Sbeveloper MixerInput::BufferReceived(BBuffer* buffer)
122678c2017Sbeveloper {
12388777023Sbeveloper 	void* data;
12488777023Sbeveloper 	size_t size;
12588777023Sbeveloper 	bigtime_t start;
126e92593f4Sbeveloper 	bigtime_t buffer_duration;
12788777023Sbeveloper 
128d5848e21Sbeveloper 	if (!fMixBuffer) {
129b543dbc2SStephan Aßmus 		ERROR("MixerInput::BufferReceived: dropped incoming buffer as we "
130b543dbc2SStephan Aßmus 			"don't have a mix buffer\n");
131d5848e21Sbeveloper 		return;
132d5848e21Sbeveloper 	}
1332e9d6607Sbeveloper 
13488777023Sbeveloper 	data = buffer->Data();
13588777023Sbeveloper 	size = buffer->SizeUsed();
13688777023Sbeveloper 	start = buffer->Header()->start_time;
137b543dbc2SStephan Aßmus 	buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate,
138b543dbc2SStephan Aßmus 		size / bytes_per_frame(fInput.format.u.raw_audio));
1398d28117fSbeveloper 	if (start < 0) {
140b543dbc2SStephan Aßmus 		ERROR("MixerInput::BufferReceived: buffer with negative start time of "
141*425ac1b6SAlexander von Gluck IV 			"%lld dropped\n", start);
1428d28117fSbeveloper 		return;
1438d28117fSbeveloper 	}
14488777023Sbeveloper 
14588777023Sbeveloper 	// swap the byte order of this buffer, if necessary
14688777023Sbeveloper 	if (fInputByteSwap)
14788777023Sbeveloper 		fInputByteSwap->Swap(data, size);
14888777023Sbeveloper 
149b543dbc2SStephan Aßmus 	int offset = frames_for_duration(fMixBufferFrameRate, start)
150b543dbc2SStephan Aßmus 		% fMixBufferFrameCount;
1518d28117fSbeveloper 
152b543dbc2SStephan Aßmus 	PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n",
153b543dbc2SStephan Aßmus 		start, offset);
1547b0daf5cSbeveloper 
155191033efSbeveloper 	int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio);
15623bfcc55SJulian Harnath 	double frames = ((double)in_frames * fMixBufferFrameRate)
157b543dbc2SStephan Aßmus 		/ fInput.format.u.raw_audio.frame_rate;
158e92593f4Sbeveloper 	int out_frames = int(frames);
159e92593f4Sbeveloper 	fFractionalFrames += frames - double(out_frames);
160e92593f4Sbeveloper 	if (fFractionalFrames >= 1.0) {
161e92593f4Sbeveloper 		fFractionalFrames -= 1.0;
1627619f562Sbeveloper 		out_frames++;
163e92593f4Sbeveloper 	}
164e92593f4Sbeveloper 
165e92593f4Sbeveloper 	// if fLastDataFrameWritten != -1, then we have a valid last position
166e92593f4Sbeveloper 	// and can do glitch compensation
167e92593f4Sbeveloper 	if (fLastDataFrameWritten >= 0) {
168b543dbc2SStephan Aßmus 		int expected_frame = (fLastDataFrameWritten + 1)
169b543dbc2SStephan Aßmus 			% fMixBufferFrameCount;
170e92593f4Sbeveloper 		if (offset != expected_frame) {
171e92593f4Sbeveloper 			// due to rounding and other errors, offset might be off by +/- 1
172e92593f4Sbeveloper 			// this is not really a bad glitch, we just adjust the position
173e92593f4Sbeveloper 			if (offset == fLastDataFrameWritten) {
174b543dbc2SStephan Aßmus //				printf("MixerInput::BufferReceived: -1 frame GLITCH! last "
175b543dbc2SStephan Aßmus //					"frame was %ld, expected frame was %d, new frame is %d\n",
176b543dbc2SStephan Aßmus //					fLastDataFrameWritten, expected_frame, offset);
177e92593f4Sbeveloper 				offset = expected_frame;
178b543dbc2SStephan Aßmus 			} else if (offset == ((fLastDataFrameWritten + 2)
179b543dbc2SStephan Aßmus 				% fMixBufferFrameCount)) {
180b543dbc2SStephan Aßmus //				printf("MixerInput::BufferReceived: +1 frame GLITCH! last "
181b543dbc2SStephan Aßmus //					"frame was %ld, expected frame was %d, new frame is %d\n",
182b543dbc2SStephan Aßmus //					fLastDataFrameWritten, expected_frame, offset);
183e92593f4Sbeveloper 				offset = expected_frame;
184e92593f4Sbeveloper 			} else {
185b543dbc2SStephan Aßmus 				printf("MixerInput::BufferReceived: GLITCH! last frame was "
186973f1214SJérôme Duval 					"%4" B_PRId32 ", expected frame was %4d, new frame is %4d"
187973f1214SJérôme Duval 					"\n", fLastDataFrameWritten, expected_frame, offset);
188e92593f4Sbeveloper 
189e92593f4Sbeveloper 				if (start > fLastDataAvailableTime) {
190b543dbc2SStephan Aßmus 					if ((start - fLastDataAvailableTime)
191b543dbc2SStephan Aßmus 						< (buffer_duration / 10)) {
192e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too late
193b543dbc2SStephan Aßmus 						printf("short glitch, buffer too late, time delta "
194973f1214SJérôme Duval 							"%" B_PRIdBIGTIME "\n", start
195973f1214SJérôme Duval 							- fLastDataAvailableTime);
196e92593f4Sbeveloper 						offset = expected_frame;
197e92593f4Sbeveloper 						out_frames++;
198e92593f4Sbeveloper 					} else {
199e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too late
200b543dbc2SStephan Aßmus 						// TODO: zerofill buffer
201b543dbc2SStephan Aßmus 						printf("MAJOR glitch, buffer too late, time delta "
202973f1214SJérôme Duval 							"%" B_PRIdBIGTIME "\n", start
203973f1214SJérôme Duval 							- fLastDataAvailableTime);
204e92593f4Sbeveloper 					}
205e92593f4Sbeveloper 				} else { // start <= fLastDataAvailableTime
206e92593f4Sbeveloper 					// the new buffer is too early
207b543dbc2SStephan Aßmus 					if ((fLastDataAvailableTime - start)
208b543dbc2SStephan Aßmus 						< (buffer_duration / 10)) {
209e92593f4Sbeveloper 						// buffer is less than 10% of buffer duration too early
210b543dbc2SStephan Aßmus 						printf("short glitch, buffer too early, time delta "
211973f1214SJérôme Duval 							"%" B_PRIdBIGTIME "\n", fLastDataAvailableTime
212973f1214SJérôme Duval 							- start);
213e92593f4Sbeveloper 						offset = expected_frame;
214e92593f4Sbeveloper 						out_frames--;
215e92593f4Sbeveloper 						if (out_frames < 1)
216e92593f4Sbeveloper 							out_frames = 1;
217e92593f4Sbeveloper 					} else {
218e92593f4Sbeveloper 						// buffer more than 10% of buffer duration too early
219b543dbc2SStephan Aßmus 						// TODO: zerofill buffer
220b543dbc2SStephan Aßmus 						printf("MAJOR glitch, buffer too early, time delta "
221973f1214SJérôme Duval 							"%" B_PRIdBIGTIME "\n", fLastDataAvailableTime
222973f1214SJérôme Duval 							- start);
223e92593f4Sbeveloper 					}
224e92593f4Sbeveloper 				}
225e92593f4Sbeveloper 			}
226e92593f4Sbeveloper 		}
227e92593f4Sbeveloper 	}
2287b0daf5cSbeveloper 
229b543dbc2SStephan Aßmus //	printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n",
230b543dbc2SStephan Aßmus //		start,
231b543dbc2SStephan Aßmus //		start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
232b543dbc2SStephan Aßmus //		frames_per_buffer(fInput.format.u.raw_audio)), offset,
233b543dbc2SStephan Aßmus //		offset + out_frames);
2347b0daf5cSbeveloper 	if (offset + out_frames > fMixBufferFrameCount) {
2357b0daf5cSbeveloper 		int out_frames1 = fMixBufferFrameCount - offset;
2367b0daf5cSbeveloper 		int out_frames2 = out_frames - out_frames1;
2377b0daf5cSbeveloper 		int in_frames1 = (out_frames1 * in_frames) / out_frames;
2387b0daf5cSbeveloper 		int in_frames2 = in_frames - in_frames1;
2397b0daf5cSbeveloper 
240b543dbc2SStephan Aßmus //		printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at "
241b543dbc2SStephan Aßmus //			"frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(),
242b543dbc2SStephan Aßmus //			start,
243b543dbc2SStephan Aßmus //			start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
244b543dbc2SStephan Aßmus //			frames_per_buffer(fInput.format.u.raw_audio)), offset,
245b543dbc2SStephan Aßmus //			offset + out_frames1 - 1, 0, out_frames2 - 1);
246b543dbc2SStephan Aßmus 		PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at "
247b543dbc2SStephan Aßmus 			"frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(),
248b543dbc2SStephan Aßmus 			start,
249b543dbc2SStephan Aßmus 			start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
250b543dbc2SStephan Aßmus 			frames_per_buffer(fInput.format.u.raw_audio)), offset,
251b543dbc2SStephan Aßmus 			offset + out_frames1 - 1, 0, out_frames2 - 1);
252b543dbc2SStephan Aßmus 		PRINT(5, "  in_frames %5d, out_frames %5d, in_frames1 %5d, "
253b543dbc2SStephan Aßmus 			"out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n",
254b543dbc2SStephan Aßmus 			in_frames, out_frames, in_frames1, out_frames1, in_frames2,
255b543dbc2SStephan Aßmus 			out_frames2);
2567b0daf5cSbeveloper 
257e92593f4Sbeveloper 		fLastDataFrameWritten = out_frames2 - 1;
258e92593f4Sbeveloper 
259b543dbc2SStephan Aßmus 		// convert offset from frames into bytes
260b543dbc2SStephan Aßmus 		offset *= sizeof(float) * fInputChannelCount;
2618d28117fSbeveloper 
2627b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
263b543dbc2SStephan Aßmus 			fResampler[i]->Resample(
264b543dbc2SStephan Aßmus 				reinterpret_cast<char*>(data)
265b543dbc2SStephan Aßmus 					+ i * bytes_per_sample(fInput.format.u.raw_audio),
266b543dbc2SStephan Aßmus 				bytes_per_frame(fInput.format.u.raw_audio), in_frames1,
267b543dbc2SStephan Aßmus 				reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base)
268b543dbc2SStephan Aßmus 					+ offset, fInputChannelCount * sizeof(float), out_frames1,
2697b0daf5cSbeveloper 				fInputChannelInfo[i].gain);
2707b0daf5cSbeveloper 
271b543dbc2SStephan Aßmus 			fResampler[i]->Resample(
272b543dbc2SStephan Aßmus 				reinterpret_cast<char*>(data)
273b543dbc2SStephan Aßmus 					+ i * bytes_per_sample(fInput.format.u.raw_audio)
274b543dbc2SStephan Aßmus 					+ in_frames1 * bytes_per_frame(fInput.format.u.raw_audio),
275b543dbc2SStephan Aßmus 				bytes_per_frame(fInput.format.u.raw_audio), in_frames2,
2767b0daf5cSbeveloper 				reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base),
277b543dbc2SStephan Aßmus 				fInputChannelCount * sizeof(float), out_frames2,
2787b0daf5cSbeveloper 				fInputChannelInfo[i].gain);
279e92593f4Sbeveloper 
2807b0daf5cSbeveloper 		}
2817b0daf5cSbeveloper 	} else {
282b543dbc2SStephan Aßmus //		printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at "
283b543dbc2SStephan Aßmus //			"frames %ld to %ld\n", fCore->fTimeSource->Now(), start,
284b543dbc2SStephan Aßmus //			start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
285b543dbc2SStephan Aßmus //			frames_per_buffer(fInput.format.u.raw_audio)), offset,
286b543dbc2SStephan Aßmus //			offset + out_frames - 1);
287b543dbc2SStephan Aßmus 		PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at "
288b543dbc2SStephan Aßmus 			"frames %ld to %ld\n", fCore->fTimeSource->Now(), start,
289b543dbc2SStephan Aßmus 			start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
290b543dbc2SStephan Aßmus 			frames_per_buffer(fInput.format.u.raw_audio)), offset,
291b543dbc2SStephan Aßmus 			offset + out_frames - 1);
292191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d\n", in_frames, out_frames);
2938d28117fSbeveloper 
294e92593f4Sbeveloper 		fLastDataFrameWritten = offset + out_frames - 1;
295b543dbc2SStephan Aßmus 		// convert offset from frames into bytes
296b543dbc2SStephan Aßmus 		offset *= sizeof(float) * fInputChannelCount;
2977b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
298b543dbc2SStephan Aßmus 			fResampler[i]->Resample(
299b543dbc2SStephan Aßmus 				reinterpret_cast<char*>(data)
300b543dbc2SStephan Aßmus 					+ i * bytes_per_sample(fInput.format.u.raw_audio),
301b543dbc2SStephan Aßmus 				bytes_per_frame(fInput.format.u.raw_audio), in_frames,
302b543dbc2SStephan Aßmus 				reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base)
303b543dbc2SStephan Aßmus 					+ offset, fInputChannelCount * sizeof(float),
304b543dbc2SStephan Aßmus 				out_frames, fInputChannelInfo[i].gain);
3057b0daf5cSbeveloper 		}
3067b0daf5cSbeveloper 	}
307e92593f4Sbeveloper 	fLastDataAvailableTime = start + buffer_duration;
308678c2017Sbeveloper }
3097ee2c804Sbeveloper 
310bf7ab50dSStephan Aßmus 
311b006bbe1SStephan Aßmus void
UpdateResamplingAlgorithm()312b006bbe1SStephan Aßmus MixerInput::UpdateResamplingAlgorithm()
3137ee2c804Sbeveloper {
314b006bbe1SStephan Aßmus 	if (fResampler != NULL) {
315b006bbe1SStephan Aßmus 		for (int i = 0; i < fInputChannelCount; i++)
316b006bbe1SStephan Aßmus 			delete fResampler[i];
317b006bbe1SStephan Aßmus 		delete[] fResampler;
3187ee2c804Sbeveloper 	}
319b006bbe1SStephan Aßmus 	// create resamplers
320b006bbe1SStephan Aßmus 	fResampler = new Resampler*[fInputChannelCount];
321b006bbe1SStephan Aßmus 	for (int i = 0; i < fInputChannelCount; i++) {
322b006bbe1SStephan Aßmus 		switch (fCore->Settings()->ResamplingAlgorithm()) {
323b006bbe1SStephan Aßmus 			case 2:
324b006bbe1SStephan Aßmus 				fResampler[i] = new Interpolate(
325b006bbe1SStephan Aßmus 					fInput.format.u.raw_audio.format,
326b006bbe1SStephan Aßmus 					media_raw_audio_format::B_AUDIO_FLOAT);
327b006bbe1SStephan Aßmus 				break;
328b006bbe1SStephan Aßmus 			default:
329b006bbe1SStephan Aßmus 				fResampler[i] = new Resampler(
330b006bbe1SStephan Aßmus 					fInput.format.u.raw_audio.format,
331b006bbe1SStephan Aßmus 					media_raw_audio_format::B_AUDIO_FLOAT);
332b006bbe1SStephan Aßmus 		}
333b006bbe1SStephan Aßmus 	}
334e6c7c99fSbeveloper }
335e6c7c99fSbeveloper 
336bf7ab50dSStephan Aßmus 
337d91580cdSbeveloper int
GetInputChannelCount()338fae6ce82Sbeveloper MixerInput::GetInputChannelCount()
339fae6ce82Sbeveloper {
340fae6ce82Sbeveloper 	return fInputChannelCount;
341fae6ce82Sbeveloper }
342fae6ce82Sbeveloper 
343bf7ab50dSStephan Aßmus 
3442e9d6607Sbeveloper void
AddInputChannelDestination(int channel,int destination_type)3459c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type)
3462e9d6607Sbeveloper {
3479c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
348e6c7c99fSbeveloper 
3492e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3502e9d6607Sbeveloper 		return;
3512e9d6607Sbeveloper 
3522e9d6607Sbeveloper 	// test if it is already set
3539c3be6a5Sbeveloper 	if (fInputChannelInfo[channel].destination_mask & mask)
3542e9d6607Sbeveloper 		return;
3552e9d6607Sbeveloper 
3569c3be6a5Sbeveloper 	// verify that no other channel has id
3579c3be6a5Sbeveloper 	if (-1 != GetInputChannelForDestination(destination_type)) {
358b543dbc2SStephan Aßmus 		ERROR("MixerInput::AddInputChannelDestination: destination_type %d "
359b543dbc2SStephan Aßmus 			"already assigned to channel %d\n", destination_type,
360b543dbc2SStephan Aßmus 			GetInputChannelForDestination(destination_type));
3619c3be6a5Sbeveloper 		return;
3629c3be6a5Sbeveloper 	}
3632e9d6607Sbeveloper 
3642e9d6607Sbeveloper 	// add it to specified channel
3659c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask |= mask;
3662e9d6607Sbeveloper 
3679c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
368b006bbe1SStephan Aßmus 	_UpdateInputChannelDestinations();
3692e9d6607Sbeveloper }
3702e9d6607Sbeveloper 
371a9cf57cfSAxel Dörfler 
3722e9d6607Sbeveloper void
RemoveInputChannelDestination(int channel,int destination_type)3739c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
3742e9d6607Sbeveloper {
3759c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
3762e9d6607Sbeveloper 
3772e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3782e9d6607Sbeveloper 		return;
3792e9d6607Sbeveloper 
3802e9d6607Sbeveloper 	// test if it is really set
3819c3be6a5Sbeveloper 	if ((fInputChannelInfo[channel].destination_mask & mask) == 0)
3822e9d6607Sbeveloper 		return;
3832e9d6607Sbeveloper 
3842e9d6607Sbeveloper 	// remove it from specified channel
3859c3be6a5Sbeveloper 	fInputChannelInfo[channel].destination_mask &= ~mask;
3862e9d6607Sbeveloper 
3879c3be6a5Sbeveloper 	fUserOverridesChannelDestinations = true;
388b006bbe1SStephan Aßmus 	_UpdateInputChannelDestinations();
3892e9d6607Sbeveloper }
3902e9d6607Sbeveloper 
391a9cf57cfSAxel Dörfler 
3929c3be6a5Sbeveloper bool
HasInputChannelDestination(int channel,int destination_type)3939c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type)
3942e9d6607Sbeveloper {
3952e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
3969c3be6a5Sbeveloper 		return false;
3979c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
3989c3be6a5Sbeveloper 		return false;
399b543dbc2SStephan Aßmus 	return fInputChannelInfo[channel].destination_mask
400b543dbc2SStephan Aßmus 		& ChannelTypeToChannelMask(destination_type);
4012e9d6607Sbeveloper }
4022e9d6607Sbeveloper 
403a9cf57cfSAxel Dörfler 
4049c3be6a5Sbeveloper int
GetInputChannelForDestination(int destination_type)4059c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type)
4069c3be6a5Sbeveloper {
4079c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
4089c3be6a5Sbeveloper 		return -1;
4099c3be6a5Sbeveloper 	uint32 mask = ChannelTypeToChannelMask(destination_type);
4109c3be6a5Sbeveloper 	for (int chan = 0; chan < fInputChannelCount; chan++) {
4119c3be6a5Sbeveloper 		if (fInputChannelInfo[chan].destination_mask & mask)
4129c3be6a5Sbeveloper 			return chan;
4139c3be6a5Sbeveloper 	}
4149c3be6a5Sbeveloper 	return -1;
4159c3be6a5Sbeveloper }
4169c3be6a5Sbeveloper 
417a9cf57cfSAxel Dörfler 
4189c3be6a5Sbeveloper int
GetInputChannelType(int channel)4192e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel)
4202e9d6607Sbeveloper {
4212e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
4222e9d6607Sbeveloper 		return 0;
4239c3be6a5Sbeveloper 	return GetChannelType(channel, fInputChannelMask);
4242e9d6607Sbeveloper }
4252e9d6607Sbeveloper 
426a9cf57cfSAxel Dörfler 
4272e9d6607Sbeveloper void
SetInputChannelGain(int channel,float gain)4282e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain)
4292e9d6607Sbeveloper {
4302e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
4312e9d6607Sbeveloper 		return;
4322e9d6607Sbeveloper 	if (gain < 0.0f)
4332e9d6607Sbeveloper 		gain = 0.0f;
4342e9d6607Sbeveloper 
4352e9d6607Sbeveloper 	fInputChannelInfo[channel].gain = gain;
4362e9d6607Sbeveloper }
4372e9d6607Sbeveloper 
438a9cf57cfSAxel Dörfler 
4392e9d6607Sbeveloper float
GetInputChannelGain(int channel)4402e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel)
4412e9d6607Sbeveloper {
4422e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
4432e9d6607Sbeveloper 		return 0.0f;
4442e9d6607Sbeveloper 	return fInputChannelInfo[channel].gain;
4452e9d6607Sbeveloper }
4462e9d6607Sbeveloper 
447a9cf57cfSAxel Dörfler 
4482e9d6607Sbeveloper void
_UpdateInputChannelDestinationMask()449b006bbe1SStephan Aßmus MixerInput::_UpdateInputChannelDestinationMask()
4502e9d6607Sbeveloper {
4512e9d6607Sbeveloper 	// is the user already messed with the assignmens, don't do anything.
4529c3be6a5Sbeveloper 	if (fUserOverridesChannelDestinations)
4532e9d6607Sbeveloper 		return;
4542e9d6607Sbeveloper 
455b006bbe1SStephan Aßmus 	TRACE("_UpdateInputChannelDestinationMask: enter\n");
4562e9d6607Sbeveloper 
457806cf560Sbeveloper 	// first apply a 1:1 mapping
458b543dbc2SStephan Aßmus 	for (int i = 0; i < fInputChannelCount; i++) {
459b543dbc2SStephan Aßmus 		fInputChannelInfo[i].destination_mask = GetChannelMask(i,
460b543dbc2SStephan Aßmus 			fInputChannelMask);
461b543dbc2SStephan Aßmus 	}
462806cf560Sbeveloper 
463806cf560Sbeveloper 	// specialize this, depending on the available physical output channels
464643e1b2eSbeveloper 	if (fCore->OutputChannelCount() <= 2) {
465643e1b2eSbeveloper 		// less or equal two channels
466b543dbc2SStephan Aßmus 		if (fInputChannelCount == 1
467b543dbc2SStephan Aßmus 			&& (GetChannelMask(0, fInputChannelMask)
468b543dbc2SStephan Aßmus 				& (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
469ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
470806cf560Sbeveloper 		}
471643e1b2eSbeveloper 	} else {
472643e1b2eSbeveloper 		// more than two channel output card
473b543dbc2SStephan Aßmus 		if (fInputChannelCount == 1
474b543dbc2SStephan Aßmus 			&& (GetChannelMask(0, fInputChannelMask)
475b543dbc2SStephan Aßmus 				& (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
476ab276ac8Sbeveloper 			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
477806cf560Sbeveloper 		}
478b543dbc2SStephan Aßmus 		if (fInputChannelCount == 2
479b543dbc2SStephan Aßmus 			&& (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) {
480b543dbc2SStephan Aßmus 			fInputChannelInfo[0].destination_mask
481b543dbc2SStephan Aßmus 				= B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
482806cf560Sbeveloper 		}
483b543dbc2SStephan Aßmus 		if (fInputChannelCount == 2
484b543dbc2SStephan Aßmus 			&& (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) {
485b543dbc2SStephan Aßmus 			fInputChannelInfo[0].destination_mask
486b543dbc2SStephan Aßmus 				= B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
487806cf560Sbeveloper 		}
488b543dbc2SStephan Aßmus 		if (fInputChannelCount == 2
489b543dbc2SStephan Aßmus 			&& (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) {
490b543dbc2SStephan Aßmus 			fInputChannelInfo[1].destination_mask
491b543dbc2SStephan Aßmus 				= B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
492806cf560Sbeveloper 		}
493b543dbc2SStephan Aßmus 		if (fInputChannelCount == 2
494b543dbc2SStephan Aßmus 			&& (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) {
495b543dbc2SStephan Aßmus 			fInputChannelInfo[1].destination_mask
496b543dbc2SStephan Aßmus 				= B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
497806cf560Sbeveloper 		}
4982e9d6607Sbeveloper 	}
4992e9d6607Sbeveloper 
500b543dbc2SStephan Aßmus 	for (int i = 0; i < fInputChannelCount; i++) {
501b006bbe1SStephan Aßmus 		TRACE("_UpdateInputChannelDestinationMask: input channel %d, "
502b543dbc2SStephan Aßmus 			"destination_mask 0x%08lX, base %p, gain %.3f\n", i,
503b543dbc2SStephan Aßmus 			fInputChannelInfo[i].destination_mask,
504b543dbc2SStephan Aßmus 			fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
505b543dbc2SStephan Aßmus 	}
506b006bbe1SStephan Aßmus 	TRACE("_UpdateInputChannelDestinationMask: leave\n");
5072e9d6607Sbeveloper }
5082e9d6607Sbeveloper 
509a9cf57cfSAxel Dörfler 
5102e9d6607Sbeveloper void
_UpdateInputChannelDestinations()511b006bbe1SStephan Aßmus MixerInput::_UpdateInputChannelDestinations()
5122e9d6607Sbeveloper {
513d91580cdSbeveloper 	int channel_count;
5142e9d6607Sbeveloper 	uint32 all_bits;
5152e9d6607Sbeveloper 	uint32 mask;
5162e9d6607Sbeveloper 
517b006bbe1SStephan Aßmus 	TRACE("_UpdateInputChannelDestinations: enter\n");
518b543dbc2SStephan Aßmus 	for (int i = 0; i < fInputChannelCount; i++) {
519b006bbe1SStephan Aßmus 		TRACE("_UpdateInputChannelDestinations: input channel %d, "
520b543dbc2SStephan Aßmus 			"destination_mask 0x%08lX, base %p, gain %.3f\n", i,
521b543dbc2SStephan Aßmus 			fInputChannelInfo[i].destination_mask,
522b543dbc2SStephan Aßmus 			fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
523b543dbc2SStephan Aßmus 	}
5242e9d6607Sbeveloper 
5252e9d6607Sbeveloper 	all_bits = 0;
5262e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
5279c3be6a5Sbeveloper 		all_bits |= fInputChannelInfo[i].destination_mask;
5282e9d6607Sbeveloper 
529b006bbe1SStephan Aßmus 	TRACE("_UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
5302e9d6607Sbeveloper 
5312e9d6607Sbeveloper 	channel_count = count_nonzero_bits(all_bits);
532b006bbe1SStephan Aßmus 	TRACE("_UpdateInputChannelDestinations: %d input channels, %d mixer "
533b543dbc2SStephan Aßmus 		"channels (%d old)\n", fInputChannelCount, channel_count,
534b543dbc2SStephan Aßmus 		fMixerChannelCount);
5352e9d6607Sbeveloper 	if (channel_count != fMixerChannelCount) {
5369c3be6a5Sbeveloper 		delete [] fMixerChannelInfo;
5372e9d6607Sbeveloper 		fMixerChannelInfo = new mixer_chan_info[channel_count];
5382e9d6607Sbeveloper 		fMixerChannelCount = channel_count;
5392e9d6607Sbeveloper 	}
5402e9d6607Sbeveloper 
5412e9d6607Sbeveloper 	// assign each mixer channel one type
5429c3be6a5Sbeveloper 	// and the gain from the fChannelTypeGain[]
543d91580cdSbeveloper 	mask = 1;
544d91580cdSbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
5452e9d6607Sbeveloper 		while (mask != 0 && (all_bits & mask) == 0)
5462e9d6607Sbeveloper 			mask <<= 1;
5479c3be6a5Sbeveloper 		fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask);
548b543dbc2SStephan Aßmus 		fMixerChannelInfo[i].destination_gain
549b543dbc2SStephan Aßmus 			= fChannelTypeGain[fMixerChannelInfo[i].destination_type];
5502e9d6607Sbeveloper 		mask <<= 1;
5512e9d6607Sbeveloper 	}
5522e9d6607Sbeveloper 
5532e9d6607Sbeveloper 	// assign buffer_base pointer for each mixer channel
5542e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
5552e9d6607Sbeveloper 		int j;
5562e9d6607Sbeveloper 		for (j = 0; j < fInputChannelCount; j++) {
557b543dbc2SStephan Aßmus 			if (fInputChannelInfo[j].destination_mask
558b543dbc2SStephan Aßmus 					& ChannelTypeToChannelMask(
559b543dbc2SStephan Aßmus 						fMixerChannelInfo[i].destination_type)) {
560b543dbc2SStephan Aßmus 				fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j]
561b543dbc2SStephan Aßmus 					: 0;
5622e9d6607Sbeveloper 				break;
5632e9d6607Sbeveloper 			}
5642e9d6607Sbeveloper 		}
5652e9d6607Sbeveloper 		if (j == fInputChannelCount) {
566a2ca4723Sbeveloper 			ERROR("buffer assignment failed for mixer chan %d\n", i);
5672e9d6607Sbeveloper 			fMixerChannelInfo[i].buffer_base = fMixBuffer;
5682e9d6607Sbeveloper 		}
5692e9d6607Sbeveloper 	}
5702e9d6607Sbeveloper 
571b543dbc2SStephan Aßmus 	for (int i = 0; i < fMixerChannelCount; i++) {
572b006bbe1SStephan Aßmus 		TRACE("_UpdateInputChannelDestinations: mixer channel %d, type %2d, "
573b543dbc2SStephan Aßmus 			"base %p, gain %.3f\n", i, fMixerChannelInfo[i].destination_type,
574b543dbc2SStephan Aßmus 			fMixerChannelInfo[i].buffer_base,
575b543dbc2SStephan Aßmus 			fMixerChannelInfo[i].destination_gain);
576b543dbc2SStephan Aßmus 	}
5772e9d6607Sbeveloper 
578b006bbe1SStephan Aßmus 	TRACE("_UpdateInputChannelDestinations: leave\n");
5792e9d6607Sbeveloper }
580bf7ab50dSStephan Aßmus 
581a9cf57cfSAxel Dörfler 
582bf7ab50dSStephan Aßmus // Note: The following code is outcommented on purpose
583bf7ab50dSStephan Aßmus // and is about to be modified at a later point
58469517c15Sbeveloper /*
5852e9d6607Sbeveloper void
586b543dbc2SStephan Aßmus MixerInput::SetInputChannelDestinationGain(int channel, int destination_type,
587b543dbc2SStephan Aßmus 	float gain)
5882e9d6607Sbeveloper {
589b543dbc2SStephan Aßmus 	TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d,
590b543dbc2SStephan Aßmus 		gain %.4f\n", channel, destination_type, gain);
5919c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
5929c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
5939c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
5942e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
5952e9d6607Sbeveloper 		return;
5969c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
5979c3be6a5Sbeveloper 		return;
5982e9d6607Sbeveloper 	if (gain < 0.0f)
5992e9d6607Sbeveloper 		gain = 0.0f;
6009c3be6a5Sbeveloper 	fChannelTypeGain[destination_type] = gain;
6019c3be6a5Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++) {
6029c3be6a5Sbeveloper 		if (fMixerChannelInfo[i].destination_type == destination_type) {
6039c3be6a5Sbeveloper 			fMixerChannelInfo[i].destination_gain = gain;
6049c3be6a5Sbeveloper 			return;
6059c3be6a5Sbeveloper 		}
6069c3be6a5Sbeveloper 	}
6072e9d6607Sbeveloper }
6082e9d6607Sbeveloper 
609a9cf57cfSAxel Dörfler 
6102e9d6607Sbeveloper float
6119c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type)
6122e9d6607Sbeveloper {
6139c3be6a5Sbeveloper 	// we don't need the channel, as each destination_type can only exist
6149c3be6a5Sbeveloper 	// once for each MixerInput, but we use it for parameter validation
6159c3be6a5Sbeveloper 	// and to have a interface similar to MixerOutput
6162e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
6179c3be6a5Sbeveloper 		return 0.0f;
6189c3be6a5Sbeveloper 	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
6199c3be6a5Sbeveloper 		return 0.0f;
6209c3be6a5Sbeveloper 	return fChannelTypeGain[destination_type];
6212e9d6607Sbeveloper }
62269517c15Sbeveloper */
62369517c15Sbeveloper 
624a9cf57cfSAxel Dörfler 
62569517c15Sbeveloper void
SetMixerChannelGain(int mixer_channel,float gain)62669517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain)
62769517c15Sbeveloper {
62869517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
62969517c15Sbeveloper 		return;
63069517c15Sbeveloper 	if (gain < 0.0f)
63169517c15Sbeveloper 		gain = 0.0f;
63269517c15Sbeveloper 
63369517c15Sbeveloper 	fMixerChannelInfo[mixer_channel].destination_gain = gain;
63469517c15Sbeveloper 	fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain;
63569517c15Sbeveloper }
63669517c15Sbeveloper 
637a9cf57cfSAxel Dörfler 
63869517c15Sbeveloper float
GetMixerChannelGain(int mixer_channel)63969517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel)
64069517c15Sbeveloper {
64169517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
64269517c15Sbeveloper 		return 0.0;
64369517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_gain;
64469517c15Sbeveloper }
64569517c15Sbeveloper 
646a9cf57cfSAxel Dörfler 
64769517c15Sbeveloper int
GetMixerChannelType(int mixer_channel)64869517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel)
64969517c15Sbeveloper {
65069517c15Sbeveloper 	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
65169517c15Sbeveloper 		return -1;
65269517c15Sbeveloper 	return fMixerChannelInfo[mixer_channel].destination_type;
65369517c15Sbeveloper }
6542e9d6607Sbeveloper 
655a9cf57cfSAxel Dörfler 
6562e9d6607Sbeveloper void
SetEnabled(bool yesno)6571c237c18Sbeveloper MixerInput::SetEnabled(bool yesno)
6581c237c18Sbeveloper {
6591c237c18Sbeveloper 	fEnabled = yesno;
6601c237c18Sbeveloper }
6611c237c18Sbeveloper 
662a9cf57cfSAxel Dörfler 
6631c237c18Sbeveloper bool
IsEnabled()6641c237c18Sbeveloper MixerInput::IsEnabled()
6651c237c18Sbeveloper {
6661c237c18Sbeveloper 	return fEnabled;
6671c237c18Sbeveloper }
6681c237c18Sbeveloper 
669a9cf57cfSAxel Dörfler 
6701c237c18Sbeveloper void
SetMixBufferFormat(int32 framerate,int32 frames)6718d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
6722e9d6607Sbeveloper {
673a9cf57cfSAxel Dörfler 	TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n",
674a9cf57cfSAxel Dörfler 		framerate, frames);
675d5848e21Sbeveloper 
6767b0daf5cSbeveloper 	fMixBufferFrameRate = framerate;
677a9cf57cfSAxel Dörfler 	fDebugMixBufferFrames = frames;
6782e9d6607Sbeveloper 
679d5848e21Sbeveloper 	// frames and/or framerate can be 0 (if no output is connected)
680d5848e21Sbeveloper 	if (framerate == 0 || frames == 0) {
681a9cf57cfSAxel Dörfler 		if (fMixBuffer != NULL) {
682d5848e21Sbeveloper 			rtm_free(fMixBuffer);
683a9cf57cfSAxel Dörfler 			fMixBuffer = NULL;
684d5848e21Sbeveloper 		}
685d5848e21Sbeveloper 		for (int i = 0; i < fInputChannelCount; i++)
686d5848e21Sbeveloper 			fInputChannelInfo[i].buffer_base = 0;
687d5848e21Sbeveloper 		fMixBufferFrameCount = 0;
688d5848e21Sbeveloper 
689b006bbe1SStephan Aßmus 		_UpdateInputChannelDestinationMask();
690b006bbe1SStephan Aßmus 		_UpdateInputChannelDestinations();
691d5848e21Sbeveloper 		return;
692d5848e21Sbeveloper 	}
6937b0daf5cSbeveloper 
6947b0daf5cSbeveloper 	// make fMixBufferFrameCount an integral multiple of frames,
6957b0daf5cSbeveloper 	// but at least 3 times duration of our input buffer
6967b0daf5cSbeveloper 	// and at least 2 times duration of the output buffer
697b543dbc2SStephan Aßmus 	bigtime_t inputBufferLength  = duration_for_frames(
698b543dbc2SStephan Aßmus 		fInput.format.u.raw_audio.frame_rate,
699b543dbc2SStephan Aßmus 		frames_per_buffer(fInput.format.u.raw_audio));
7007b0daf5cSbeveloper 	bigtime_t outputBufferLength = duration_for_frames(framerate, frames);
701b543dbc2SStephan Aßmus 	bigtime_t mixerBufferLength
702b543dbc2SStephan Aßmus 		= max_c(3 * inputBufferLength, 2 * outputBufferLength);
7037b0daf5cSbeveloper 	int temp = frames_for_duration(framerate, mixerBufferLength);
7047b0daf5cSbeveloper 	fMixBufferFrameCount = ((temp / frames) + 1) * frames;
7057b0daf5cSbeveloper 
706a2ca4723Sbeveloper 	TRACE("  inputBufferLength    %10Ld\n", inputBufferLength);
707a2ca4723Sbeveloper 	TRACE("  outputBufferLength   %10Ld\n", outputBufferLength);
708a2ca4723Sbeveloper 	TRACE("  mixerBufferLength    %10Ld\n", mixerBufferLength);
709d91580cdSbeveloper 	TRACE("  fMixBufferFrameCount %10d\n", fMixBufferFrameCount);
7107b0daf5cSbeveloper 
7118d28117fSbeveloper 	ASSERT((fMixBufferFrameCount % frames) == 0);
7128d28117fSbeveloper 
713e92593f4Sbeveloper 	fLastDataFrameWritten = -1;
714e92593f4Sbeveloper 	fFractionalFrames = 0.0;
715e92593f4Sbeveloper 
7162e9d6607Sbeveloper 	rtm_free(fMixBuffer);
717356855c3Sbeveloper 	rtm_delete_pool(fRtmPool);
718a9cf57cfSAxel Dörfler 
7197b0daf5cSbeveloper 	int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
720a9cf57cfSAxel Dörfler 	if (rtm_create_pool(&fRtmPool, size) != B_OK)
721a9cf57cfSAxel Dörfler 		fRtmPool = NULL;
722a9cf57cfSAxel Dörfler 
723356855c3Sbeveloper 	fMixBuffer = (float*)rtm_alloc(fRtmPool, size);
724a9cf57cfSAxel Dörfler 	if (fMixBuffer == NULL)
725a9cf57cfSAxel Dörfler 		return;
7267b0daf5cSbeveloper 
7277b0daf5cSbeveloper 	memset(fMixBuffer, 0, size);
7282e9d6607Sbeveloper 
7292e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
7307b0daf5cSbeveloper 		fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
731d5848e21Sbeveloper 
732b006bbe1SStephan Aßmus 	_UpdateInputChannelDestinationMask();
733b006bbe1SStephan Aßmus 	_UpdateInputChannelDestinations();
7342e9d6607Sbeveloper }
735