All pastes #2009196 Raw Edit

Something

public text v1 · immutable
#2009196 ·published 2010-12-03 03:19 UTC
rendered paste body
diff --git a/mythtv/libs/libmyth/audio/audiooutpututil.cpp b/mythtv/libs/libmyth/audio/audiooutpututil.cpp
index d9af347..2d096d2 100644
--- a/mythtv/libs/libmyth/audio/audiooutpututil.cpp
+++ b/mythtv/libs/libmyth/audio/audiooutpututil.cpp
@@ -3,6 +3,8 @@
 using namespace std;
 #include "mythconfig.h"
 #include "audiooutpututil.h"
+#include <sys/types.h>
+#include <byteswap.h>
 
 #define LOC QString("AO: ")
 #define LOC_ERR QString("AO, ERROR: ")
@@ -629,3 +631,41 @@ void AudioOutputUtil::MuteChannel(int obits, int channels, int ch,
     else
         _MuteChannel((int *)buffer, channels, ch, frames);
 }
+
+#if HAVE_BIGENDIAN
+#define LE_SHORT(v)		bswap_16(v)
+#else
+#define LE_SHORT(v)		(v)
+#endif
+
+char *AudioOutputUtil::GeneratePinkSamples(char *frames, int channels,
+                                           int channel,
+                                           int count)
+{
+    pink_noise_t pink;
+
+    initialize_pink_noise(&pink, 16);
+  
+    double   res;
+    int32_t  ires;
+    int16_t *samp16 = (int16_t*) frames;
+
+    while (count-- > 0)
+    {
+        for(int chn = 0 ; chn < channels; chn++)
+        {
+            if (chn==channel)
+            {
+                res = generate_pink_noise_sample(&pink) * 0x03fffffff; /* Don't use MAX volume */
+                ires = res;
+                *samp16++ = LE_SHORT(ires >> 16);
+            }
+            else
+            {
+                *samp16++ = 0;
+            }
+        }
+    }    
+    return frames;
+}
+  
diff --git a/mythtv/libs/libmyth/audio/audiooutpututil.h b/mythtv/libs/libmyth/audio/audiooutpututil.h
index 858fa6e..8262f8f 100644
--- a/mythtv/libs/libmyth/audio/audiooutpututil.h
+++ b/mythtv/libs/libmyth/audio/audiooutpututil.h
@@ -4,6 +4,9 @@
 using namespace std;
 #include "mythverbose.h"
 #include "audiooutputsettings.h"
+extern "C" {
+#include "pink.h"
+}
 
 class MPUBLIC AudioOutputUtil
 {
@@ -16,6 +19,8 @@ class MPUBLIC AudioOutputUtil
                              bool music, bool upmix);
     static void MuteChannel(int obits, int channels, int ch,
                             void *buffer, int bytes);
+    static char *GeneratePinkSamples(char *frames, int channels,
+                                     int channel, int count);
 };
 
 #endif
diff --git a/mythtv/libs/libmyth/audio/pink.c b/mythtv/libs/libmyth/audio/pink.c
new file mode 100644
index 0000000..ef30755
--- /dev/null
+++ b/mythtv/libs/libmyth/audio/pink.c
@@ -0,0 +1,96 @@
+/*
+  patest_pink.c
+
+  generate Pink Noise using Gardner method.
+  Optimization suggested by James McCartney uses a tree
+  to select which random value to replace.
+
+  x x x x x x x x x x x x x x x x 
+  x   x   x   x   x   x   x   x   
+  x       x       x       x       
+  x               x               
+  x                               
+
+  Tree is generated by counting trailing zeros in an increasing index.
+  When the index is zero, no random number is selected.
+
+  This program uses the Portable Audio library which is under development.
+  For more information see:   http://www.audiomulch.com/portaudio/
+
+  Author: Phil Burk, http://www.softsynth.com
+	
+  Revision History:
+
+  Copyleft 1999 Phil Burk - No rights reserved.
+*/
+
+#include <stdio.h>
+#include <math.h>
+#include "pink.h"
+
+/************************************************************/
+/* Calculate pseudo-random 32 bit number based on linear congruential method. */
+static unsigned long generate_random_number( void )
+{
+    static unsigned long rand_seed = 22222;  /* Change this for different random sequences. */
+    rand_seed = (rand_seed * 196314165) + 907633515;
+    return rand_seed;
+}
+
+/* Setup PinkNoise structure for N rows of generators. */
+void initialize_pink_noise( pink_noise_t *pink, int num_rows )
+{
+    int i;
+    long pmax;
+    pink->pink_index = 0;
+    pink->pink_index_mask = (1<<num_rows) - 1;
+/* Calculate maximum possible signed random value. Extra 1 for white noise always added. */
+    pmax = (num_rows + 1) * (1<<(PINK_RANDOM_BITS-1));
+    pink->pink_scalar = 1.0f / pmax;
+/* Initialize rows. */
+    for( i=0; i<num_rows; i++ ) pink->pink_rows[i] = 0;
+    pink->pink_running_sum = 0;
+}
+
+/* generate Pink noise values between -1.0 and +1.0 */
+float generate_pink_noise_sample( pink_noise_t *pink )
+{
+    long new_random;
+    long sum;
+    float output;
+
+/* Increment and mask index. */
+    pink->pink_index = (pink->pink_index + 1) & pink->pink_index_mask;
+
+/* If index is zero, don't update any random values. */
+    if( pink->pink_index != 0 )
+    {
+	/* Determine how many trailing zeros in PinkIndex. */
+	/* This algorithm will hang if n==0 so test first. */
+	int num_zeros = 0;
+	int n = pink->pink_index;
+	while( (n & 1) == 0 )
+	{
+	    n = n >> 1;
+	    num_zeros++;
+	}
+
+	/* Replace the indexed ROWS random value.
+	 * Subtract and add back to Running_sum instead of adding all the random
+	 * values together. Only one changes each time.
+	 */
+	pink->pink_running_sum -= pink->pink_rows[num_zeros];
+	new_random = ((long)generate_random_number()) >> PINK_RANDOM_SHIFT;
+	pink->pink_running_sum += new_random;
+	pink->pink_rows[num_zeros] = new_random;
+    }
+	
+/* Add extra white noise value. */
+    new_random = ((long)generate_random_number()) >> PINK_RANDOM_SHIFT;
+    sum = pink->pink_running_sum + new_random;
+
+/* Scale to range of -1.0 to 0.9999. */
+    output = pink->pink_scalar * sum;
+
+    return output;
+}
diff --git a/mythtv/libs/libmyth/audio/pink.h b/mythtv/libs/libmyth/audio/pink.h
new file mode 100644
index 0000000..510bd33
--- /dev/null
+++ b/mythtv/libs/libmyth/audio/pink.h
@@ -0,0 +1,22 @@
+#ifndef AUDIOPINK
+#define AUDIOPINK
+
+#include "mythexp.h"
+
+#define PINK_MAX_RANDOM_ROWS   (30)
+#define PINK_RANDOM_BITS       (24)
+#define PINK_RANDOM_SHIFT      ((sizeof(long)*8)-PINK_RANDOM_BITS)
+
+typedef struct
+{
+  long      pink_rows[PINK_MAX_RANDOM_ROWS];
+  long      pink_running_sum;   /* Used to optimize summing of generators. */
+  int       pink_index;        /* Incremented each sample. */
+  int       pink_index_mask;    /* Index wrapped by ANDing with this mask. */
+  float     pink_scalar;       /* Used to scale within range of -1.0 to +1.0 */
+} pink_noise_t;
+
+void initialize_pink_noise( pink_noise_t *pink, int num_rows );
+float generate_pink_noise_sample( pink_noise_t *pink );
+
+#endif
diff --git a/mythtv/libs/libmyth/libmyth.pro b/mythtv/libs/libmyth/libmyth.pro
index 2178699..afa8971 100644
--- a/mythtv/libs/libmyth/libmyth.pro
+++ b/mythtv/libs/libmyth/libmyth.pro
@@ -14,7 +14,7 @@ QMAKE_CLEAN += $(TARGET) $(TARGETA) $(TARGETD) $(TARGET0) $(TARGET1) $(TARGET2)
 HEADERS += audio/audiooutput.h audio/audiooutputbase.h audio/audiooutputnull.h
 HEADERS += audio/audiooutpututil.h audio/audiooutputdownmix.h
 HEADERS += audio/audiooutputdigitalencoder.h audio/audiosettings.h
-HEADERS += audio/audiooutputsettings.h
+HEADERS += audio/audiooutputsettings.h audio/pink.h
 HEADERS += backendselect.h dbsettings.h dialogbox.h
 HEADERS += generictree.h langsettings.h
 HEADERS += managedlist.h mythconfigdialogs.h mythconfiggroups.h
@@ -39,7 +39,7 @@ HEADERS += rssparse.h             netutils.h
 # remove when everything is switched to mythui
 HEADERS += virtualkeyboard_qt.h
 
-SOURCES += audio/audiooutput.cpp audio/audiooutputbase.cpp
+SOURCES += audio/audiooutput.cpp audio/audiooutputbase.cpp audio/pink.c
 SOURCES += audio/audiooutputnull.cpp audio/audiooutputdigitalencoder.cpp
 SOURCES += audio/audiooutpututil.cpp audio/audiooutputdownmix.cpp
 SOURCES += audio/audiosettings.cpp audio/audiooutputsettings.cpp
