Started implementing input and output channel mapping controls.

Optimized inner loop of mix thread, up to 10% faster now.
Moved some #includes around.
Added #define for maximum supported channel types.
Removed static buffers.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3812 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2003-07-02 22:30:51 +00:00
parent 2091bd588f
commit 0c63c7d061
8 changed files with 100 additions and 43 deletions
@@ -854,6 +854,15 @@ AudioMixer::CreateBufferGroup()
#define DB_TO_GAIN(_db) (20.0 * log10(_db)) #define DB_TO_GAIN(_db) (20.0 * log10(_db))
#define GAIN_TO_DB(_gain) (pow(10.0, (_gain) / 20.0)) #define GAIN_TO_DB(_gain) (pow(10.0, (_gain) / 20.0))
#define PARAM_SRC_ENABLE(id, chan, src) (((id) << 16) | ((chan) << 14) | ((src) << 8) | 1)
#define PARAM_SRC_PERCENT(id, chan, src) (((id) << 16) | ((chan) << 14) | ((src) << 8) | 2)
#define PARAM_DST_ENABLE(id, chan, dst) (((id) << 16) | ((chan) << 14) | ((dst) << 8) | 3)
#define PARAM_DST_PERCENT(id, chan, dst) (((id) << 16) | ((chan) << 14) | ((dst) << 8) | 4)
#define PARAM_SRC(id, chan) (((id) << 16) | ((chan) << 14) | 5)
#define PARAM_DST(id, chan) (((id) << 16) | ((chan) << 14) | 6)
#define PARAM_STR(id) (((id) << 16) | 7)
status_t status_t
AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change, AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change,
void *value, size_t *ioSize) void *value, size_t *ioSize)
@@ -970,8 +979,12 @@ AudioMixer::UpdateParameterWeb()
BParameterGroup *outputchannels; BParameterGroup *outputchannels;
BParameterGroup *inputchannels; BParameterGroup *inputchannels;
BParameterGroup *group; BParameterGroup *group;
BParameterGroup *subgroup;
BParameterGroup *subsubgroup;
BParameterGroup *subsubsubgroup;
MixerInput *in; MixerInput *in;
MixerOutput *out; MixerOutput *out;
char buf[50];
top = web->MakeGroup("Gain Controls"); top = web->MakeGroup("Gain Controls");
@@ -981,7 +994,7 @@ AudioMixer::UpdateParameterWeb()
if (!out) { if (!out) {
group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC); group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC);
} else { } else {
group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, StringForFormat(out), B_GENERIC); group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, StringForFormat(buf, out), B_GENERIC);
group->MakeDiscreteParameter(PARAM_MUTE(0), B_MEDIA_RAW_AUDIO, "Mute", B_MUTE); group->MakeDiscreteParameter(PARAM_MUTE(0), B_MEDIA_RAW_AUDIO, "Mute", B_MUTE);
group->MakeContinuousParameter(PARAM_GAIN(0), B_MEDIA_RAW_AUDIO, "Gain", B_MASTER_GAIN, "dB", -60.0, 18.0, 0.5) group->MakeContinuousParameter(PARAM_GAIN(0), B_MEDIA_RAW_AUDIO, "Gain", B_MASTER_GAIN, "dB", -60.0, 18.0, 0.5)
->SetChannelCount(out->GetOutputChannelCount()); ->SetChannelCount(out->GetOutputChannelCount());
@@ -991,7 +1004,7 @@ AudioMixer::UpdateParameterWeb()
for (int i = 0; (in = fCore->Input(i)); i++) { for (int i = 0; (in = fCore->Input(i)); i++) {
group = top->MakeGroup(""); group = top->MakeGroup("");
group->MakeNullParameter(PARAM_INPUT(in->ID()), B_MEDIA_RAW_AUDIO, in->MediaInput().name, B_WEB_BUFFER_INPUT); group->MakeNullParameter(PARAM_INPUT(in->ID()), B_MEDIA_RAW_AUDIO, in->MediaInput().name, B_WEB_BUFFER_INPUT);
group->MakeNullParameter(PARAM_FORMAT(in->ID()), B_MEDIA_RAW_AUDIO, StringForFormat(in), B_GENERIC); group->MakeNullParameter(PARAM_FORMAT(in->ID()), B_MEDIA_RAW_AUDIO, StringForFormat(buf, in), B_GENERIC);
group->MakeDiscreteParameter(PARAM_MUTE(in->ID()), B_MEDIA_RAW_AUDIO, "Mute", B_MUTE); group->MakeDiscreteParameter(PARAM_MUTE(in->ID()), B_MEDIA_RAW_AUDIO, "Mute", B_MUTE);
group->MakeContinuousParameter(PARAM_GAIN(in->ID()), B_MEDIA_RAW_AUDIO, "Gain", B_GAIN, "dB", -60.0, 18.0, 0.5) group->MakeContinuousParameter(PARAM_GAIN(in->ID()), B_MEDIA_RAW_AUDIO, "Gain", B_GAIN, "dB", -60.0, 18.0, 0.5)
->SetChannelCount(in->GetInputChannelCount()); ->SetChannelCount(in->GetInputChannelCount());
@@ -1008,17 +1021,43 @@ AudioMixer::UpdateParameterWeb()
if (!out) { if (!out) {
group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC); group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC);
} else { } else {
for (int chan = 0; chan < out->GetOutputChannelCount(); chan++) {
subgroup = group->MakeGroup("");
subgroup->MakeNullParameter(PARAM_SRC(0, chan), B_MEDIA_RAW_AUDIO,
StringForChannelType(buf, out->GetOutputChannelType(chan)), B_GENERIC);
for (int src = 0; src < MAX_CHANNEL_TYPES; src++) {
subsubgroup = subgroup->MakeGroup("");
subsubgroup->MakeDiscreteParameter(PARAM_SRC_ENABLE(0, chan, src), B_MEDIA_RAW_AUDIO, "", B_ENABLE);
subsubgroup->MakeContinuousParameter(PARAM_SRC_PERCENT(0, chan, src), B_MEDIA_RAW_AUDIO,
StringForChannelType(buf, src), B_GAIN, "%", 0.0, 100.0, 1.0);
}
}
} }
top = web->MakeGroup("Input Mapping"); // top level group top = web->MakeGroup("Input Mapping"); // top level group
inputchannels = top->MakeGroup(""); inputchannels = top->MakeGroup("");
inputchannels->MakeNullParameter(10003, B_MEDIA_RAW_AUDIO, "Input Channel Destinations", B_GENERIC); inputchannels->MakeNullParameter(10003, B_MEDIA_RAW_AUDIO, "Input Channel Destinations", B_GENERIC);
for (int i = 0; (in = fCore->Input(i)); i++) { // for (int i = 0; (in = fCore->Input(i)); i++) {
if ((in = fCore->Input(1)) || (in = fCore->Input(0))) { // XXX limited to input 1 or 0 to aviod BSlider problems
group = inputchannels->MakeGroup(""); group = inputchannels->MakeGroup("");
group->MakeNullParameter(1000 + in->ID(), B_MEDIA_RAW_AUDIO, in->MediaInput().name, B_GENERIC); group->MakeNullParameter(PARAM_STR(in->ID()), B_MEDIA_RAW_AUDIO, in->MediaInput().name, B_GENERIC);
group = group->MakeGroup(""); group = group->MakeGroup("");
for (int chan = 0; chan < in->GetInputChannelCount(); chan++) {
subgroup = group->MakeGroup("");
subgroup->MakeNullParameter(PARAM_DST(in->ID(), chan), B_MEDIA_RAW_AUDIO,
StringForChannelType(buf, in->GetInputChannelType(chan)), B_GENERIC);
for (int dst = 0; dst < MAX_CHANNEL_TYPES; dst++) {
subsubgroup = subgroup->MakeGroup("");
subsubgroup->MakeDiscreteParameter(PARAM_DST_ENABLE(in->ID(), chan, dst), B_MEDIA_RAW_AUDIO, "", B_ENABLE);
subsubgroup->MakeContinuousParameter(PARAM_DST_PERCENT(in->ID(), chan, dst), B_MEDIA_RAW_AUDIO,
StringForChannelType(buf, dst), B_GAIN, "%", 0.0, 100.0, 1.0);
}
}
} }
fCore->Unlock(); fCore->Unlock();
@@ -415,9 +415,10 @@ MixerCore::MixThread()
TRACE("starting MixThread, start %Ld, time_base %Ld, frame_base %Ld\n", start, time_base, frame_base); TRACE("starting MixThread, start %Ld, time_base %Ld, frame_base %Ld\n", start, time_base, frame_base);
#define MAX_TYPES 18 ASSERT(fMixBufferFrameCount > 0);
RtList<chan_info> InputChanInfos[MAX_TYPES];
RtList<chan_info> MixChanInfos[fOutput->GetOutputChannelCount()]; // XXX this does not support changing output channel count RtList<chan_info> InputChanInfos[MAX_CHANNEL_TYPES];
RtList<chan_info> MixChanInfos[fMixBufferChannelCount]; // XXX this does not support changing output channel count
event_time = time_base; event_time = time_base;
frame_pos = 0; frame_pos = 0;
@@ -477,7 +478,7 @@ MixerCore::MixThread()
float gain; float gain;
if (!input->GetMixerChannelInfo(chan, cur_framepos, event_time, &base, &sample_offset, &type, &gain)) if (!input->GetMixerChannelInfo(chan, cur_framepos, event_time, &base, &sample_offset, &type, &gain))
continue; continue;
if (type < 0 || type >= MAX_TYPES) if (type < 0 || type >= MAX_CHANNEL_TYPES)
continue; continue;
chan_info *info = InputChanInfos[type].Create(); chan_info *info = InputChanInfos[type].Create();
info->base = (const char *)base; info->base = (const char *)base;
@@ -492,7 +493,7 @@ MixerCore::MixThread()
int type; int type;
float gain; float gain;
fOutput->GetMixerChannelInfo(chan, i, &type, &gain); fOutput->GetMixerChannelInfo(chan, i, &type, &gain);
if (type < 0 || type >= MAX_TYPES) if (type < 0 || type >= MAX_CHANNEL_TYPES)
continue; continue;
int count = InputChanInfos[type].CountItems(); int count = InputChanInfos[type].CountItems();
for (int j = 0; j < count; j++) { for (int j = 0; j < count; j++) {
@@ -505,22 +506,26 @@ MixerCore::MixThread()
} }
} }
uint32 dst_sample_offset;
dst_sample_offset = fMixBufferChannelCount * sizeof(float);
memset(fMixBuffer, 0, fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float)); memset(fMixBuffer, 0, fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float));
for (int chan = 0; chan < fMixBufferChannelCount; chan++) { for (int chan = 0; chan < fMixBufferChannelCount; chan++) {
PRINT(5, "MixThread: chan %d has %d sources\n", chan, MixChanInfos[chan].CountItems()); PRINT(5, "MixThread: chan %d has %d sources\n", chan, MixChanInfos[chan].CountItems());
int count = MixChanInfos[chan].CountItems(); int count = MixChanInfos[chan].CountItems();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
chan_info *info = MixChanInfos[chan].ItemAt(i); chan_info *info = MixChanInfos[chan].ItemAt(i);
char *dst = (char *)&fMixBuffer[chan];
PRINT(5, "MixThread: base %p, sample-offset %2d, gain %.3f\n", info->base, info->sample_offset, info->gain); PRINT(5, "MixThread: base %p, sample-offset %2d, gain %.3f\n", info->base, info->sample_offset, info->gain);
for (int j = 0; j < fMixBufferFrameCount; j++) { // This looks slightly ugly, but the current GCC will generate the fastest
*(float *)dst += *(const float *)info->base * info->gain; // code this way. fMixBufferFrameCount is always > 0.
uint32 dst_sample_offset = fMixBufferChannelCount * sizeof(float);
uint32 src_sample_offset = info->sample_offset;
register char *dst = (char *)&fMixBuffer[chan];
register char *src = (char *)info->base;
register float gain = info->gain;
register int j = fMixBufferFrameCount;
do {
*(float *)dst += *(const float *)src * gain;
dst += dst_sample_offset; dst += dst_sample_offset;
info->base += info->sample_offset; src += src_sample_offset;
} } while (--j);
} }
} }
@@ -561,7 +566,7 @@ MixerCore::MixThread()
} }
// make all lists empty // make all lists empty
for (int i = 0; i < MAX_TYPES; i++) for (int i = 0; i < MAX_CHANNEL_TYPES; i++)
InputChanInfos[i].MakeEmpty(); InputChanInfos[i].MakeEmpty();
for (int i = 0; i < fOutput->GetOutputChannelCount(); i++) for (int i = 0; i < fOutput->GetOutputChannelCount(); i++)
MixChanInfos[i].MakeEmpty(); MixChanInfos[i].MakeEmpty();
@@ -8,6 +8,10 @@ class MixerInput;
class MixerOutput; class MixerOutput;
class Resampler; class Resampler;
// The number of "enum media_multi_channels" types from MediaDefs.h
// XXX should be 18, currently limited to 9
#define MAX_CHANNEL_TYPES 9
class MixerCore class MixerCore
{ {
public: public:
@@ -223,11 +223,11 @@ MixerOutput::AssignDefaultSources()
} }
uint32 uint32
MixerOutput::GetOutputChannelDesignation(int channel) MixerOutput::GetOutputChannelType(int channel)
{ {
if (channel < 0 || channel >= fOutputChannelCount) if (channel < 0 || channel >= fOutputChannelCount)
return 0; return 0;
return fOutputChannelInfo[channel].designation; return ChannelMaskToChannelType(fOutputChannelInfo[channel].designation);
} }
void void
@@ -20,7 +20,7 @@ public:
void ChangeFormat(const media_multi_audio_format &format); void ChangeFormat(const media_multi_audio_format &format);
uint32 GetOutputChannelCount(); uint32 GetOutputChannelCount();
uint32 GetOutputChannelDesignation(int channel); uint32 GetOutputChannelType(int channel);
void SetOutputChannelGain(int channel, float gain); void SetOutputChannelGain(int channel, float gain);
float GetOutputChannelGain(int channel); float GetOutputChannelGain(int channel);
@@ -8,16 +8,16 @@
#include "MixerOutput.h" #include "MixerOutput.h"
#include "debug.h" #include "debug.h"
const char *StringForFormat(const media_format & format, int index); const char *StringForFormat(char *str, const media_format & format);
void const char *
string_for_channel_mask(char *str, uint32 mask) StringForChannelMask(char *str, uint32 mask)
{ {
str[0] = 0;
if (mask == 0) { if (mask == 0) {
strcpy(str, "<none>"); strcpy(str, "<none>");
return; return str;
} }
str[0] = 0;
#define DECODE(type, text) if (mask & (type)) \ #define DECODE(type, text) if (mask & (type)) \
do { strcat(str, text); mask &= ~(type); if (mask != 0) strcat(str, ", "); } while (0) do { strcat(str, text); mask &= ~(type); if (mask != 0) strcat(str, ", "); } while (0)
DECODE(B_CHANNEL_LEFT, "Left"); DECODE(B_CHANNEL_LEFT, "Left");
@@ -41,6 +41,7 @@ string_for_channel_mask(char *str, uint32 mask)
#undef DECODE #undef DECODE
if (mask) if (mask)
sprintf(str + strlen(str), "0x%08X", mask); sprintf(str + strlen(str), "0x%08X", mask);
return str;
} }
int int
@@ -240,10 +241,9 @@ s_to_us(double secs)
return (bigtime_t) (secs * 1000000.0); return (bigtime_t) (secs * 1000000.0);
} }
const char *StringForFormat(const media_format & format, int index) const char *StringForFormat(char *str, const media_format & format)
{ {
static char str[2][50]; char fmtstr[20];
static char fmtstr[2][40];
const char *fmt; const char *fmt;
switch (format.u.raw_audio.format) { switch (format.u.raw_audio.format) {
case media_raw_audio_format::B_AUDIO_FLOAT: case media_raw_audio_format::B_AUDIO_FLOAT:
@@ -251,8 +251,8 @@ const char *StringForFormat(const media_format & format, int index)
break; break;
case media_raw_audio_format::B_AUDIO_INT: case media_raw_audio_format::B_AUDIO_INT:
if (format.u.raw_audio.valid_bits != 0) { if (format.u.raw_audio.valid_bits != 0) {
sprintf(fmtstr[index & 1], "%d bit", format.u.raw_audio.valid_bits); sprintf(fmtstr, "%d bit", format.u.raw_audio.valid_bits);
fmt = fmtstr[index & 1]; fmt = fmtstr;
} else { } else {
fmt = "32 bit"; fmt = "32 bit";
} }
@@ -274,18 +274,26 @@ const char *StringForFormat(const media_format & format, int index)
a = int(format.u.raw_audio.frame_rate + 0.05) / 1000; a = int(format.u.raw_audio.frame_rate + 0.05) / 1000;
b = int(format.u.raw_audio.frame_rate + 0.05) % 1000; b = int(format.u.raw_audio.frame_rate + 0.05) % 1000;
if (b) if (b)
sprintf(str[index & 1], "%d.%d kHz %s", a, b / 100, fmt); sprintf(str, "%d.%d kHz %s", a, b / 100, fmt);
else else
sprintf(str[index & 1], "%d kHz %s", a, fmt); sprintf(str, "%d kHz %s", a, fmt);
return str[index & 1]; return str;
} }
const char *StringForFormat(MixerOutput *output) const char *
StringForFormat(char *buf, MixerOutput *output)
{ {
return StringForFormat(output->MediaOutput().format, 0); return StringForFormat(buf, output->MediaOutput().format);
} }
const char *StringForFormat(MixerInput *input) const char *
StringForFormat(char *buf, MixerInput *input)
{ {
return StringForFormat(input->MediaInput().format, 1); return StringForFormat(buf, input->MediaInput().format);
}
const char *
StringForChannelType(char *buf, int type)
{
return StringForChannelMask(buf, 1 << type);
} }
@@ -2,7 +2,7 @@
#define _MIXER_UTILS_H #define _MIXER_UTILS_H
#if DEBUG > 0 #if DEBUG > 0
#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) #define PRINT_CHANNEL_MASK(fmt) do { char s[200]; StringForChannelMask(s, (fmt).u.raw_audio.channel_mask); printf(" channel_mask 0x%08X %s\n", (fmt).u.raw_audio.channel_mask, s); } while (0)
#else #else
#define PRINT_CHANNEL_MASK(fmt) ((void)0) #define PRINT_CHANNEL_MASK(fmt) ((void)0)
#endif #endif
@@ -10,7 +10,6 @@
template<class t> const t & max(const t &t1, const t &t2) { return (t1 > t2) ? t1 : t2; } template<class t> const t & max(const t &t1, const t &t2) { return (t1 > t2) ? t1 : t2; }
template<class t> const t & min(const t &t1, const t &t2) { return (t1 < t2) ? t1 : t2; } template<class t> const t & min(const t &t1, const t &t2) { return (t1 < t2) ? t1 : t2; }
void string_for_channel_mask(char *str, uint32 mask);
void fix_multiaudio_format(media_multi_audio_format *format); void fix_multiaudio_format(media_multi_audio_format *format);
int count_nonzero_bits(uint32 value); int count_nonzero_bits(uint32 value);
@@ -40,7 +39,9 @@ bigtime_t s_to_us(double secs);
class MixerInput; class MixerInput;
class MixerOutput; class MixerOutput;
const char *StringForFormat(MixerOutput *output); // not thread save const char *StringForFormat(char *buf, MixerOutput *output);
const char *StringForFormat(MixerInput *input); // not thread save const char *StringForFormat(char *buf, MixerInput *input);
const char *StringForChannelMask(char *buf, uint32 mask);
const char *StringForChannelType(char *buf, int type);
#endif //_MIXER_UTILS_H #endif //_MIXER_UTILS_H
@@ -5,7 +5,7 @@
* *
* A simple list template that uses realtime * A simple list template that uses realtime
* memory and does no error checking. Since * memory and does no error checking. Since
* it doesn't call constructors ot destructors, * it doesn't call constructors or destructors,
* don't use it to store objects. * don't use it to store objects.
*/ */