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