diff --git a/mythtv/programs/mythfrontend/audiosettings.cpp b/mythtv/programs/mythfrontend/audiosettings.cpp
new file mode 100644
index 0000000..0e19f97
--- /dev/null
+++ b/mythtv/programs/mythfrontend/audiosettings.cpp
@@ -0,0 +1,804 @@
+
+// -*- Mode: c++ -*-
+
+// Standard UNIX C headers
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+// Qt headers
+#include <QCoreApplication>
+#include <QEvent>
+#include <QDialog>
+#include <QCursor>
+#include <QDir>
+#include <QThread>
+
+// MythTV headers
+#include "mythconfig.h"
+#include "mythcorecontext.h"
+#include "mythverbose.h"
+#include "audiosettings.h"
+#include "audiooutpututil.h"
+#include "mythscreenstack.h"
+#include "mythprogressdialog.h"
+#include "mythdialogbox.h"
+
+class TriggeredItem : public TriggeredConfigurationGroup
+{
+  public:
+    TriggeredItem(Setting *checkbox, ConfigurationGroup *group) :
+        TriggeredConfigurationGroup(false, false, false, false)
+    {
+        setTrigger(checkbox);
+
+        addTarget("1", group);
+        addTarget("0", new VerticalConfigurationGroup(true));
+    }
+    TriggeredItem(Setting *checkbox, Setting *setting) :
+        TriggeredConfigurationGroup(false, false, false, false)
+    {
+        setTrigger(checkbox);
+
+        addTarget("1", setting);
+        addTarget("0", new VerticalConfigurationGroup(false, false));
+    }
+};
+
+AudioDeviceComboBox::AudioDeviceComboBox(AudioConfigSettings *parent) :
+    HostComboBox("AudioOutputDevice", true), m_parent(parent)
+{
+    setLabel(QObject::tr("Audio output device"));
+#ifdef USING_ALSA
+    QString dflt = "ALSA:default";
+#elif USING_PULSEOUTPUT
+    QString dflt = "PulseAudio:default";
+#elif CONFIG_DARWIN
+    QString dflt = "CoreAudio:";
+#elif USING_MINGW
+    QString dflt = "Windows:";
+#else
+    QString dflt = "NULL";
+#endif
+    QString current = gCoreContext->GetSetting(QString("AudioOutputDevice"),
+                                               dflt);
+    addSelection(current, current, true);
+
+    connect(this, SIGNAL(valueChanged(const QString&)),
+            this, SLOT(AudioDescriptionHelp(const QString&)));
+}
+
+void AudioDeviceComboBox::AudioRescan()
+{
+    AudioOutput::ADCVect &vect = m_parent->AudioDeviceVect();
+    AudioOutput::ADCVect::const_iterator it;
+
+    if (vect.empty())
+        return;
+
+    QString value = getValue();
+    clearSelections();
+    resetMaxCount(vect.size());
+
+    bool found = false;
+    for (it = vect.begin(); it != vect.end(); it++)
+        addSelection(it->name, it->name,
+                     value == it->name ? (found = true) : false);
+    if (!found)
+    {
+        resetMaxCount(vect.size()+1);
+        addSelection(value, value, true);
+    }
+        // For some reason, it adds an empty entry, remove it
+    removeSelection(QString::null);
+}
+
+void AudioDeviceComboBox::AudioDescriptionHelp(const QString &device)
+{
+    QString desc = m_parent->AudioDeviceMap().value(device).desc;
+    setHelpText(desc);
+}
+
+AudioConfigSettings::AudioConfigSettings() :
+    VerticalConfigurationGroup(false, true, false, false),
+    m_OutputDevice(NULL),   m_MaxAudioChannels(NULL),
+    m_AudioUpmix(NULL),     m_AudioUpmixType(NULL),
+    m_AC3PassThrough(NULL), m_DTSPassThrough(NULL),
+    m_EAC3PassThrough(NULL),m_TrueHDPassThrough(NULL),
+    m_passthrough8(false)
+{
+    setLabel(QObject::tr("Audio System"));
+    setUseLabel(false);
+
+    ConfigurationGroup *devicegroup = new HorizontalConfigurationGroup(false,
+                                                                       false);
+    devicegroup->addChild((m_OutputDevice = new AudioDeviceComboBox(this)));
+        // Rescan button
+    TransButtonSetting *rescan = new TransButtonSetting("rescan");
+    rescan->setLabel(QObject::tr("Rescan"));
+    rescan->setHelpText(QObject::tr("Rescan for available audio devices. "
+                                    "Current entry will be checked and "
+                                    "capability entries populated."));
+    devicegroup->addChild(rescan);
+    connect(rescan, SIGNAL(pressed()), this, SLOT(AudioRescan()));
+    addChild(devicegroup);
+
+    QString name = m_OutputDevice->getValue();
+    AudioOutput::AudioDeviceConfig *adc =
+        AudioOutput::GetAudioDeviceConfig(name, name, true);
+    if (adc->settings.IsInvalid())
+        VERBOSE(VB_IMPORTANT, QString("Audio device %1 isn't usable "
+                                      "Check audio configuration").arg(name));
+    audiodevs.insert(name, *adc);
+    devices.append(*adc);
+
+    delete adc;
+    CheckPassthrough();
+
+    ConfigurationGroup *maingroup = new VerticalConfigurationGroup(false,
+                                                                   false);
+    addChild(maingroup);
+
+    m_triggerDigital = new TransCheckBoxSetting();
+    m_AC3PassThrough = AC3PassThrough();
+    m_DTSPassThrough = DTSPassThrough();
+    m_EAC3PassThrough = EAC3PassThrough();
+    m_TrueHDPassThrough = TrueHDPassThrough();
+
+    m_cgsettings = new HorizontalConfigurationGroup();
+    m_cgsettings->setLabel(QObject::tr("Digital Audio Capabilities"));
+    m_cgsettings->addChild(m_AC3PassThrough);
+    m_cgsettings->addChild(m_DTSPassThrough);
+    m_cgsettings->addChild(m_EAC3PassThrough);
+    m_cgsettings->addChild(m_TrueHDPassThrough);
+
+    TriggeredItem *sub1 = new TriggeredItem(m_triggerDigital, m_cgsettings);
+
+    maingroup->addChild(sub1);
+
+    maingroup->addChild((m_MaxAudioChannels = MaxAudioChannels()));
+
+    TransButtonSetting *advanced = new TransButtonSetting("advanced");
+    advanced->setLabel(QObject::tr("Advanced Audio Settings"));
+    advanced->setHelpText(QObject::tr("Enable extra audio settings. Under most "
+                                  "usage all options should be unchecked"));
+    connect(advanced, SIGNAL(pressed()), this, SLOT(AudioAdvanced()));
+    addChild(advanced);
+
+    TransButtonSetting *test = new TransButtonSetting("test");
+    test->setLabel(QObject::tr("Test"));
+    test->setHelpText(QObject::tr("Will play a test pattern on all configured "
+                                  "speakers"));
+    connect(test, SIGNAL(pressed()), this, SLOT(AudioTest()));
+    addChild(test);
+
+    maingroup->addChild((m_AudioUpmix = AudioUpmix()));
+    maingroup->addChild((m_AudioUpmixType = AudioUpmixType()));
+
+        // Set slots
+    connect(m_MaxAudioChannels, SIGNAL(valueChanged(const QString&)),
+            this, SLOT(UpdateVisibility(const QString&)));
+    connect(m_OutputDevice, SIGNAL(valueChanged(const QString&)),
+            this, SLOT(UpdateCapabilities(const QString&)));
+    connect(m_AC3PassThrough, SIGNAL(valueChanged(const QString&)),
+            this, SLOT(UpdateCapabilities(const QString&)));
+    connect(m_DTSPassThrough, SIGNAL(valueChanged(const QString&)),
+            this, SLOT(UpdateCapabilities(const QString&)));
+    connect(m_EAC3PassThrough, SIGNAL(valueChanged(const QString&)),
+            this, SLOT(UpdateCapabilities(const QString&)));
+    connect(m_TrueHDPassThrough, SIGNAL(valueChanged(const QString&)),
+            this, SLOT(UpdateCapabilities(const QString&)));
+
+    AudioRescan();
+}
+
+void AudioConfigSettings::AudioRescan()
+{
+    if (!slotlock.tryLock())
+        return;
+
+    QVector<AudioOutput::AudioDeviceConfig>* list =
+        AudioOutput::GetOutputList();
+    QVector<AudioOutput::AudioDeviceConfig>::const_iterator it;
+
+    audiodevs.clear();
+    for (it = list->begin(); it != list->end(); it++)
+        audiodevs.insert(it->name, *it);
+
+    devices = *list;
+    delete list;
+
+    QString name = m_OutputDevice->getValue();
+    if (!audiodevs.contains(name))
+    {
+            // Scan for possible custom entry that isn't in the list
+        AudioOutput::AudioDeviceConfig *adc =
+            AudioOutput::GetAudioDeviceConfig(name, name, true);
+        if (adc->settings.IsInvalid())
+        {
+            QString msg = name + QObject::tr(" is invalid or not useable.");
+            MythPopupBox::showOkPopup(
+                GetMythMainWindow(), QObject::tr("Warning"), msg);
+            VERBOSE(VB_IMPORTANT, QString("Audio device %1 isn't usable ")
+                    .arg(name));
+        }
+        audiodevs.insert(name, *adc);
+        devices.append(*adc);
+        delete adc;
+    }
+    m_OutputDevice->AudioRescan();
+    slotlock.unlock();
+    UpdateCapabilities(QString::null);
+}
+
+void AudioConfigSettings::AudioAdvanced()
+{
+    QString out  = m_OutputDevice->getValue();
+    bool invalid = false;
+    AudioOutputSettings settings;
+
+    if (!audiodevs.contains(out))
+    {
+        invalid = true;
+    }
+    else
+    {
+        settings = audiodevs.value(out).settings;
+    }
+
+    AudioAdvancedSettingsGroup audiosettings(invalid ||
+                                             (settings.canLPCM() &&
+                                              settings.canPassthrough() >= 0));
+
+    if (audiosettings.exec() == kDialogCodeAccepted)
+    {
+        CheckPassthrough();
+        UpdateCapabilities(QString::null);
+    }
+}
+
+class AudioTestThread : public QThread
+{
+public:
+    void run()
+        {
+            char *frames_in = new char[m_channels * 48000 * sizeof(int16_t) + 15];
+            char *frames = (char *)(((long)frames_in + 15) & ~0xf);
+            for (int i = 0; i < m_channels; i++)
+            {
+                AudioOutputUtil::GeneratePinkSamples(frames, m_channels,
+                                                     i, 48000);
+                if (!m_audioOutput->AddFrames(frames, 48000, -1))
+                {
+                    VERBOSE(VB_AUDIO, "AddAudioData() "
+                            "Audio buffer overflow, audio data lost!");
+                }
+                if (m_dialog)
+                {
+                        // Send event here
+                        //QApplication::postEvent(m_dialog, NULL);
+                }
+                sleep(1);
+            }
+            delete[] frames_in;
+        }
+    QString result()
+        {
+            QString errMsg;
+            
+            if (!m_audioOutput)
+                errMsg = QObject::tr("Unable to create AudioOutput.");
+            else
+                errMsg = m_audioOutput->GetError();
+            return errMsg;
+        }
+    void setUIWindow(MythUIProgressDialog *dialog)
+        {
+            m_dialog = dialog;
+        }
+    
+    AudioTestThread(QString main, QString pass, int channels)
+        : m_channels(channels), m_dialog(NULL)
+        {
+            m_audioOutput = AudioOutput::OpenAudio(main,
+                                                   pass,
+                                                   FORMAT_S16, channels,
+                                                   0, 48000,
+                                                   AUDIOOUTPUT_VIDEO,
+                                                   true, false);
+        }
+    ~AudioTestThread()
+        {
+            if (m_audioOutput)
+                delete m_audioOutput;
+        }
+    
+private:
+    AudioOutput          *m_audioOutput;
+    int                   m_channels;
+    MythUIProgressDialog *m_dialog;
+};
+    
+void AudioConfigSettings::AudioTest()
+{
+    QString out  = m_OutputDevice->getValue();
+    QString name;
+    int channels = m_MaxAudioChannels->getValue().toInt();
+    QString errMsg;
+
+    if (gCoreContext->GetNumSetting("PassThruDeviceOverride", false))
+    {
+        name = gCoreContext->GetSetting("PassThruOutputDevice");
+    }
+    AudioTestThread *att = new AudioTestThread(out, name, channels);
+
+    QString result = att->result();
+    if (!result.isEmpty())
+    {
+        MythPopupBox::showOkPopup(
+            GetMythMainWindow(), QObject::tr("Error"), errMsg);
+        delete att;
+        att = NULL;
+    }
+    else
+    {
+            // set MythUI recipient here
+        att->setUIWindow(NULL);
+        att->start();
+    }
+    if (att && att->wait())
+    {
+        delete att;
+    }
+}
+
+bool AudioConfigSettings::CheckPassthrough()
+{
+    m_passthrough8 = false;
+    if (gCoreContext->GetNumSetting("PassThruDeviceOverride", false))
+    {
+        QString name = gCoreContext->GetSetting("PassThruOutputDevice");
+        AudioOutput::AudioDeviceConfig *adc =
+            AudioOutput::GetAudioDeviceConfig(name, name, true);
+        if (adc->settings.IsInvalid())
+        {
+            VERBOSE(VB_IMPORTANT, QString("Passthru device %1 isn't usable "
+                                 "Check audio configuration").arg(name));
+        }
+        else
+        {
+            if (adc->settings.BestSupportedChannels() >= 8)
+            {
+                m_passthrough8 = true;
+            }
+        }
+        delete adc;
+    }
+    return m_passthrough8;
+}
+
+void AudioConfigSettings::UpdateVisibility(const QString &device)
+{
+    if (!m_MaxAudioChannels && !m_AudioUpmix && !m_AudioUpmixType)
+        return;
+
+    int cur_speakers = m_MaxAudioChannels->getValue().toInt();
+    m_AudioUpmix->setEnabled(cur_speakers > 2);
+    m_AudioUpmixType->setEnabled(cur_speakers > 2);
+}
+
+void AudioConfigSettings::UpdateCapabilities(const QString &device)
+{
+    int max_speakers = 8;
+    bool invalid = false;
+    AudioOutputSettings settings;
+
+        // Test if everything is set yet
+    if (!m_OutputDevice    || !m_MaxAudioChannels   ||
+        !m_AC3PassThrough  || !m_DTSPassThrough     ||
+        !m_EAC3PassThrough || !m_TrueHDPassThrough)
+        return;
+
+    if (!slotlock.tryLock()) // Doing a rescan of channels
+        return;
+
+    bool bForceDigital = gCoreContext->GetNumSetting("PassThruDeviceOverride",
+                                                     false);
+
+    QString out = m_OutputDevice->getValue();
+    if (!audiodevs.contains(out))
+    {
+        VERBOSE(VB_AUDIO, QString("Update not found (%1)").arg(out));
+        invalid = true;
+    }
+    else
+    {
+        settings = audiodevs.value(out).settings;
+
+        max_speakers = settings.BestSupportedChannels();
+
+        bool bAC3  = (settings.canAC3() || bForceDigital) &&
+            m_AC3PassThrough->boolValue();
+        bool bDTS  = (settings.canDTS() || bForceDigital) &&
+            m_DTSPassThrough->boolValue();
+        bool bLPCM = settings.canPassthrough() == -1 ||
+            (settings.canLPCM() &&
+             !gCoreContext->GetNumSetting("StereoPCM", false));
+
+        if (max_speakers > 2 && !bLPCM)
+            max_speakers = 2;
+        if (max_speakers == 2 && (bAC3 || bDTS))
+            max_speakers = 6;
+    }
+
+    m_triggerDigital->setValue(invalid || bForceDigital ||
+                               settings.canAC3() || settings.canDTS());
+    m_EAC3PassThrough->setEnabled(invalid || m_passthrough8 ||
+                                  (settings.canPassthrough() >= 0 &&
+                                   max_speakers >= 8));
+    m_TrueHDPassThrough->setEnabled(invalid || m_passthrough8 ||
+                                    (settings.canPassthrough() >= 0 &&
+                                     max_speakers >= 8));
+    if (m_EAC3PassThrough->boolValue() || m_TrueHDPassThrough->boolValue())
+    {
+        max_speakers = 8;
+    }
+
+    int cur_speakers = m_MaxAudioChannels->getValue().toInt();
+
+    if (cur_speakers > max_speakers)
+    {
+        VERBOSE(VB_AUDIO, QString("Reset device %1").arg(out));
+        cur_speakers = max_speakers;
+    }
+
+        // Remove everything and re-add available channels
+    m_MaxAudioChannels->clearSelections();
+    m_MaxAudioChannels->resetMaxCount(3);
+    for (int i = 1; i <= max_speakers; i++)
+    {
+        if (invalid || settings.IsSupportedChannels(i) ||
+            (bForceDigital && i >= 6 ))
+        {
+            QString txt;
+
+            switch (i)
+            {
+                case 2:
+                    txt = QObject::tr("Stereo");
+                    break;
+                case 6:
+                    txt = QObject::tr("5.1");
+                    break;
+                case 8:
+                    txt = QObject::tr("7.1");
+                    break;
+                default:
+                    continue;
+            }
+            m_MaxAudioChannels->addSelection(txt, QString::number(i),
+                                             i == cur_speakers);
+        }
+    }
+    slotlock.unlock();
+}
+
+HostComboBox *AudioConfigSettings::MaxAudioChannels()
+{
+    QString name = "MaxChannels";
+    HostComboBox *gc = new HostComboBox(name, false);
+    gc->setLabel(QObject::tr("Speaker configuration"));
+    gc->addSelection(QObject::tr("Stereo"), "2", true); // default
+    gc->setHelpText(QObject::tr("Select the maximum number of audio "
+                                "channels supported by your receiver "
+                                "and speakers."));
+    return gc;
+}
+
+HostCheckBox *AudioConfigSettings::AudioUpmix()
+{
+    HostCheckBox *gc = new HostCheckBox("AudioDefaultUpmix");
+    gc->setLabel(QObject::tr("Upconvert stereo to 5.1 surround"));
+    gc->setValue(true);
+    gc->setHelpText(QObject::tr("If enabled, MythTV will upconvert stereo "
+                    "to 5.1 audio. You can enable or disable "
+                    "the upconversion during playback at any time."));
+    return gc;
+}
+
+HostComboBox *AudioConfigSettings::AudioUpmixType()
+{
+    HostComboBox *gc = new HostComboBox("AudioUpmixType",false);
+    gc->setLabel(QObject::tr("Upmix Quality"));
+    gc->addSelection(QObject::tr("Good"), "1");
+    gc->addSelection(QObject::tr("Best"), "2", true);  // default
+    gc->setHelpText(QObject::tr("Set the audio surround-upconversion quality."));
+    return gc;
+}
+
+HostCheckBox *AudioConfigSettings::AC3PassThrough()
+{
+    HostCheckBox *gc = new HostCheckBox("AC3PassThru");
+    gc->setLabel(QObject::tr("Dolby Digital"));
+    gc->setValue(false);
+    gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+                    "supports AC3/Dolby Digital. You must use a digital "
+                    "connection. Uncheck if using an analog connection."));
+    return gc;
+}
+
+HostCheckBox *AudioConfigSettings::DTSPassThrough()
+{
+    HostCheckBox *gc = new HostCheckBox("DTSPassThru");
+    gc->setLabel(QObject::tr("DTS"));
+    gc->setValue(false);
+    gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+                    "supports DTS. You must use a digital connection. Uncheck "
+                    "if using an analog connection"));
+    return gc;
+}
+
+HostCheckBox *AudioConfigSettings::EAC3PassThrough()
+{
+    HostCheckBox *gc = new HostCheckBox("EAC3PassThru");
+    gc->setLabel(QObject::tr("E-AC3/DTS-HD"));
+    gc->setValue(false);
+    gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+                    "supports E-AC3 (DD+) or DTS-HD. You must use a hdmi "
+                    "connection."));
+    return gc;
+}
+
+HostCheckBox *AudioConfigSettings::TrueHDPassThrough()
+{
+    HostCheckBox *gc = new HostCheckBox("TrueHDPassThru");
+    gc->setLabel(QObject::tr("TrueHD"));
+    gc->setValue(false);
+    gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+                    "supports Dolby TrueHD. You must use a hdmi connection."));
+    return gc;
+}
+
+static HostCheckBox *MythControlsVolume()
+{
+    HostCheckBox *gc = new HostCheckBox("MythControlsVolume");
+    gc->setLabel(QObject::tr("Use internal volume controls"));
+    gc->setValue(true);
+    gc->setHelpText(QObject::tr("If enabled, MythTV will control the PCM and "
+                    "master mixer volume. Disable this option if you prefer "
+                    "to control the volume externally (for example, using "
+                    "your amplifier) or if you use an external mixer program."));
+    return gc;
+}
+
+HostComboBox *AudioMixerSettings::MixerDevice()
+{
+    HostComboBox *gc = new HostComboBox("MixerDevice", true);
+    gc->setLabel(QObject::tr("Mixer device"));
+
+#ifdef USING_OSS
+    QDir dev("/dev", "mixer*", QDir::Name, QDir::System);
+    gc->fillSelectionsFromDir(dev);
+
+    dev.setPath("/dev/sound");
+    if (dev.exists())
+    {
+        gc->fillSelectionsFromDir(dev);
+    }
+#endif
+#ifdef USING_ALSA
+    gc->addSelection("ALSA:default", "ALSA:default");
+#endif
+#ifdef USING_MINGW
+    gc->addSelection("DirectX:", "DirectX:");
+    gc->addSelection("Windows:", "Windows:");
+#endif
+#if !defined(USING_MINGW)
+    gc->addSelection("software", "software");
+    gc->setHelpText(QObject::tr("Setting the mixer device to \"software\" "
+                    "lets MythTV control the volume of all audio at the "
+                    "expense of a slight quality loss."));
+#endif
+
+    return gc;
+}
+
+const char* AudioMixerSettings::MixerControlControls[] = { "PCM",
+                                                           "Master" };
+
+HostComboBox *AudioMixerSettings::MixerControl()
+{
+    HostComboBox *gc = new HostComboBox("MixerControl", true);
+    gc->setLabel(QObject::tr("Mixer controls"));
+    for (unsigned int i = 0; i < sizeof(MixerControlControls) / sizeof(char*);
+         ++i)
+    {
+        gc->addSelection(QObject::tr(MixerControlControls[i]),
+                         MixerControlControls[i]);
+    }
+
+    gc->setHelpText(QObject::tr("Changing the volume adjusts the selected "
+                                "mixer."));
+    return gc;
+}
+
+HostSlider *AudioMixerSettings::MixerVolume()
+{
+    HostSlider *gs = new HostSlider("MasterMixerVolume", 0, 100, 1);
+    gs->setLabel(QObject::tr("Master mixer volume"));
+    gs->setValue(70);
+    gs->setHelpText(QObject::tr("Initial volume for the Master mixer. "
+                    "This affects all sound created by the audio device. "
+                    "Note: Do not set this too low."));
+    return gs;
+}
+
+HostSlider *AudioMixerSettings::PCMVolume()
+{
+    HostSlider *gs = new HostSlider("PCMMixerVolume", 0, 100, 1);
+    gs->setLabel(QObject::tr("PCM mixer volume"));
+    gs->setValue(70);
+    gs->setHelpText(QObject::tr("Initial volume for PCM output. Using the "
+                    "volume keys in MythTV will adjust this parameter."));
+    return gs;
+}
+
+AudioMixerSettings::AudioMixerSettings() :
+    TriggeredConfigurationGroup(false, true, false, false)
+{
+    setLabel(QObject::tr("Audio Mixer"));
+    setUseLabel(false);
+
+    Setting *volumeControl = MythControlsVolume();
+    addChild(volumeControl);
+
+        // Mixer settings
+    ConfigurationGroup *settings =
+        new VerticalConfigurationGroup(false, true, false, false);
+    settings->addChild(MixerDevice());
+    settings->addChild(MixerControl());
+    settings->addChild(MixerVolume());
+    settings->addChild(PCMVolume());
+
+    ConfigurationGroup *dummy =
+        new VerticalConfigurationGroup(false, true, false, false);
+
+        // Show Mixer config only if internal volume controls enabled
+    setTrigger(volumeControl);
+    addTarget("0", dummy);
+    addTarget("1", settings);
+}
+
+AudioGeneralSettings::AudioGeneralSettings()
+{
+    addChild(new AudioConfigSettings());
+    addChild(new AudioMixerSettings());
+}
+
+HostCheckBox *AudioAdvancedSettings::MPCM()
+{
+    HostCheckBox *gc = new HostCheckBox("StereoPCM");
+    gc->setLabel(QObject::tr("Stereo PCM Only"));
+    gc->setValue(false);
+    gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+                    "only supports 2 channels PCM (typically an old HDMI 1.0 "
+                    "device). Multi-channels audio will be re-encoded to AC3 "
+                    "when required"));
+    return gc;
+}
+
+HostCheckBox *AudioAdvancedSettings::SRCQualityOverride()
+{
+    HostCheckBox *gc = new HostCheckBox("SRCQualityOverride");
+    gc->setLabel(QObject::tr("Override SRC quality"));
+    gc->setValue(false);
+    gc->setHelpText(QObject::tr("Enable to override audio sample rate "
+                    "conversion quality."));
+    return gc;
+}
+
+HostComboBox *AudioAdvancedSettings::SRCQuality()
+{
+    HostComboBox *gc = new HostComboBox("SRCQuality", false);
+    gc->setLabel(QObject::tr("Sample rate conversion"));
+    gc->addSelection(QObject::tr("Disabled"), "-1");
+    gc->addSelection(QObject::tr("Fastest"), "0");
+    gc->addSelection(QObject::tr("Good"), "1", true); // default
+    gc->addSelection(QObject::tr("Best"), "2");
+    gc->setHelpText(QObject::tr("Set the quality of audio sample-rate "
+                    "conversion. \"Good\" (default) provides the best "
+                    "compromise between CPU usage and quality. \"Disabled\" "
+                    "lets the audio device handle sample-rate conversion."));
+    return gc;
+}
+
+HostCheckBox *AudioAdvancedSettings::Audio48kOverride()
+{
+    HostCheckBox *gc = new HostCheckBox("Audio48kOverride");
+    gc->setLabel(QObject::tr("Force audio device output to 48kHz"));
+    gc->setValue(false);
+    gc->setHelpText(QObject::tr("Force audio sample rate to 48kHz. "
+                                "Some audio devices will report various rates, "
+                                "but they ultimately crash."));
+    return gc;
+}
+
+HostCheckBox *AudioAdvancedSettings::PassThroughOverride()
+{
+    HostCheckBox *gc = new HostCheckBox("PassThruDeviceOverride");
+    gc->setLabel(QObject::tr("Separate digital output device"));
+    gc->setValue(false);
+    gc->setHelpText(QObject::tr("Use a distinct digital output device from "
+                                "default."));
+    return gc;
+}
+
+HostComboBox *AudioAdvancedSettings::PassThroughOutputDevice()
+{
+    HostComboBox *gc = new HostComboBox("PassThruOutputDevice", true);
+
+    gc->setLabel(QObject::tr("Digital output device"));
+    gc->addSelection(QObject::tr("Default"), "Default");
+#ifdef USING_MINGW
+    gc->addSelection("DirectX:Primary Sound Driver");
+#else
+    gc->addSelection("ALSA:iec958:{ AES0 0x02 }",
+                     "ALSA:iec958:{ AES0 0x02 }");
+    gc->addSelection("ALSA:hdmi", "ALSA:hdmi");
+    gc->addSelection("ALSA:plughw:0,3", "ALSA:plughw:0,3");
+#endif
+
+    gc->setHelpText(QObject::tr("Deprecated. Audio output device to use for "
+                        "digital audio. This value is currently only used "
+                        "with ALSA and DirectX sound output."));
+    return gc;
+}
+
+AudioAdvancedSettings::AudioAdvancedSettings(bool mpcm)
+{
+    ConfigurationGroup *settings3 =
+        new HorizontalConfigurationGroup(false, false);
+
+    m_PassThroughOverride = PassThroughOverride();
+    TriggeredItem *sub3 =
+        new TriggeredItem(m_PassThroughOverride, PassThroughOutputDevice());
+    settings3->addChild(m_PassThroughOverride);
+    settings3->addChild(sub3);
+
+    ConfigurationGroup *settings4 =
+        new HorizontalConfigurationGroup(false, false);
+    Setting *srcqualityoverride = SRCQualityOverride();
+    TriggeredItem *sub4 =
+        new TriggeredItem(srcqualityoverride, SRCQuality());
+    settings4->addChild(srcqualityoverride);
+    settings4->addChild(sub4);
+
+    ConfigurationGroup *settings5 =
+        new HorizontalConfigurationGroup(false, false);
+    settings5->addChild(Audio48kOverride());
+
+    ConfigurationGroup *settings6;
+
+    if (mpcm)
+    {
+        settings6 = new HorizontalConfigurationGroup(false, false);
+        settings6->addChild(MPCM());
+    }
+    
+    addChild(settings4);
+    addChild(settings5);
+    addChild(settings3);
+    if (mpcm)
+    {
+        addChild(settings6);
+    }
+}
+
+AudioAdvancedSettingsGroup::AudioAdvancedSettingsGroup(bool mpcm)
+{
+    addChild(new AudioAdvancedSettings(mpcm));
+}
+
+// vim:set sw=4 ts=4 expandtab:
+
diff --git a/mythtv/programs/mythfrontend/audiosettings.h b/mythtv/programs/mythfrontend/audiosettings.h
new file mode 100644
index 0000000..037a8be
--- /dev/null
+++ b/mythtv/programs/mythfrontend/audiosettings.h
@@ -0,0 +1,117 @@
+#ifndef MYTHAUDIOSETTINGS_H
+#define MYTHAUDIOSETTINGS_H
+
+#include <QStringList>
+#include <QObject>
+
+#include "settings.h"
+#include "mythcontext.h"
+
+#include <QMutex>
+#include "audiooutput.h"
+
+class AudioDeviceComboBox;
+
+class AudioConfigSettings : public VerticalConfigurationGroup
+{
+    Q_OBJECT
+
+  public:
+    AudioConfigSettings();
+
+    typedef QMap<QString,AudioOutput::AudioDeviceConfig> ADCMap;
+
+    ADCMap &AudioDeviceMap(void) { return audiodevs; };
+    AudioOutput::ADCVect &AudioDeviceVect(void) { return devices; };
+
+  private slots:
+    void UpdateVisibility(const QString&);
+    void UpdateCapabilities(const QString&);
+    void AudioRescan();
+    void AudioAdvanced();
+    void AudioTest();
+
+  private:
+    AudioDeviceComboBox  *OutputDevice();
+    HostComboBox         *MaxAudioChannels();
+    HostCheckBox         *AudioUpmix();
+    HostComboBox         *AudioUpmixType();
+    HostCheckBox         *AC3PassThrough();
+    HostCheckBox         *DTSPassThrough();
+    HostCheckBox         *EAC3PassThrough();
+    HostCheckBox         *TrueHDPassThrough();
+    bool                  CheckPassthrough();
+
+    ConfigurationGroup   *m_cgsettings;
+    AudioDeviceComboBox  *m_OutputDevice;
+    HostComboBox         *m_MaxAudioChannels;
+    HostCheckBox         *m_AudioUpmix;
+    HostComboBox         *m_AudioUpmixType;
+    TransCheckBoxSetting *m_triggerDigital;
+    HostCheckBox         *m_AC3PassThrough;
+    HostCheckBox         *m_DTSPassThrough;
+    HostCheckBox         *m_EAC3PassThrough;
+    HostCheckBox         *m_TrueHDPassThrough;
+    ADCMap                audiodevs;
+    AudioOutput::ADCVect  devices;
+    QMutex                slotlock;
+    bool                  m_passthrough8;
+};
+
+class AudioDeviceComboBox : public HostComboBox
+{
+    Q_OBJECT
+  public:
+    AudioDeviceComboBox(AudioConfigSettings*);
+    void AudioRescan();
+
+  private slots:
+    void AudioDescriptionHelp(const QString&);
+
+  private:
+    AudioConfigSettings *m_parent;
+};
+
+class AudioMixerSettings : public TriggeredConfigurationGroup
+{
+  public:
+    AudioMixerSettings();
+  private:
+    HostComboBox        *MixerDevice();
+    HostComboBox        *MixerControl();
+    HostSlider          *MixerVolume();
+    HostSlider          *PCMVolume();
+    static const char   *MixerControlControls[];
+};
+
+class AudioGeneralSettings : public ConfigurationWizard
+{
+  public:
+    AudioGeneralSettings();
+};
+
+class AudioAdvancedSettings : public VerticalConfigurationGroup
+{
+    Q_OBJECT
+
+  public:
+    AudioAdvancedSettings(bool mpcm);
+    HostCheckBox         *MPCM();
+    HostCheckBox         *SRCQualityOverride();
+    HostComboBox         *SRCQuality();
+    HostCheckBox         *Audio48kOverride();
+    HostCheckBox         *PassThroughOverride();
+    HostComboBox         *PassThroughOutputDevice();
+
+    TransCheckBoxSetting *m_triggerMPCM;
+    HostCheckBox         *m_MPCM;
+    HostCheckBox         *m_PassThroughOverride;
+};
+
+class AudioAdvancedSettingsGroup : public ConfigurationWizard
+{
+  public:
+    AudioAdvancedSettingsGroup(bool mpcm);
+};
+
+#endif
diff --git a/mythtv/programs/mythfrontend/globalsettings.cpp b/mythtv/programs/mythfrontend/globalsettings.cpp
index 3e17a46..57f91a5 100644
--- a/mythtv/programs/mythfrontend/globalsettings.cpp
+++ b/mythtv/programs/mythfrontend/globalsettings.cpp
@@ -29,6 +29,7 @@
 #include "iso639.h"
 #include "playbackbox.h"
 #include "globalsettings.h"
