From 7b0daf5ccadfdb073a738f291a2f4a74b29c46f0 Mon Sep 17 00:00:00 2001 From: beveloper Date: Tue, 24 Jun 2003 22:41:02 +0000 Subject: [PATCH] allocate mixer buffers of the correct size, place incoming data in input specific mix buffer git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3646 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../media/media-add-ons/mixer/AudioMixer.cpp | 8 +- .../media/media-add-ons/mixer/MixerCore.cpp | 102 ++++++++++++++---- .../media/media-add-ons/mixer/MixerCore.h | 24 +++-- .../media/media-add-ons/mixer/MixerInput.cpp | 101 +++++++++++++++-- .../media/media-add-ons/mixer/MixerInput.h | 11 +- 5 files changed, 199 insertions(+), 47 deletions(-) diff --git a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp index 7caca28819..faccd5c30a 100644 --- a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp +++ b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp @@ -334,7 +334,7 @@ AudioMixer::FormatChanged(const media_source &producer, const media_destination // tell core about format change fCore->Lock(); - fCore->InputFormatChanged(consumer.id, &format); + fCore->InputFormatChanged(consumer.id, format.u.raw_audio); fCore->Unlock(); return B_OK; @@ -420,7 +420,7 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin // apply format change fCore->Lock(); - fCore->OutputFormatChanged(io_format); + fCore->OutputFormatChanged(io_format->u.raw_audio); fCore->Unlock(); return B_OK; @@ -617,7 +617,7 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest fCore->Output()->MediaOutput().destination = dest; fCore->EnableOutput(true); - fCore->SetTimeSource(TimeSource()->ID()); + fCore->SetTimeSource(TimeSource()); fCore->SetOutputBufferGroup(fBufferGroup); fCore->Unlock(); } @@ -710,7 +710,7 @@ AudioMixer::SetTimeSource(BTimeSource * time_source) { printf("AudioMixer::SetTimeSource: timesource is now %ld\n", time_source->ID()); fCore->Lock(); - fCore->SetTimeSource(time_source->ID()); + fCore->SetTimeSource(time_source); fCore->Unlock(); } 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 1300046522..3d218dc4e0 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp @@ -1,30 +1,46 @@ +#include #include +#include #include +#include #include "MixerCore.h" #include "MixerInput.h" #include "MixerOutput.h" #include "MixerUtils.h" #include "Debug.h" -#define MAX_OUTPUT_BUFFER_LENGTH 50000LL /* 50 ms */ +#define DOUBLE_RATE_MIXING 1 #define ASSERT_LOCKED() if (fLocker->IsLocked()) {} else debugger("core not locked, meltdown occurred") /* Mixer channels are identified by a type number, each type number corresponds * to the one of the channel masks of enum media_multi_channels. + * + * The mixer buffer uses either the same frame rate and same count of frames as the + * output buffer, or the double frame rate and frame count. + * + * All mixer input ring buffers must be an exact multiple of the mixer buffer size, + * so that we do not get any buffer wrap around during reading from the input buffers. + * The mixer input is told by constructor (or after a format change by SetMixBufferFormat()) + * of the current mixer buffer propertys, and must allocate a buffer that is an exact multiple, */ 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), - fRunning(false) + fRunning(false), + fMixBuffer(0), + fMixBufferFrameRate(0), + fMixBufferFrameCount(0), + fMixBufferChannelTypes(0), + fMixBufferChannelCount(0), + fDoubleRateMixing(DOUBLE_RATE_MIXING), + fLastMixStartTime(0), + fBufferGroup(0), + fTimeSource(0) { } @@ -32,13 +48,21 @@ MixerCore::~MixerCore() { delete fLocker; delete fInputs; + + if (fMixBuffer) + rtm_free(fMixBuffer); + + if (fTimeSource) + fTimeSource->Release(); + + delete fMixBufferChannelTypes; } bool MixerCore::AddInput(const media_input &input) { ASSERT_LOCKED(); - fInputs->AddItem(new MixerInput(this, input, fMixFrameRate, frames_for_duration(fMixFrameRate, fInputBufferLength), fMixStartTime)); + fInputs->AddItem(new MixerInput(this, input, fMixBufferFrameRate, fMixBufferFrameCount, fLastMixStartTime)); return true; } @@ -49,6 +73,8 @@ MixerCore::AddOutput(const media_output &output) if (fOutput) return false; fOutput = new MixerOutput(this, output); + // the output format might have been adjusted inside MixerOutput + OutputFormatChanged(fOutput->MediaOutput().format.u.raw_audio); } bool @@ -114,36 +140,77 @@ MixerCore::BufferReceived(BBuffer *buffer, bigtime_t lateness) } void -MixerCore::InputFormatChanged(int32 inputID, const media_format *format) +MixerCore::InputFormatChanged(int32 inputID, const media_multi_audio_format &format) { ASSERT_LOCKED(); + printf("MixerCore::InputFormatChanged not handled\n"); } void -MixerCore::OutputFormatChanged(const media_format *format) +MixerCore::OutputFormatChanged(const media_multi_audio_format &format) { ASSERT_LOCKED(); - -// void ChangeMixBufferFormat(float samplerate, int32 frames, int32 channelcount, uint32 channel_mask); + if (fMixBuffer) + rtm_free(fMixBuffer); + + delete fMixBufferChannelTypes; + + fMixBufferFrameRate = (int32)format.frame_rate; + fMixBufferFrameCount = frames_per_buffer(format); + if (fDoubleRateMixing) { + fMixBufferFrameRate *= 2; + fMixBufferFrameCount *= 2; + } + fMixBufferChannelCount = format.channel_count; + fMixBufferChannelTypes = new int32 [format.channel_count]; + + for (int i = 0; i < fMixBufferChannelCount; i++) + fMixBufferChannelTypes[i] = ChannelMaskToChannelType(GetChannelMask(i, format.channel_mask)); + + fMixBuffer = (float *)rtm_alloc(NULL, sizeof(float) * fMixBufferFrameCount * fMixBufferChannelCount); + + printf("MixerCore::OutputFormatChanged:\n"); + printf(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate); + printf(" fMixBufferFrameCount %ld\n", fMixBufferFrameCount); + printf(" fMixBufferChannelCount %ld\n", fMixBufferChannelCount); + for (int i = 0; i < fMixBufferChannelCount; i++) + printf(" fMixBufferChannelTypes[%i] %ld\n", i, fMixBufferChannelTypes[i]); + + MixerInput *input; + for (int i = 0; (input = Input(i)); i++) + input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount, fLastMixStartTime); } void MixerCore::SetOutputBufferGroup(BBufferGroup *group) { ASSERT_LOCKED(); + + fBufferGroup = group; } void -MixerCore::SetTimeSource(media_node_id id) +MixerCore::SetTimeSource(BTimeSource *ts) { ASSERT_LOCKED(); + + if (fTimeSource) + fTimeSource->Release(); + + fTimeSource = dynamic_cast(ts->Acquire()); + fLastMixStartTime = fTimeSource->Now(); + + MixerInput *input; + for (int i = 0; (input = Input(i)); i++) + input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount, fLastMixStartTime); } void MixerCore::EnableOutput(bool enabled) { ASSERT_LOCKED(); + printf("MixerCore::EnableOutput %d\n", enabled); } void @@ -170,7 +237,9 @@ uint32 MixerCore::OutputBufferSize() { ASSERT_LOCKED(); - return 1; + + uint32 size = sizeof(float) * fMixBufferFrameCount * fMixBufferChannelCount; + return fDoubleRateMixing ? (size / 2) : size; } bool @@ -180,11 +249,6 @@ MixerCore::IsStarted() return fRunning; } -void -MixerCore::OutputBufferLengthChanged(bigtime_t length) -{ -} - /* void BufferReceived(BBuffer *buffer, bigtime_t lateness); @@ -225,4 +289,4 @@ AudioMixer::MixThread() } -*/ \ No newline at end of file +*/ 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 25d52c8899..5f7fe57261 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.h @@ -28,11 +28,11 @@ public: void BufferReceived(BBuffer *buffer, bigtime_t lateness); - void InputFormatChanged(int32 inputID, const media_format *format); - void OutputFormatChanged(const media_format *format); + void InputFormatChanged(int32 inputID, const media_multi_audio_format &format); + void OutputFormatChanged(const media_multi_audio_format &format); void SetOutputBufferGroup(BBufferGroup *group); - void SetTimeSource(media_node_id id); + void SetTimeSource(BTimeSource *ts); void EnableOutput(bool enabled); void Start(bigtime_t time); void Stop(); @@ -43,7 +43,6 @@ public: uint32 OutputChannelCount(); private: - void OutputBufferLengthChanged(bigtime_t length); // handle mixing in separate thread // not implemented (yet) @@ -54,15 +53,21 @@ private: private: BLocker *fLocker; - bigtime_t fOutputBufferLength; - bigtime_t fInputBufferLength; - float fMixFrameRate; - bigtime_t fMixStartTime; - BList *fInputs; MixerOutput *fOutput; int32 fNextInputID; bool fRunning; + + float *fMixBuffer; + int32 fMixBufferFrameRate; + int32 fMixBufferFrameCount; + int32 fMixBufferChannelCount; + int32 *fMixBufferChannelTypes; //array + bool fDoubleRateMixing; + bigtime_t fLastMixStartTime; + + BBufferGroup *fBufferGroup; + BTimeSource *fTimeSource; }; @@ -77,4 +82,3 @@ inline void MixerCore::Unlock() } #endif - 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 93757245f4..d80b8c5e14 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp @@ -1,12 +1,16 @@ #include #include #include +#include #include "MixerInput.h" #include "MixerCore.h" #include "MixerUtils.h" +#include "Resampler.h" #include "ByteSwap.h" #include "debug.h" +template const t & max(const t &t1, const t &t2) { return (t1 > t2) ? t1 : t2; } + MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixSampleRate, int32 mixFramesCount, bigtime_t mixStartTime) : fCore(core), fInput(input), @@ -17,9 +21,10 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixSampl fMixerChannelInfo(0), fMixerChannelCount(0), fMixBuffer(0), - fMixBufferSampleRate(0), - fMixBufferFrames(0), + fMixBufferFrameRate(0), + fMixBufferFrameCount(0), fMixBufferStartTime(0), + fResampler(0), fUserOverridesChannelDesignations(false) { fix_multiaudio_format(&fInput.format.u.raw_audio); @@ -47,6 +52,11 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixSampl fInputChannelInfo[i].designations = 0; // will be set by UpdateChannelDesignations() fInputChannelInfo[i].gain = 1.0; } + + // create resamplers + fResampler = new Resampler * [fInputChannelCount]; + for (int i = 0; i < fInputChannelCount; i++) + fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT); // fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateMixerChannels() @@ -69,6 +79,11 @@ MixerInput::~MixerInput() rtm_free(fMixBuffer); delete [] fInputChannelInfo; delete [] fMixerChannelInfo; + + // delete resamplers + for (int i = 0; i < fInputChannelCount; i++) + delete fResampler[i]; + delete [] fResampler; } void @@ -88,8 +103,54 @@ MixerInput::BufferReceived(BBuffer *buffer) if (fInputByteSwap) fInputByteSwap->Swap(data, size); + int32 offset = frames_for_duration(fMixBufferFrameRate, start - fMixBufferStartTime) % fMixBufferFrameCount; + + printf("MixerInput::BufferReceived: mix buffer start %14Ld, buffer start %14Ld, offset %6d\n", fMixBufferStartTime, start, offset); + + int in_frames = frames_per_buffer(fInput.format.u.raw_audio); // XXX use size + int out_frames = (int)((in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate); // XXX losing fractions - printf("mix buffer start %14Ld, buffer start %14Ld\n", fMixBufferStartTime, start); + if (offset + out_frames > fMixBufferFrameCount) { + + int out_frames1 = fMixBufferFrameCount - offset; + int out_frames2 = out_frames - out_frames1; + int in_frames1 = (out_frames1 * in_frames) / out_frames; + int in_frames2 = in_frames - in_frames1; + + printf(" in_frames %5d, out_frames %5d, in_frames1 %5d, out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n", + in_frames, out_frames, in_frames1, out_frames1, in_frames2, out_frames2); + + for (int i = 0; i < fInputChannelCount; i++) { + fResampler[i]->Resample(reinterpret_cast(data) + i * bytes_per_frame(fInput.format.u.raw_audio), + fInputChannelCount * bytes_per_frame(fInput.format.u.raw_audio), + in_frames1, + reinterpret_cast(fInputChannelInfo[i].buffer_base) + (offset * sizeof(float) * fInputChannelCount), + fInputChannelCount * sizeof(float), + out_frames1, + fInputChannelInfo[i].gain); + + fResampler[i]->Resample(reinterpret_cast(data) + i * bytes_per_frame(fInput.format.u.raw_audio), + fInputChannelCount * bytes_per_frame(fInput.format.u.raw_audio), + in_frames2, + reinterpret_cast(fInputChannelInfo[i].buffer_base), + fInputChannelCount * sizeof(float), + out_frames2, + fInputChannelInfo[i].gain); + } + } else { + + printf(" in_frames %5d, out_frames %5d\n", in_frames, out_frames); + + for (int i = 0; i < fInputChannelCount; i++) { + fResampler[i]->Resample(reinterpret_cast(data) + i * bytes_per_frame(fInput.format.u.raw_audio), + fInputChannelCount * bytes_per_frame(fInput.format.u.raw_audio), + in_frames, + reinterpret_cast(fInputChannelInfo[i].buffer_base) + (offset * sizeof(float) * fInputChannelCount), + fInputChannelCount * sizeof(float), + out_frames, + fInputChannelInfo[i].gain); + } + } } media_input & @@ -303,11 +364,12 @@ MixerInput::GetMixerChannelCount() } void -MixerInput::GetMixerChannelInfo(int channel, const float **buffer, uint32 *sample_offset, int *type, float *gain) +MixerInput::GetMixerChannelInfo(int channel, int64 framepos, const float **buffer, uint32 *sample_offset, int *type, float *gain) { ASSERT(fMixBuffer); ASSERT(channel >= 0 && channel < fMixerChannelCount); - *buffer = fMixerChannelInfo[channel].buffer_base; + int32 offset = framepos % fMixBufferFrameCount; + *buffer = reinterpret_cast(reinterpret_cast(fMixerChannelInfo[channel].buffer_base) + (offset * sizeof(float) * fInputChannelCount)); *sample_offset = sizeof(float) * fInputChannelCount; *type = fMixerChannelInfo[channel].type; *gain = fMixerChannelInfo[channel].gain; @@ -332,16 +394,35 @@ MixerInput::GetMixerChannelGain(int channel) } void -MixerInput::SetMixBufferFormat(float samplerate, int32 frames, bigtime_t starttime) +MixerInput::SetMixBufferFormat(int32 framerate, int32 frames, bigtime_t starttime) { - fMixBufferSampleRate = samplerate; - fMixBufferFrames = frames; + fMixBufferFrameRate = framerate; fMixBufferStartTime = starttime; + printf("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld, starttime %Ld\n", framerate, frames, starttime); + + // make fMixBufferFrameCount an integral multiple of frames, + // but at least 3 times duration of our input buffer + // and at least 2 times duration of the output buffer + bigtime_t inputBufferLength = duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)); + bigtime_t outputBufferLength = duration_for_frames(framerate, frames); + bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength); + int temp = frames_for_duration(framerate, mixerBufferLength); + fMixBufferFrameCount = ((temp / frames) + 1) * frames; + + printf(" inputBufferLength %10Ld\n", inputBufferLength); + printf(" outputBufferLength %10Ld\n", outputBufferLength); + printf(" mixerBufferLength %10Ld\n", mixerBufferLength); + printf(" fMixBufferFrameCount %10ld\n", fMixBufferFrameCount); + if (fMixBuffer) rtm_free(fMixBuffer); - fMixBuffer = (float *)rtm_alloc(NULL, sizeof(float) * fInputChannelCount * fMixBufferFrames); + int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount; + fMixBuffer = (float *)rtm_alloc(NULL, size); + ASSERT(fMixBuffer); + + memset(fMixBuffer, 0, size); for (int i = 0; i < fInputChannelCount; i++) - fInputChannelInfo[i].buffer_base = &fMixBuffer[i * fMixBufferFrames]; + fInputChannelInfo[i].buffer_base = &fMixBuffer[i]; } 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 4c85e17867..2f61580603 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.h @@ -3,6 +3,7 @@ class MixerCore; class ByteSwap; +class Resampler; class MixerInput { @@ -17,7 +18,7 @@ public: media_input & MediaInput(); uint32 GetMixerChannelCount(); - void GetMixerChannelInfo(int channel, const float **buffer, uint32 *sample_offset, int *type, float *gain); + void GetMixerChannelInfo(int channel, int64 framepos, const float **buffer, uint32 *sample_offset, int *type, float *gain); void SetMixerChannelGain(int channel, float gain); float GetMixerChannelGain(int channel); @@ -30,7 +31,7 @@ public: protected: friend class MixerCore; - void SetMixBufferFormat(float samplerate, int32 frames, bigtime_t starttime); + void SetMixBufferFormat(int32 framerate, int32 frames, bigtime_t starttime); private: void UpdateChannelDesignations(); @@ -62,9 +63,11 @@ private: float *fMixBuffer; - float fMixBufferSampleRate; - uint32 fMixBufferFrames; + float fMixBufferFrameRate; + uint32 fMixBufferFrameCount; bigtime_t fMixBufferStartTime; + + Resampler **fResampler; // array bool fUserOverridesChannelDesignations; };