added mixer setup tab functionality and storage of settings
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4287 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -59,6 +59,8 @@ AudioMixer::AudioMixer(BMediaAddOn *addOn)
|
|||||||
fDefaultFormat.u.raw_audio.channel_mask = 0;
|
fDefaultFormat.u.raw_audio.channel_mask = 0;
|
||||||
fDefaultFormat.u.raw_audio.valid_bits = 0;
|
fDefaultFormat.u.raw_audio.valid_bits = 0;
|
||||||
fDefaultFormat.u.raw_audio.matrix_mask = 0;
|
fDefaultFormat.u.raw_audio.matrix_mask = 0;
|
||||||
|
|
||||||
|
ApplySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioMixer::~AudioMixer()
|
AudioMixer::~AudioMixer()
|
||||||
@@ -80,6 +82,14 @@ AudioMixer::~AudioMixer()
|
|||||||
DEBUG_ONLY(fCore = 0; fBufferGroup = 0; fWeb = 0);
|
DEBUG_ONLY(fCore = 0; fBufferGroup = 0; fWeb = 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioMixer::ApplySettings()
|
||||||
|
{
|
||||||
|
fCore->Lock();
|
||||||
|
fCore->SetOutputAttenuation(fCore->Settings()->AttenuateOutput() ? 0.708 : 1.0);
|
||||||
|
fCore->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioMixer::DisableNodeStop()
|
AudioMixer::DisableNodeStop()
|
||||||
{
|
{
|
||||||
@@ -984,7 +994,53 @@ AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change,
|
|||||||
TRACE("GetParameterValue: id 0x%08x, ioSize %ld\n", id, *ioSize);
|
TRACE("GetParameterValue: id 0x%08x, ioSize %ld\n", id, *ioSize);
|
||||||
int param = PARAM(id);
|
int param = PARAM(id);
|
||||||
fCore->Lock();
|
fCore->Lock();
|
||||||
if (param == 0) {
|
if (PARAM_IS_ETC(id)) {
|
||||||
|
switch (ETC(id)) {
|
||||||
|
case 10: // Attenuate mixer output by 3dB
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->AttenuateOutput();
|
||||||
|
break;
|
||||||
|
case 20: // Use non linear gain sliders
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->NonLinearGainSlider();
|
||||||
|
break;
|
||||||
|
case 30: // Display balance control for stereo connections
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->UseBalanceControl();
|
||||||
|
break;
|
||||||
|
case 40: // Allow output channel remapping
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->AllowOutputChannelRemapping();
|
||||||
|
break;
|
||||||
|
case 50: // Allow input channel remapping
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->AllowInputChannelRemapping();
|
||||||
|
break;
|
||||||
|
case 60: // Input gain controls
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->InputGainControls();
|
||||||
|
break;
|
||||||
|
case 70: // Resampling algorithm
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->ResamplingAlgorithm();
|
||||||
|
break;
|
||||||
|
case 80: // Refuse output format changes
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->RefuseOutputFormatChange();
|
||||||
|
break;
|
||||||
|
case 90: // Refuse input format changes
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->RefuseInputFormatChange();
|
||||||
|
break;
|
||||||
|
case 100: // Display performance profiling data
|
||||||
|
*ioSize = sizeof(int32);
|
||||||
|
static_cast<int32 *>(value)[0] = fCore->Settings()->DisplayProfilingData();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("unhandled ETC 0x%08lx\n", id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (param == 0) {
|
||||||
MixerOutput *output = fCore->Output();
|
MixerOutput *output = fCore->Output();
|
||||||
if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id)))
|
if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id)))
|
||||||
goto err;
|
goto err;
|
||||||
@@ -1060,7 +1116,74 @@ AudioMixer::SetParameterValue(int32 id, bigtime_t when,
|
|||||||
bool update = false;
|
bool update = false;
|
||||||
int param = PARAM(id);
|
int param = PARAM(id);
|
||||||
fCore->Lock();
|
fCore->Lock();
|
||||||
if (param == 0) {
|
if (PARAM_IS_ETC(id)) {
|
||||||
|
switch (ETC(id)) {
|
||||||
|
case 10: // Attenuate mixer output by 3dB
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetAttenuateOutput(static_cast<const int32 *>(value)[0]);
|
||||||
|
// this value is special (see MixerCore.h) and we need to notify the core
|
||||||
|
fCore->SetOutputAttenuation((static_cast<const int32 *>(value)[0]) ? 0.708 : 1.0);
|
||||||
|
break;
|
||||||
|
case 20: // Use non linear gain sliders
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetNonLinearGainSlider(static_cast<const int32 *>(value)[0]);
|
||||||
|
update = true; // XXX should use BroadcastChangedParameter()
|
||||||
|
break;
|
||||||
|
case 30: // Display balance control for stereo connections
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetUseBalanceControl(static_cast<const int32 *>(value)[0]);
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
case 40: // Allow output channel remapping
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetAllowOutputChannelRemapping(static_cast<const int32 *>(value)[0]);
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
case 50: // Allow input channel remapping
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetAllowInputChannelRemapping(static_cast<const int32 *>(value)[0]);
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
case 60: // Input gain controls represent
|
||||||
|
// (0, "Physical input channels")
|
||||||
|
// (1, "Virtual output channels")
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetInputGainControls(static_cast<const int32 *>(value)[0]);
|
||||||
|
update = true; // XXX should use BroadcastChangedParameter()
|
||||||
|
break;
|
||||||
|
case 70: // Resampling algorithm
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetResamplingAlgorithm(static_cast<const int32 *>(value)[0]);
|
||||||
|
// XXX tell the core to change the algorithm
|
||||||
|
break;
|
||||||
|
case 80: // Refuse output format changes
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetRefuseOutputFormatChange(static_cast<const int32 *>(value)[0]);
|
||||||
|
break;
|
||||||
|
case 90: // Refuse input format changes
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetRefuseInputFormatChange(static_cast<const int32 *>(value)[0]);
|
||||||
|
break;
|
||||||
|
case 100: // Display performance profiling data
|
||||||
|
if (size != sizeof(int32))
|
||||||
|
goto err;
|
||||||
|
fCore->Settings()->SetDisplayProfilingData(static_cast<const int32 *>(value)[0]);
|
||||||
|
// XXX tell the core to display it
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("unhandled ETC 0x%08lx\n", id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (param == 0) {
|
||||||
MixerOutput *output = fCore->Output();
|
MixerOutput *output = fCore->Output();
|
||||||
if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id)))
|
if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id)))
|
||||||
goto err;
|
goto err;
|
||||||
@@ -1187,47 +1310,49 @@ AudioMixer::UpdateParameterWeb()
|
|||||||
group->MakeNullParameter(PARAM_STR3(in->ID()), B_MEDIA_RAW_AUDIO, "To Master", B_WEB_BUFFER_OUTPUT);
|
group->MakeNullParameter(PARAM_STR3(in->ID()), B_MEDIA_RAW_AUDIO, "To Master", B_WEB_BUFFER_OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
top = web->MakeGroup("Output Mapping"); // top level group
|
if (fCore->Settings()->AllowOutputChannelRemapping()) {
|
||||||
outputchannels = top->MakeGroup("");
|
top = web->MakeGroup("Output Mapping"); // top level group
|
||||||
outputchannels->MakeNullParameter(PARAM_STR4(0), B_MEDIA_RAW_AUDIO, "Output Channel Sources", B_GENERIC);
|
outputchannels = top->MakeGroup("");
|
||||||
|
outputchannels->MakeNullParameter(PARAM_STR4(0), B_MEDIA_RAW_AUDIO, "Output Channel Sources", B_GENERIC);
|
||||||
|
|
||||||
group = outputchannels->MakeGroup("");
|
group = outputchannels->MakeGroup("");
|
||||||
group->MakeNullParameter(PARAM_STR5(0), B_MEDIA_RAW_AUDIO, "Master Output", B_GENERIC);
|
group->MakeNullParameter(PARAM_STR5(0), B_MEDIA_RAW_AUDIO, "Master Output", B_GENERIC);
|
||||||
group = group->MakeGroup("");
|
group = group->MakeGroup("");
|
||||||
if (!out) {
|
if (!out) {
|
||||||
group->MakeNullParameter(PARAM_STR6(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC);
|
group->MakeNullParameter(PARAM_STR6(0), B_MEDIA_RAW_AUDIO, "not connected", B_GENERIC);
|
||||||
} else {
|
} else {
|
||||||
for (int chan = 0; chan < out->GetOutputChannelCount(); chan++) {
|
for (int chan = 0; chan < out->GetOutputChannelCount(); chan++) {
|
||||||
subgroup = group->MakeGroup("");
|
subgroup = group->MakeGroup("");
|
||||||
subgroup->MakeNullParameter(PARAM_SRC_STR(0, chan), B_MEDIA_RAW_AUDIO,
|
subgroup->MakeNullParameter(PARAM_SRC_STR(0, chan), B_MEDIA_RAW_AUDIO,
|
||||||
StringForChannelType(buf, out->GetOutputChannelType(chan)), B_GENERIC);
|
StringForChannelType(buf, out->GetOutputChannelType(chan)), B_GENERIC);
|
||||||
for (int src = 0; src < MAX_CHANNEL_TYPES; src++) {
|
for (int src = 0; src < MAX_CHANNEL_TYPES; src++) {
|
||||||
subsubgroup = subgroup->MakeGroup("");
|
subsubgroup = subgroup->MakeGroup("");
|
||||||
subsubgroup->MakeDiscreteParameter(PARAM_SRC_ENABLE(0, chan, src), B_MEDIA_RAW_AUDIO, "", B_ENABLE);
|
subsubgroup->MakeDiscreteParameter(PARAM_SRC_ENABLE(0, chan, src), B_MEDIA_RAW_AUDIO, "", B_ENABLE);
|
||||||
subsubgroup->MakeContinuousParameter(PARAM_SRC_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO,
|
subsubgroup->MakeContinuousParameter(PARAM_SRC_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO,
|
||||||
StringForChannelType(buf, src), B_GAIN, "%", 0.0, 100.0, 0.1);
|
StringForChannelType(buf, src), B_GAIN, "%", 0.0, 100.0, 0.1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
top = web->MakeGroup("Input Mapping"); // top level group
|
if (fCore->Settings()->AllowInputChannelRemapping()) {
|
||||||
inputchannels = top->MakeGroup("");
|
top = web->MakeGroup("Input Mapping"); // top level group
|
||||||
inputchannels->MakeNullParameter(PARAM_STR7(0), B_MEDIA_RAW_AUDIO, "Input Channel Destinations", B_GENERIC);
|
inputchannels = top->MakeGroup("");
|
||||||
|
inputchannels->MakeNullParameter(PARAM_STR7(0), 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++) {
|
||||||
group = inputchannels->MakeGroup("");
|
group = inputchannels->MakeGroup("");
|
||||||
group->MakeNullParameter(PARAM_STR4(in->ID()), B_MEDIA_RAW_AUDIO, in->MediaInput().name, B_GENERIC);
|
group->MakeNullParameter(PARAM_STR4(in->ID()), B_MEDIA_RAW_AUDIO, in->MediaInput().name, B_GENERIC);
|
||||||
group = group->MakeGroup("");
|
group = group->MakeGroup("");
|
||||||
|
|
||||||
for (int chan = 0; chan < in->GetInputChannelCount(); chan++) {
|
for (int chan = 0; chan < in->GetInputChannelCount(); chan++) {
|
||||||
subgroup = group->MakeGroup("");
|
subgroup = group->MakeGroup("");
|
||||||
subgroup->MakeNullParameter(PARAM_DST_STR(in->ID(), chan), B_MEDIA_RAW_AUDIO,
|
subgroup->MakeNullParameter(PARAM_DST_STR(in->ID(), chan), B_MEDIA_RAW_AUDIO,
|
||||||
StringForChannelType(buf, in->GetInputChannelType(chan)), B_GENERIC);
|
StringForChannelType(buf, in->GetInputChannelType(chan)), B_GENERIC);
|
||||||
for (int dst = 0; dst < MAX_CHANNEL_TYPES; dst++) {
|
for (int dst = 0; dst < MAX_CHANNEL_TYPES; dst++) {
|
||||||
subgroup->MakeDiscreteParameter(PARAM_DST_ENABLE(in->ID(), chan, dst), B_MEDIA_RAW_AUDIO, StringForChannelType(buf, dst), B_ENABLE);
|
subgroup->MakeDiscreteParameter(PARAM_DST_ENABLE(in->ID(), chan, dst), B_MEDIA_RAW_AUDIO, StringForChannelType(buf, dst), B_ENABLE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1247,10 +1372,11 @@ AudioMixer::UpdateParameterWeb()
|
|||||||
|
|
||||||
dp = group->MakeDiscreteParameter(PARAM_ETC(70), B_MEDIA_RAW_AUDIO, "Resampling algorithm", B_INPUT_MUX);
|
dp = group->MakeDiscreteParameter(PARAM_ETC(70), B_MEDIA_RAW_AUDIO, "Resampling algorithm", B_INPUT_MUX);
|
||||||
dp->AddItem(0, "Drop/repeat samples");
|
dp->AddItem(0, "Drop/repeat samples");
|
||||||
|
/*
|
||||||
dp->AddItem(1, "Drop/repeat samples (template based)");
|
dp->AddItem(1, "Drop/repeat samples (template based)");
|
||||||
dp->AddItem(2, "Linear interpolation");
|
dp->AddItem(2, "Linear interpolation");
|
||||||
dp->AddItem(3, "17th order filtering");
|
dp->AddItem(3, "17th order filtering");
|
||||||
|
*/
|
||||||
group->MakeDiscreteParameter(PARAM_ETC(80), B_MEDIA_RAW_AUDIO, "Refuse output format changes", B_ENABLE);
|
group->MakeDiscreteParameter(PARAM_ETC(80), B_MEDIA_RAW_AUDIO, "Refuse output format changes", B_ENABLE);
|
||||||
group->MakeDiscreteParameter(PARAM_ETC(90), B_MEDIA_RAW_AUDIO, "Refuse input format changes", B_ENABLE);
|
group->MakeDiscreteParameter(PARAM_ETC(90), B_MEDIA_RAW_AUDIO, "Refuse input format changes", B_ENABLE);
|
||||||
group->MakeDiscreteParameter(PARAM_ETC(100), B_MEDIA_RAW_AUDIO, "Display performance profiling data", B_ENABLE);
|
group->MakeDiscreteParameter(PARAM_ETC(100), B_MEDIA_RAW_AUDIO, "Display performance profiling data", B_ENABLE);
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ class AudioMixer :
|
|||||||
|
|
||||||
// AudioMixer support
|
// AudioMixer support
|
||||||
|
|
||||||
|
void ApplySettings();
|
||||||
|
|
||||||
|
|
||||||
void UpdateParameterWeb();
|
void UpdateParameterWeb();
|
||||||
|
|
||||||
void HandleInputBuffer(BBuffer *buffer, bigtime_t lateness);
|
void HandleInputBuffer(BBuffer *buffer, bigtime_t lateness);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ do_nothing(void *buffer, size_t bytecount)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __INTEL__
|
#if __INTEL__
|
||||||
|
|
||||||
// optimized for IA32 platform
|
// optimized for IA32 platform
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ Addon mixer.media_addon : media :
|
|||||||
MixerCore.cpp
|
MixerCore.cpp
|
||||||
MixerInput.cpp
|
MixerInput.cpp
|
||||||
MixerOutput.cpp
|
MixerOutput.cpp
|
||||||
|
MixerSettings.cpp
|
||||||
MixerUtils.cpp
|
MixerUtils.cpp
|
||||||
Resampler.cpp
|
Resampler.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -51,16 +51,20 @@ MixerCore::MixerCore(AudioMixer *node)
|
|||||||
fMixBufferChannelCount(0),
|
fMixBufferChannelCount(0),
|
||||||
fDoubleRateMixing(DOUBLE_RATE_MIXING),
|
fDoubleRateMixing(DOUBLE_RATE_MIXING),
|
||||||
fDownstreamLatency(1),
|
fDownstreamLatency(1),
|
||||||
|
fSettings(new MixerSettings),
|
||||||
fNode(node),
|
fNode(node),
|
||||||
fBufferGroup(0),
|
fBufferGroup(0),
|
||||||
fTimeSource(0),
|
fTimeSource(0),
|
||||||
fMixThread(-1),
|
fMixThread(-1),
|
||||||
fMixThreadWaitSem(-1)
|
fMixThreadWaitSem(-1),
|
||||||
|
fOutputGain(1.0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MixerCore::~MixerCore()
|
MixerCore::~MixerCore()
|
||||||
{
|
{
|
||||||
|
delete fSettings;
|
||||||
|
|
||||||
delete fLocker;
|
delete fLocker;
|
||||||
delete fInputs;
|
delete fInputs;
|
||||||
|
|
||||||
@@ -83,6 +87,19 @@ MixerCore::~MixerCore()
|
|||||||
delete fMixBufferChannelTypes;
|
delete fMixBufferChannelTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MixerSettings *
|
||||||
|
MixerCore::Settings()
|
||||||
|
{
|
||||||
|
return fSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerCore::SetOutputAttenuation(float gain)
|
||||||
|
{
|
||||||
|
ASSERT_LOCKED();
|
||||||
|
fOutputGain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MixerCore::AddInput(const media_input &input)
|
MixerCore::AddInput(const media_input &input)
|
||||||
{
|
{
|
||||||
@@ -542,7 +559,7 @@ MixerCore::MixThread()
|
|||||||
reinterpret_cast<char *>(buf->Data()) + (i * bytes_per_sample(fOutput->MediaOutput().format.u.raw_audio)),
|
reinterpret_cast<char *>(buf->Data()) + (i * bytes_per_sample(fOutput->MediaOutput().format.u.raw_audio)),
|
||||||
bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio),
|
bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio),
|
||||||
frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio),
|
frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio),
|
||||||
fOutput->GetOutputChannelGain(i));
|
fOutputGain * fOutput->GetOutputChannelGain(i));
|
||||||
}
|
}
|
||||||
PRINT(4, "send buffer, inframes %ld, outframes %ld\n", fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio));
|
PRINT(4, "send buffer, inframes %ld, outframes %ld\n", fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio));
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define _MIXER_CORE_H
|
#define _MIXER_CORE_H
|
||||||
|
|
||||||
#include <Locker.h>
|
#include <Locker.h>
|
||||||
|
#include "MixerSettings.h"
|
||||||
|
|
||||||
class AudioMixer;
|
class AudioMixer;
|
||||||
class MixerInput;
|
class MixerInput;
|
||||||
@@ -21,6 +22,13 @@ public:
|
|||||||
MixerCore(AudioMixer *node);
|
MixerCore(AudioMixer *node);
|
||||||
~MixerCore();
|
~MixerCore();
|
||||||
|
|
||||||
|
MixerSettings *Settings();
|
||||||
|
|
||||||
|
// To avoid calling Settings()->AttenuateOutput() for every outgoing
|
||||||
|
// buffer, this setting is cached in fOutputGain and must be set by
|
||||||
|
// the audio mixer node using SetOutputAttenuation()
|
||||||
|
void SetOutputAttenuation(float gain);
|
||||||
|
|
||||||
bool AddInput(const media_input &input);
|
bool AddInput(const media_input &input);
|
||||||
bool AddOutput(const media_output &output);
|
bool AddOutput(const media_output &output);
|
||||||
|
|
||||||
@@ -80,11 +88,14 @@ private:
|
|||||||
|
|
||||||
friend class MixerInput; // XXX debug only
|
friend class MixerInput; // XXX debug only
|
||||||
|
|
||||||
AudioMixer *fNode;
|
MixerSettings *fSettings;
|
||||||
BBufferGroup *fBufferGroup;
|
AudioMixer *fNode;
|
||||||
BTimeSource *fTimeSource;
|
BBufferGroup *fBufferGroup;
|
||||||
|
BTimeSource *fTimeSource;
|
||||||
thread_id fMixThread;
|
thread_id fMixThread;
|
||||||
sem_id fMixThreadWaitSem;
|
sem_id fMixThreadWaitSem;
|
||||||
|
|
||||||
|
float fOutputGain;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,413 @@
|
|||||||
|
#include <MediaDefs.h>
|
||||||
|
#include <Locker.h>
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include "MixerCore.h"
|
||||||
|
#include "MixerInput.h"
|
||||||
|
#include "MixerOutput.h"
|
||||||
|
#include "MixerSettings.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#define SAVE_DELAY 8000000 // delay saving of settings for 8s
|
||||||
|
#define SAVE_RUNTIME 40000000 // stop save thread after 40s inactivity
|
||||||
|
|
||||||
|
MixerSettings::MixerSettings()
|
||||||
|
: fLocker(new BLocker),
|
||||||
|
fSettingsDirty(false),
|
||||||
|
fSettingsLastChange(0),
|
||||||
|
fSaveThread(-1),
|
||||||
|
fSaveThreadWaitSem(-1)
|
||||||
|
{
|
||||||
|
Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
MixerSettings::~MixerSettings()
|
||||||
|
{
|
||||||
|
StopDeferredSave();
|
||||||
|
if (fSettingsDirty)
|
||||||
|
Save();
|
||||||
|
delete fLocker;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerSettings::AttenuateOutput()
|
||||||
|
{
|
||||||
|
bool temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.AttenuateOutput;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetAttenuateOutput(bool yesno)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.AttenuateOutput = yesno;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerSettings::NonLinearGainSlider()
|
||||||
|
{
|
||||||
|
bool temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.NonLinearGainSlider;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetNonLinearGainSlider(bool yesno)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.NonLinearGainSlider = yesno;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerSettings::UseBalanceControl()
|
||||||
|
{
|
||||||
|
bool temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.UseBalanceControl;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetUseBalanceControl(bool yesno)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.UseBalanceControl = yesno;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerSettings::AllowOutputChannelRemapping()
|
||||||
|
{
|
||||||
|
bool temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.AllowOutputChannelRemapping;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetAllowOutputChannelRemapping(bool yesno)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.AllowOutputChannelRemapping = yesno;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerSettings::AllowInputChannelRemapping()
|
||||||
|
{
|
||||||
|
bool temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.AllowInputChannelRemapping;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetAllowInputChannelRemapping(bool yesno)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.AllowInputChannelRemapping = yesno;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MixerSettings::InputGainControls()
|
||||||
|
{
|
||||||
|
int temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.InputGainControls;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetInputGainControls(int value)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.InputGainControls = value;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MixerSettings::ResamplingAlgorithm()
|
||||||
|
{
|
||||||
|
int temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.ResamplingAlgorithm;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetResamplingAlgorithm(int value)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.ResamplingAlgorithm = value;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerSettings::RefuseOutputFormatChange()
|
||||||
|
{
|
||||||
|
bool temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.RefuseOutputFormatChange;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetRefuseOutputFormatChange(bool yesno)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.RefuseOutputFormatChange = yesno;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerSettings::RefuseInputFormatChange()
|
||||||
|
{
|
||||||
|
bool temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.RefuseInputFormatChange;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetRefuseInputFormatChange(bool yesno)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.RefuseInputFormatChange = yesno;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerSettings::DisplayProfilingData()
|
||||||
|
{
|
||||||
|
bool temp;
|
||||||
|
fLocker->Lock();
|
||||||
|
temp = fSettings.DisplayProfilingData;
|
||||||
|
fLocker->Unlock();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SetDisplayProfilingData(bool yesno)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fSettings.DisplayProfilingData = yesno;
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SaveGain(MixerInput *input)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::LoadGain(MixerInput *input)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SaveGain(MixerOutput *output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::LoadGain(MixerOutput *output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SaveGainSetting(const char *name, uint32 channel_mask, const float *gain, int gain_count)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
|
||||||
|
// XXX work
|
||||||
|
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::LoadGainSetting(const char *name, uint32 channel_mask, float *gain, int gain_count)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
|
||||||
|
// XXX work
|
||||||
|
|
||||||
|
fLocker->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SaveSetting(const char *name, int value)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
|
||||||
|
// XXX work
|
||||||
|
|
||||||
|
fLocker->Unlock();
|
||||||
|
StartDeferredSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::LoadSetting(const char *name, int *value, int default_value /* = 0 */)
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
|
||||||
|
// XXX work
|
||||||
|
|
||||||
|
fLocker->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::Save()
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
TRACE("MixerSettings: SAVE!\n");
|
||||||
|
|
||||||
|
|
||||||
|
// XXX work
|
||||||
|
|
||||||
|
fSettingsDirty = false;
|
||||||
|
fLocker->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::Load()
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
|
||||||
|
// XXX work
|
||||||
|
|
||||||
|
fSettings.AttenuateOutput = true;
|
||||||
|
fSettings.NonLinearGainSlider = true;
|
||||||
|
fSettings.UseBalanceControl = false;
|
||||||
|
fSettings.AllowOutputChannelRemapping = false;
|
||||||
|
fSettings.AllowInputChannelRemapping = false;
|
||||||
|
fSettings.InputGainControls = 0;
|
||||||
|
fSettings.ResamplingAlgorithm = 0;
|
||||||
|
fSettings.RefuseOutputFormatChange = false;
|
||||||
|
fSettings.RefuseInputFormatChange = false;
|
||||||
|
fSettings.DisplayProfilingData = false;
|
||||||
|
|
||||||
|
fLocker->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::StartDeferredSave()
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
|
||||||
|
fSettingsDirty = true;
|
||||||
|
fSettingsLastChange = system_time();
|
||||||
|
|
||||||
|
if (fSaveThread < 0) {
|
||||||
|
ASSERT(fSaveThreadWaitSem < 0);
|
||||||
|
fSaveThreadWaitSem = create_sem(0, "save thread wait");
|
||||||
|
if (fSaveThreadWaitSem < B_OK) {
|
||||||
|
ERROR("MixerSettings: can't create semaphore\n");
|
||||||
|
Save();
|
||||||
|
fLocker->Unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fSaveThread = spawn_thread(_save_thread_, "deferred settings save", 7, this);
|
||||||
|
if (fSaveThread < B_OK) {
|
||||||
|
ERROR("MixerSettings: can't spawn thread\n");
|
||||||
|
delete_sem(fSaveThreadWaitSem);
|
||||||
|
fSaveThreadWaitSem = -1;
|
||||||
|
Save();
|
||||||
|
fLocker->Unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fLocker->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::StopDeferredSave()
|
||||||
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
|
||||||
|
if (fSaveThread > 0) {
|
||||||
|
ASSERT(fSaveThreadWaitSem > 0);
|
||||||
|
|
||||||
|
status_t unused;
|
||||||
|
delete_sem(fSaveThreadWaitSem);
|
||||||
|
wait_for_thread(fSaveThread, &unused);
|
||||||
|
|
||||||
|
fSaveThread = -1;
|
||||||
|
fSaveThreadWaitSem = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fLocker->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerSettings::SaveThread()
|
||||||
|
{
|
||||||
|
bigtime_t timeout;
|
||||||
|
status_t rv;
|
||||||
|
|
||||||
|
TRACE("MixerSettings: save thread started\n");
|
||||||
|
|
||||||
|
fLocker->Lock();
|
||||||
|
timeout = fSettingsLastChange + SAVE_DELAY;
|
||||||
|
fLocker->Unlock();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
rv = acquire_sem_etc(fSaveThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, timeout);
|
||||||
|
if (rv == B_INTERRUPTED)
|
||||||
|
continue;
|
||||||
|
if (rv != B_TIMED_OUT && rv < B_OK)
|
||||||
|
break;
|
||||||
|
if (B_OK != fLocker->LockWithTimeout(200000))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TRACE("MixerSettings: save thread running\n");
|
||||||
|
|
||||||
|
bigtime_t delta = system_time() - fSettingsLastChange;
|
||||||
|
|
||||||
|
if (fSettingsDirty && delta > SAVE_DELAY) {
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta > SAVE_RUNTIME) {
|
||||||
|
fLocker->Unlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = system_time() + SAVE_DELAY;
|
||||||
|
fLocker->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("MixerSettings: save thread ended\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
MixerSettings::_save_thread_(void *arg)
|
||||||
|
{
|
||||||
|
static_cast<MixerSettings *>(arg)->SaveThread();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#ifndef _MIXER_SETTINGS_H
|
||||||
|
#define _MIXER_SETTINGS_H
|
||||||
|
|
||||||
|
class MixerInput;
|
||||||
|
class MixerOutput;
|
||||||
|
|
||||||
|
class MixerSettings
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MixerSettings();
|
||||||
|
~MixerSettings();
|
||||||
|
|
||||||
|
bool AttenuateOutput();
|
||||||
|
void SetAttenuateOutput(bool yesno);
|
||||||
|
|
||||||
|
bool NonLinearGainSlider();
|
||||||
|
void SetNonLinearGainSlider(bool yesno);
|
||||||
|
|
||||||
|
bool UseBalanceControl();
|
||||||
|
void SetUseBalanceControl(bool yesno);
|
||||||
|
|
||||||
|
bool AllowOutputChannelRemapping();
|
||||||
|
void SetAllowOutputChannelRemapping(bool yesno);
|
||||||
|
|
||||||
|
bool AllowInputChannelRemapping();
|
||||||
|
void SetAllowInputChannelRemapping(bool yesno);
|
||||||
|
|
||||||
|
int InputGainControls();
|
||||||
|
void SetInputGainControls(int value);
|
||||||
|
|
||||||
|
int ResamplingAlgorithm();
|
||||||
|
void SetResamplingAlgorithm(int value);
|
||||||
|
|
||||||
|
bool RefuseOutputFormatChange();
|
||||||
|
void SetRefuseOutputFormatChange(bool yesno);
|
||||||
|
|
||||||
|
bool RefuseInputFormatChange();
|
||||||
|
void SetRefuseInputFormatChange(bool yesno);
|
||||||
|
|
||||||
|
bool DisplayProfilingData();
|
||||||
|
void SetDisplayProfilingData(bool yesno);
|
||||||
|
|
||||||
|
void SaveGain(MixerInput *input);
|
||||||
|
void LoadGain(MixerInput *input);
|
||||||
|
|
||||||
|
void SaveGain(MixerOutput *output);
|
||||||
|
void LoadGain(MixerOutput *output);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void SaveGainSetting(const char *name, uint32 channel_mask, const float *gain, int gain_count);
|
||||||
|
void LoadGainSetting(const char *name, uint32 channel_mask, float *gain, int gain_count);
|
||||||
|
|
||||||
|
void SaveSetting(const char *name, int value);
|
||||||
|
void LoadSetting(const char *name, int *value, int default_value = 0);
|
||||||
|
|
||||||
|
void StartDeferredSave();
|
||||||
|
void StopDeferredSave();
|
||||||
|
|
||||||
|
void Save();
|
||||||
|
void Load();
|
||||||
|
|
||||||
|
static int32 _save_thread_(void *arg);
|
||||||
|
void SaveThread();
|
||||||
|
|
||||||
|
BLocker *fLocker;
|
||||||
|
bool fSettingsDirty;
|
||||||
|
bigtime_t fSettingsLastChange;
|
||||||
|
|
||||||
|
thread_id fSaveThread;
|
||||||
|
sem_id fSaveThreadWaitSem;
|
||||||
|
|
||||||
|
struct settings
|
||||||
|
{
|
||||||
|
bool AttenuateOutput;
|
||||||
|
bool NonLinearGainSlider;
|
||||||
|
bool UseBalanceControl;
|
||||||
|
bool AllowOutputChannelRemapping;
|
||||||
|
bool AllowInputChannelRemapping;
|
||||||
|
int InputGainControls;
|
||||||
|
int ResamplingAlgorithm;
|
||||||
|
bool RefuseOutputFormatChange;
|
||||||
|
bool RefuseInputFormatChange;
|
||||||
|
bool DisplayProfilingData;
|
||||||
|
};
|
||||||
|
|
||||||
|
settings fSettings;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_MIXER_SETTINGS_H
|
||||||
Reference in New Issue
Block a user