* Resolved TODO and implemented updating resampling implementation on the fly.

* Reordered some methods in the source to align with declaration order.
 * Applied naming conventions for private methods.
 * Switched asterix style in MixerInput.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38488 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2010-09-01 09:09:10 +00:00
parent e9ec3d5a49
commit b006bbe130
5 changed files with 198 additions and 151 deletions

View File

@ -1475,7 +1475,7 @@ AudioMixer::SetParameterValue(int32 id, bigtime_t when, const void *value,
if (size != sizeof(int32))
goto err;
fCore->Settings()->SetResamplingAlgorithm(static_cast<const int32 *>(value)[0]);
// XXX tell the core to change the algorithm
fCore->UpdateResamplingAlgorithm();
break;
case 80: // Refuse output format changes
if (size != sizeof(int32))

View File

@ -120,6 +120,21 @@ MixerCore::Settings()
}
void
MixerCore::UpdateResamplingAlgorithm()
{
ASSERT_LOCKED();
_UpdateResamplers(fOutput->MediaOutput().format.u.raw_audio);
for (int32 i = fInputs->CountItems() - 1; i >= 0; i--) {
MixerInput* input
= reinterpret_cast<MixerInput*>(fInputs->ItemAtFast(i));
input->UpdateResamplingAlgorithm();
}
}
void
MixerCore::SetOutputAttenuation(float gain)
{
@ -133,7 +148,7 @@ MixerCore::AddInput(const media_input& input)
{
ASSERT_LOCKED();
MixerInput* in = new MixerInput(this, input, fMixBufferFrameRate,
fMixBufferFrameCount, Settings()->ResamplingAlgorithm());
fMixBufferFrameCount);
fInputs->AddItem(in);
return in;
}
@ -149,7 +164,7 @@ MixerCore::AddOutput(const media_output& output)
}
fOutput = new MixerOutput(this, output);
// the output format might have been adjusted inside MixerOutput
ApplyOutputFormat();
_ApplyOutputFormat();
ASSERT(!fRunning);
if (fStarted && fOutputEnabled)
@ -252,76 +267,13 @@ MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
Stop();
fOutput->ChangeFormat(format);
ApplyOutputFormat();
_ApplyOutputFormat();
if (was_started)
Start();
}
void
MixerCore::ApplyOutputFormat()
{
ASSERT_LOCKED();
media_multi_audio_format format = fOutput->MediaOutput().format.u.raw_audio;
if (fMixBuffer != NULL)
rtm_free(fMixBuffer);
delete fMixBufferChannelTypes;
fMixBufferFrameRate = (int32)(0.5 + format.frame_rate);
fMixBufferFrameCount = frames_per_buffer(format);
if (fDoubleRateMixing) {
fMixBufferFrameRate *= 2;
fMixBufferFrameCount *= 2;
}
fMixBufferChannelCount = format.channel_count;
ASSERT(fMixBufferChannelCount == fOutput->GetOutputChannelCount());
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);
ASSERT(fMixBuffer != NULL);
if (fResampler != NULL) {
for (int i = 0; i < fMixBufferChannelCount; i++)
delete fResampler[i];
delete[] fResampler;
}
fResampler = new Resampler*[fMixBufferChannelCount];
for (int i = 0; i < fMixBufferChannelCount; i++) {
switch (Settings()->ResamplingAlgorithm()) {
case 2:
fResampler[i] = new Interpolate(
media_raw_audio_format::B_AUDIO_FLOAT, format.format);
break;
default:
fResampler[i] = new Resampler(
media_raw_audio_format::B_AUDIO_FLOAT, format.format);
}
}
TRACE("MixerCore::OutputFormatChanged:\n");
TRACE(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate);
TRACE(" fMixBufferFrameCount %ld\n", fMixBufferFrameCount);
TRACE(" fMixBufferChannelCount %ld\n", fMixBufferChannelCount);
for (int i = 0; i < fMixBufferChannelCount; i++)
TRACE(" fMixBufferChannelTypes[%i] %ld\n", i, fMixBufferChannelTypes[i]);
MixerInput *input;
for (int i = 0; (input = Input(i)); i++)
input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount);
}
void
MixerCore::SetOutputBufferGroup(BBufferGroup *group)
{
@ -411,8 +363,8 @@ MixerCore::StartMixThread()
ASSERT(fOutput);
fRunning = true;
fMixThreadWaitSem = create_sem(0, "mix thread wait");
fMixThread = spawn_thread(MixThreadEntry, "Yeah baby, very shagadelic", 120,
this);
fMixThread = spawn_thread(_MixThreadEntry, "Yeah baby, very shagadelic",
120, this);
resume_thread(fMixThread);
}
@ -434,16 +386,92 @@ MixerCore::StopMixThread()
}
int32
MixerCore::MixThreadEntry(void* arg)
// #pragma mark - private
void
MixerCore::_UpdateResamplers(const media_multi_audio_format& format)
{
static_cast<MixerCore*>(arg)->MixThread();
ASSERT_LOCKED();
if (fResampler != NULL) {
for (int i = 0; i < fMixBufferChannelCount; i++)
delete fResampler[i];
delete[] fResampler;
}
fResampler = new Resampler*[fMixBufferChannelCount];
for (int i = 0; i < fMixBufferChannelCount; i++) {
switch (Settings()->ResamplingAlgorithm()) {
case 2:
fResampler[i] = new Interpolate(
media_raw_audio_format::B_AUDIO_FLOAT, format.format);
break;
default:
fResampler[i] = new Resampler(
media_raw_audio_format::B_AUDIO_FLOAT, format.format);
}
}
}
void
MixerCore::_ApplyOutputFormat()
{
ASSERT_LOCKED();
const media_multi_audio_format& format
= fOutput->MediaOutput().format.u.raw_audio;
if (fMixBuffer != NULL)
rtm_free(fMixBuffer);
delete fMixBufferChannelTypes;
fMixBufferFrameRate = (int32)(0.5 + format.frame_rate);
fMixBufferFrameCount = frames_per_buffer(format);
if (fDoubleRateMixing) {
fMixBufferFrameRate *= 2;
fMixBufferFrameCount *= 2;
}
fMixBufferChannelCount = format.channel_count;
ASSERT(fMixBufferChannelCount == fOutput->GetOutputChannelCount());
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);
ASSERT(fMixBuffer != NULL);
_UpdateResamplers(format);
TRACE("MixerCore::OutputFormatChanged:\n");
TRACE(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate);
TRACE(" fMixBufferFrameCount %ld\n", fMixBufferFrameCount);
TRACE(" fMixBufferChannelCount %ld\n", fMixBufferChannelCount);
for (int i = 0; i < fMixBufferChannelCount; i++)
TRACE(" fMixBufferChannelTypes[%i] %ld\n", i, fMixBufferChannelTypes[i]);
MixerInput *input;
for (int i = 0; (input = Input(i)); i++)
input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount);
}
int32
MixerCore::_MixThreadEntry(void* arg)
{
static_cast<MixerCore*>(arg)->_MixThread();
return 0;
}
void
MixerCore::MixThread()
MixerCore::_MixThread()
{
// The broken BeOS R5 multiaudio node starts with time 0,
// then publishes negative times for about 50ms, publishes 0
@ -453,7 +481,7 @@ MixerCore::MixThread()
bigtime_t start = fTimeSource->Now();
Unlock();
while (start <= 0) {
TRACE("MixerCore: delaying MixThread start, timesource is at %Ld\n",
TRACE("MixerCore: delaying _MixThread start, timesource is at %Ld\n",
start);
snooze(5000);
if (!LockFromMixThread())
@ -471,7 +499,7 @@ MixerCore::MixThread()
bigtime_t bufferRequestTimeout = buffer_duration(
fOutput->MediaOutput().format.u.raw_audio) / 2;
TRACE("MixerCore: starting MixThread at %Ld with latency %Ld and "
TRACE("MixerCore: starting _MixThread at %Ld with latency %Ld and "
"downstream latency %Ld, bufferRequestTimeout %Ld\n", start, latency,
fDownstreamLatency, bufferRequestTimeout);
@ -483,7 +511,7 @@ MixerCore::MixThread()
bigtime_t timeBase = duration_for_frames(fMixBufferFrameRate, frameBase);
Unlock();
TRACE("MixerCore: starting MixThread, start %Ld, timeBase %Ld, "
TRACE("MixerCore: starting _MixThread, start %Ld, timeBase %Ld, "
"frameBase %Ld\n", start, timeBase, frameBase);
ASSERT(fMixBufferFrameCount > 0);
@ -603,13 +631,13 @@ MixerCore::MixThread()
memset(fMixBuffer, 0,
fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float));
for (int channel = 0; channel < fMixBufferChannelCount; channel++) {
PRINT(5, "MixThread: channel %d has %d sources\n", channel,
PRINT(5, "_MixThread: channel %d has %d sources\n", channel,
mixChanInfos[channel].CountItems());
int count = mixChanInfos[channel].CountItems();
for (int i = 0; i < count; i++) {
chan_info* info = mixChanInfos[channel].ItemAt(i);
PRINT(5, "MixThread: base %p, sample-offset %2d, gain %.3f\n",
PRINT(5, "_MixThread: base %p, sample-offset %2d, gain %.3f\n",
info->base, info->sample_offset, info->gain);
// This looks slightly ugly, but the current GCC will generate
// the fastest code this way.

View File

@ -36,6 +36,7 @@ public:
virtual ~MixerCore();
MixerSettings* Settings();
void UpdateResamplingAlgorithm();
// To avoid calling Settings()->AttenuateOutput() for every outgoing
// buffer, this setting is cached in fOutputGain and must be set by
@ -77,9 +78,11 @@ public:
uint32 OutputChannelCount();
private:
void ApplyOutputFormat();
static int32 MixThreadEntry(void* arg);
void MixThread();
void _UpdateResamplers(
const media_multi_audio_format& format);
void _ApplyOutputFormat();
static int32 _MixThreadEntry(void* arg);
void _MixThread();
private:
BLocker* fLocker;

View File

@ -20,26 +20,26 @@
#include "Resampler.h"
MixerInput::MixerInput(MixerCore *core, const media_input &input,
float mixFrameRate, int32 mixFrameCount, int resamplingAlgorithm)
MixerInput::MixerInput(MixerCore* core, const media_input& input,
float mixFrameRate, int32 mixFrameCount)
:
fCore(core),
fInput(input),
fInputByteSwap(0),
fInputByteSwap(NULL),
fEnabled(true),
fInputChannelInfo(0),
fInputChannelInfo(NULL),
fInputChannelCount(0),
fInputChannelMask(0),
fMixerChannelInfo(0),
fMixerChannelCount(0),
fMixBuffer(0),
fMixBuffer(NULL),
fMixBufferFrameRate(0),
fMixBufferFrameCount(0),
fLastDataFrameWritten(-1),
fLastDataAvailableTime(-1),
fFractionalFrames(0.0),
fResampler(0),
fRtmPool(0),
fResampler(NULL),
fRtmPool(NULL),
fUserOverridesChannelDestinations(false)
{
fix_multiaudio_format(&fInput.format.u.raw_audio);
@ -72,28 +72,14 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input,
fInputChannelInfo[i].buffer_base = 0;
// will be set by SetMixBufferFormat()
fInputChannelInfo[i].destination_mask = 0;
// will be set by UpdateInputChannelDestinationMask()
// will be set by _UpdateInputChannelDestinationMask()
fInputChannelInfo[i].gain = 1.0;
}
// create resamplers
fResampler = new Resampler * [fInputChannelCount];
for (int i = 0; i < fInputChannelCount; i++) {
switch (resamplingAlgorithm) {
case 2:
fResampler[i] = new Interpolate(
fInput.format.u.raw_audio.format,
media_raw_audio_format::B_AUDIO_FLOAT);
break;
default:
fResampler[i] = new Resampler(
fInput.format.u.raw_audio.format,
media_raw_audio_format::B_AUDIO_FLOAT);
}
}
UpdateResamplingAlgorithm();
// fMixerChannelInfo and fMixerChannelCount will be initialized by
// UpdateInputChannelDestinations()
// _UpdateInputChannelDestinations()
SetMixBufferFormat((int32)mixFrameRate, mixFrameCount);
}
@ -104,21 +90,37 @@ MixerInput::~MixerInput()
rtm_free(fMixBuffer);
if (fRtmPool)
rtm_delete_pool(fRtmPool);
delete [] fInputChannelInfo;
delete [] fMixerChannelInfo;
delete[] fInputChannelInfo;
delete[] fMixerChannelInfo;
// delete resamplers
for (int i = 0; i < fInputChannelCount; i++)
delete fResampler[i];
delete [] fResampler;
if (fResampler != NULL) {
for (int i = 0; i < fInputChannelCount; i++)
delete fResampler[i];
delete[] fResampler;
}
delete fInputByteSwap;
}
void
MixerInput::BufferReceived(BBuffer *buffer)
int32
MixerInput::ID()
{
void *data;
return fInput.destination.id;
}
media_input&
MixerInput::MediaInput()
{
return fInput;
}
void
MixerInput::BufferReceived(BBuffer* buffer)
{
void* data;
size_t size;
bigtime_t start;
bigtime_t buffer_duration;
@ -255,19 +257,19 @@ MixerInput::BufferReceived(BBuffer *buffer)
for (int i = 0; i < fInputChannelCount; i++) {
fResampler[i]->Resample(
reinterpret_cast<char *>(data)
reinterpret_cast<char*>(data)
+ i * bytes_per_sample(fInput.format.u.raw_audio),
bytes_per_frame(fInput.format.u.raw_audio), in_frames1,
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base)
reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base)
+ offset, fInputChannelCount * sizeof(float), out_frames1,
fInputChannelInfo[i].gain);
fResampler[i]->Resample(
reinterpret_cast<char *>(data)
reinterpret_cast<char*>(data)
+ i * bytes_per_sample(fInput.format.u.raw_audio)
+ in_frames1 * bytes_per_frame(fInput.format.u.raw_audio),
bytes_per_frame(fInput.format.u.raw_audio), in_frames2,
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base),
reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base),
fInputChannelCount * sizeof(float), out_frames2,
fInputChannelInfo[i].gain);
@ -290,10 +292,10 @@ MixerInput::BufferReceived(BBuffer *buffer)
offset *= sizeof(float) * fInputChannelCount;
for (int i = 0; i < fInputChannelCount; i++) {
fResampler[i]->Resample(
reinterpret_cast<char *>(data)
reinterpret_cast<char*>(data)
+ i * bytes_per_sample(fInput.format.u.raw_audio),
bytes_per_frame(fInput.format.u.raw_audio), in_frames,
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base)
reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base)
+ offset, fInputChannelCount * sizeof(float),
out_frames, fInputChannelInfo[i].gain);
}
@ -302,17 +304,29 @@ MixerInput::BufferReceived(BBuffer *buffer)
}
media_input &
MixerInput::MediaInput()
void
MixerInput::UpdateResamplingAlgorithm()
{
return fInput;
}
int32
MixerInput::ID()
{
return fInput.destination.id;
if (fResampler != NULL) {
for (int i = 0; i < fInputChannelCount; i++)
delete fResampler[i];
delete[] fResampler;
}
// create resamplers
fResampler = new Resampler*[fInputChannelCount];
for (int i = 0; i < fInputChannelCount; i++) {
switch (fCore->Settings()->ResamplingAlgorithm()) {
case 2:
fResampler[i] = new Interpolate(
fInput.format.u.raw_audio.format,
media_raw_audio_format::B_AUDIO_FLOAT);
break;
default:
fResampler[i] = new Resampler(
fInput.format.u.raw_audio.format,
media_raw_audio_format::B_AUDIO_FLOAT);
}
}
}
@ -347,7 +361,7 @@ MixerInput::AddInputChannelDestination(int channel, int destination_type)
fInputChannelInfo[channel].destination_mask |= mask;
fUserOverridesChannelDestinations = true;
UpdateInputChannelDestinations();
_UpdateInputChannelDestinations();
}
@ -367,7 +381,7 @@ MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
fInputChannelInfo[channel].destination_mask &= ~mask;
fUserOverridesChannelDestinations = true;
UpdateInputChannelDestinations();
_UpdateInputChannelDestinations();
}
@ -428,13 +442,13 @@ MixerInput::GetInputChannelGain(int channel)
void
MixerInput::UpdateInputChannelDestinationMask()
MixerInput::_UpdateInputChannelDestinationMask()
{
// is the user already messed with the assignmens, don't do anything.
if (fUserOverridesChannelDestinations)
return;
TRACE("UpdateInputChannelDestinationMask: enter\n");
TRACE("_UpdateInputChannelDestinationMask: enter\n");
// first apply a 1:1 mapping
for (int i = 0; i < fInputChannelCount; i++) {
@ -480,25 +494,25 @@ MixerInput::UpdateInputChannelDestinationMask()
}
for (int i = 0; i < fInputChannelCount; i++) {
TRACE("UpdateInputChannelDestinationMask: input channel %d, "
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);
}
TRACE("UpdateInputChannelDestinationMask: leave\n");
TRACE("_UpdateInputChannelDestinationMask: leave\n");
}
void
MixerInput::UpdateInputChannelDestinations()
MixerInput::_UpdateInputChannelDestinations()
{
int channel_count;
uint32 all_bits;
uint32 mask;
TRACE("UpdateInputChannelDestinations: enter\n");
TRACE("_UpdateInputChannelDestinations: enter\n");
for (int i = 0; i < fInputChannelCount; i++) {
TRACE("UpdateInputChannelDestinations: input channel %d, "
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);
@ -508,10 +522,10 @@ MixerInput::UpdateInputChannelDestinations()
for (int i = 0; i < fInputChannelCount; i++)
all_bits |= fInputChannelInfo[i].destination_mask;
TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
TRACE("_UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
channel_count = count_nonzero_bits(all_bits);
TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer "
TRACE("_UpdateInputChannelDestinations: %d input channels, %d mixer "
"channels (%d old)\n", fInputChannelCount, channel_count,
fMixerChannelCount);
if (channel_count != fMixerChannelCount) {
@ -551,13 +565,13 @@ MixerInput::UpdateInputChannelDestinations()
}
for (int i = 0; i < fMixerChannelCount; i++) {
TRACE("UpdateInputChannelDestinations: mixer channel %d, type %2d, "
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);
}
TRACE("UpdateInputChannelDestinations: leave\n");
TRACE("_UpdateInputChannelDestinations: leave\n");
}
@ -668,8 +682,8 @@ MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
fInputChannelInfo[i].buffer_base = 0;
fMixBufferFrameCount = 0;
UpdateInputChannelDestinationMask();
UpdateInputChannelDestinations();
_UpdateInputChannelDestinationMask();
_UpdateInputChannelDestinations();
return;
}
@ -711,6 +725,6 @@ MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
for (int i = 0; i < fInputChannelCount; i++)
fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
UpdateInputChannelDestinationMask();
UpdateInputChannelDestinations();
_UpdateInputChannelDestinationMask();
_UpdateInputChannelDestinations();
}

View File

@ -25,14 +25,16 @@ class MixerInput {
public:
MixerInput(MixerCore* core,
const media_input& input,
float mixFrameRate, int32 mixFrameCount,
int resamplingAlgorithm);
float mixFrameRate, int32 mixFrameCount);
~MixerInput();
int32 ID();
void BufferReceived(BBuffer* buffer);
media_input& MediaInput();
void BufferReceived(BBuffer* buffer);
void UpdateResamplingAlgorithm();
// The physical input channels
int GetInputChannelCount();
int GetInputChannelType(int channel);
@ -74,8 +76,8 @@ protected:
int32 frames);
private:
void UpdateInputChannelDestinationMask();
void UpdateInputChannelDestinations();
void _UpdateInputChannelDestinationMask();
void _UpdateInputChannelDestinations();
struct input_chan_info {
float* buffer_base;