+#include "audiosettings.h"
 #include "recordingprofile.h"
 #include "mythxdisplay.h"
 #include "DisplayRes.h"
@@ -39,556 +40,6 @@
 #include "mythdirs.h"
 #include "mythuihelper.h"
 
-class TriggeredItem : public TriggeredConfigurationGroup
-{
-  public:
-    TriggeredItem(Setting *checkbox, ConfigurationGroup *group) :
-        TriggeredConfigurationGroup(false, false, false, false)
-    {
-        setTrigger(checkbox);
-
-        addTarget("1", group);
-        addTarget("0", new VerticalConfigurationGroup(true));
-    }
-    TriggeredItem(Setting *checkbox, Setting *setting) :
-        TriggeredConfigurationGroup(false, false, false, false)
-    {
-        setTrigger(checkbox);
-
-        addTarget("1", setting);
-        addTarget("0", new VerticalConfigurationGroup(false, false));
-    }
-};
-
-AudioDeviceComboBox::AudioDeviceComboBox(AudioConfigSettings *parent) :
-    HostComboBox("AudioOutputDevice", true), m_parent(parent)
-{
-    setLabel(QObject::tr("Audio output device"));
-#ifdef USING_ALSA
-    QString dflt = "ALSA:default";
-#elif USING_PULSEOUTPUT
-    QString dflt = "PulseAudio:default";
-#elif CONFIG_DARWIN
-    QString dflt = "CoreAudio:";
-#elif USING_MINGW
-    QString dflt = "Windows:";
-#else
-    QString dflt = "NULL";
-#endif
-    QString current = gCoreContext->GetSetting(QString("AudioOutputDevice"),
-                                               dflt);
-    addSelection(current, current, true);
-
-    connect(this, SIGNAL(valueChanged(const QString&)),
-            this, SLOT(AudioDescriptionHelp(const QString&)));
-}
-
-void AudioDeviceComboBox::AudioRescan()
-{
-    AudioOutput::ADCVect &vect = m_parent->AudioDeviceVect();
-    AudioOutput::ADCVect::const_iterator it;
-
-    if (vect.empty())
-        return;
-
-    QString value = getValue();
-    clearSelections();
-    resetMaxCount(vect.size());
-
-    bool found = false;
-    for (it = vect.begin(); it != vect.end(); it++)
-        addSelection(it->name, it->name,
-                     value == it->name ? (found = true) : false);
-    if (!found)
-    {
-        resetMaxCount(vect.size()+1);
-        addSelection(value, value, true);
-    }
-        // For some reason, it adds an empty entry, remove it
-    removeSelection(QString::null);
-}
-
-void AudioDeviceComboBox::AudioDescriptionHelp(const QString &device)
-{
-    QString desc = m_parent->AudioDeviceMap().value(device).desc;
-    setHelpText(desc);
-}
-
-AudioConfigSettings::AudioConfigSettings() :
-    VerticalConfigurationGroup(false, true, false, false),
-    m_OutputDevice(NULL),   m_MaxAudioChannels(NULL),
-    m_AudioUpmix(NULL),     m_AudioUpmixType(NULL),
-    m_AC3PassThrough(NULL), m_DTSPassThrough(NULL),  m_MPCM(NULL),
-    m_AdvancedAudioSettings(NULL),                   m_PassThroughOverride(NULL)
-{
-    setLabel(QObject::tr("Audio System"));
-    setUseLabel(false);
-
-        // Rescan button
-    TransButtonSetting *rescan = new TransButtonSetting("rescan");
-    rescan->setLabel(QObject::tr("Scan for audio devices"));
-    rescan->setHelpText(QObject::tr("Scan for available audio devices. "
-                                    "Custom entry will be scanned and "
-                                    "capability entries populated."));
-    addChild(rescan);
-    connect(rescan, SIGNAL(pressed()), this, SLOT(AudioRescan()));
-
-    addChild((m_OutputDevice = new AudioDeviceComboBox(this)));
-
-    QString name = m_OutputDevice->getValue();
-    AudioOutput::AudioDeviceConfig *adc =
-        AudioOutput::GetAudioDeviceConfig(name, name, true);
-    if (adc->settings.IsInvalid())
-        VERBOSE(VB_IMPORTANT, QString("Audio device %1 isn't usable "
-                                      "Check audio configuration").arg(name));
-    audiodevs.insert(name, *adc);
-    devices.append(*adc);
-    delete adc;
-
-    ConfigurationGroup *maingroup = new VerticalConfigurationGroup(false,
-                                                                   false);
-    addChild(maingroup);
-
-    m_triggerDigital = new TransCheckBoxSetting();
-    m_AC3PassThrough = AC3PassThrough();
-    m_DTSPassThrough = DTSPassThrough();
-
-    m_cgsettings = new HorizontalConfigurationGroup();
-    m_cgsettings->setLabel(QObject::tr("Digital Audio Capabilities"));
-    m_cgsettings->addChild(m_AC3PassThrough);
-    m_cgsettings->addChild(m_DTSPassThrough);
-
-    TriggeredItem *sub1 = new TriggeredItem(m_triggerDigital, m_cgsettings);
-
-    maingroup->addChild(sub1);
-
-    maingroup->addChild((m_MaxAudioChannels = MaxAudioChannels()));
-    maingroup->addChild((m_AudioUpmix = AudioUpmix()));
-    maingroup->addChild((m_AudioUpmixType = AudioUpmixType()));
-
-    m_AdvancedAudioSettings = AdvancedAudioSettings();
-    addChild(m_AdvancedAudioSettings);
-
-    ConfigurationGroup *group2 =
-        new VerticalConfigurationGroup(false);
-
-    TriggeredItem *sub2 = new TriggeredItem(m_AdvancedAudioSettings, group2);
-    addChild(sub2);
-
-    ConfigurationGroup *settings3 =
-        new HorizontalConfigurationGroup(false, false);
-
-    m_PassThroughOverride = PassThroughOverride();
-    TriggeredItem *sub3 =
-        new TriggeredItem(m_PassThroughOverride, PassThroughOutputDevice());
-    settings3->addChild(m_PassThroughOverride);
-    settings3->addChild(sub3);
-
-    ConfigurationGroup *settings4 =
-        new HorizontalConfigurationGroup(false, false);
-    Setting *srcqualityoverride = SRCQualityOverride();
-    TriggeredItem *sub4 =
-        new TriggeredItem(srcqualityoverride, SRCQuality());
-    settings4->addChild(srcqualityoverride);
-    settings4->addChild(sub4);
-
-    ConfigurationGroup *settings5 =
-        new HorizontalConfigurationGroup(false, false);
-    settings5->addChild(Audio48kOverride());
-
-    m_triggerMPCM = new TransCheckBoxSetting();
-    m_MPCM = MPCM();
-    TriggeredItem *subMPCM = new TriggeredItem(m_triggerMPCM, m_MPCM);
-
-    ConfigurationGroup *settings6 =
-        new HorizontalConfigurationGroup(false, false);
-    settings6->addChild(subMPCM);
-
-    group2->addChild(settings4);
-    group2->addChild(settings5);
-    group2->addChild(settings3);
-    group2->addChild(settings6);
-
-        // Set slots
-    connect(m_MaxAudioChannels, SIGNAL(valueChanged(const QString&)),
-            this, SLOT(UpdateVisibility(const QString&)));
-    connect(m_OutputDevice, SIGNAL(valueChanged(const QString&)),
-            this, SLOT(UpdateCapabilities(const QString&)));
-    connect(m_AC3PassThrough, SIGNAL(valueChanged(const QString&)),
-            this, SLOT(UpdateCapabilities(const QString&)));
-    connect(m_DTSPassThrough, SIGNAL(valueChanged(const QString&)),
-            this, SLOT(UpdateCapabilities(const QString&)));
-    connect(m_MPCM, SIGNAL(valueChanged(const QString&)),
-            this, SLOT(UpdateCapabilities(const QString&)));
-    connect(m_PassThroughOverride, SIGNAL(valueChanged(const QString&)),
-            this, SLOT(UpdateCapabilities(const QString&)));
-    connect(m_AdvancedAudioSettings, SIGNAL(valueChanged(const QString&)),
-            this, SLOT(UpdateCapabilities(const QString&)));
-}
-
-void AudioConfigSettings::AudioRescan()
-{
-    if (!slotlock.tryLock())
-        return;
-
-    QVector<AudioOutput::AudioDeviceConfig>* list =
-        AudioOutput::GetOutputList();
-    QVector<AudioOutput::AudioDeviceConfig>::const_iterator it;
-
-    audiodevs.clear();
-    for (it = list->begin(); it != list->end(); it++)
-        audiodevs.insert(it->name, *it);
-
-    devices = *list;
-    delete list;
-
-    QString name = m_OutputDevice->getValue();
-    if (!audiodevs.contains(name))
-    {
-            // Scan for possible custom entry that isn't in the list
-        AudioOutput::AudioDeviceConfig *adc =
-            AudioOutput::GetAudioDeviceConfig(name, name, true);
-        if (adc->settings.IsInvalid())
-        {
-            QString msg = name + QObject::tr(" is invalid or not useable.");
-            MythPopupBox::showOkPopup(
-                GetMythMainWindow(), QObject::tr("Warning"), msg);
-            VERBOSE(VB_IMPORTANT, QString("Audio device %1 isn't usable ")
-                    .arg(name));
-        }
-        audiodevs.insert(name, *adc);
-        devices.append(*adc);
-        delete adc;
-    }
-    m_OutputDevice->AudioRescan();
-    slotlock.unlock();
-    UpdateCapabilities(QString::null);
-}
-
-void AudioConfigSettings::UpdateVisibility(const QString &device)
-{
-    if (!m_MaxAudioChannels && !m_AudioUpmix && !m_AudioUpmixType)
-        return;
-
-    int cur_speakers = m_MaxAudioChannels->getValue().toInt();
-    m_AudioUpmix->setEnabled(cur_speakers > 2);
-    m_AudioUpmixType->setEnabled(cur_speakers > 2);
-}
-
-void AudioConfigSettings::UpdateCapabilities(const QString &device)
-{
-    int max_speakers = 8;
-    bool invalid = false;
-    AudioOutputSettings settings;
-
-        // Test if everything is set yet
-    if (!m_OutputDevice   || !m_MaxAudioChannels || !m_AdvancedAudioSettings ||
-        !m_AC3PassThrough || !m_DTSPassThrough   || !m_MPCM ||
-        !m_PassThroughOverride)
-        return;
-
-    if (!slotlock.tryLock()) // Doing a rescan of channels
-        return;
-
-    bool bForceDigital = (m_AdvancedAudioSettings->boolValue() &&
-                          m_PassThroughOverride->boolValue());
-
-    QString out = m_OutputDevice->getValue();
-    if (!audiodevs.contains(out))
-    {
-        VERBOSE(VB_AUDIO, QString("Update not found (%1)").arg(out));
-        invalid = true;
-    }
-    else
-    {
-        settings = audiodevs.value(out).settings;
-
-        max_speakers = settings.BestSupportedChannels();
-
-        bool bAC3  = (settings.canAC3() || bForceDigital) &&
-            m_AC3PassThrough->boolValue();
-        bool bDTS  = (settings.canDTS() || bForceDigital) &&
-            m_DTSPassThrough->boolValue();
-        bool bLPCM = settings.canPassthrough() == -1 ||
-            (settings.canLPCM() &&
-             m_AdvancedAudioSettings->boolValue() && !m_MPCM->boolValue());
-
-        if (max_speakers > 2 && !bLPCM)
-            max_speakers = 2;
-        if (max_speakers == 2 && (bAC3 || bDTS))
-            max_speakers = 6;
-    }
-
-    m_triggerDigital->setValue(invalid || bForceDigital ||
-                               settings.canAC3() || settings.canDTS());
-    m_triggerMPCM->setValue(invalid || (settings.canLPCM() &&
-                                        settings.canPassthrough() >= 0));
-
-    int cur_speakers = m_MaxAudioChannels->getValue().toInt();
-
-    if (cur_speakers > max_speakers)
-    {
-        VERBOSE(VB_AUDIO, QString("Reset device %1").arg(out));
-        cur_speakers = max_speakers;
-    }
-
-        // Remove everything and re-add available channels
-    m_MaxAudioChannels->clearSelections();
-    m_MaxAudioChannels->resetMaxCount(3);
-    for (int i = 1; i <= max_speakers; i++)
-    {
-        if (invalid || settings.IsSupportedChannels(i) ||
-            (bForceDigital && i == 6))
-        {
-            QString txt;
-
-            switch (i)
-            {
-                case 2:
-                    txt = QObject::tr("Stereo");
-                    break;
-                case 6:
-                    txt = QObject::tr("5.1");
-                    break;
-                case 8:
-                    txt = QObject::tr("7.1");
-                    break;
-                default:
-                    continue;
-            }
-            m_MaxAudioChannels->addSelection(txt, QString::number(i),
-                                             i == cur_speakers);
-        }
-    }
-    slotlock.unlock();
-}
-
-HostComboBox *AudioConfigSettings::MaxAudioChannels()
-{
-    QString name = "MaxChannels";
-    HostComboBox *gc = new HostComboBox(name, false);
-    gc->setLabel(QObject::tr("Speaker configuration"));
-    gc->addSelection(QObject::tr("Stereo"), "2", true); // default
-    gc->setHelpText(QObject::tr("Select the maximum number of audio "
-                                "channels supported by your receiver "
-                                "and speakers."));
-    return gc;
-}
-
-HostCheckBox *AudioConfigSettings::AudioUpmix()
-{
-    HostCheckBox *gc = new HostCheckBox("AudioDefaultUpmix");
-    gc->setLabel(QObject::tr("Upconvert stereo to 5.1 surround"));
-    gc->setValue(true);
-    gc->setHelpText(QObject::tr("If enabled, MythTV will upconvert stereo "
-                    "to 5.1 audio. You can enable or disable "
-                    "the upconversion during playback at any time."));
-    return gc;
-}
-
-HostComboBox *AudioConfigSettings::AudioUpmixType()
-{
-    HostComboBox *gc = new HostComboBox("AudioUpmixType",false);
-    gc->setLabel(QObject::tr("Upmix Quality"));
-    gc->addSelection(QObject::tr("Good"), "1");
-    gc->addSelection(QObject::tr("Best"), "2", true);  // default
-    gc->setHelpText(QObject::tr("Set the audio surround-upconversion quality."));
-    return gc;
-}
-
-HostCheckBox *AudioConfigSettings::AC3PassThrough()
-{
-    HostCheckBox *gc = new HostCheckBox("AC3PassThru");
-    gc->setLabel(QObject::tr("Dolby Digital"));
-    gc->setValue(false);
-    gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
-                    "supports AC3/Dolby Digital. You must use a digital "
-                    "connection. Uncheck if using an analog connection."));
-    return gc;
-}
-
-HostCheckBox *AudioConfigSettings::DTSPassThrough()
-{
-    HostCheckBox *gc = new HostCheckBox("DTSPassThru");
-    gc->setLabel(QObject::tr("DTS"));
-    gc->setValue(false);
-    gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
-                    "supports DTS. You must use a digital connection. Uncheck "
-                    "if using an analog connection"));
-    return gc;
-}
-
-HostCheckBox *AudioConfigSettings::MPCM()
-{
-    HostCheckBox *gc = new HostCheckBox("StereoPCM");
-    gc->setLabel(QObject::tr("Stereo PCM Only"));
-    gc->setValue(false);
-    gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
-                    "only supports 2 channels PCM (typically an old HDMI 1.0 "
-                    "device). Multi-channels audio will be re-encoded to AC3 "
-                    "when required"));
-    return gc;
-}
-
-HostCheckBox *AudioConfigSettings::AdvancedAudioSettings()
-{
-    HostCheckBox *gc = new HostCheckBox("AdvancedAudioSettings");
-    gc->setLabel(QObject::tr("Advanced audio configuration"));
-    gc->setValue(false);
-    gc->setHelpText(QObject::tr("Enable extra audio settings."));
-    return gc;
-}
-
-HostCheckBox *AudioConfigSettings::SRCQualityOverride()
-{
-    HostCheckBox *gc = new HostCheckBox("SRCQualityOverride");
-    gc->setLabel(QObject::tr("Override SRC quality"));
-    gc->setValue(false);
-    gc->setHelpText(QObject::tr("Enable to override audio sample rate "
-                    "conversion quality."));
-    return gc;
-}
-
-HostComboBox *AudioConfigSettings::SRCQuality()
-{
-    HostComboBox *gc = new HostComboBox("SRCQuality", false);
-    gc->setLabel(QObject::tr("Sample rate conversion"));
-    gc->addSelection(QObject::tr("Disabled"), "-1");
-    gc->addSelection(QObject::tr("Fastest"), "0");
-    gc->addSelection(QObject::tr("Good"), "1", true); // default
-    gc->addSelection(QObject::tr("Best"), "2");
-    gc->setHelpText(QObject::tr("Set the quality of audio sample-rate "
-                    "conversion. \"Good\" (default) provides the best "
-                    "compromise between CPU usage and quality. \"Disabled\" "
-                    "lets the audio device handle sample-rate conversion."));
-    return gc;
-}
-
-HostCheckBox *AudioConfigSettings::Audio48kOverride()
-{
-    HostCheckBox *gc = new HostCheckBox("Audio48kOverride");
-    gc->setLabel(QObject::tr("Force audio device output to 48kHz"));
-    gc->setValue(false);
-    gc->setHelpText(QObject::tr("Force audio sample rate to 48kHz. "
-                                "Some audio devices will report various rates, "
-                                "but they ultimately crash."));
-    return gc;
-}
-
-HostCheckBox *AudioConfigSettings::PassThroughOverride()
-{
-    HostCheckBox *gc = new HostCheckBox("PassThruDeviceOverride");
-    gc->setLabel(QObject::tr("Separate digital output device"));
-    gc->setValue(false);
-    gc->setHelpText(QObject::tr("Use a distinct digital output device from "
-                                "default."));
-    return gc;
-}
-
-HostComboBox *AudioConfigSettings::PassThroughOutputDevice()
-{
-    HostComboBox *gc = new HostComboBox("PassThruOutputDevice", true);
-
-    gc->setLabel(QObject::tr("Digital output device"));
-    gc->addSelection(QObject::tr("Default"), "Default");
-#ifdef USING_MINGW
-    gc->addSelection("DirectX:Primary Sound Driver");
-#else
-    gc->addSelection("ALSA:iec958:{ AES0 0x02 }",
-                     "ALSA:iec958:{ AES0 0x02 }");
-    gc->addSelection("ALSA:hdmi", "ALSA:hdmi");
-    gc->addSelection("ALSA:plughw:0,3", "ALSA:plughw:0,3");
-#endif
-
-    gc->setHelpText(QObject::tr("Deprecated. Audio output device to use for "
-                        "digital audio. This value is currently only used "
-                        "with ALSA and DirectX sound output."));
-    return gc;
-}
-
-static HostCheckBox *MythControlsVolume()
-{
-    HostCheckBox *gc = new HostCheckBox("MythControlsVolume");
-    gc->setLabel(QObject::tr("Use internal volume controls"));
-    gc->setValue(true);
-    gc->setHelpText(QObject::tr("If enabled, MythTV will control the PCM and "
-                    "master mixer volume. Disable this option if you prefer "
-                    "to control the volume externally (for example, using "
-                    "your amplifier) or if you use an external mixer program."));
-    return gc;
-}
-
-static HostComboBox *MixerDevice()
-{
-    HostComboBox *gc = new HostComboBox("MixerDevice", true);
-    gc->setLabel(QObject::tr("Mixer device"));
-
-#ifdef USING_OSS
-    QDir dev("/dev", "mixer*", QDir::Name, QDir::System);
-    gc->fillSelectionsFromDir(dev);
-
-    dev.setPath("/dev/sound");
-    if (dev.exists())
-    {
-        gc->fillSelectionsFromDir(dev);
-    }
-#endif
-#ifdef USING_ALSA
-    gc->addSelection("ALSA:default", "ALSA:default");
-#endif
-#ifdef USING_MINGW
-    gc->addSelection("DirectX:", "DirectX:");
-    gc->addSelection("Windows:", "Windows:");
-#endif
-#if !defined(USING_MINGW)
-    gc->addSelection("software", "software");
-    gc->setHelpText(QObject::tr("Setting the mixer device to \"software\" "
-                    "lets MythTV control the volume of all audio at the "
-                    "expense of a slight quality loss."));
-#endif
-
-    return gc;
-}
-
-static const char* MixerControlControls[] = { "PCM",
-                                              "Master" };
-
-static HostComboBox *MixerControl()
-{
-    HostComboBox *gc = new HostComboBox("MixerControl", true);
-    gc->setLabel(QObject::tr("Mixer controls"));
-    for (unsigned int i = 0; i < sizeof(MixerControlControls) / sizeof(char*);
-         ++i)
-    {
-        gc->addSelection(QObject::tr(MixerControlControls[i]),
-                         MixerControlControls[i]);
-    }
-
-    gc->setHelpText(QObject::tr("Changing the volume adjusts the selected mixer."));
-    return gc;
-}
-
-static HostSlider *MixerVolume()
-{
-    HostSlider *gs = new HostSlider("MasterMixerVolume", 0, 100, 1);
-    gs->setLabel(QObject::tr("Master mixer volume"));
-    gs->setValue(70);
-    gs->setHelpText(QObject::tr("Initial volume for the Master mixer. "
-                    "This affects all sound created by the audio device. "
-                    "Note: Do not set this too low."));
-    return gs;
-}
-
-static HostSlider *PCMVolume()
-{
-    HostSlider *gs = new HostSlider("PCMMixerVolume", 0, 100, 1);
-    gs->setLabel(QObject::tr("PCM mixer volume"));
-    gs->setValue(70);
-    gs->setHelpText(QObject::tr("Initial volume for PCM output. Using the "
-                    "volume keys in MythTV will adjust this parameter."));
-    return gs;
-}
-
 static HostCheckBox *DecodeExtraAudio()
 {
     HostCheckBox *gc = new HostCheckBox("DecodeExtraAudio");
@@ -3196,36 +2647,6 @@ static HostSpinBox *EPGRecThreshold()
     return gs;
 }
 
