1bf7ab50dSStephan Aßmus /* 2*a9cf57cfSAxel Dörfler * Copyright 2003-2009 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 */ 8*a9cf57cfSAxel Dörfler 9*a9cf57cfSAxel Dörfler 10bf7ab50dSStephan Aßmus #include "MixerCore.h" 11*a9cf57cfSAxel Dörfler 12*a9cf57cfSAxel Dörfler #include <Buffer.h> 13*a9cf57cfSAxel Dörfler #include <string.h> 14*a9cf57cfSAxel Dörfler #include <TimeSource.h> // TODO: debug only 15*a9cf57cfSAxel Dörfler 16*a9cf57cfSAxel Dörfler #include "ByteSwap.h" 17bf7ab50dSStephan Aßmus #include "MixerInput.h" 18bf7ab50dSStephan Aßmus #include "MixerUtils.h" 19bf7ab50dSStephan Aßmus #include "Resampler.h" 20bf7ab50dSStephan Aßmus 21678c2017Sbeveloper 22*a9cf57cfSAxel Dörfler MixerInput::MixerInput(MixerCore *core, const media_input &input, 23*a9cf57cfSAxel Dörfler float mixFrameRate, int32 mixFrameCount) 24*a9cf57cfSAxel Dörfler : 25*a9cf57cfSAxel Dörfler fCore(core), 262e9d6607Sbeveloper fInput(input), 2788777023Sbeveloper fInputByteSwap(0), 281c237c18Sbeveloper fEnabled(true), 292e9d6607Sbeveloper fInputChannelInfo(0), 302e9d6607Sbeveloper fInputChannelCount(0), 312e9d6607Sbeveloper fInputChannelMask(0), 322e9d6607Sbeveloper fMixerChannelInfo(0), 332e9d6607Sbeveloper fMixerChannelCount(0), 342e9d6607Sbeveloper fMixBuffer(0), 357b0daf5cSbeveloper fMixBufferFrameRate(0), 367b0daf5cSbeveloper fMixBufferFrameCount(0), 37e92593f4Sbeveloper fLastDataFrameWritten(-1), 38af8d0a4dSbeveloper fLastDataAvailableTime(-1), 39e92593f4Sbeveloper fFractionalFrames(0.0), 407b0daf5cSbeveloper fResampler(0), 41356855c3Sbeveloper fRtmPool(0), 429c3be6a5Sbeveloper fUserOverridesChannelDestinations(false) 43678c2017Sbeveloper { 44e6c7c99fSbeveloper fix_multiaudio_format(&fInput.format.u.raw_audio); 45e6c7c99fSbeveloper PRINT_INPUT("MixerInput::MixerInput", fInput); 46e6c7c99fSbeveloper PRINT_CHANNEL_MASK(fInput.format); 472e9d6607Sbeveloper 482e9d6607Sbeveloper ASSERT(fInput.format.u.raw_audio.channel_count > 0); 492e9d6607Sbeveloper 509c3be6a5Sbeveloper for (int i = 0; i < MAX_CHANNEL_TYPES; i++) 519c3be6a5Sbeveloper fChannelTypeGain[i] = 1.0f; 529c3be6a5Sbeveloper 532e9d6607Sbeveloper fInputChannelCount = fInput.format.u.raw_audio.channel_count; 542e9d6607Sbeveloper fInputChannelMask = fInput.format.u.raw_audio.channel_mask; 552e9d6607Sbeveloper fInputChannelInfo = new input_chan_info[fInputChannelCount]; 562e9d6607Sbeveloper 5788777023Sbeveloper // perhaps we need byte swapping 5888777023Sbeveloper if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) { 59*a9cf57cfSAxel Dörfler if (fInput.format.u.raw_audio.format 60*a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_FLOAT 61*a9cf57cfSAxel Dörfler || fInput.format.u.raw_audio.format 62*a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_INT 63*a9cf57cfSAxel Dörfler || fInput.format.u.raw_audio.format 64*a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_SHORT) { 6588777023Sbeveloper fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format); 6688777023Sbeveloper } 6788777023Sbeveloper } 6888777023Sbeveloper 692e9d6607Sbeveloper // initialize fInputChannelInfo 702e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) { 712e9d6607Sbeveloper fInputChannelInfo[i].buffer_base = 0; // will be set by SetMixBufferFormat() 729c3be6a5Sbeveloper fInputChannelInfo[i].destination_mask = 0; // will be set by UpdateInputChannelDestinationMask() 732e9d6607Sbeveloper fInputChannelInfo[i].gain = 1.0; 742e9d6607Sbeveloper } 752e9d6607Sbeveloper 767b0daf5cSbeveloper // create resamplers 777b0daf5cSbeveloper fResampler = new Resampler * [fInputChannelCount]; 787b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) 79f0a85f97SJérôme Duval fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT); 807b0daf5cSbeveloper 819c3be6a5Sbeveloper // fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateInputChannelDestinations() 82bf7ab50dSStephan Aßmus SetMixBufferFormat((int32)mixFrameRate, mixFrameCount); 83678c2017Sbeveloper } 84678c2017Sbeveloper 85*a9cf57cfSAxel Dörfler 86678c2017Sbeveloper MixerInput::~MixerInput() 87678c2017Sbeveloper { 882e9d6607Sbeveloper if (fMixBuffer) 892e9d6607Sbeveloper rtm_free(fMixBuffer); 90356855c3Sbeveloper if (fRtmPool) 91356855c3Sbeveloper rtm_delete_pool(fRtmPool); 922e9d6607Sbeveloper delete [] fInputChannelInfo; 932e9d6607Sbeveloper delete [] fMixerChannelInfo; 947b0daf5cSbeveloper 957b0daf5cSbeveloper // delete resamplers 967b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) 977b0daf5cSbeveloper delete fResampler[i]; 987b0daf5cSbeveloper delete [] fResampler; 99678c2017Sbeveloper } 100678c2017Sbeveloper 101*a9cf57cfSAxel Dörfler 102678c2017Sbeveloper void 103678c2017Sbeveloper MixerInput::BufferReceived(BBuffer *buffer) 104678c2017Sbeveloper { 10588777023Sbeveloper void *data; 10688777023Sbeveloper size_t size; 10788777023Sbeveloper bigtime_t start; 108e92593f4Sbeveloper bigtime_t buffer_duration; 10988777023Sbeveloper 110d5848e21Sbeveloper if (!fMixBuffer) { 111a2ca4723Sbeveloper ERROR("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n"); 112d5848e21Sbeveloper return; 113d5848e21Sbeveloper } 1142e9d6607Sbeveloper 11588777023Sbeveloper data = buffer->Data(); 11688777023Sbeveloper size = buffer->SizeUsed(); 11788777023Sbeveloper start = buffer->Header()->start_time; 118e92593f4Sbeveloper buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate, size / bytes_per_frame(fInput.format.u.raw_audio)); 1198d28117fSbeveloper if (start < 0) { 120a2ca4723Sbeveloper ERROR("MixerInput::BufferReceived: buffer with negative start time of %Ld dropped\n", start); 1218d28117fSbeveloper return; 1228d28117fSbeveloper } 12388777023Sbeveloper 12488777023Sbeveloper // swap the byte order of this buffer, if necessary 12588777023Sbeveloper if (fInputByteSwap) 12688777023Sbeveloper fInputByteSwap->Swap(data, size); 12788777023Sbeveloper 128d91580cdSbeveloper int offset = frames_for_duration(fMixBufferFrameRate, start) % fMixBufferFrameCount; 1298d28117fSbeveloper 130191033efSbeveloper PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", start, offset); 1317b0daf5cSbeveloper 132191033efSbeveloper int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio); 133e92593f4Sbeveloper double frames = double(in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate; 134e92593f4Sbeveloper int out_frames = int(frames); 135e92593f4Sbeveloper fFractionalFrames += frames - double(out_frames); 136e92593f4Sbeveloper if (fFractionalFrames >= 1.0) { 137e92593f4Sbeveloper fFractionalFrames -= 1.0; 1387619f562Sbeveloper out_frames++; 139e92593f4Sbeveloper } 140e92593f4Sbeveloper 141e92593f4Sbeveloper // if fLastDataFrameWritten != -1, then we have a valid last position 142e92593f4Sbeveloper // and can do glitch compensation 143e92593f4Sbeveloper if (fLastDataFrameWritten >= 0) { 144e92593f4Sbeveloper int expected_frame = (fLastDataFrameWritten + 1) % fMixBufferFrameCount; 145e92593f4Sbeveloper if (offset != expected_frame) { 146e92593f4Sbeveloper // due to rounding and other errors, offset might be off by +/- 1 147e92593f4Sbeveloper // this is not really a bad glitch, we just adjust the position 148e92593f4Sbeveloper if (offset == fLastDataFrameWritten) { 149e92593f4Sbeveloper //printf("MixerInput::BufferReceived: -1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset); 150e92593f4Sbeveloper offset = expected_frame; 151e92593f4Sbeveloper } else if (offset == ((fLastDataFrameWritten + 2) % fMixBufferFrameCount)) { 152e92593f4Sbeveloper //printf("MixerInput::BufferReceived: +1 frame GLITCH! last frame was %ld, expected frame was %d, new frame is %d\n", fLastDataFrameWritten, expected_frame, offset); 153e92593f4Sbeveloper offset = expected_frame; 154e92593f4Sbeveloper } else { 155dbaf884cSbeveloper printf("MixerInput::BufferReceived: GLITCH! last frame was %4ld, expected frame was %4d, new frame is %4d\n", fLastDataFrameWritten, expected_frame, offset); 156e92593f4Sbeveloper 157e92593f4Sbeveloper if (start > fLastDataAvailableTime) { 158e92593f4Sbeveloper if ((start - fLastDataAvailableTime) < (buffer_duration / 10)) { 159e92593f4Sbeveloper // buffer is less than 10% of buffer duration too late 160e92593f4Sbeveloper printf("short glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime); 161e92593f4Sbeveloper offset = expected_frame; 162e92593f4Sbeveloper out_frames++; 163e92593f4Sbeveloper } else { 164e92593f4Sbeveloper // buffer more than 10% of buffer duration too late 165e92593f4Sbeveloper // XXX zerofill buffer 166e92593f4Sbeveloper printf("MAJOR glitch, buffer too late, time delta %Ld\n", start - fLastDataAvailableTime); 167e92593f4Sbeveloper } 168e92593f4Sbeveloper } else { // start <= fLastDataAvailableTime 169e92593f4Sbeveloper // the new buffer is too early 170e92593f4Sbeveloper if ((fLastDataAvailableTime - start) < (buffer_duration / 10)) { 171e92593f4Sbeveloper // buffer is less than 10% of buffer duration too early 172e92593f4Sbeveloper printf("short glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start); 173e92593f4Sbeveloper offset = expected_frame; 174e92593f4Sbeveloper out_frames--; 175e92593f4Sbeveloper if (out_frames < 1) 176e92593f4Sbeveloper out_frames = 1; 177e92593f4Sbeveloper } else { 178e92593f4Sbeveloper // buffer more than 10% of buffer duration too early 179e92593f4Sbeveloper // XXX zerofill buffer 180e92593f4Sbeveloper printf("MAJOR glitch, buffer too early, time delta %Ld\n", fLastDataAvailableTime - start); 181e92593f4Sbeveloper } 182e92593f4Sbeveloper } 183e92593f4Sbeveloper } 184e92593f4Sbeveloper } 185e92593f4Sbeveloper } 1867b0daf5cSbeveloper 1878d28117fSbeveloper //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); 1887b0daf5cSbeveloper if (offset + out_frames > fMixBufferFrameCount) { 1897b0daf5cSbeveloper int out_frames1 = fMixBufferFrameCount - offset; 1907b0daf5cSbeveloper int out_frames2 = out_frames - out_frames1; 1917b0daf5cSbeveloper int in_frames1 = (out_frames1 * in_frames) / out_frames; 1927b0daf5cSbeveloper int in_frames2 = in_frames - in_frames1; 1937b0daf5cSbeveloper 194e92593f4Sbeveloper //printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames1 - 1, 0, out_frames2 - 1); 1957619f562Sbeveloper 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); 196191033efSbeveloper PRINT(5, " in_frames %5d, out_frames %5d, in_frames1 %5d, out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n", 197191033efSbeveloper in_frames, out_frames, in_frames1, out_frames1, in_frames2, out_frames2); 1987b0daf5cSbeveloper 199e92593f4Sbeveloper fLastDataFrameWritten = out_frames2 - 1; 200e92593f4Sbeveloper 2018d28117fSbeveloper offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes 2028d28117fSbeveloper 2037b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 20478563dcaSbeveloper fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio), 20578563dcaSbeveloper bytes_per_frame(fInput.format.u.raw_audio), 2067b0daf5cSbeveloper in_frames1, 2078d28117fSbeveloper reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset, 2087b0daf5cSbeveloper fInputChannelCount * sizeof(float), 2097b0daf5cSbeveloper out_frames1, 2107b0daf5cSbeveloper fInputChannelInfo[i].gain); 2117b0daf5cSbeveloper 2127d970b31Sbeveloper 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), 21378563dcaSbeveloper bytes_per_frame(fInput.format.u.raw_audio), 2147b0daf5cSbeveloper in_frames2, 2157b0daf5cSbeveloper reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base), 2167b0daf5cSbeveloper fInputChannelCount * sizeof(float), 2177b0daf5cSbeveloper out_frames2, 2187b0daf5cSbeveloper fInputChannelInfo[i].gain); 219e92593f4Sbeveloper 2207b0daf5cSbeveloper } 2217b0daf5cSbeveloper } else { 222e92593f4Sbeveloper //printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames - 1); 2237619f562Sbeveloper 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); 224191033efSbeveloper PRINT(5, " in_frames %5d, out_frames %5d\n", in_frames, out_frames); 2258d28117fSbeveloper 226e92593f4Sbeveloper fLastDataFrameWritten = offset + out_frames - 1; 2278d28117fSbeveloper offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes 2287b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 22978563dcaSbeveloper fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio), 23078563dcaSbeveloper bytes_per_frame(fInput.format.u.raw_audio), 2317b0daf5cSbeveloper in_frames, 2328d28117fSbeveloper reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset, 2337b0daf5cSbeveloper fInputChannelCount * sizeof(float), 2347b0daf5cSbeveloper out_frames, 2357b0daf5cSbeveloper fInputChannelInfo[i].gain); 2367b0daf5cSbeveloper } 2377b0daf5cSbeveloper } 238e92593f4Sbeveloper fLastDataAvailableTime = start + buffer_duration; 239678c2017Sbeveloper } 2407ee2c804Sbeveloper 241bf7ab50dSStephan Aßmus 2427ee2c804Sbeveloper media_input & 2437ee2c804Sbeveloper MixerInput::MediaInput() 2447ee2c804Sbeveloper { 2457ee2c804Sbeveloper return fInput; 2467ee2c804Sbeveloper } 247e6c7c99fSbeveloper 248bf7ab50dSStephan Aßmus 249e6c7c99fSbeveloper int32 250e6c7c99fSbeveloper MixerInput::ID() 251e6c7c99fSbeveloper { 252e6c7c99fSbeveloper return fInput.destination.id; 253e6c7c99fSbeveloper } 254e6c7c99fSbeveloper 255bf7ab50dSStephan Aßmus 256d91580cdSbeveloper int 257fae6ce82Sbeveloper MixerInput::GetInputChannelCount() 258fae6ce82Sbeveloper { 259fae6ce82Sbeveloper return fInputChannelCount; 260fae6ce82Sbeveloper } 261fae6ce82Sbeveloper 262bf7ab50dSStephan Aßmus 2632e9d6607Sbeveloper void 2649c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type) 2652e9d6607Sbeveloper { 2669c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 267e6c7c99fSbeveloper 2682e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 2692e9d6607Sbeveloper return; 2702e9d6607Sbeveloper 2712e9d6607Sbeveloper // test if it is already set 2729c3be6a5Sbeveloper if (fInputChannelInfo[channel].destination_mask & mask) 2732e9d6607Sbeveloper return; 2742e9d6607Sbeveloper 2759c3be6a5Sbeveloper // verify that no other channel has id 2769c3be6a5Sbeveloper if (-1 != GetInputChannelForDestination(destination_type)) { 2779c3be6a5Sbeveloper ERROR("MixerInput::AddInputChannelDestination: destination_type %d already assigned to channel %d\n", destination_type, GetInputChannelForDestination(destination_type)); 2789c3be6a5Sbeveloper return; 2799c3be6a5Sbeveloper } 2802e9d6607Sbeveloper 2812e9d6607Sbeveloper // add it to specified channel 2829c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask |= mask; 2832e9d6607Sbeveloper 2849c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 2859c3be6a5Sbeveloper UpdateInputChannelDestinations(); 2862e9d6607Sbeveloper } 2872e9d6607Sbeveloper 288*a9cf57cfSAxel Dörfler 2892e9d6607Sbeveloper void 2909c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type) 2912e9d6607Sbeveloper { 2929c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 2932e9d6607Sbeveloper 2942e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 2952e9d6607Sbeveloper return; 2962e9d6607Sbeveloper 2972e9d6607Sbeveloper // test if it is really set 2989c3be6a5Sbeveloper if ((fInputChannelInfo[channel].destination_mask & mask) == 0) 2992e9d6607Sbeveloper return; 3002e9d6607Sbeveloper 3012e9d6607Sbeveloper // remove it from specified channel 3029c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask &= ~mask; 3032e9d6607Sbeveloper 3049c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 3059c3be6a5Sbeveloper UpdateInputChannelDestinations(); 3062e9d6607Sbeveloper } 3072e9d6607Sbeveloper 308*a9cf57cfSAxel Dörfler 3099c3be6a5Sbeveloper bool 3109c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type) 3112e9d6607Sbeveloper { 3122e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3139c3be6a5Sbeveloper return false; 3149c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 3159c3be6a5Sbeveloper return false; 3169c3be6a5Sbeveloper return fInputChannelInfo[channel].destination_mask & ChannelTypeToChannelMask(destination_type); 3172e9d6607Sbeveloper } 3182e9d6607Sbeveloper 319*a9cf57cfSAxel Dörfler 3209c3be6a5Sbeveloper int 3219c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type) 3229c3be6a5Sbeveloper { 3239c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 3249c3be6a5Sbeveloper return -1; 3259c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 3269c3be6a5Sbeveloper for (int chan = 0; chan < fInputChannelCount; chan++) { 3279c3be6a5Sbeveloper if (fInputChannelInfo[chan].destination_mask & mask) 3289c3be6a5Sbeveloper return chan; 3299c3be6a5Sbeveloper } 3309c3be6a5Sbeveloper return -1; 3319c3be6a5Sbeveloper } 3329c3be6a5Sbeveloper 333*a9cf57cfSAxel Dörfler 3349c3be6a5Sbeveloper int 3352e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel) 3362e9d6607Sbeveloper { 3372e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3382e9d6607Sbeveloper return 0; 3399c3be6a5Sbeveloper return GetChannelType(channel, fInputChannelMask); 3402e9d6607Sbeveloper } 3412e9d6607Sbeveloper 342*a9cf57cfSAxel Dörfler 3432e9d6607Sbeveloper void 3442e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain) 3452e9d6607Sbeveloper { 3462e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3472e9d6607Sbeveloper return; 3482e9d6607Sbeveloper if (gain < 0.0f) 3492e9d6607Sbeveloper gain = 0.0f; 3502e9d6607Sbeveloper 3512e9d6607Sbeveloper fInputChannelInfo[channel].gain = gain; 3522e9d6607Sbeveloper } 3532e9d6607Sbeveloper 354*a9cf57cfSAxel Dörfler 3552e9d6607Sbeveloper float 3562e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel) 3572e9d6607Sbeveloper { 3582e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3592e9d6607Sbeveloper return 0.0f; 3602e9d6607Sbeveloper return fInputChannelInfo[channel].gain; 3612e9d6607Sbeveloper } 3622e9d6607Sbeveloper 363*a9cf57cfSAxel Dörfler 3642e9d6607Sbeveloper void 3659c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinationMask() 3662e9d6607Sbeveloper { 3672e9d6607Sbeveloper // is the user already messed with the assignmens, don't do anything. 3689c3be6a5Sbeveloper if (fUserOverridesChannelDestinations) 3692e9d6607Sbeveloper return; 3702e9d6607Sbeveloper 3719c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinationMask: enter\n"); 3722e9d6607Sbeveloper 373806cf560Sbeveloper // first apply a 1:1 mapping 3742e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 3759c3be6a5Sbeveloper fInputChannelInfo[i].destination_mask = GetChannelMask(i, fInputChannelMask); 376806cf560Sbeveloper 377806cf560Sbeveloper // specialize this, depending on the available physical output channels 378643e1b2eSbeveloper if (fCore->OutputChannelCount() <= 2) { 379643e1b2eSbeveloper // less or equal two channels 380806cf560Sbeveloper if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 381ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 382806cf560Sbeveloper } 383643e1b2eSbeveloper } else { 384643e1b2eSbeveloper // more than two channel output card 385806cf560Sbeveloper if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 386ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 387806cf560Sbeveloper } 388806cf560Sbeveloper if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) { 3899c3be6a5Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 390806cf560Sbeveloper } 391806cf560Sbeveloper if (fInputChannelCount == 2 && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) { 3929c3be6a5Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 393806cf560Sbeveloper } 394806cf560Sbeveloper if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) { 3959c3be6a5Sbeveloper fInputChannelInfo[1].destination_mask = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 396806cf560Sbeveloper } 397806cf560Sbeveloper if (fInputChannelCount == 2 && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) { 3989c3be6a5Sbeveloper fInputChannelInfo[1].destination_mask = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 399806cf560Sbeveloper } 4002e9d6607Sbeveloper } 4012e9d6607Sbeveloper 4022e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 403d91580cdSbeveloper TRACE("UpdateInputChannelDestinationMask: input channel %d, destination_mask 0x%08lX, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 4049c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinationMask: leave\n"); 4052e9d6607Sbeveloper } 4062e9d6607Sbeveloper 407*a9cf57cfSAxel Dörfler 4082e9d6607Sbeveloper void 4099c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinations() 4102e9d6607Sbeveloper { 411d91580cdSbeveloper int channel_count; 4122e9d6607Sbeveloper uint32 all_bits; 4132e9d6607Sbeveloper uint32 mask; 4142e9d6607Sbeveloper 4159c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinations: enter\n"); 4162e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 417d91580cdSbeveloper TRACE("UpdateInputChannelDestinations: input channel %d, destination_mask 0x%08lX, base %p, gain %.3f\n", i, fInputChannelInfo[i].destination_mask, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 4182e9d6607Sbeveloper 4192e9d6607Sbeveloper all_bits = 0; 4202e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 4219c3be6a5Sbeveloper all_bits |= fInputChannelInfo[i].destination_mask; 4222e9d6607Sbeveloper 423d91580cdSbeveloper TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits); 4242e9d6607Sbeveloper 4252e9d6607Sbeveloper channel_count = count_nonzero_bits(all_bits); 426d91580cdSbeveloper TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer channels (%d old)\n", fInputChannelCount, channel_count, fMixerChannelCount); 4272e9d6607Sbeveloper if (channel_count != fMixerChannelCount) { 4289c3be6a5Sbeveloper delete [] fMixerChannelInfo; 4292e9d6607Sbeveloper fMixerChannelInfo = new mixer_chan_info[channel_count]; 4302e9d6607Sbeveloper fMixerChannelCount = channel_count; 4312e9d6607Sbeveloper } 4322e9d6607Sbeveloper 4332e9d6607Sbeveloper // assign each mixer channel one type 4349c3be6a5Sbeveloper // and the gain from the fChannelTypeGain[] 435d91580cdSbeveloper mask = 1; 436d91580cdSbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 4372e9d6607Sbeveloper while (mask != 0 && (all_bits & mask) == 0) 4382e9d6607Sbeveloper mask <<= 1; 4399c3be6a5Sbeveloper fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask); 4409c3be6a5Sbeveloper fMixerChannelInfo[i].destination_gain = fChannelTypeGain[fMixerChannelInfo[i].destination_type]; 4412e9d6607Sbeveloper mask <<= 1; 4422e9d6607Sbeveloper } 4432e9d6607Sbeveloper 4442e9d6607Sbeveloper // assign buffer_base pointer for each mixer channel 4452e9d6607Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 4462e9d6607Sbeveloper int j; 4472e9d6607Sbeveloper for (j = 0; j < fInputChannelCount; j++) { 4489c3be6a5Sbeveloper if (fInputChannelInfo[j].destination_mask & ChannelTypeToChannelMask(fMixerChannelInfo[i].destination_type)) { 449d5848e21Sbeveloper fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] : 0; 4502e9d6607Sbeveloper break; 4512e9d6607Sbeveloper } 4522e9d6607Sbeveloper } 4532e9d6607Sbeveloper if (j == fInputChannelCount) { 454a2ca4723Sbeveloper ERROR("buffer assignment failed for mixer chan %d\n", i); 4552e9d6607Sbeveloper fMixerChannelInfo[i].buffer_base = fMixBuffer; 4562e9d6607Sbeveloper } 4572e9d6607Sbeveloper } 4582e9d6607Sbeveloper 4592e9d6607Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) 4609c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinations: mixer channel %d, type %2d, base %p, gain %.3f\n", i, fMixerChannelInfo[i].destination_type, fMixerChannelInfo[i].buffer_base, fMixerChannelInfo[i].destination_gain); 4612e9d6607Sbeveloper 4629c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinations: leave\n"); 4632e9d6607Sbeveloper } 464bf7ab50dSStephan Aßmus 465*a9cf57cfSAxel Dörfler 466bf7ab50dSStephan Aßmus // Note: The following code is outcommented on purpose 467bf7ab50dSStephan Aßmus // and is about to be modified at a later point 46869517c15Sbeveloper /* 4692e9d6607Sbeveloper void 4709c3be6a5Sbeveloper MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, float gain) 4712e9d6607Sbeveloper { 4729c3be6a5Sbeveloper TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, gain %.4f\n", channel, destination_type, gain); 4739c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 4749c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 4759c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 4762e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 4772e9d6607Sbeveloper return; 4789c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 4799c3be6a5Sbeveloper return; 4802e9d6607Sbeveloper if (gain < 0.0f) 4812e9d6607Sbeveloper gain = 0.0f; 4829c3be6a5Sbeveloper fChannelTypeGain[destination_type] = gain; 4839c3be6a5Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 4849c3be6a5Sbeveloper if (fMixerChannelInfo[i].destination_type == destination_type) { 4859c3be6a5Sbeveloper fMixerChannelInfo[i].destination_gain = gain; 4869c3be6a5Sbeveloper return; 4879c3be6a5Sbeveloper } 4889c3be6a5Sbeveloper } 4892e9d6607Sbeveloper } 4902e9d6607Sbeveloper 491*a9cf57cfSAxel Dörfler 4922e9d6607Sbeveloper float 4939c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type) 4942e9d6607Sbeveloper { 4959c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 4969c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 4979c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 4982e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 4999c3be6a5Sbeveloper return 0.0f; 5009c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 5019c3be6a5Sbeveloper return 0.0f; 5029c3be6a5Sbeveloper return fChannelTypeGain[destination_type]; 5032e9d6607Sbeveloper } 50469517c15Sbeveloper */ 50569517c15Sbeveloper 506*a9cf57cfSAxel Dörfler 50769517c15Sbeveloper void 50869517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain) 50969517c15Sbeveloper { 51069517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 51169517c15Sbeveloper return; 51269517c15Sbeveloper if (gain < 0.0f) 51369517c15Sbeveloper gain = 0.0f; 51469517c15Sbeveloper 51569517c15Sbeveloper fMixerChannelInfo[mixer_channel].destination_gain = gain; 51669517c15Sbeveloper fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain; 51769517c15Sbeveloper } 51869517c15Sbeveloper 519*a9cf57cfSAxel Dörfler 52069517c15Sbeveloper float 52169517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel) 52269517c15Sbeveloper { 52369517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 52469517c15Sbeveloper return 0.0; 52569517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_gain; 52669517c15Sbeveloper } 52769517c15Sbeveloper 528*a9cf57cfSAxel Dörfler 52969517c15Sbeveloper int 53069517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel) 53169517c15Sbeveloper { 53269517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 53369517c15Sbeveloper return -1; 53469517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_type; 53569517c15Sbeveloper } 5362e9d6607Sbeveloper 537*a9cf57cfSAxel Dörfler 5382e9d6607Sbeveloper void 5391c237c18Sbeveloper MixerInput::SetEnabled(bool yesno) 5401c237c18Sbeveloper { 5411c237c18Sbeveloper fEnabled = yesno; 5421c237c18Sbeveloper } 5431c237c18Sbeveloper 544*a9cf57cfSAxel Dörfler 5451c237c18Sbeveloper bool 5461c237c18Sbeveloper MixerInput::IsEnabled() 5471c237c18Sbeveloper { 5481c237c18Sbeveloper return fEnabled; 5491c237c18Sbeveloper } 5501c237c18Sbeveloper 551*a9cf57cfSAxel Dörfler 5521c237c18Sbeveloper void 5538d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames) 5542e9d6607Sbeveloper { 555*a9cf57cfSAxel Dörfler TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", 556*a9cf57cfSAxel Dörfler framerate, frames); 557d5848e21Sbeveloper 5587b0daf5cSbeveloper fMixBufferFrameRate = framerate; 559*a9cf57cfSAxel Dörfler fDebugMixBufferFrames = frames; 5602e9d6607Sbeveloper 561d5848e21Sbeveloper // frames and/or framerate can be 0 (if no output is connected) 562d5848e21Sbeveloper if (framerate == 0 || frames == 0) { 563*a9cf57cfSAxel Dörfler if (fMixBuffer != NULL) { 564d5848e21Sbeveloper rtm_free(fMixBuffer); 565*a9cf57cfSAxel Dörfler fMixBuffer = NULL; 566d5848e21Sbeveloper } 567d5848e21Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 568d5848e21Sbeveloper fInputChannelInfo[i].buffer_base = 0; 569d5848e21Sbeveloper fMixBufferFrameCount = 0; 570d5848e21Sbeveloper 5719c3be6a5Sbeveloper UpdateInputChannelDestinationMask(); 5729c3be6a5Sbeveloper UpdateInputChannelDestinations(); 573d5848e21Sbeveloper return; 574d5848e21Sbeveloper } 5757b0daf5cSbeveloper 5767b0daf5cSbeveloper // make fMixBufferFrameCount an integral multiple of frames, 5777b0daf5cSbeveloper // but at least 3 times duration of our input buffer 5787b0daf5cSbeveloper // and at least 2 times duration of the output buffer 5797b0daf5cSbeveloper bigtime_t inputBufferLength = duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)); 5807b0daf5cSbeveloper bigtime_t outputBufferLength = duration_for_frames(framerate, frames); 5817b0daf5cSbeveloper bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength); 5827b0daf5cSbeveloper int temp = frames_for_duration(framerate, mixerBufferLength); 5837b0daf5cSbeveloper fMixBufferFrameCount = ((temp / frames) + 1) * frames; 5847b0daf5cSbeveloper 585a2ca4723Sbeveloper TRACE(" inputBufferLength %10Ld\n", inputBufferLength); 586a2ca4723Sbeveloper TRACE(" outputBufferLength %10Ld\n", outputBufferLength); 587a2ca4723Sbeveloper TRACE(" mixerBufferLength %10Ld\n", mixerBufferLength); 588d91580cdSbeveloper TRACE(" fMixBufferFrameCount %10d\n", fMixBufferFrameCount); 5897b0daf5cSbeveloper 5908d28117fSbeveloper ASSERT((fMixBufferFrameCount % frames) == 0); 5918d28117fSbeveloper 592e92593f4Sbeveloper fLastDataFrameWritten = -1; 593e92593f4Sbeveloper fFractionalFrames = 0.0; 594e92593f4Sbeveloper 5952e9d6607Sbeveloper rtm_free(fMixBuffer); 596356855c3Sbeveloper rtm_delete_pool(fRtmPool); 597*a9cf57cfSAxel Dörfler 5987b0daf5cSbeveloper int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount; 599*a9cf57cfSAxel Dörfler if (rtm_create_pool(&fRtmPool, size) != B_OK) 600*a9cf57cfSAxel Dörfler fRtmPool = NULL; 601*a9cf57cfSAxel Dörfler 602356855c3Sbeveloper fMixBuffer = (float *)rtm_alloc(fRtmPool, size); 603*a9cf57cfSAxel Dörfler if (fMixBuffer == NULL) 604*a9cf57cfSAxel Dörfler return; 6057b0daf5cSbeveloper 6067b0daf5cSbeveloper memset(fMixBuffer, 0, size); 6072e9d6607Sbeveloper 6082e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 6097b0daf5cSbeveloper fInputChannelInfo[i].buffer_base = &fMixBuffer[i]; 610d5848e21Sbeveloper 6119c3be6a5Sbeveloper UpdateInputChannelDestinationMask(); 6129c3be6a5Sbeveloper UpdateInputChannelDestinations(); 6132e9d6607Sbeveloper } 614