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 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
AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change,
void *value, size_t *ioSize)
@@ -970,8 +979,12 @@ AudioMixer::UpdateParameterWeb()
BParameterGroup *outputchannels;
BParameterGroup *inputchannels;
BParameterGroup *group;
BParameterGroup *subgroup;
BParameterGroup *subsubgroup;
BParameterGroup *subsubsubgroup;
MixerInput *in;
MixerOutput *out;
char buf[50];
top = web->MakeGroup("Gain Controls");
@@ -981,7 +994,7 @@ AudioMixer::UpdateParameterWeb()
if (!out) {
group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC);
} 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->MakeContinuousParameter(PARAM_GAIN(0), B_MEDIA_RAW_AUDIO, "Gain", B_MASTER_GAIN, "dB", -60.0, 18.0, 0.5)
->SetChannelCount(out->GetOutputChannelCount());
@@ -991,7 +1004,7 @@ AudioMixer::UpdateParameterWeb()
for (int i = 0; (in = fCore->Input(i)); i++) {
group = top->MakeGroup("");
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->MakeContinuousParameter(PARAM_GAIN(in->ID()), B_MEDIA_RAW_AUDIO, "Gain", B_GAIN, "dB", -60.0, 18.0, 0.5)
->SetChannelCount(in->GetInputChannelCount());
@@ -1008,16 +1021,42 @@ AudioMixer::UpdateParameterWeb()
if (!out) {
group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC);
} 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
inputchannels = top->MakeGroup("");
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->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("");
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);
}
}
}
@@ -414,10 +414,11 @@ MixerCore::MixThread()
Unlock();
TRACE("starting MixThread, start %Ld, time_base %Ld, frame_base %Ld\n", start, time_base, frame_base);
ASSERT(fMixBufferFrameCount > 0);
#define MAX_TYPES 18
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;
frame_pos = 0;
@@ -477,7 +478,7 @@ MixerCore::MixThread()
float gain;
if (!input->GetMixerChannelInfo(chan, cur_framepos, event_time, &base, &sample_offset, &type, &gain))
continue;
if (type < 0 || type >= MAX_TYPES)
if (type < 0 || type >= MAX_CHANNEL_TYPES)
continue;
chan_info *info = InputChanInfos[type].Create();
info->base = (const char *)base;
@@ -492,7 +493,7 @@ MixerCore::MixThread()
int type;
float gain;
fOutput->GetMixerChannelInfo(chan, i, &type, &gain);
if (type < 0 || type >= MAX_TYPES)
if (type < 0 || type >= MAX_CHANNEL_TYPES)
continue;
int count = InputChanInfos[type].CountItems();
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));
for (int chan = 0; chan < fMixBufferChannelCount; chan++) {
PRINT(5, "MixThread: chan %d has %d sources\n", chan, MixChanInfos[chan].CountItems());
int count = MixChanInfos[chan].CountItems();
for (int i = 0; i < count; 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);
for (int j = 0; j < fMixBufferFrameCount; j++) {
*(float *)dst += *(const float *)info->base * info->gain;
// This looks slightly ugly, but the current GCC will generate the fastest
// 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;
info->base += info->sample_offset;
}
src += src_sample_offset;
} while (--j);
}
}
@@ -561,7 +566,7 @@ MixerCore::MixThread()
}
// make all lists empty
for (int i = 0; i < MAX_TYPES; i++)
for (int i = 0; i < MAX_CHANNEL_TYPES; i++)
InputChanInfos[i].MakeEmpty();
for (int i = 0; i < fOutput->GetOutputChannelCount(); i++)
MixChanInfos[i].MakeEmpty();
@@ -8,6 +8,10 @@ class MixerInput;
class MixerOutput;
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
{
public:
@@ -223,11 +223,11 @@ MixerOutput::AssignDefaultSources()
}
uint32
MixerOutput::GetOutputChannelDesignation(int channel)
MixerOutput::GetOutputChannelType(int channel)
{
if (channel < 0 || channel >= fOutputChannelCount)
return 0;
return fOutputChannelInfo[channel].designation;
return ChannelMaskToChannelType(fOutputChannelInfo[channel].designation);
}
void
@@ -20,7 +20,7 @@ public:
void ChangeFormat(const media_multi_audio_format &format);
uint32 GetOutputChannelCount();
uint32 GetOutputChannelDesignation(int channel);
uint32 GetOutputChannelType(int channel);
void SetOutputChannelGain(int channel, float gain);
float GetOutputChannelGain(int channel);
@@ -8,16 +8,16 @@
#include "MixerOutput.h"
#include "debug.h"
const char *StringForFormat(const media_format & format, int index);
const char *StringForFormat(char *str, const media_format & format);
void
string_for_channel_mask(char *str, uint32 mask)
const char *
StringForChannelMask(char *str, uint32 mask)
{
str[0] = 0;
if (mask == 0) {
strcpy(str, "<none>");
return;
return str;
}
str[0] = 0;
#define DECODE(type, text) if (mask & (type)) \
do { strcat(str, text); mask &= ~(type); if (mask != 0) strcat(str, ", "); } while (0)
DECODE(B_CHANNEL_LEFT, "Left");
@@ -41,6 +41,7 @@ string_for_channel_mask(char *str, uint32 mask)
#undef DECODE
if (mask)
sprintf(str + strlen(str), "0x%08X", mask);
return str;
}
int
@@ -240,10 +241,9 @@ s_to_us(double secs)
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];
static char fmtstr[2][40];
char fmtstr[20];
const char *fmt;
switch (format.u.raw_audio.format) {
case media_raw_audio_format::B_AUDIO_FLOAT:
@@ -251,8 +251,8 @@ const char *StringForFormat(const media_format & format, int index)
break;
case media_raw_audio_format::B_AUDIO_INT:
if (format.u.raw_audio.valid_bits != 0) {
sprintf(fmtstr[index & 1], "%d bit", format.u.raw_audio.valid_bits);
fmt = fmtstr[index & 1];
sprintf(fmtstr, "%d bit", format.u.raw_audio.valid_bits);
fmt = fmtstr;
} else {
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;
b = int(format.u.raw_audio.frame_rate + 0.05) % 1000;
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
sprintf(str[index & 1], "%d kHz %s", a, fmt);
return str[index & 1];
sprintf(str, "%d kHz %s", a, fmt);
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
#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
#define PRINT_CHANNEL_MASK(fmt) ((void)0)
#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 & 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);
int count_nonzero_bits(uint32 value);
@@ -40,7 +39,9 @@ bigtime_t s_to_us(double secs);
class MixerInput;
class MixerOutput;
const char *StringForFormat(MixerOutput *output); // not thread save
const char *StringForFormat(MixerInput *input); // not thread save
const char *StringForFormat(char *buf, MixerOutput *output);
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
@@ -5,7 +5,7 @@
*
* A simple list template that uses realtime
* 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.
*/