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:
@@ -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.
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user