Changeset 2487

Show
Ignore:
Timestamp:
03/06/14 02:25:08 (10 years ago)
Author:
mocchi
Message:

bebob: improve support for PreSonus? Inspire1394

This device uses AV/C Vendor Dependent commands for its mic-preamp.

This commit add 'Inspire1394Device', 'Inspire1394Cmd' and 'BinaryControl?' class in 'BeBoB::PreSonus?' namespace and improve current python script fir ffado-mixer.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/libffado/src/bebob/bebob_avdevice.cpp

    r2482 r2487  
    3939#include "bebob/maudio/maudio_normal_avdevice.h" 
    4040#include "bebob/presonus/firebox_avdevice.h" 
     41#include "bebob/presonus/inspire1394_avdevice.h" 
    4142 
    4243#include "libieee1394/configrom.h" 
     
    187188        case 0x00010000: 
    188189            return new Presonus::FireboxDevice(d, configRom); 
     190        case 0x00010001: 
     191            return new Presonus::Inspire1394Device(d, configRom); 
    189192        default: 
    190193            return new Device(d, configRom); 
  • trunk/libffado/src/bebob/presonus/inspire1394_avdevice.cpp

    r2482 r2487  
    2626 
    2727#include "libutil/ByteSwap.h" 
    28 #include <iostream> 
     28#include "libutil/cmd_serialize.h" 
    2929 
    3030namespace BeBoB { 
    3131namespace Presonus { 
    3232 
    33 Inspire1394VendorDependentCmd::Inspire1394VendorDependentCmd(Ieee1394Service& ieee1394service) 
     33Inspire1394Cmd::Inspire1394Cmd(Ieee1394Service& ieee1394service) 
    3434    : VendorDependentCmd( ieee1394service ) 
    3535    , m_subfunc( 0x00 ) 
     
    3838{ 
    3939    m_companyId = 0x000a92; 
    40 
    41 bool Inspire1394VendorDependentCmd::serialize( Util::Cmd::IOSSerialize& se ) 
     40    setSubunitType( AVC::eST_Audio ); 
     41    setSubunitId( 0x00 ); 
     42
     43bool Inspire1394Cmd::serialize( Util::Cmd::IOSSerialize& se ) 
    4244{ 
    4345    bool result = true; 
    4446    result &= VendorDependentCmd::serialize( se ); 
    45     result &= se.write(m_subfunc, "Inspire1394VendorDependentCmd subfunc"); 
    46     result &= se.write(m_idx, "Inspire1394VendorDependentCmd idx"); 
    47     result &= se.write(m_arg, "Inspire1394VendorDependentCmd arg"); 
     47    result &= se.write(m_subfunc, "Inspire1394Cmd subfunc"); 
     48    result &= se.write(m_idx, "Inspire1394Cmd idx"); 
     49    result &= se.write(m_arg, "Inspire1394Cmd arg"); 
    4850 
    4951    return result; 
    5052} 
    51 bool Inspire1394VendorDependentCmd::deserialize( Util::Cmd::IOSDeserialize& de ) 
     53bool Inspire1394Cmd::deserialize( Util::Cmd::IISDeserialize& de ) 
    5254{ 
    5355    bool result = true; 
     
    6163 
    6264BinaryControl::BinaryControl(Inspire1394Device& parent, 
    63                 EInspire1394SubFunc subfunc, 
     65                EInspire1394CmdSubfunc subfunc, 
    6466                std::string name, std::string label, std::string desc) 
    6567    : Control::Discrete(&parent) 
     
    7375bool BinaryControl::setValue(int idx, int v) 
    7476{ 
    75     uint32_t val = v; 
     77    uint8_t val = v; 
    7678 
    7779    debugOutput(DEBUG_LEVEL_VERBOSE, 
     
    8890int BinaryControl::getValue(int idx) 
    8991{ 
    90     uint32_t val; 
     92    uint8_t val; 
    9193 
    9294    if ( !m_Parent.getSpecificValue(m_subfunc, idx, &val) ) { 
     
    108110    addSpecificControls(); 
    109111} 
     112Inspire1394Device::~Inspire1394Device(void)  
     113{ 
     114} 
    110115void Inspire1394Device::showDevice() 
    111116{ 
     
    114119    BeBoB::Device::showDevice(); 
    115120} 
    116 bool Inspire1394Device::addSpecificControls(
     121bool Inspire1394Device::addSpecificControls(void
    117122{ 
    118123    Control::Container *ctls; 
    119     BinaryControl ctl; 
     124    BinaryControl *ctl; 
    120125    bool result = true; 
    121126 
     
    123128                "Building a PreSonus Inspire1394 mixer...\n"); 
    124129 
    125     ctls = new Control::Container(m_eap, "GlobalMute"); 
     130    ctls = new Control::Container(this, "Preamp"); 
    126131    if ( !addElement(ctls) ) { 
    127132        debugWarning("Could not register specific controls to device\n"); 
     
    130135    } 
    131136 
    132     ctl = BinaryControl(*this, Inspire1394CmdTypePhono, 
     137    // RIAA equalization curve for Analog In 3/4 
     138    ctl = new BinaryControl(*this, EInspire1394CmdSubfuncPhono, 
    133139                        "PhonoSwitch", "Phono Switch", "Phono Switch"); 
    134140    result &= ctls->addElement(ctl); 
    135141 
    136     ctl = BinaryControl(*this, Inspire1394CmdTypePhantom, 
     142    // 48V for Analog In 1/2 
     143    ctl = new BinaryControl(*this, EInspire1394CmdSubfuncPhantom, 
    137144                        "PhantomPower", "Phantom Power", "Phantom Power"); 
    138145    result &= ctls->addElement(ctl); 
    139146 
    140     ctl = BinaryControl(*this, Inspire1394CmdTypeBoost, 
     147    // +20dB for Analog In 1/2  
     148    ctl = new BinaryControl(*this, EInspire1394CmdSubfuncBoost, 
    141149                        "MicBoost", "Mic Boost", "Mic Boost"); 
    142150    result &= ctls->addElement(ctl); 
    143151 
    144     ctl = BinaryControl(*this, Inspire1394CmdTypeLine, 
    145                         "LineSwitch", "Line Switch", "Line Switch"); 
     152    // Limitter of preamp for Analog In 1/2 
     153    ctl = new BinaryControl(*this, EInspire1394CmdSubfuncLimit, 
     154                        "MicLimit", "Mic Limit", "Mic Limit"); 
    146155    result &= ctls->addElement(ctl); 
    147156 
     
    154163    return true; 
    155164} 
    156 bool Inspire1394Device::getSpecificValue(EInspire1394CmdSubFunc subfunc, 
    157                                          int idx, uint32_t *val) 
    158 { 
    159     Inspire1394VendorDependentCmd cmd( get1394Service() ); 
     165bool Inspire1394Device::getSpecificValue(EInspire1394CmdSubfunc subfunc, 
     166                                         int idx, uint8_t *val) 
     167{ 
     168    Inspire1394Cmd cmd( get1394Service() ); 
    160169    cmd.setCommandType( AVC::AVCCommand::eCT_Status ); 
    161     cmd.setNodeId( getConfigRom() ); 
     170    cmd.setNodeId( getConfigRom().getNodeId() ); 
    162171    cmd.setVerbose( getDebugLevel() ); 
    163172 
    164     cmd.setSubFunc(subfunc); 
     173    cmd.setSubfunc(subfunc); 
    165174    cmd.setIdx(idx); 
    166175    cmd.setArg(0xff); 
    167176 
    168177    if ( !cmd.fire() ) { 
    169         debugError( "Inspire1394VendorDependentCmd failed\n" ); 
     178        debugError( "Inspire1394Cmd failed\n" ); 
     179        return false; 
     180    } else if (cmd.getResponse() != AVC::AVCCommand::eR_Implemented ) { 
     181        debugError("Inspire1394Cmd received error response\n"); 
    170182        return false; 
    171183    } 
     
    175187    return true; 
    176188} 
    177 bool Inspire1394Device::setSpecificValue(EInspire1394CmdSubFUnc type
    178                                          int idx, uint32_t val) 
    179 { 
    180     Inspire1394VendorDependentCmd cmd( get1394Service() ); 
     189bool Inspire1394Device::setSpecificValue(EInspire1394CmdSubfunc subfunc
     190                                         int idx, uint8_t val) 
     191{ 
     192    Inspire1394Cmd cmd( get1394Service() ); 
    181193    cmd.setCommandType( AVC::AVCCommand::eCT_Control ); 
    182     cmd.setNodeId( getConfigRom() ); 
     194    cmd.setNodeId( getConfigRom().getNodeId() ); 
    183195    cmd.setVerbose( getDebugLevel() ); 
    184196 
    185     cmd.setSubFunc(type); 
     197    cmd.setSubfunc(subfunc); 
    186198    cmd.setIdx(idx); 
    187199    cmd.setArg(val); 
    188200 
    189201    if ( !cmd.fire() ) { 
    190         debugError( "Inspire1394VendorDependentCmd failed\n" ); 
    191         return false; 
    192     } 
    193  
    194     return true; 
    195 
     202        debugError( "Inspire1394Cmd failed\n" ); 
     203        return false; 
     204    } else if (cmd.getResponse() != AVC::AVCCommand::eR_Accepted) { 
     205        debugError("Inspire1394Cmd received error response\n"); 
     206        return false; 
     207    } 
     208 
     209    return true; 
    196210} 
    197211 
  • trunk/libffado/src/bebob/presonus/inspire1394_avdevice.h

    r2482 r2487  
    3030#include "bebob/bebob_avdevice.h" 
    3131 
     32#include "libavc/general/avc_vendor_dependent_cmd.h" 
     33 
    3234namespace BeBoB { 
    3335namespace Presonus { 
    3436 
    35 enum EInspire1394CmdSubFunc { 
    36     EInspire1394CmdSubFuncPhono
    37     EInspire1394CmdSubFuncPhantom, 
    38     EInspire1394CmdSubFuncBoost, 
    39     EInspire1394CmdSubFuncLimit 
     37enum EInspire1394CmdSubfunc { 
     38    EInspire1394CmdSubfuncPhono = 0
     39    EInspire1394CmdSubfuncPhantom, 
     40    EInspire1394CmdSubfuncBoost, 
     41    EInspire1394CmdSubfuncLimit 
    4042}; 
    4143 
    42 class Inspire1394VendorDependentCmd:: public AVC::VendorDependentCmd 
     44class Inspire1394Device : public BeBoB::Device { 
     45public: 
     46    Inspire1394Device( DeviceManager& d, std::auto_ptr<ConfigRom>( configRom )); 
     47    virtual ~Inspire1394Device(); 
     48 
     49    virtual void showDevice(); 
     50 
     51    bool setSpecificValue(EInspire1394CmdSubfunc subfunc, 
     52                          int idx, uint8_t val); 
     53    bool getSpecificValue(EInspire1394CmdSubfunc subfunc, 
     54                          int idx, uint8_t *val); 
     55private: 
     56    bool addSpecificControls(void); 
     57}; 
     58 
     59class Inspire1394Cmd : public AVC::VendorDependentCmd 
    4360{ 
    4461public: 
    45     Inspire1394VendorDependentCmd( Ieee1394Service& ieee1394service ); 
    46     virtual ~Inspire1394VendorDependentCmd
     62    Inspire1394Cmd( Ieee1394Service& ieee1394service ); 
     63    virtual ~Inspire1394Cmd() {}
    4764 
    4865    virtual bool serialize( Util::Cmd::IOSSerialize& se); 
    49     virtual bool deserialize( Util::Cmd::IOSDeserialize& de ); 
     66    virtual bool deserialize( Util::Cmd::IISDeserialize& de ); 
    5067 
    5168    virtual const char* getCmdName() const 
    52     { return "Inspire1394VendorDependentCmd"; } 
     69    { return "Inspire1394Cmd"; } 
    5370 
    54     virtual void setSubFunc(EInspire1394CmdSubFunc subfunc) 
     71    virtual void setSubfunc(uint8_t subfunc) 
    5572    { m_subfunc = subfunc; } 
    5673    virtual void setIdx(int idx) 
     
    6380 
    6481protected: 
    65     EInspire1394CmdSubFunc m_subfunc; 
    66     uint32_t m_idx; 
    67     uint32_t m_arg; 
    68 } 
     82    uint8_t m_subfunc; 
     83    uint8_t m_idx; 
     84    uint8_t m_arg; 
     85}; 
    6986 
    70 class BinaryControl 
    71     : public Control::Discrete 
     87class BinaryControl : public Control::Discrete 
    7288{ 
    7389public: 
    7490    BinaryControl(Inspire1394Device& parent, 
    75                   EInspire1394CmdSubFunc subfunc, 
     91                  EInspire1394CmdSubfunc subfunc, 
    7692                  std::string name, std::string label, std::string desc); 
    7793 
    78     virtual bool setValue(int val) { 
    79         { return setValue(0, val); } 
    80     virtual int getValue() { 
    81         { return getValue(0); } 
    8294    virtual bool setValue(int idx, int val); 
    8395    virtual int getValue(int idx); 
     96    virtual bool setValue(int val) 
     97        { return setValue(0, val); } 
     98    virtual int getValue(void) 
     99        { return getValue(0); } 
    84100 
    85     virtual int getMinimum() {return 0;}; 
    86     virtual int getMaximum() {return 1;}; 
     101    virtual int getMinimum() { return 0; }; 
     102    virtual int getMaximum() { return 1; }; 
    87103 
    88104private: 
    89105    Inspire1394Device&      m_Parent; 
    90     EInspire1394CmdSubFuncm_subfunc; 
    91 }; 
    92  
    93 class Inspire1394Device : public BeBoB::Device { 
    94 public: 
    95     Inspire1394Device( DeviceManager& d, std::auto_ptr<ConfigRom>( configRom )); 
    96     virtual ~Inspire1394Device(); 
    97  
    98     virtual void showDevice(); 
    99  
    100 private: 
    101     bool getSpecificValue(); 
    102     bool setSpecificValue(); 
     106    EInspire1394CmdSubfunc  m_subfunc; 
    103107}; 
    104108 
  • trunk/libffado/src/SConscript

    r2482 r2487  
    100100        bebob/maudio/maudio_normal_avdevice.cpp \ 
    101101        bebob/presonus/firebox_avdevice.cpp \ 
     102        bebob/presonus/inspire1394_avdevice.cpp \ 
    102103' ) 
    103104 
  • trunk/libffado/support/mixer-qt4/ffado/mixer/presonus_inspire1394.py

    r2486 r2487  
    2323from PyQt4.QtCore import QObject, Qt, SIGNAL 
    2424from PyQt4.QtGui import QHBoxLayout, QVBoxLayout, QGridLayout 
    25 from PyQt4.QtGui import QGroupBox, QLabel, QSizePolicy, QSlider, QComboBox, QToolButton 
     25from PyQt4.QtGui import QGroupBox, QLabel, QSizePolicy, QSlider, QDial, QComboBox, QToolButton 
    2626from math import log10 
    2727from ffado.config import * 
     
    3535    mixer_src = [[3, "Analog in 1/2"], 
    3636                 [4, "Analog in 3/4"], 
    37                  [5, "Stream in 5/6"]] 
     37                 [5, "Stream in 1/2"]] 
    3838 
    3939    # feature id/name 
     
    5353        self.Selectors = {} 
    5454        self.Volumes = {} 
     55        self.Preamps = {} 
     56        self.Pannings = {} 
     57        self.Mutes = {} 
    5558 
    5659        plain_layout = QHBoxLayout(self) 
     
    7376        box.setTitle("Analog Inputs") 
    7477 
    75         grid = QGroupBox(box) 
    76         box_layout.addWidget(grid) 
    7778        grid_layout = QGridLayout() 
    78         grid.setLayout(grid_layout) 
     79        box_layout.addLayout(grid_layout) 
    7980     
    80         self.addVolumes(self.inputs, grid, grid_layout) 
     81        self.addVolumes(self.inputs, 0, box, grid_layout) 
    8182 
    8283    def addAnalogOutputs(self, box): 
     
    8586        box.setTitle("Analog Outputs") 
    8687 
    87         cmb = QComboBox(box) 
    88         box_layout.addWidget(cmb) 
    89         for i in range(len(self.out_src[1])): 
    90             cmb.addItem(self.out_src[1][i], i) 
    91             self.Selectors[cmb] = ["/Mixer/Selector_%d" % self.out_src[0]] 
    92  
    93         grid = QGroupBox(box) 
    94         box_layout.addWidget(grid) 
    9588        grid_layout = QGridLayout() 
    96         grid.setLayout(grid_layout) 
    97  
    98         self.addVolumes(self.outputs, grid, grid_layout) 
     89        box_layout.addLayout(grid_layout) 
     90 
     91        self.addVolumes(self.outputs, 2, box, grid_layout) 
    9992 
    10093    def addInternalMixer(self, box): 
     
    10396        box.setTitle("Hardware Mixer") 
    10497 
    105         self.addVolumes(self.mixer_src, box, box_layout) 
    106  
    107     def addVolumes(self, elms, parent, layout): 
     98        self.addVolumes(self.mixer_src, 1, box, box_layout) 
     99 
     100    def addVolumes(self, elms, kind, parent, layout): 
     101        def addPreampParam(label, ch, path, layout): 
     102            button = self.getThinButton(parent, label) 
     103            layout.addWidget(button) 
     104            self.Preamps[button] = ["/Preamp/%s" % path, ch] 
     105            return 
     106 
    108107        for col in range(len(elms)): 
    109108            label = QLabel(parent) 
    110109            label.setText(elms[col][1]) 
    111             layout.addWidget(label, 0, col * 2, 1, 2, Qt.AlignHCenter) 
     110            layout.addWidget(label, 0, col * 2, 1, 2, Qt.AlignHCenter | Qt.AlignTop) 
     111 
     112            if kind == 0: 
     113                if col == 0: 
     114                    for ch in range(2): 
     115                        box_layout = QVBoxLayout() 
     116                        layout.addLayout(box_layout, 1, col * 2 + ch, Qt.AlignHCenter | Qt.AlignBottom) 
     117                        if col == 0: 
     118                            addPreampParam("+48V", ch + 1, "PhantomPower", box_layout) 
     119                            addPreampParam("Boost", ch + 1, "MicBoost", box_layout) 
     120                            addPreampParam("Limit", ch + 1, "MicLimit", box_layout) 
     121                else: 
     122                    box_layout = QVBoxLayout() 
     123                    addPreampParam("Phono", 0, "PhonoSwitch", box_layout) 
     124                    layout.addLayout(box_layout, 1, col * 2, 1, 2, Qt.AlignHCenter | Qt.AlignBottom) 
     125            elif kind == 1: 
     126                l_dial = self.getDial(parent) 
     127                r_dial = self.getDial(parent) 
     128 
     129                layout.addWidget(l_dial, 1, col * 2, Qt.AlignHCenter | Qt.AlignBottom) 
     130                layout.addWidget(r_dial, 1, col * 2 + 1, Qt.AlignHCenter | Qt.AlignBottom) 
     131 
     132                path = "/Mixer/Feature_LRBalance_%d" % elms[col][0] 
     133                self.Pannings[l_dial] = [path, 1] 
     134                self.Pannings[r_dial] = [path, 2] 
     135 
     136                if col == 2: 
     137                    l_dial.setDisabled(True) 
     138                    r_dial.setDisabled(True) 
     139 
     140            elif col == 0: 
     141                cmb = QComboBox(parent) 
     142                layout.addWidget(cmb, 1, col * 2, 1, 4, Qt.AlignHCenter | Qt.AlignBottom) 
     143                for i in range(len(self.out_src[1])): 
     144                    cmb.addItem(self.out_src[1][i], i) 
     145                    self.Selectors[cmb] = ["/Mixer/Selector_%d" % self.out_src[0]] 
    112146 
    113147            l_sld = self.getSlider(parent) 
    114148            r_sld = self.getSlider(parent) 
    115             layout.addWidget(l_sld, 1, col * 2, Qt.AlignHCenter) 
    116             layout.addWidget(r_sld, 1, col * 2 + 1, Qt.AlignHCenter) 
    117  
    118             link = self.getLink(parent) 
    119             layout.addWidget(link, 2, col * 2, 1, 2, Qt.AlignHCenter) 
     149            layout.addWidget(l_sld, 2, col * 2, Qt.AlignHCenter) 
     150            layout.addWidget(r_sld, 2, col * 2 + 1, Qt.AlignHCenter) 
     151 
     152            l_mute = self.getThinButton(parent, "Mute") 
     153            r_mute = self.getThinButton(parent, "Mute") 
     154            layout.addWidget(l_mute, 3, col * 2, Qt.AlignHCenter) 
     155            layout.addWidget(r_mute, 3, col * 2 + 1, Qt.AlignHCenter) 
     156 
     157            link = self.getWideButton(parent, "Link") 
     158            layout.addWidget(link, 4, col * 2, 1, 2, Qt.AlignHCenter) 
    120159 
    121160            path = "/Mixer/Feature_Volume_%d" % elms[col][0] 
    122             self.Volumes[l_sld] = [path, 1, r_sld, link] 
    123             self.Volumes[r_sld] = [path, 2, l_sld, link] 
     161            self.Volumes[l_sld] = [path, 1, r_sld, l_mute, link] 
     162            self.Volumes[r_sld] = [path, 2, l_sld, r_mute, link] 
     163 
     164            self.Mutes[l_mute] = [r_mute, l_sld] 
     165            self.Mutes[r_mute] = [l_mute, r_sld] 
    124166 
    125167    # widget helper functions 
     
    136178        return sld 
    137179 
    138     def getLink(self, parent): 
    139         link = QToolButton(parent) 
    140         link.setText("link") 
    141         link.setCheckable(True) 
    142         link.setMinimumWidth(100) 
    143         link.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) 
    144         return link 
     180    def getDial(self, parent): 
     181        dial = QDial(parent) 
     182        dial.setNotchesVisible(True) 
     183        dial.setNotchTarget(25.0) 
     184        dial.setMaximumHeight(40) 
     185        return dial; 
     186  
     187    def getThinButton(self, parent, text): 
     188        button = QToolButton(parent) 
     189        button.setText(text) 
     190        button.setCheckable(True) 
     191        button.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) 
     192        return button 
     193 
     194    def getWideButton(self, parent, label): 
     195        button = QToolButton(parent) 
     196        button.setText(label) 
     197        button.setCheckable(True) 
     198        button.setMinimumWidth(100) 
     199        button.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) 
     200        return button 
    145201 
    146202    def initValues(self): 
     
    155211           idx  = params[1] 
    156212           pair = params[2] 
    157            link = params[3] 
     213           mute = params[3] 
     214           link = params[4] 
    158215 
    159216           db = self.hw.getContignuous(path, idx) 
     
    162219           QObject.connect(ctl, SIGNAL('valueChanged(int)'), self.updateVolume) 
    163220 
     221           if vol == 0: 
     222               mute.setChecked(True) 
     223 
    164224           if idx == 2: 
    165225               pair_db = self.hw.getContignuous(path, 1) 
     
    167227                   link.setChecked(True) 
    168228 
     229        for ctl, params in self.Preamps.items(): 
     230            path = params[0] 
     231            idx = params[1] 
     232 
     233            vol = self.hw.getDiscrete(path, idx) 
     234            if vol > 0: 
     235                ctl.setChecked(True) 
     236 
     237            QObject.connect(ctl, SIGNAL('clicked(bool)'), self.updatePreamps) 
     238 
     239        #       Right - Center - Left 
     240        # 0x8000 - 0x0000 - 0x0001 - 0x7FFE 
     241        #        ..., -1, 0, +1, ... 
     242        for ctl, params in self.Pannings.items(): 
     243            path = params[0] 
     244            idx = params[1] 
     245 
     246            val = self.hw.getContignuous(path, idx) 
     247            state = -(val / 0x7FFE) * 50 + 50 
     248            ctl.setValue(state) 
     249            QObject.connect(ctl, SIGNAL('valueChanged(int)'), self.updatePanning) 
     250 
     251        for ctl, params in self.Mutes.items(): 
     252            QObject.connect(ctl, SIGNAL('clicked(bool)'), self.updateMute) 
     253 
    169254    # helper functions 
    170255    def vol2db(self, vol): 
     
    179264        self.hw.setDiscrete(path, state) 
    180265 
     266    def updatePreamps(self, state): 
     267        sender = self.sender() 
     268        path = self.Preamps[sender][0] 
     269        idx = self.Preamps[sender][1] 
     270        self.hw.setDiscrete(path, idx, state) 
     271 
    181272    def updateVolume(self, vol): 
    182273        sender = self.sender() 
     
    184275        idx    = self.Volumes[sender][1] 
    185276        pair   = self.Volumes[sender][2] 
    186         link   = self.Volumes[sender][3] 
     277        mute   = self.Volumes[sender][3] 
     278        link   = self.Volumes[sender][4] 
     279 
     280        if mute.isChecked(): 
     281                return 
    187282 
    188283        db = self.vol2db(vol) 
     
    191286        if link.isChecked(): 
    192287           pair.setValue(vol) 
     288 
     289    def updatePanning(self, state): 
     290        sender = self.sender() 
     291        path = self.Pannings[sender][0] 
     292        idx = self.Pannings[sender][1] 
     293        val  = (state - 50) * 0x7FFE / -50 
     294        self.hw.setContignuous(path, idx, val) 
     295 
     296    def updateMute(self, state): 
     297        sender = self.sender() 
     298        pair = self.Mutes[sender][0] 
     299        sld = self.Mutes[sender][1] 
     300 
     301        path = self.Volumes[sld][0] 
     302        idx = self.Volumes[sld][1] 
     303        pair_sld = self.Volumes[sld][2] 
     304        link = self.Volumes[sld][4] 
     305 
     306        if state: 
     307            db = 0x8000 
     308            vol = 0 
     309        else: 
     310            db = 0x0000 
     311            vol = 99 
     312 
     313        self.hw.setContignuous(path, db, idx) 
     314        sld.setValue(vol) 
     315        sld.setDisabled(state) 
     316 
     317        if link.isChecked(): 
     318            if idx == 1: 
     319               idx = 2 
     320            else: 
     321               idx = 1 
     322            self.hw.setContignuous(path, db, idx) 
     323            pair.setChecked(state) 
     324            pair_sld.setValue(vol) 
     325            pair_sld.setDisabled(state)