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:
beveloper 2003-08-16 17:40:28 +00:00
parent 84e10936b8
commit 26bf7cd399
8 changed files with 707 additions and 46 deletions

View File

@ -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);

View File

@ -41,6 +41,9 @@ class AudioMixer :
void DisableNodeStop();
// AudioMixer support
void ApplySettings();
void UpdateParameterWeb();

View File

@ -41,7 +41,7 @@ do_nothing(void *buffer, size_t bytecount)
{
}
#ifdef __INTEL__
#if __INTEL__
// optimized for IA32 platform

View File

@ -9,6 +9,7 @@ Addon mixer.media_addon : media :
MixerCore.cpp
MixerInput.cpp
MixerOutput.cpp
MixerSettings.cpp
MixerUtils.cpp
Resampler.cpp
;

View File

@ -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));

View File

@ -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;
};

View 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;
}

View 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