From 2e9d660756e64ccd9bd2b779020a167b8c7a5824 Mon Sep 17 00:00:00 2001 From: beveloper Date: Fri, 20 Jun 2003 16:55:19 +0000 Subject: [PATCH] mixer input buffer assignment and gain setting implemented git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3585 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../media/media-add-ons/mixer/MixerCore.cpp | 11 +- .../media/media-add-ons/mixer/MixerCore.h | 4 + .../media/media-add-ons/mixer/MixerInput.cpp | 290 +++++++++++++++++- .../media/media-add-ons/mixer/MixerInput.h | 53 +++- .../media/media-add-ons/mixer/MixerUtils.cpp | 56 +++- .../media/media-add-ons/mixer/MixerUtils.h | 17 + 6 files changed, 420 insertions(+), 11 deletions(-) diff --git a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp index 24f72006ec..60364ad25e 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp @@ -2,6 +2,7 @@ #include "MixerCore.h" #include "MixerInput.h" #include "MixerOutput.h" +#include "MixerUtils.h" #include "Debug.h" #define MAX_OUTPUT_BUFFER_LENGTH 50000LL /* 50 ms */ @@ -12,6 +13,8 @@ MixerCore::MixerCore() : fLocker(new BLocker), fOutputBufferLength(MAX_OUTPUT_BUFFER_LENGTH), fInputBufferLength(3 * MAX_OUTPUT_BUFFER_LENGTH), + fMixFrameRate(96000), + fMixStartTime(0), fInputs(new BList), fOutput(0), fNextInputID(1), @@ -24,12 +27,12 @@ MixerCore::~MixerCore() delete fLocker; delete fInputs; } - + bool MixerCore::AddInput(const media_input &input) { ASSERT_LOCKED(); - fInputs->AddItem(new MixerInput(this, input)); + fInputs->AddItem(new MixerInput(this, input, fMixFrameRate, frames_for_duration(fMixFrameRate, fInputBufferLength), fMixStartTime)); return true; } @@ -105,6 +108,9 @@ void MixerCore::OutputFormatChanged(const media_format *format) { ASSERT_LOCKED(); + + void ChangeMixBufferFormat(float samplerate, int32 frames, int32 channelcount, uint32 channel_mask); + } void @@ -165,7 +171,6 @@ MixerCore::OutputBufferLengthChanged(bigtime_t length) } - /* void BufferReceived(BBuffer *buffer, bigtime_t lateness); diff --git a/src/add-ons/media/media-add-ons/mixer/MixerCore.h b/src/add-ons/media/media-add-ons/mixer/MixerCore.h index 2ece2b6a73..1d99a5ff31 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.h @@ -40,6 +40,8 @@ public: uint32 OutputBufferSize(); bool IsStarted(); + + uint32 OutputChannelCount(); private: void OutputBufferLengthChanged(bigtime_t length); @@ -55,6 +57,8 @@ private: bigtime_t fOutputBufferLength; bigtime_t fInputBufferLength; + float fMixFrameRate; + bigtime_t fMixStartTime; BList *fInputs; MixerOutput *fOutput; diff --git a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp index 3d933e613c..08a97ddc71 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp @@ -1,25 +1,71 @@ #include +#include +#include #include "MixerInput.h" #include "MixerCore.h" #include "MixerUtils.h" #include "debug.h" -MixerInput::MixerInput(MixerCore *core, const media_input &input) +MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixSampleRate, int32 mixFramesCount, bigtime_t mixStartTime) : fCore(core), - fInput(input) + fInput(input), + fInputChannelInfo(0), + fInputChannelCount(0), + fInputChannelMask(0), + fMixerChannelInfo(0), + fMixerChannelCount(0), + fMixBuffer(0), + fMixBufferSampleRate(0), + fMixBufferFrames(0), + fMixBufferStartTime(0), + fUserOverridesChannelDesignations(false) { fix_multiaudio_format(&fInput.format.u.raw_audio); PRINT_INPUT("MixerInput::MixerInput", fInput); PRINT_CHANNEL_MASK(fInput.format); + + ASSERT(fInput.format.u.raw_audio.channel_count > 0); + + fInputChannelCount = fInput.format.u.raw_audio.channel_count; + fInputChannelMask = fInput.format.u.raw_audio.channel_mask; + fInputChannelInfo = new input_chan_info[fInputChannelCount]; + + // initialize fInputChannelInfo + for (int i = 0; i < fInputChannelCount; i++) { + fInputChannelInfo[i].buffer_base = 0; // will be set by SetMixBufferFormat() + fInputChannelInfo[i].designations = 0; // will be set by UpdateChannelDesignations() + fInputChannelInfo[i].gain = 1.0; + } + + // fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateMixerChannels() + + SetMixBufferFormat(mixSampleRate, mixFramesCount, mixStartTime); + UpdateChannelDesignations(); + UpdateMixerChannels(); + + + // XXX a test: + SetMixerChannelGain(0, 0.222); + SetMixerChannelGain(1, 0.444); + AddInputChannelDesignation(0, B_CHANNEL_REARRIGHT); + SetMixerChannelGain(2, 0.666); + AddInputChannelDesignation(1, B_CHANNEL_REARLEFT); } MixerInput::~MixerInput() { + if (fMixBuffer) + rtm_free(fMixBuffer); + delete [] fInputChannelInfo; + delete [] fMixerChannelInfo; } void MixerInput::BufferReceived(BBuffer *buffer) { + ASSERT(fMixBuffer); + + printf("mix buffer start %14Ld, buffer start %14Ld\n", fMixBufferStartTime, buffer->Header()->start_time); } media_input & @@ -34,4 +80,244 @@ MixerInput::ID() return fInput.destination.id; } +void +MixerInput::AddInputChannelDesignation(int channel, uint32 des) +{ + ASSERT(count_nonzero_bits(des) == 1); + + // test if the channel is valid + if (channel < 0 || channel >= fInputChannelCount) + return; + // test if it is already set + if (fInputChannelInfo[channel].designations & des) + return; + + // remove it from all other channels that might have it + for (int i = 0; i < fInputChannelCount; i++) + fInputChannelInfo[i].designations &= ~des; + + // add it to specified channel + fInputChannelInfo[channel].designations |= des; + + fUserOverridesChannelDesignations = true; + UpdateMixerChannels(); +} + +void +MixerInput::RemoveInputChannelDesignation(int channel, uint32 des) +{ + ASSERT(count_nonzero_bits(des) == 1); + + // test if the channel is valid + if (channel < 0 || channel >= fInputChannelCount) + return; + + // test if it is really set + if ((fInputChannelInfo[channel].designations & des) == 0) + return; + + // remove it from specified channel + fInputChannelInfo[channel].designations &= ~des; + + fUserOverridesChannelDesignations = true; + UpdateMixerChannels(); +} + +uint32 +MixerInput::GetInputChannelDesignations(int channel) +{ + // test if the channel is valid + if (channel < 0 || channel >= fInputChannelCount) + return 0; + return fInputChannelInfo[channel].designations; +} + +uint32 +MixerInput::GetInputChannelType(int channel) +{ + // test if the channel is valid + if (channel < 0 || channel >= fInputChannelCount) + return 0; + return GetChannelMask(channel, fInputChannelMask); +} + +void +MixerInput::SetInputChannelGain(int channel, float gain) +{ + // test if the channel is valid + if (channel < 0 || channel >= fInputChannelCount) + return; + if (gain < 0.0f) + gain = 0.0f; + + fInputChannelInfo[channel].gain = gain; +} + +float +MixerInput::GetInputChannelGain(int channel) +{ + // test if the channel is valid + if (channel < 0 || channel >= fInputChannelCount) + return 0.0f; + return fInputChannelInfo[channel].gain; +} + +void +MixerInput::UpdateChannelDesignations() +{ + // is the user already messed with the assignmens, don't do anything. + if (fUserOverridesChannelDesignations) + return; + + printf("UpdateChannelDesignations: enter\n"); + + if (fInputChannelCount == 1 && (GetChannelMask(0, fInputChannelMask) & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { + // a left or right channel get's output as stereo on both + fInputChannelInfo[0].designations = B_CHANNEL_LEFT | B_CHANNEL_RIGHT; + } else { + // everything else get's mapped 1:1 + for (int i = 0; i < fInputChannelCount; i++) + fInputChannelInfo[i].designations = GetChannelMask(i, fInputChannelMask); + } + + for (int i = 0; i < fInputChannelCount; i++) + printf("UpdateChannelDesignations: input channel %d, designations 0x%08X, base %p, gain %.3f\n", i, fInputChannelInfo[i].designations, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); + + printf("UpdateChannelDesignations: enter\n"); +} + +void +MixerInput::UpdateMixerChannels() +{ + uint32 channel_count; + uint32 all_bits; + uint32 mask; + + mixer_chan_info *old_mixer_channel_info; + uint32 old_mixer_channel_count; + + ASSERT(fMixBuffer); + + printf("UpdateMixerChannels: enter\n"); + + for (int i = 0; i < fInputChannelCount; i++) + printf("UpdateMixerChannels: input channel %d, designations 0x%08X, base %p, gain %.3f\n", i, fInputChannelInfo[i].designations, fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); + + all_bits = 0; + for (int i = 0; i < fInputChannelCount; i++) + all_bits |= fInputChannelInfo[i].designations; + + printf("UpdateMixerChannels: all_bits = %08x\n", all_bits); + + channel_count = count_nonzero_bits(all_bits); + + printf("UpdateMixerChannels: %ld input channels, %ld mixer channels (%ld old)\n", fInputChannelCount, channel_count, fMixerChannelCount); + + // If we resize the channel info array, we preserve the gain setting + // by saving the old array until new assignments are finished, and + // then applying the old gains. New gains are set to 1.0 + if (channel_count != fMixerChannelCount) { + old_mixer_channel_info = fMixerChannelInfo; + old_mixer_channel_count = fMixerChannelCount; + fMixerChannelInfo = new mixer_chan_info[channel_count]; + fMixerChannelCount = channel_count; + for (int i = 0; i < fMixerChannelCount; i++) + fMixerChannelInfo[i].gain = 1.0; + } else { + old_mixer_channel_info = 0; + old_mixer_channel_count = 0; + } + + // assign each mixer channel one type + for (int i = 0, mask = 1; i < fMixerChannelCount; i++) { + while (mask != 0 && (all_bits & mask) == 0) + mask <<= 1; + fMixerChannelInfo[i].designation = mask; + mask <<= 1; + } + + // assign buffer_base pointer for each mixer channel + for (int i = 0; i < fMixerChannelCount; i++) { + int j; + for (j = 0; j < fInputChannelCount; j++) { + if (fInputChannelInfo[j].designations & fMixerChannelInfo[i].designation) { + fMixerChannelInfo[i].buffer_base = &fMixBuffer[j]; + break; + } + } + if (j == fInputChannelCount) { + printf("buffer assignment failed for mixer chan %d\n", i); + fMixerChannelInfo[i].buffer_base = fMixBuffer; + } + } + + // apply old gains, overriding the 1.0 defaults for the old channels + if (old_mixer_channel_info != 0) { + for (int i = 0; i < fMixerChannelCount; i++) { + for (int j = 0; j < old_mixer_channel_count; j++) { + if (fMixerChannelInfo[i].designation == old_mixer_channel_info[j].designation) { + fMixerChannelInfo[i].gain = old_mixer_channel_info[j].gain; + break; + } + } + } + // also delete the old info array + delete [] old_mixer_channel_info; + } + + for (int i = 0; i < fMixerChannelCount; i++) + printf("UpdateMixerChannels: mixer channel %d, designation 0x%08X, base %p, gain %.3f\n", i, fMixerChannelInfo[i].designation, fMixerChannelInfo[i].buffer_base, fMixerChannelInfo[i].gain); + + printf("UpdateMixerChannels: leave\n"); +} + +uint32 +MixerInput::GetMixerChannelCount() +{ + return fMixerChannelCount; +} + +void +MixerInput::GetMixerChannelInfo(int channel, const float **buffer, uint32 *sample_offset, uint32 *type, float *gain) +{ + ASSERT(fMixBuffer); + ASSERT(channel >= 0 && channel < fMixerChannelCount); + *buffer = fMixerChannelInfo[channel].buffer_base; + *sample_offset = sizeof(float) * fInputChannelCount; + *type = fMixerChannelInfo[channel].designation; + *gain = fMixerChannelInfo[channel].gain; +} + +void +MixerInput::SetMixerChannelGain(int channel, float gain) +{ + if (channel < 0 || channel >= fMixerChannelCount) + return; + if (gain < 0.0f) + gain = 0.0f; + fMixerChannelInfo[channel].gain = gain; +} + +float +MixerInput::GetMixerChannelGain(int channel) +{ + if (channel < 0 || channel >= fMixerChannelCount) + return 1.0; + return fMixerChannelInfo[channel].gain; +} + +void +MixerInput::SetMixBufferFormat(float samplerate, int32 frames, bigtime_t starttime) +{ + fMixBufferSampleRate = samplerate; + fMixBufferFrames = frames; + fMixBufferStartTime = starttime; + + if (fMixBuffer) + rtm_free(fMixBuffer); + fMixBuffer = (float *)rtm_alloc(NULL, sizeof(float) * fInputChannelCount * fMixBufferFrames); + + for (int i = 0; i < fInputChannelCount; i++) + fInputChannelInfo[i].buffer_base = &fMixBuffer[i * fMixBufferFrames]; +} diff --git a/src/add-ons/media/media-add-ons/mixer/MixerInput.h b/src/add-ons/media/media-add-ons/mixer/MixerInput.h index 79584db8d6..cc312677b7 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.h @@ -6,7 +6,7 @@ class MixerCore; class MixerInput { public: - MixerInput(MixerCore *core, const media_input &input); + MixerInput(MixerCore *core, const media_input &input, float mixSampleRate, int32 mixFramesCount, bigtime_t mixStartTime); ~MixerInput(); int32 ID(); @@ -15,9 +15,56 @@ public: media_input & MediaInput(); + uint32 GetMixerChannelCount(); + void GetMixerChannelInfo(int channel, const float **buffer, uint32 *sample_offset, uint32 *type, float *gain); + void SetMixerChannelGain(int channel, float gain); + float GetMixerChannelGain(int channel); + + void AddInputChannelDesignation(int channel, uint32 des); + void RemoveInputChannelDesignation(int channel, uint32 des); + uint32 GetInputChannelDesignations(int channel); + uint32 GetInputChannelType(int channel); + void SetInputChannelGain(int channel, float gain); + float GetInputChannelGain(int channel); + +protected: + friend class MixerCore; + void SetMixBufferFormat(float samplerate, int32 frames, bigtime_t starttime); + private: - MixerCore *fCore; - media_input fInput; + void UpdateChannelDesignations(); + void UpdateMixerChannels(); + +private: + struct input_chan_info { + float *buffer_base; + uint32 designations; // multiple or no bits sets + float gain; + }; + struct mixer_chan_info { + float *buffer_base; + uint32 designation; // only one bit is set + float gain; + }; + +private: + MixerCore *fCore; + media_input fInput; + + input_chan_info *fInputChannelInfo; // array + uint32 fInputChannelCount; + uint32 fInputChannelMask; + + mixer_chan_info *fMixerChannelInfo; // array + uint32 fMixerChannelCount; + + float *fMixBuffer; + + float fMixBufferSampleRate; + uint32 fMixBufferFrames; + bigtime_t fMixBufferStartTime; + + bool fUserOverridesChannelDesignations; }; #endif diff --git a/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp b/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp index a9eef8a1c5..e0636e270f 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp @@ -3,8 +3,10 @@ #include #include "MixerUtils.h" +#include "debug.h" -void string_for_channel_mask(char *str, uint32 mask) +void +string_for_channel_mask(char *str, uint32 mask) { str[0] = 0; if (mask == 0) { @@ -36,7 +38,8 @@ void string_for_channel_mask(char *str, uint32 mask) sprintf(str + strlen(str), "0x%08X", mask); } -int count_nonzero_bits(uint32 value) +int +count_nonzero_bits(uint32 value) { int count = 0; for (int i = 0; i < 32; i++) @@ -45,7 +48,8 @@ int count_nonzero_bits(uint32 value) return count; } -void fix_multiaudio_format(media_multi_audio_format *format) +void +fix_multiaudio_format(media_multi_audio_format *format) { if (format->format == media_raw_audio_format::B_AUDIO_INT) { if (format->valid_bits != 0 && (format->valid_bits < 16 || format->valid_bits >= 32)) @@ -68,6 +72,12 @@ void fix_multiaudio_format(media_multi_audio_format *format) format->matrix_mask = 0; } break; + case 3: + if (count_nonzero_bits(format->channel_mask) != 3) { + format->channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_CENTER; + format->matrix_mask = 0; + } + break; case 4: if (count_nonzero_bits(format->channel_mask) != 4) { format->channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT; @@ -92,5 +102,45 @@ void fix_multiaudio_format(media_multi_audio_format *format) format->matrix_mask = 0; } break; + + default: + break; + } +} + +uint32 +GetChannelMask(int channel, uint32 all_channel_masks) +{ + ASSERT(channel <= count_nonzero_bits(all_channel_masks)); + + uint32 mask = 1; + int pos = 0; + for (;;) { + while ((all_channel_masks & mask) == 0) + mask <<= 1; + if (pos == channel) + return mask; + pos++; + mask <<= 1; + if (mask == 0) + return 0; + } +} + +void +CopySamples(float *_dst, int32 _dst_sample_offset, + const float *_src, int32 _src_sample_offset, + int32 _sample_count) +{ + ASSERT(sizeof(float) == sizeof(uint32)); + register const char * src = (const char *) _src; + register char * dst = (char *) _dst; + register int32 sample_count = _sample_count; + register int32 dst_sample_offset = _dst_sample_offset; + register int32 src_sample_offset = _src_sample_offset; + while (sample_count--) { + *(uint32 *)dst = *(const uint32 *)src; + src += src_sample_offset; + dst += dst_sample_offset; } } diff --git a/src/add-ons/media/media-add-ons/mixer/MixerUtils.h b/src/add-ons/media/media-add-ons/mixer/MixerUtils.h index 8fee6c6a37..52de93621d 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerUtils.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerUtils.h @@ -1,5 +1,22 @@ +#include void string_for_channel_mask(char *str, uint32 mask); void fix_multiaudio_format(media_multi_audio_format *format); +int count_nonzero_bits(uint32 value); + #define PRINT_CHANNEL_MASK(fmt) do { char s[200]; string_for_channel_mask(s, (fmt).u.raw_audio.channel_mask); printf(" channel_mask 0x%08X %s\n", (fmt).u.raw_audio.channel_mask, s); } while (0) + +uint32 GetChannelMask(int channel, uint32 all_channel_masks); + +void CopySamples(float *_dst, int32 _dst_sample_offset, + const float *_src, int32 _src_sample_offset, + int32 _sample_count); + + +int64 frames_for_duration(double framerate, bigtime_t duration); + +inline int64 frames_for_duration(double framerate, bigtime_t duration) +{ + return (int64) ceil(framerate * double(duration) / 1000000.0); +}