-class AudioMixerSettingsGroup : public TriggeredConfigurationGroup
-{
-  public:
-    AudioMixerSettingsGroup() :
-        TriggeredConfigurationGroup(false, true, false, false)
-    {
-        setLabel(QObject::tr("Audio Mixer"));
-        setUseLabel(false);
-
-        Setting *volumeControl = MythControlsVolume();
-        addChild(volumeControl);
-
-        // Mixer settings
-        ConfigurationGroup *settings =
-            new VerticalConfigurationGroup(false, true, false, false);
-        settings->addChild(MixerDevice());
-        settings->addChild(MixerControl());
-        settings->addChild(MixerVolume());
-        settings->addChild(PCMVolume());
-
-        ConfigurationGroup *dummy =
-            new VerticalConfigurationGroup(false, true, false, false);
-
-        // Show Mixer config only if internal volume controls enabled
-        setTrigger(volumeControl);
-        addTarget("0", dummy);
-        addTarget("1", settings);
-    }
-};
-
 static HostComboBox *MythLanguage()
 {
     HostComboBox *gc = new HostComboBox("Language");
@@ -3923,10 +3344,6 @@ MainGeneralSettings::MainGeneralSettings()
     pin->addChild(SetupPinCode());
     addChild(pin);
 
-    addChild(new AudioConfigSettings());
-
-    addChild(new AudioMixerSettingsGroup());
-
     VerticalConfigurationGroup *general =
         new VerticalConfigurationGroup(false, true, false, false);
     general->setLabel(QObject::tr("General"));
diff --git a/mythtv/programs/mythfrontend/globalsettings.h b/mythtv/programs/mythfrontend/globalsettings.h
index 7c9b4d5..90cb98a 100644
--- a/mythtv/programs/mythfrontend/globalsettings.h
+++ b/mythtv/programs/mythfrontend/globalsettings.h
@@ -9,73 +9,8 @@
 #include "videodisplayprofile.h"
 
 #include <QMutex>
-#include "audiooutput.h"
 
 class QFileInfo;
-class AudioDeviceComboBox;
-
-class AudioConfigSettings : public VerticalConfigurationGroup
-{
-    Q_OBJECT
-
-  public:
-    AudioConfigSettings();
-
-    typedef QMap<QString,AudioOutput::AudioDeviceConfig> ADCMap;
-
-    ADCMap &AudioDeviceMap(void) { return audiodevs; };
-    AudioOutput::ADCVect &AudioDeviceVect(void) { return devices; };
-
-  private slots:
-    void UpdateVisibility(const QString&);
-    void UpdateCapabilities(const QString&);
-    void AudioRescan();
-
-  private:
-    AudioDeviceComboBox  *OutputDevice();
-    HostComboBox         *MaxAudioChannels();
-    HostCheckBox         *AudioUpmix();
-    HostComboBox         *AudioUpmixType();
-    HostCheckBox         *AC3PassThrough();
-    HostCheckBox         *DTSPassThrough();
-    HostCheckBox         *MPCM();
-    HostCheckBox         *AdvancedAudioSettings();
-    HostCheckBox         *SRCQualityOverride();
-    HostComboBox         *SRCQuality();
-    HostCheckBox         *Audio48kOverride();
-    HostCheckBox         *PassThroughOverride();
-    HostComboBox         *PassThroughOutputDevice();
-
-    ConfigurationGroup   *m_cgsettings;
-    AudioDeviceComboBox  *m_OutputDevice;
-    HostComboBox         *m_MaxAudioChannels;
-    HostCheckBox         *m_AudioUpmix;
-    HostComboBox         *m_AudioUpmixType;
-    TransCheckBoxSetting *m_triggerDigital;
-    TransCheckBoxSetting *m_triggerMPCM;
-    HostCheckBox         *m_AC3PassThrough;
-    HostCheckBox         *m_DTSPassThrough;
-    HostCheckBox         *m_MPCM;
-    HostCheckBox         *m_AdvancedAudioSettings;
-    HostCheckBox         *m_PassThroughOverride;
-    ADCMap                audiodevs;
-    AudioOutput::ADCVect  devices;
-    QMutex                slotlock;
-};
-
-class AudioDeviceComboBox : public HostComboBox
-{
-    Q_OBJECT
-  public:
-    AudioDeviceComboBox(AudioConfigSettings*);
-    void AudioRescan();
-
-  private slots:
-    void AudioDescriptionHelp(const QString&);
-
-  private:
-    AudioConfigSettings *m_parent;
-};
 
 class ThemeSelector : public HostImageSelect
 {
diff --git a/mythtv/programs/mythfrontend/main.cpp b/mythtv/programs/mythfrontend/main.cpp
index 7b42569..feec308 100644
--- a/mythtv/programs/mythfrontend/main.cpp
+++ b/mythtv/programs/mythfrontend/main.cpp
@@ -33,7 +33,9 @@ using namespace std;
 #include "programrecpriority.h"
 #include "channelrecpriority.h"
 #include "custompriority.h"
+#include "audiooutput.h"
 #include "globalsettings.h"
+#include "audiosettings.h"
 #include "profilegroup.h"
 #include "playgroup.h"
 #include "networkcontrol.h"
@@ -593,6 +595,11 @@ static void TVMenuCallback(void *data, QString &selection)
         QStringList strlist( QString("REFRESH_BACKEND") );
         gCoreContext->SendReceiveStringList(strlist);
     }
+    else if (sel == "settings audiogeneral")
+    {
+        AudioGeneralSettings audiosettings;
+        audiosettings.exec();
+    }
     else if (sel == "settings playback")
     {
         PlaybackSettings settings;
diff --git a/mythtv/programs/mythfrontend/mythfrontend.pro b/mythtv/programs/mythfrontend/mythfrontend.pro
index 6531079..2b161ff 100644
--- a/mythtv/programs/mythfrontend/mythfrontend.pro
+++ b/mythtv/programs/mythfrontend/mythfrontend.pro
@@ -20,7 +20,7 @@ INSTALLS += setting
 QMAKE_CLEAN += $(TARGET)
 
 # Input
-HEADERS += playbackbox.h viewscheduled.h globalsettings.h
+HEADERS += playbackbox.h viewscheduled.h globalsettings.h audiosettings.h
 HEADERS += manualschedule.h programrecpriority.h channelrecpriority.h
 HEADERS += statusbox.h networkcontrol.h custompriority.h
 HEADERS += mediarenderer.h mythfexml.h playbackboxlistitem.h
@@ -33,7 +33,7 @@ HEADERS += proglist.h                   proglist_helpers.h
 HEADERS += playbackboxhelper.h          viewschedulediff.h
 HEADERS += themechooser.h
 
-SOURCES += main.cpp playbackbox.cpp viewscheduled.cpp
+SOURCES += main.cpp playbackbox.cpp viewscheduled.cpp audiosettings.cpp
 SOURCES += globalsettings.cpp manualschedule.cpp programrecpriority.cpp
 SOURCES += channelrecpriority.cpp statusbox.cpp networkcontrol.cpp
 SOURCES += mediarenderer.cpp mythfexml.cpp playbackboxlistitem.cpp
diff --git a/mythtv/themes/DVR/main_settings.xml b/mythtv/themes/DVR/main_settings.xml
index 2472b9a..8d1b5f8 100644
--- a/mythtv/themes/DVR/main_settings.xml
+++ b/mythtv/themes/DVR/main_settings.xml
@@ -23,6 +23,13 @@
     </button>
 
     <button>
+        <type>SETTINGS_AUDIOGENERAL</type>
+        <text>Audio</text>
+        <description>Configure local audio output</description>
+        <action>SETTINGS AUDIOGENERAL</action>
+    </button>
+
+    <button>
         <type>SCREENSETUPWIZARD</type>
         <text>Screen Setup Wizards</text>
         <description>Compensate for TVs with overscan</description>
diff --git a/mythtv/themes/MythCenter-wide/menu-ui.xml b/mythtv/themes/MythCenter-wide/menu-ui.xml
index 44d8178..e37aad5 100644
--- a/mythtv/themes/MythCenter-wide/menu-ui.xml
+++ b/mythtv/themes/MythCenter-wide/menu-ui.xml
@@ -286,6 +286,7 @@
                     <filename>watermark/appearance.png</filename>
                 </imagetype>
             </state>
+            <state name="SETTINGS_AUDIOGENERAL" from="SETUP" />
             <state name="SCREENSETUPWIZARD" from="DEFAULT">
                 <imagetype name="watermark">
                     <filename>watermark/screenwiz.png</filename>
diff --git a/mythtv/themes/MythCenter/menu-ui.xml b/mythtv/themes/MythCenter/menu-ui.xml
index d350b7d..0a22c67 100644
--- a/mythtv/themes/MythCenter/menu-ui.xml
+++ b/mythtv/themes/MythCenter/menu-ui.xml
@@ -281,6 +281,7 @@
                     <filename>watermark/appearance.png</filename>
                 </imagetype>
             </state>
+            <state name="SETTINGS_GENERAL" from="SETUP" />
             <state name="SCREENSETUPWIZARD" from="DEFAULT">
                 <imagetype name="watermark">
                     <filename>watermark/screenwiz.png</filename>
diff --git a/mythtv/themes/classic/main_settings.xml b/mythtv/themes/classic/main_settings.xml
index 986021d..742c6e4 100644
--- a/mythtv/themes/classic/main_settings.xml
+++ b/mythtv/themes/classic/main_settings.xml
@@ -23,6 +23,13 @@
     </button>
 
     <button>
+        <type>SETTINGS_AUDIOGENERAL</type>
+        <text>Audio</text>
+        <description>Configure local audio output</description>
+        <action>SETTINGS AUDIOGENERAL</action>
+    </button>
+
+    <button>
         <type>SCREENSETUPWIZARD</type>
         <text>Screen Setup Wizards</text>
         <description>Compensate for TVs with overscan</description>
diff --git a/mythtv/themes/defaultmenu/main_settings.xml b/mythtv/themes/defaultmenu/main_settings.xml
index a251a3d..a3e43b6 100644
--- a/mythtv/themes/defaultmenu/main_settings.xml
+++ b/mythtv/themes/defaultmenu/main_settings.xml
@@ -23,6 +23,13 @@
     </button>
 
     <button>
+        <type>SETTINGS_AUDIOGENERAL</type>
+        <text>Audio</text>
+        <description>Configure local audio output</description>
+        <action>SETTINGS AUDIOGENERAL</action>
+    </button>
+
+    <button>
         <type>SCREENSETUPWIZARD</type>
         <text>Screen Setup Wizards</text>
         <description>Compensate for TVs with overscan</description>
diff --git a/mythtv/themes/mediacentermenu/main_settings.xml b/mythtv/themes/mediacentermenu/main_settings.xml
index 60cdedc..d05b3cf 100644
--- a/mythtv/themes/mediacentermenu/main_settings.xml
+++ b/mythtv/themes/mediacentermenu/main_settings.xml
@@ -23,6 +23,13 @@
     </button>
 
     <button>
+        <type>SETTINGS_AUDIOGENERAL</type>
+        <text>Audio</text>
+        <description>Configure local audio output</description>
+        <action>SETTINGS AUDIOGENERAL</action>
+    </button>
+
+    <button>
         <type>SCREENSETUPWIZARD</type>
         <text>Screen Setup Wizards</text>
         <description>Compensate for TVs with overscan</description>