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 3e25facbfb..cc37a9c406 100644 --- a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp +++ b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp @@ -99,23 +99,6 @@ AudioMixer::AddOn(int32 *internal_id) const return fAddOn; } -// -// BControllable methods -// - -status_t -AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change, - void *value, size_t *ioSize) -{ - return B_ERROR; -} - -void -AudioMixer::SetParameterValue(int32 id, bigtime_t when, - const void *value, size_t size) -{ -} - // // BBufferConsumer methods // @@ -308,11 +291,13 @@ AudioMixer::Connected(const media_source &producer, const media_destination &whe fCore->AddInput(*out_input); fCore->Unlock(); - + // If we want the producer to use a specific BBufferGroup, we now need to call // BMediaRoster::SetOutputBuffersFor() here to set the producer's buffer group. // But we have no special buffer requirements anyway... + UpdateParameterWeb(); + return B_OK; } @@ -334,6 +319,8 @@ AudioMixer::Disconnected(const media_source &producer, const media_destination & } fCore->Unlock(); + + UpdateParameterWeb(); } status_t @@ -686,6 +673,8 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest fCore->SetTimingInfo(TimeSource(), fDownstreamLatency); fCore->SetOutputBufferGroup(fBufferGroup); fCore->Unlock(); + + UpdateParameterWeb(); } @@ -716,6 +705,8 @@ AudioMixer::Disconnect(const media_source &what, const media_destination &where) fCore->SetOutputBufferGroup(0); fCore->Unlock(); + + UpdateParameterWeb(); } @@ -772,6 +763,7 @@ AudioMixer::NodeRegistered() #else SetPriority(120); #endif + UpdateParameterWeb(); } void @@ -848,6 +840,197 @@ AudioMixer::CreateBufferGroup() return new BBufferGroup(size, count); } +// +// BControllable methods +// + +#define PARAM_INPUT(a) (10*(a) + 0) +#define PARAM_FORMAT(a) (10*(a) + 1) +#define PARAM_MUTE(a) (10*(a) + 2) +#define PARAM_GAIN(a) (10*(a) + 3) +#define PARAM_OUTPUT(a) (10*(a) + 4) +#define PARAM(a) ((a) / 10) +#define PARAM_IS_MUTE(a) ((a) % 10 == 2) +#define PARAM_IS_GAIN(a) ((a) % 10 == 3) +#define DB_TO_GAIN(_db) (20.0 * log10(_db)) +#define GAIN_TO_DB(_gain) (pow(10.0, (_gain) / 20.0)) + +status_t +AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change, + void *value, size_t *ioSize) +{ + TRACE("GetParameterValue: id %ld, ioSize %ld\n", id, *ioSize); + int param = PARAM(id); + fCore->Lock(); + if (param == 0) { + MixerOutput *output = fCore->Output(); + if ((!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id)) || !output) + goto err; + if (PARAM_IS_MUTE(id)) { + // output mute control + printf("get output mute control size %d\n", *ioSize); + if (*ioSize < sizeof(int32)) + goto err; + *ioSize = sizeof(int32); + static_cast(value)[0] = 0; + } + if (PARAM_IS_GAIN(id)) { + // output gain control + if (*ioSize < output->GetOutputChannelCount() * sizeof(float)) + goto err; + *ioSize = output->GetOutputChannelCount() * sizeof(float); + for (int chan = 0; chan < output->GetOutputChannelCount(); chan++) + static_cast(value)[chan] = DB_TO_GAIN(output->GetOutputChannelGain(chan)); + } + } else { + MixerInput *input; + for (int i = 0; (input = fCore->Input(i)); i++) + if (input->ID() == param) + break; + if ((!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id)) || !input) + goto err; + if (PARAM_IS_MUTE(id)) { + // input mute control + printf("get input mute control size %d\n", *ioSize); + if (*ioSize < sizeof(int32)) + goto err; + *ioSize = sizeof(int32); + static_cast(value)[0] = 0; + } + if (PARAM_IS_GAIN(id)) { + // input gain control + if (*ioSize < input->GetMixerChannelCount() * sizeof(float)) + goto err; + *ioSize = input->GetMixerChannelCount() * sizeof(float); + for (int chan = 0; chan < input->GetMixerChannelCount(); chan++) + static_cast(value)[chan] = DB_TO_GAIN(input->GetMixerChannelGain(chan)); + } + } + *last_change = TimeSource()->Now(); // XXX we could do better + fCore->Unlock(); + return B_OK; +err: + fCore->Unlock(); + return B_ERROR; +} + +void +AudioMixer::SetParameterValue(int32 id, bigtime_t when, + const void *value, size_t size) +{ + TRACE("SetParameterValue: id %ld, size %ld\n", id, size); + int param = PARAM(id); + fCore->Lock(); + if (param == 0) { + MixerOutput *output = fCore->Output(); + if ((!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id)) || !output) + goto err; + if (PARAM_IS_MUTE(id)) { + // output mute control + printf("set output mute control size %d\n", size); + if (size != sizeof(int32)) + goto err; + } + if (PARAM_IS_GAIN(id)) { + // output gain control + if (size < output->GetOutputChannelCount() * sizeof(float)) + goto err; + for (int chan = 0; chan < output->GetOutputChannelCount(); chan++) + output->SetOutputChannelGain(chan, GAIN_TO_DB(static_cast(value)[chan])); + } + } else { + MixerInput *input; + for (int i = 0; (input = fCore->Input(i)); i++) + if (input->ID() == param) + break; + if ((!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id)) || !input) + goto err; + if (PARAM_IS_MUTE(id)) { + // input mute control + printf("set input mute control size %d\n", size); + if (size != sizeof(int32)) + goto err; + } + if (PARAM_IS_GAIN(id)) { + // input gain control + if (size < input->GetMixerChannelCount() * sizeof(float)) + goto err; + for (int chan = 0; chan < input->GetMixerChannelCount(); chan++) + input->SetMixerChannelGain(chan, GAIN_TO_DB(static_cast(value)[chan])); + } + } + BroadcastNewParameterValue(when, id, const_cast(value), size); +err: + fCore->Unlock(); +} + +void +AudioMixer::UpdateParameterWeb() +{ + fCore->Lock(); + BParameterWeb *web = new BParameterWeb(); + BParameterGroup *top; + BParameterGroup *output; + BParameterGroup *inputs; + BParameterGroup *outputchannels; + BParameterGroup *inputchannels; + BParameterGroup *group; + MixerInput *in; + MixerOutput *out; + + top = web->MakeGroup("Gain Controls"); // top level group + output = top->MakeGroup(""); + inputs = top->MakeGroup(""); + + group = output->MakeGroup(""); + out = fCore->Output(); + if (!out) { + group->MakeNullParameter(PARAM_INPUT(0), B_MEDIA_RAW_AUDIO, "Master Gain", B_WEB_BUFFER_INPUT); + group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC); + } else { + group->MakeNullParameter(PARAM_INPUT(0), B_MEDIA_RAW_AUDIO, "Master Gain", B_WEB_BUFFER_INPUT); + group->MakeNullParameter(PARAM_FORMAT(0), B_MEDIA_RAW_AUDIO, StringForFormat(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_GAIN, "dB", -60.0, 18.0, 0.5) + ->SetChannelCount(out->GetOutputChannelCount()); + group->MakeNullParameter(PARAM_OUTPUT(0), B_MEDIA_RAW_AUDIO, "To Output", B_WEB_BUFFER_OUTPUT); + } + + if (!fCore->Input(0)) { + //group = inputs->MakeGroup(""); + //group->MakeNullParameter(100, B_MEDIA_RAW_AUDIO, "Input", B_WEB_BUFFER_INPUT); + //group->MakeNullParameter(100, B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC); + } + for (int i = 0; (in = fCore->Input(i)); i++) { + group = inputs->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->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->GetMixerChannelCount()); + group->MakeNullParameter(PARAM_OUTPUT(in->ID()), B_MEDIA_RAW_AUDIO, "To Master", B_WEB_BUFFER_OUTPUT); + } + + top = web->MakeGroup("Output Channels"); // top level group + outputchannels = top->MakeGroup(""); + group = outputchannels->MakeGroup(""); + + group->MakeNullParameter(10001, B_MEDIA_RAW_AUDIO, "Output Channel Sources", B_WEB_BUFFER_OUTPUT); + + top = web->MakeGroup("Input Channels"); // top level group + inputchannels = top->MakeGroup(""); + + group = inputchannels->MakeGroup(""); + group->MakeNullParameter(10002, B_MEDIA_RAW_AUDIO, "Input Channel Sources 0", B_WEB_BUFFER_OUTPUT); + + group = inputchannels->MakeGroup(""); + group->MakeNullParameter(10003, B_MEDIA_RAW_AUDIO, "Input Channel Sources 1", B_WEB_BUFFER_OUTPUT); + + SetParameterWeb(web); + + fCore->Unlock(); +} + #if USE_MEDIA_FORMAT_WORKAROUND static void raw_audio_format_specialize(media_raw_audio_format *format, const media_raw_audio_format *other) diff --git a/src/add-ons/media/media-add-ons/mixer/AudioMixer.h b/src/add-ons/media/media-add-ons/mixer/AudioMixer.h index 60fa5f9cb2..44f27ee14d 100644 --- a/src/add-ons/media/media-add-ons/mixer/AudioMixer.h +++ b/src/add-ons/media/media-add-ons/mixer/AudioMixer.h @@ -42,8 +42,7 @@ class AudioMixer : // AudioMixer support - - BParameterWeb * BuildParameterWeb(); // used to create the initial 'master' web + void UpdateParameterWeb(); void MakeWebForInput(char *name, media_format format); void HandleInputBuffer(BBuffer *buffer, bigtime_t lateness); 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 2ff6a7b56e..d2b22e2945 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp @@ -536,7 +536,7 @@ MixerCore::MixThread() reinterpret_cast(buf->Data()) + (i * bytes_per_sample(fOutput->MediaOutput().format.u.raw_audio)), bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio), frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio), - 1.0); + fOutput->GetOutputChannelGain(i)); } PRINT(4, "send buffer, inframes %ld, outframes %ld\n", fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio)); diff --git a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp index 6e2238cb59..6d7b7dd643 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp @@ -1,6 +1,4 @@ -#include #include -#include #include #include // XXX debug only #include "MixerInput.h" @@ -423,6 +421,7 @@ MixerInput::GetMixerChannelCount() void MixerInput::SetMixerChannelGain(int channel, float gain) { + TRACE("SetMixerChannelGain chan %d, gain %.5f\n", channel, gain); if (channel < 0 || channel >= fMixerChannelCount) return; if (gain < 0.0f) diff --git a/src/add-ons/media/media-add-ons/mixer/MixerInput.h b/src/add-ons/media/media-add-ons/mixer/MixerInput.h index 6885ac3922..1624b64a42 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.h @@ -1,6 +1,8 @@ #ifndef _MIXER_INPUT_H #define _MIXER_INPUT_H +#include +#include #include "debug.h" class MixerCore; 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 84973ebeed..8b156cd185 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp @@ -232,6 +232,7 @@ MixerOutput::GetOutputChannelDesignation(int channel) void MixerOutput::SetOutputChannelGain(int channel, float gain) { + TRACE("SetOutputChannelGain chan %d, gain %.5f\n", channel, gain); if (channel < 0 || channel >= fOutputChannelCount) return; fOutputChannelInfo[channel].gain = gain; 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 d13d06298d..e4615e9a72 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp @@ -4,8 +4,12 @@ #include #include "MixerUtils.h" +#include "MixerInput.h" +#include "MixerOutput.h" #include "debug.h" +const char *StringForFormat(const media_format & format, int index); + void string_for_channel_mask(char *str, uint32 mask) { @@ -235,3 +239,53 @@ s_to_us(double secs) { return (bigtime_t) (secs * 1000000.0); } + +const char *StringForFormat(const media_format & format, int index) +{ + static char str[2][50]; + static char fmtstr[2][40]; + const char *fmt; + switch (format.u.raw_audio.format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + fmt = "float"; + 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]; + } else { + fmt = "32 bit"; + } + break; + case media_raw_audio_format::B_AUDIO_SHORT: + fmt = "16 bit"; + break; + case media_raw_audio_format::B_AUDIO_CHAR: + fmt = "8 bit"; + break; + case media_raw_audio_format::B_AUDIO_UCHAR: + fmt = "8 bit unsigned"; + break; + default: + fmt = "unknown"; + break; + } + int a,b; + 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); + else + sprintf(str[index & 1], "%d kHz %s", a, fmt); + return str[index & 1]; +} + +const char *StringForFormat(MixerOutput *output) +{ + return StringForFormat(output->MediaOutput().format, 0); +} + +const char *StringForFormat(MixerInput *input) +{ + return StringForFormat(input->MediaInput().format, 1); +} 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 667866f092..100d8bc647 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerUtils.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerUtils.h @@ -34,4 +34,10 @@ uint32 ChannelTypeToChannelMask(int type); double us_to_s(bigtime_t usecs); 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 + #endif //_MIXER_UTILS_H