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:
parent
84e10936b8
commit
26bf7cd399
@ -59,6 +59,8 @@ AudioMixer::AudioMixer(BMediaAddOn *addOn)
|
||||
fDefaultFormat.u.raw_audio.channel_mask = 0;
|
||||
fDefaultFormat.u.raw_audio.valid_bits = 0;
|
||||
fDefaultFormat.u.raw_audio.matrix_mask = 0;
|
||||
|
||||
ApplySettings();
|
||||
}
|
||||
|
||||
AudioMixer::~AudioMixer()
|
||||
@ -80,6 +82,14 @@ AudioMixer::~AudioMixer()
|
||||
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
|
||||
AudioMixer::DisableNodeStop()
|
||||
{
|
||||
@ -984,7 +994,53 @@ AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change,
|
||||
TRACE("GetParameterValue: id 0x%08x, ioSize %ld\n", id, *ioSize);
|
||||
int param = PARAM(id);
|
||||
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();
|
||||
if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id)))
|
||||
goto err;
|
||||
@ -1060,7 +1116,74 @@ AudioMixer::SetParameterValue(int32 id, bigtime_t when,
|
||||
bool update = false;
|
||||
int param = PARAM(id);
|
||||
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();
|
||||
if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id)))
|
||||
goto err;
|
||||
@ -1186,48 +1309,50 @@ AudioMixer::UpdateParameterWeb()
|
||||
->SetChannelCount(in->GetMixerChannelCount());
|
||||
group->MakeNullParameter(PARAM_STR3(in->ID()), B_MEDIA_RAW_AUDIO, "To Master", B_WEB_BUFFER_OUTPUT);
|
||||
}
|
||||
|
||||
if (fCore->Settings()->AllowOutputChannelRemapping()) {
|
||||
top = web->MakeGroup("Output Mapping"); // top level group
|
||||
outputchannels = top->MakeGroup("");
|
||||
outputchannels->MakeNullParameter(PARAM_STR4(0), B_MEDIA_RAW_AUDIO, "Output Channel Sources", B_GENERIC);
|
||||
|
||||
top = web->MakeGroup("Output Mapping"); // top level group
|
||||
outputchannels = top->MakeGroup("");
|
||||
outputchannels->MakeNullParameter(PARAM_STR4(0), B_MEDIA_RAW_AUDIO, "Output Channel Sources", B_GENERIC);
|
||||
|
||||
group = outputchannels->MakeGroup("");
|
||||
group->MakeNullParameter(PARAM_STR5(0), B_MEDIA_RAW_AUDIO, "Master Output", B_GENERIC);
|
||||
group = group->MakeGroup("");
|
||||
if (!out) {
|
||||
group->MakeNullParameter(PARAM_STR6(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_STR(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_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO,
|
||||
StringForChannelType(buf, src), B_GAIN, "%", 0.0, 100.0, 0.1);
|
||||
group = outputchannels->MakeGroup("");
|
||||
group->MakeNullParameter(PARAM_STR5(0), B_MEDIA_RAW_AUDIO, "Master Output", B_GENERIC);
|
||||
group = group->MakeGroup("");
|
||||
if (!out) {
|
||||
group->MakeNullParameter(PARAM_STR6(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_STR(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_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO,
|
||||
StringForChannelType(buf, src), B_GAIN, "%", 0.0, 100.0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
top = web->MakeGroup("Input Mapping"); // top level group
|
||||
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++) {
|
||||
group = inputchannels->MakeGroup("");
|
||||
group->MakeNullParameter(PARAM_STR4(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_STR(in->ID(), chan), B_MEDIA_RAW_AUDIO,
|
||||
StringForChannelType(buf, in->GetInputChannelType(chan)), B_GENERIC);
|
||||
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);
|
||||
}
|
||||
|
||||
if (fCore->Settings()->AllowInputChannelRemapping()) {
|
||||
top = web->MakeGroup("Input Mapping"); // top level group
|
||||
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++) {
|
||||
group = inputchannels->MakeGroup("");
|
||||
group->MakeNullParameter(PARAM_STR4(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_STR(in->ID(), chan), B_MEDIA_RAW_AUDIO,
|
||||
StringForChannelType(buf, in->GetInputChannelType(chan)), B_GENERIC);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1247,10 +1372,11 @@ AudioMixer::UpdateParameterWeb()
|
||||
|
||||
dp = group->MakeDiscreteParameter(PARAM_ETC(70), B_MEDIA_RAW_AUDIO, "Resampling algorithm", B_INPUT_MUX);
|
||||
dp->AddItem(0, "Drop/repeat samples");
|
||||
/*
|
||||
dp->AddItem(1, "Drop/repeat samples (template based)");
|
||||
dp->AddItem(2, "Linear interpolation");
|
||||
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(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);
|
||||
|
@ -41,6 +41,9 @@ class AudioMixer :
|
||||
void DisableNodeStop();
|
||||
|
||||
// AudioMixer support
|
||||
|
||||
void ApplySettings();
|
||||
|
||||
|
||||
void UpdateParameterWeb();
|
||||
|
||||
|
@ -41,7 +41,7 @@ do_nothing(void *buffer, size_t bytecount)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef __INTEL__
|
||||
#if __INTEL__
|
||||
|
||||
// optimized for IA32 platform
|
||||
|
||||
|
@ -9,6 +9,7 @@ Addon mixer.media_addon : media :
|
||||
MixerCore.cpp
|
||||
MixerInput.cpp
|
||||
MixerOutput.cpp
|
||||
MixerSettings.cpp
|
||||
MixerUtils.cpp
|
||||
Resampler.cpp
|
||||
;
|
||||
|
@ -51,16 +51,20 @@ MixerCore::MixerCore(AudioMixer *node)
|
||||
fMixBufferChannelCount(0),
|
||||
fDoubleRateMixing(DOUBLE_RATE_MIXING),
|
||||
fDownstreamLatency(1),
|
||||
fSettings(new MixerSettings),
|
||||
fNode(node),
|
||||
fBufferGroup(0),
|
||||
fTimeSource(0),
|
||||
fMixThread(-1),
|
||||
fMixThreadWaitSem(-1)
|
||||
fMixThreadWaitSem(-1),
|
||||
fOutputGain(1.0)
|
||||
{
|
||||
}
|
||||
|
||||
MixerCore::~MixerCore()
|
||||
{
|
||||
delete fSettings;
|
||||
|
||||
delete fLocker;
|
||||
delete fInputs;
|
||||
|
||||
@ -83,6 +87,19 @@ MixerCore::~MixerCore()
|
||||
delete fMixBufferChannelTypes;
|
||||
}
|
||||
|
||||
MixerSettings *
|
||||
MixerCore::Settings()
|
||||
{
|
||||
return fSettings;
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::SetOutputAttenuation(float gain)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
fOutputGain = gain;
|
||||
}
|
||||
|
||||
bool
|
||||
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)),
|
||||
bytes_per_frame(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));
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define _MIXER_CORE_H
|
||||
|
||||
#include <Locker.h>
|
||||
#include "MixerSettings.h"
|
||||
|
||||
class AudioMixer;
|
||||
class MixerInput;
|
||||
@ -21,6 +22,13 @@ public:
|
||||
MixerCore(AudioMixer *node);
|
||||
~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 AddOutput(const media_output &output);
|
||||
|
||||
@ -80,11 +88,14 @@ private:
|
||||
|
||||
friend class MixerInput; // XXX debug only
|
||||
|
||||
AudioMixer *fNode;
|
||||
BBufferGroup *fBufferGroup;
|
||||
BTimeSource *fTimeSource;
|
||||
MixerSettings *fSettings;
|
||||
AudioMixer *fNode;
|
||||
BBufferGroup *fBufferGroup;
|
||||
BTimeSource *fTimeSource;
|
||||
thread_id fMixThread;
|
||||
sem_id fMixThreadWaitSem;
|
||||
|
||||
float fOutputGain;
|
||||
};
|
||||
|
||||
|
||||
|
413
src/add-ons/media/media-add-ons/mixer/MixerSettings.cpp
Normal file
413
src/add-ons/media/media-add-ons/mixer/MixerSettings.cpp
Normal file
@ -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;
|
||||
}
|
90
src/add-ons/media/media-add-ons/mixer/MixerSettings.h
Normal file
90
src/add-ons/media/media-add-ons/mixer/MixerSettings.h
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user