From 0c63c7d061f2d4490205d48b1e5008c8a2cf95f2 Mon Sep 17 00:00:00 2001 From: beveloper Date: Wed, 2 Jul 2003 22:30:51 +0000 Subject: [PATCH] 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 --- .../media/media-add-ons/mixer/AudioMixer.cpp | 47 +++++++++++++++++-- .../media/media-add-ons/mixer/MixerCore.cpp | 33 +++++++------ .../media/media-add-ons/mixer/MixerCore.h | 4 ++ .../media/media-add-ons/mixer/MixerOutput.cpp | 4 +- .../media/media-add-ons/mixer/MixerOutput.h | 2 +- .../media/media-add-ons/mixer/MixerUtils.cpp | 42 ++++++++++------- .../media/media-add-ons/mixer/MixerUtils.h | 9 ++-- .../media/media-add-ons/mixer/RtList.h | 2 +- 8 files changed, 100 insertions(+), 43 deletions(-) diff --git a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp index b40f710ca7..689d3fffa4 100644 --- a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp +++ b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp @@ -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); + } + + } } diff --git a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp index e477dbe730..15e71c735c 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp @@ -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 InputChanInfos[MAX_TYPES]; - RtList MixChanInfos[fOutput->GetOutputChannelCount()]; // XXX this does not support changing output channel count + RtList InputChanInfos[MAX_CHANNEL_TYPES]; + RtList 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(); diff --git a/src/add-ons/media/media-add-ons/mixer/MixerCore.h b/src/add-ons/media/media-add-ons/mixer/MixerCore.h index 25f332172e..b125b49911 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.h @@ -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: diff --git a/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp b/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp index 823a88e991..72be9550a9 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp @@ -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 diff --git a/src/add-ons/media/media-add-ons/mixer/MixerOutput.h b/src/add-ons/media/media-add-ons/mixer/MixerOutput.h index 52cf012251..b654568f3e 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerOutput.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerOutput.h @@ -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); diff --git a/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp b/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp index e4615e9a72..832f9226ea 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp @@ -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, ""); - 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); } diff --git a/src/add-ons/media/media-add-ons/mixer/MixerUtils.h b/src/add-ons/media/media-add-ons/mixer/MixerUtils.h index 62946956dd..235b23ce13 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerUtils.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerUtils.h @@ -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 const t & max(const t &t1, const t &t2) { return (t1 > t2) ? t1 : t2; } template 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 diff --git a/src/add-ons/media/media-add-ons/mixer/RtList.h b/src/add-ons/media/media-add-ons/mixer/RtList.h index fabef04461..40fd70f045 100644 --- a/src/add-ons/media/media-add-ons/mixer/RtList.h +++ b/src/add-ons/media/media-add-ons/mixer/RtList.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. */