xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp (revision 1c237c1852883cd806f6b7f712f8d76c430d83ba)
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 
117b0daf5cSbeveloper template<class t> const t & max(const t &t1, const t &t2) { return (t1 > t2) ?  t1 : t2; }
127b0daf5cSbeveloper 
138d28117fSbeveloper MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount)
14e6c7c99fSbeveloper  :	fCore(core),
152e9d6607Sbeveloper  	fInput(input),
1688777023Sbeveloper 	fInputByteSwap(0),
17*1c237c18Sbeveloper 	fEnabled(true),
182e9d6607Sbeveloper 	fInputChannelInfo(0),
192e9d6607Sbeveloper 	fInputChannelCount(0),
202e9d6607Sbeveloper 	fInputChannelMask(0),
212e9d6607Sbeveloper 	fMixerChannelInfo(0),
222e9d6607Sbeveloper 	fMixerChannelCount(0),
232e9d6607Sbeveloper 	fMixBuffer(0),
247b0daf5cSbeveloper 	fMixBufferFrameRate(0),
257b0daf5cSbeveloper 	fMixBufferFrameCount(0),
26af8d0a4dSbeveloper 	fLastDataAvailableTime(-1),
277b0daf5cSbeveloper 	fResampler(0),
28356855c3Sbeveloper 	fRtmPool(0),
292e9d6607Sbeveloper 	fUserOverridesChannelDesignations(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 
372e9d6607Sbeveloper 	fInputChannelCount = fInput.format.u.raw_audio.channel_count;
382e9d6607Sbeveloper 	fInputChannelMask = fInput.format.u.raw_audio.channel_mask;
392e9d6607Sbeveloper 	fInputChannelInfo = new input_chan_info[fInputChannelCount];
402e9d6607Sbeveloper 
4188777023Sbeveloper 	// perhaps we need byte swapping
4288777023Sbeveloper 	if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
4388777023Sbeveloper 		if (	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
4488777023Sbeveloper 			 ||	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT
4588777023Sbeveloper 			 ||	fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
4688777023Sbeveloper 			fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format);
4788777023Sbeveloper 		}
4888777023Sbeveloper 	}
4988777023Sbeveloper 
502e9d6607Sbeveloper 	// initialize fInputChannelInfo
512e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++) {
522e9d6607Sbeveloper 		fInputChannelInfo[i].buffer_base = 0;	// will be set by SetMixBufferFormat()
532e9d6607Sbeveloper 		fInputChannelInfo[i].designations = 0;	// will be set by UpdateChannelDesignations()
542e9d6607Sbeveloper 		fInputChannelInfo[i].gain = 1.0;
552e9d6607Sbeveloper 	}
562e9d6607Sbeveloper 
577b0daf5cSbeveloper 	// create resamplers
587b0daf5cSbeveloper 	fResampler = new Resampler * [fInputChannelCount];
597b0daf5cSbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
607b0daf5cSbeveloper 		fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT);
617b0daf5cSbeveloper 
622e9d6607Sbeveloper 	// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateMixerChannels()
632e9d6607Sbeveloper 
648d28117fSbeveloper 	SetMixBufferFormat(mixFrameRate, mixFrameCount);
652e9d6607Sbeveloper 
662e9d6607Sbeveloper 	// XXX a test:
678d28117fSbeveloper /*
682e9d6607Sbeveloper 	SetMixerChannelGain(0, 0.222);
692e9d6607Sbeveloper 	SetMixerChannelGain(1, 0.444);
702e9d6607Sbeveloper 	AddInputChannelDesignation(0, B_CHANNEL_REARRIGHT);
712e9d6607Sbeveloper 	SetMixerChannelGain(2, 0.666);
722e9d6607Sbeveloper 	AddInputChannelDesignation(1, B_CHANNEL_REARLEFT);
738d28117fSbeveloper */
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;
9788777023Sbeveloper 
98d5848e21Sbeveloper 	if (!fMixBuffer) {
99a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n");
100d5848e21Sbeveloper 		return;
101d5848e21Sbeveloper 	}
1022e9d6607Sbeveloper 
10388777023Sbeveloper 	data = buffer->Data();
10488777023Sbeveloper 	size = buffer->SizeUsed();
10588777023Sbeveloper 	start = buffer->Header()->start_time;
1068d28117fSbeveloper 	if (start < 0) {
107a2ca4723Sbeveloper 		ERROR("MixerInput::BufferReceived: buffer with negative start time of %Ld dropped\n", start);
1088d28117fSbeveloper 		return;
1098d28117fSbeveloper 	}
11088777023Sbeveloper 
111af8d0a4dSbeveloper 	fLastDataAvailableTime = start + buffer_duration(fInput.format.u.raw_audio);
112af8d0a4dSbeveloper 
11388777023Sbeveloper 	// swap the byte order of this buffer, if necessary
11488777023Sbeveloper 	if (fInputByteSwap)
11588777023Sbeveloper 		fInputByteSwap->Swap(data, size);
11688777023Sbeveloper 
1178d28117fSbeveloper 	int32 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);
1227619f562Sbeveloper 	int out_frames = int((in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate); // XXX losing fractions
1237619f562Sbeveloper 	// XXX we should better accumulate the fractions from previous buffers, and also check previous end offset
1247619f562Sbeveloper 	// XXX to only add an output frame if needed (but we also need to use arrival times to cope with lost buffers).
1257619f562Sbeveloper 	// XXX This workaround will very often (but not always) cause the first sample of the next buffer to overwrite
1267619f562Sbeveloper 	// XXX the last sample of the current buffer (but that's better then having some random data at that place)
1277619f562Sbeveloper 	if (fMixBufferFrameRate % int(0.5 + fInput.format.u.raw_audio.frame_rate) != 0)
1287619f562Sbeveloper 		out_frames++;
1297b0daf5cSbeveloper 
1308d28117fSbeveloper 	//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);
1318df36cddSbeveloper 
1327b0daf5cSbeveloper 	if (offset + out_frames > fMixBufferFrameCount) {
1337b0daf5cSbeveloper 
1347b0daf5cSbeveloper 		int out_frames1 = fMixBufferFrameCount - offset;
1357b0daf5cSbeveloper 		int out_frames2 = out_frames - out_frames1;
1367b0daf5cSbeveloper 		int in_frames1 = (out_frames1 * in_frames) / out_frames;
1377b0daf5cSbeveloper 		int in_frames2 = in_frames - in_frames1;
1387b0daf5cSbeveloper 
1397619f562Sbeveloper 		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);
1408df36cddSbeveloper 
141191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d, in_frames1 %5d, out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n",
142191033efSbeveloper 			  in_frames, out_frames, in_frames1, out_frames1, in_frames2, out_frames2);
1437b0daf5cSbeveloper 
1448d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
1458d28117fSbeveloper 
1467b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
14778563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
14878563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
1497b0daf5cSbeveloper 									in_frames1,
1508d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
1517b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
1527b0daf5cSbeveloper 									out_frames1,
1537b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
1547b0daf5cSbeveloper 
1557d970b31Sbeveloper 			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),
15678563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
1577b0daf5cSbeveloper 									in_frames2,
1587b0daf5cSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base),
1597b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
1607b0daf5cSbeveloper 									out_frames2,
1617b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
1627b0daf5cSbeveloper 		}
1637b0daf5cSbeveloper 	} else {
1647b0daf5cSbeveloper 
1657619f562Sbeveloper 		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);
166191033efSbeveloper 		PRINT(5, "  in_frames %5d, out_frames %5d\n", in_frames, out_frames);
1678d28117fSbeveloper 
1688d28117fSbeveloper 		offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
1697b0daf5cSbeveloper 
1707b0daf5cSbeveloper 		for (int i = 0; i < fInputChannelCount; i++) {
17178563dcaSbeveloper 			fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
17278563dcaSbeveloper 									bytes_per_frame(fInput.format.u.raw_audio),
1737b0daf5cSbeveloper 									in_frames,
1748d28117fSbeveloper 									reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
1757b0daf5cSbeveloper 									fInputChannelCount * sizeof(float),
1767b0daf5cSbeveloper 									out_frames,
1777b0daf5cSbeveloper 									fInputChannelInfo[i].gain);
1787b0daf5cSbeveloper 		}
1797b0daf5cSbeveloper 	}
180678c2017Sbeveloper }
1817ee2c804Sbeveloper 
1827ee2c804Sbeveloper media_input &
1837ee2c804Sbeveloper MixerInput::MediaInput()
1847ee2c804Sbeveloper {
1857ee2c804Sbeveloper 	return fInput;
1867ee2c804Sbeveloper }
187e6c7c99fSbeveloper 
188e6c7c99fSbeveloper int32
189e6c7c99fSbeveloper MixerInput::ID()
190e6c7c99fSbeveloper {
191e6c7c99fSbeveloper 	return fInput.destination.id;
192e6c7c99fSbeveloper }
193e6c7c99fSbeveloper 
194fae6ce82Sbeveloper uint32
195fae6ce82Sbeveloper MixerInput::GetInputChannelCount()
196fae6ce82Sbeveloper {
197fae6ce82Sbeveloper 	return fInputChannelCount;
198fae6ce82Sbeveloper }
199fae6ce82Sbeveloper 
2002e9d6607Sbeveloper void
2012e9d6607Sbeveloper MixerInput::AddInputChannelDesignation(int channel, uint32 des)
2022e9d6607Sbeveloper {
2032e9d6607Sbeveloper 	ASSERT(count_nonzero_bits(des) == 1);
204e6c7c99fSbeveloper 
2052e9d6607Sbeveloper 	// test if the channel is valid
2062e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2072e9d6607Sbeveloper 		return;
2082e9d6607Sbeveloper 
2092e9d6607Sbeveloper 	// test if it is already set
2102e9d6607Sbeveloper 	if (fInputChannelInfo[channel].designations & des)
2112e9d6607Sbeveloper 		return;
2122e9d6607Sbeveloper 
2132e9d6607Sbeveloper 	// remove it from all other channels that might have it
2142e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
2152e9d6607Sbeveloper 		fInputChannelInfo[i].designations &= ~des;
2162e9d6607Sbeveloper 
2172e9d6607Sbeveloper 	// add it to specified channel
2182e9d6607Sbeveloper 	fInputChannelInfo[channel].designations |= des;
2192e9d6607Sbeveloper 
2202e9d6607Sbeveloper 	fUserOverridesChannelDesignations = true;
2212e9d6607Sbeveloper 	UpdateMixerChannels();
2222e9d6607Sbeveloper }
2232e9d6607Sbeveloper 
2242e9d6607Sbeveloper void
2252e9d6607Sbeveloper MixerInput::RemoveInputChannelDesignation(int channel, uint32 des)
2262e9d6607Sbeveloper {
2272e9d6607Sbeveloper 	ASSERT(count_nonzero_bits(des) == 1);
2282e9d6607Sbeveloper 
2292e9d6607Sbeveloper 	// test if the channel is valid
2302e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2312e9d6607Sbeveloper 		return;
2322e9d6607Sbeveloper 
2332e9d6607Sbeveloper 	// test if it is really set
2342e9d6607Sbeveloper 	if ((fInputChannelInfo[channel].designations & des) == 0)
2352e9d6607Sbeveloper 		return;
2362e9d6607Sbeveloper 
2372e9d6607Sbeveloper 	// remove it from specified channel
2382e9d6607Sbeveloper 	fInputChannelInfo[channel].designations &= ~des;
2392e9d6607Sbeveloper 
2402e9d6607Sbeveloper 	fUserOverridesChannelDesignations = true;
2412e9d6607Sbeveloper 	UpdateMixerChannels();
2422e9d6607Sbeveloper }
2432e9d6607Sbeveloper 
2442e9d6607Sbeveloper uint32
2452e9d6607Sbeveloper MixerInput::GetInputChannelDesignations(int channel)
2462e9d6607Sbeveloper {
2472e9d6607Sbeveloper 	// test if the channel is valid
2482e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2492e9d6607Sbeveloper 		return 0;
2502e9d6607Sbeveloper 	return fInputChannelInfo[channel].designations;
2512e9d6607Sbeveloper }
2522e9d6607Sbeveloper 
2532e9d6607Sbeveloper uint32
2542e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel)
2552e9d6607Sbeveloper {
2562e9d6607Sbeveloper 	// test if the channel is valid
2572e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2582e9d6607Sbeveloper 		return 0;
2592e9d6607Sbeveloper 	return GetChannelMask(channel, fInputChannelMask);
2602e9d6607Sbeveloper }
2612e9d6607Sbeveloper 
2622e9d6607Sbeveloper void
2632e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain)
2642e9d6607Sbeveloper {
2652e9d6607Sbeveloper 	// test if the channel is valid
2662e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2672e9d6607Sbeveloper 		return;
2682e9d6607Sbeveloper 	if (gain < 0.0f)
2692e9d6607Sbeveloper 		gain = 0.0f;
2702e9d6607Sbeveloper 
2712e9d6607Sbeveloper 	fInputChannelInfo[channel].gain = gain;
2722e9d6607Sbeveloper }
2732e9d6607Sbeveloper 
2742e9d6607Sbeveloper float
2752e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel)
2762e9d6607Sbeveloper {
2772e9d6607Sbeveloper 	// test if the channel is valid
2782e9d6607Sbeveloper 	if (channel < 0 || channel >= fInputChannelCount)
2792e9d6607Sbeveloper 		return 0.0f;
2802e9d6607Sbeveloper 	return fInputChannelInfo[channel].gain;
2812e9d6607Sbeveloper }
2822e9d6607Sbeveloper 
2832e9d6607Sbeveloper void
2842e9d6607Sbeveloper MixerInput::UpdateChannelDesignations()
2852e9d6607Sbeveloper {
2862e9d6607Sbeveloper 	// is the user already messed with the assignmens, don't do anything.
2872e9d6607Sbeveloper 	if (fUserOverridesChannelDesignations)
2882e9d6607Sbeveloper 		return;
2892e9d6607Sbeveloper 
290a2ca4723Sbeveloper 	TRACE("UpdateChannelDesignations: enter\n");
2912e9d6607Sbeveloper 
292806cf560Sbeveloper 	// first apply a 1:1 mapping
2932e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
2942e9d6607Sbeveloper 		fInputChannelInfo[i].designations = GetChannelMask(i, fInputChannelMask);
295806cf560Sbeveloper 
296806cf560Sbeveloper 	// specialize this, depending on the available physical output channels
297806cf560Sbeveloper 	switch (fCore->OutputChannelCount()) {
298806cf560Sbeveloper 		case 0:
299806cf560Sbeveloper 		case 1:
300806cf560Sbeveloper 			break;
301806cf560Sbeveloper 
302806cf560Sbeveloper 		case 2:
303806cf560Sbeveloper 			if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
304806cf560Sbeveloper 				fInputChannelInfo[0].designations = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
305806cf560Sbeveloper 			}
306806cf560Sbeveloper 			break;
307806cf560Sbeveloper 
308806cf560Sbeveloper 		default:
309806cf560Sbeveloper 			if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
310806cf560Sbeveloper 				fInputChannelInfo[0].designations = B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT;
311806cf560Sbeveloper 			}
312806cf560Sbeveloper 			if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) {
313806cf560Sbeveloper 				fInputChannelInfo[0].designations = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
314806cf560Sbeveloper 			}
315806cf560Sbeveloper 			if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) {
316806cf560Sbeveloper 				fInputChannelInfo[0].designations = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
317806cf560Sbeveloper 			}
318806cf560Sbeveloper 			if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) {
319806cf560Sbeveloper 				fInputChannelInfo[1].designations = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
320806cf560Sbeveloper 			}
321806cf560Sbeveloper 			if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) {
322806cf560Sbeveloper 				fInputChannelInfo[1].designations = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
323806cf560Sbeveloper 			}
324806cf560Sbeveloper 			break;
3252e9d6607Sbeveloper 	}
3262e9d6607Sbeveloper 
3272e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
328a2ca4723Sbeveloper 		TRACE("UpdateChannelDesignations: input channel %d, designations 0x%08X, base %p, gain %.3f\n", i, fInputChannelInfo[i].designations, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
3292e9d6607Sbeveloper 
330a2ca4723Sbeveloper 	TRACE("UpdateChannelDesignations: leave\n");
3312e9d6607Sbeveloper }
3322e9d6607Sbeveloper 
3332e9d6607Sbeveloper void
3342e9d6607Sbeveloper MixerInput::UpdateMixerChannels()
3352e9d6607Sbeveloper {
3362e9d6607Sbeveloper 	uint32 channel_count;
3372e9d6607Sbeveloper 	uint32 all_bits;
3382e9d6607Sbeveloper 	uint32 mask;
3392e9d6607Sbeveloper 
3402e9d6607Sbeveloper 	mixer_chan_info *old_mixer_channel_info;
3412e9d6607Sbeveloper 	uint32 old_mixer_channel_count;
3422e9d6607Sbeveloper 
343a2ca4723Sbeveloper 	TRACE("UpdateMixerChannels: enter\n");
3442e9d6607Sbeveloper 
3452e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
346a2ca4723Sbeveloper 		TRACE("UpdateMixerChannels: input channel %d, designations 0x%08X, base %p, gain %.3f\n", i, fInputChannelInfo[i].designations, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
3472e9d6607Sbeveloper 
3482e9d6607Sbeveloper 	all_bits = 0;
3492e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
3502e9d6607Sbeveloper 		all_bits |= fInputChannelInfo[i].designations;
3512e9d6607Sbeveloper 
352a2ca4723Sbeveloper 	TRACE("UpdateMixerChannels: all_bits = %08x\n", all_bits);
3532e9d6607Sbeveloper 
3542e9d6607Sbeveloper 	channel_count = count_nonzero_bits(all_bits);
3552e9d6607Sbeveloper 
356a2ca4723Sbeveloper 	TRACE("UpdateMixerChannels: %ld input channels, %ld mixer channels (%ld old)\n", fInputChannelCount, channel_count, fMixerChannelCount);
3572e9d6607Sbeveloper 
3582e9d6607Sbeveloper 	// If we resize the channel info array, we preserve the gain setting
3592e9d6607Sbeveloper 	// by saving the old array until new assignments are finished, and
3602e9d6607Sbeveloper 	// then applying the old gains. New gains are set to 1.0
3612e9d6607Sbeveloper 	if (channel_count != fMixerChannelCount) {
3622e9d6607Sbeveloper 		old_mixer_channel_info = fMixerChannelInfo;
3632e9d6607Sbeveloper 		old_mixer_channel_count = fMixerChannelCount;
3642e9d6607Sbeveloper 		fMixerChannelInfo = new mixer_chan_info[channel_count];
3652e9d6607Sbeveloper 		fMixerChannelCount = channel_count;
3662e9d6607Sbeveloper 		for (int i = 0; i < fMixerChannelCount; i++)
3672e9d6607Sbeveloper 			fMixerChannelInfo[i].gain = 1.0;
3682e9d6607Sbeveloper 	} else {
3692e9d6607Sbeveloper 		old_mixer_channel_info = 0;
3702e9d6607Sbeveloper 		old_mixer_channel_count = 0;
3712e9d6607Sbeveloper 	}
3722e9d6607Sbeveloper 
3732e9d6607Sbeveloper 	// assign each mixer channel one type
3742e9d6607Sbeveloper 	for (int i  = 0, mask = 1; i < fMixerChannelCount; i++) {
3752e9d6607Sbeveloper 		while (mask != 0 && (all_bits & mask) == 0)
3762e9d6607Sbeveloper 			mask <<= 1;
377a4b8db85Sbeveloper 		fMixerChannelInfo[i].type = ChannelMaskToChannelType(mask);
3782e9d6607Sbeveloper 		mask <<= 1;
3792e9d6607Sbeveloper 	}
3802e9d6607Sbeveloper 
3812e9d6607Sbeveloper 	// assign buffer_base pointer for each mixer channel
3822e9d6607Sbeveloper 	for (int i  = 0; i < fMixerChannelCount; i++) {
3832e9d6607Sbeveloper 		int j;
3842e9d6607Sbeveloper 		for (j = 0; j < fInputChannelCount; j++) {
385a4b8db85Sbeveloper 			if (fInputChannelInfo[j].designations & ChannelTypeToChannelMask(fMixerChannelInfo[i].type)) {
386d5848e21Sbeveloper 				fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] : 0;
3872e9d6607Sbeveloper 				break;
3882e9d6607Sbeveloper 			}
3892e9d6607Sbeveloper 		}
3902e9d6607Sbeveloper 		if (j == fInputChannelCount) {
391a2ca4723Sbeveloper 			ERROR("buffer assignment failed for mixer chan %d\n", i);
3922e9d6607Sbeveloper 			fMixerChannelInfo[i].buffer_base = fMixBuffer;
3932e9d6607Sbeveloper 		}
3942e9d6607Sbeveloper 	}
3952e9d6607Sbeveloper 
3962e9d6607Sbeveloper 	// apply old gains, overriding the 1.0 defaults for the old channels
3972e9d6607Sbeveloper 	if (old_mixer_channel_info != 0) {
3982e9d6607Sbeveloper 		for (int i  = 0; i < fMixerChannelCount; i++) {
3992e9d6607Sbeveloper 			for (int j = 0; j < old_mixer_channel_count; j++) {
400a4b8db85Sbeveloper 				if (fMixerChannelInfo[i].type == old_mixer_channel_info[j].type) {
4012e9d6607Sbeveloper 					fMixerChannelInfo[i].gain = old_mixer_channel_info[j].gain;
4022e9d6607Sbeveloper 					break;
4032e9d6607Sbeveloper 				}
4042e9d6607Sbeveloper 			}
4052e9d6607Sbeveloper 		}
4062e9d6607Sbeveloper 		// also delete the old info array
4072e9d6607Sbeveloper 		delete [] old_mixer_channel_info;
4082e9d6607Sbeveloper 	}
4092e9d6607Sbeveloper 
4102e9d6607Sbeveloper 	for (int i = 0; i < fMixerChannelCount; i++)
411a2ca4723Sbeveloper 		TRACE("UpdateMixerChannels: mixer channel %d, type %2d, des 0x%08X, base %p, gain %.3f\n", i, fMixerChannelInfo[i].type, ChannelTypeToChannelMask(fMixerChannelInfo[i].type), fMixerChannelInfo[i].buffer_base, fMixerChannelInfo[i].gain);
4122e9d6607Sbeveloper 
413a2ca4723Sbeveloper 	TRACE("UpdateMixerChannels: leave\n");
4142e9d6607Sbeveloper }
4152e9d6607Sbeveloper 
4162e9d6607Sbeveloper uint32
4172e9d6607Sbeveloper MixerInput::GetMixerChannelCount()
4182e9d6607Sbeveloper {
4192e9d6607Sbeveloper 	return fMixerChannelCount;
4202e9d6607Sbeveloper }
4212e9d6607Sbeveloper 
4222e9d6607Sbeveloper void
4232e9d6607Sbeveloper MixerInput::SetMixerChannelGain(int channel, float gain)
4242e9d6607Sbeveloper {
4259391f0a5Sbeveloper 	TRACE("SetMixerChannelGain chan %d, gain %.5f\n", channel, gain);
4262e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4272e9d6607Sbeveloper 		return;
4282e9d6607Sbeveloper 	if (gain < 0.0f)
4292e9d6607Sbeveloper 		gain = 0.0f;
4302e9d6607Sbeveloper 	fMixerChannelInfo[channel].gain = gain;
4312e9d6607Sbeveloper }
4322e9d6607Sbeveloper 
4332e9d6607Sbeveloper float
4342e9d6607Sbeveloper MixerInput::GetMixerChannelGain(int channel)
4352e9d6607Sbeveloper {
4362e9d6607Sbeveloper 	if (channel < 0 || channel >= fMixerChannelCount)
4372e9d6607Sbeveloper 		return 1.0;
4382e9d6607Sbeveloper 	return fMixerChannelInfo[channel].gain;
4392e9d6607Sbeveloper }
4402e9d6607Sbeveloper 
4412e9d6607Sbeveloper void
442*1c237c18Sbeveloper MixerInput::SetEnabled(bool yesno)
443*1c237c18Sbeveloper {
444*1c237c18Sbeveloper 	fEnabled = yesno;
445*1c237c18Sbeveloper }
446*1c237c18Sbeveloper 
447*1c237c18Sbeveloper bool
448*1c237c18Sbeveloper MixerInput::IsEnabled()
449*1c237c18Sbeveloper {
450*1c237c18Sbeveloper 	return fEnabled;
451*1c237c18Sbeveloper }
452*1c237c18Sbeveloper 
453*1c237c18Sbeveloper void
4548d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
4552e9d6607Sbeveloper {
456a2ca4723Sbeveloper 	TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
457d5848e21Sbeveloper 
4587b0daf5cSbeveloper 	fMixBufferFrameRate = framerate;
4598df36cddSbeveloper 	debugMixBufferFrames = frames;
4602e9d6607Sbeveloper 
461d5848e21Sbeveloper 	// frames and/or framerate can be 0 (if no output is connected)
462d5848e21Sbeveloper 	if (framerate == 0 || frames == 0) {
463d5848e21Sbeveloper 		if (fMixBuffer) {
464d5848e21Sbeveloper 			rtm_free(fMixBuffer);
465d5848e21Sbeveloper 			fMixBuffer = 0;
466d5848e21Sbeveloper 		}
467d5848e21Sbeveloper 		for (int i = 0; i < fInputChannelCount; i++)
468d5848e21Sbeveloper 			fInputChannelInfo[i].buffer_base = 0;
469d5848e21Sbeveloper 		fMixBufferFrameCount = 0;
470d5848e21Sbeveloper 
471d5848e21Sbeveloper 		UpdateChannelDesignations();
472d5848e21Sbeveloper 		UpdateMixerChannels();
473d5848e21Sbeveloper 		return;
474d5848e21Sbeveloper 	}
4757b0daf5cSbeveloper 
4767b0daf5cSbeveloper 	// make fMixBufferFrameCount an integral multiple of frames,
4777b0daf5cSbeveloper 	// but at least 3 times duration of our input buffer
4787b0daf5cSbeveloper 	// and at least 2 times duration of the output buffer
4797b0daf5cSbeveloper 	bigtime_t inputBufferLength  = duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio));
4807b0daf5cSbeveloper 	bigtime_t outputBufferLength = duration_for_frames(framerate, frames);
4817b0daf5cSbeveloper 	bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength);
4827b0daf5cSbeveloper 	int temp = frames_for_duration(framerate, mixerBufferLength);
4837b0daf5cSbeveloper 	fMixBufferFrameCount = ((temp / frames) + 1) * frames;
4847b0daf5cSbeveloper 
485a2ca4723Sbeveloper 	TRACE("  inputBufferLength  %10Ld\n", inputBufferLength);
486a2ca4723Sbeveloper 	TRACE("  outputBufferLength %10Ld\n", outputBufferLength);
487a2ca4723Sbeveloper 	TRACE("  mixerBufferLength  %10Ld\n", mixerBufferLength);
488a2ca4723Sbeveloper 	TRACE("  fMixBufferFrameCount   %10ld\n", fMixBufferFrameCount);
4897b0daf5cSbeveloper 
4908d28117fSbeveloper 	ASSERT((fMixBufferFrameCount % frames) == 0);
4918d28117fSbeveloper 
4922e9d6607Sbeveloper 	if (fMixBuffer)
4932e9d6607Sbeveloper 		rtm_free(fMixBuffer);
494356855c3Sbeveloper 	if (fRtmPool)
495356855c3Sbeveloper 		rtm_delete_pool(fRtmPool);
4967b0daf5cSbeveloper 	int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
497356855c3Sbeveloper 	if (B_OK != rtm_create_pool(&fRtmPool, size))
498356855c3Sbeveloper 		fRtmPool = 0;
499356855c3Sbeveloper 	fMixBuffer = (float *)rtm_alloc(fRtmPool, size);
5007b0daf5cSbeveloper 	ASSERT(fMixBuffer);
5017b0daf5cSbeveloper 
5027b0daf5cSbeveloper 	memset(fMixBuffer, 0, size);
5032e9d6607Sbeveloper 
5042e9d6607Sbeveloper 	for (int i = 0; i < fInputChannelCount; i++)
5057b0daf5cSbeveloper 		fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
506d5848e21Sbeveloper 
507d5848e21Sbeveloper 	UpdateChannelDesignations();
508d5848e21Sbeveloper 	UpdateMixerChannels();
5092e9d6607Sbeveloper }
510