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
This commit is contained in:
beveloper 2003-06-24 22:41:02 +00:00
parent 299d70ad2d
commit 7b0daf5cca
5 changed files with 199 additions and 47 deletions

View File

@ -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();
}

View File

@ -1,30 +1,46 @@
#include <RealtimeAlloc.h>
#include <MediaNode.h>
#include <TimeSource.h>
#include <Buffer.h>
#include <BufferGroup.h>
#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<BTimeSource *>(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()
}
*/
*/

View File

@ -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

View File

@ -1,12 +1,16 @@
#include <MediaNode.h>
#include <Buffer.h>
#include <RealtimeAlloc.h>
#include <string.h>
#include "MixerInput.h"
#include "MixerCore.h"
#include "MixerUtils.h"
#include "Resampler.h"
#include "ByteSwap.h"
#include "debug.h"
template<class t> 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<char *>(data) + i * bytes_per_frame(fInput.format.u.raw_audio),
fInputChannelCount * bytes_per_frame(fInput.format.u.raw_audio),
in_frames1,
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + (offset * sizeof(float) * fInputChannelCount),
fInputChannelCount * sizeof(float),
out_frames1,
fInputChannelInfo[i].gain);
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_frame(fInput.format.u.raw_audio),
fInputChannelCount * bytes_per_frame(fInput.format.u.raw_audio),
in_frames2,
reinterpret_cast<char *>(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<char *>(data) + i * bytes_per_frame(fInput.format.u.raw_audio),
fInputChannelCount * bytes_per_frame(fInput.format.u.raw_audio),
in_frames,
reinterpret_cast<char *>(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<float *>(reinterpret_cast<char *>(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];
}

View File

@ -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;
};