added mixer gain controls

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3775 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2003-06-30 23:57:13 +00:00
parent c2c29c32a6
commit 9391f0a552
8 changed files with 267 additions and 23 deletions
@@ -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<int32 *>(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<float *>(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<int32 *>(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<float *>(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<float *>(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<float *>(value)[chan]));
}
}
BroadcastNewParameterValue(when, id, const_cast<void *>(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)
@@ -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);
@@ -536,7 +536,7 @@ MixerCore::MixThread()
reinterpret_cast<char *>(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));
@@ -1,6 +1,4 @@
#include <MediaNode.h>
#include <Buffer.h>
#include <RealtimeAlloc.h>
#include <string.h>
#include <TimeSource.h> // 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)
@@ -1,6 +1,8 @@
#ifndef _MIXER_INPUT_H
#define _MIXER_INPUT_H
#include <RealtimeAlloc.h>
#include <MediaNode.h>
#include "debug.h"
class MixerCore;
@@ -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;
@@ -4,8 +4,12 @@
#include <math.h>
#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);
}
@@ -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