| @@ -43,38 +43,66 @@ else | |||||
| fi | fi | ||||
| # ---------------------------------------------- | # ---------------------------------------------- | ||||
| wanted_capture_ports=0 # -1 means default | |||||
| wanted_playback_ports=0 # -1 means default | |||||
| PLAY_ONLY="no" | |||||
| arg_is_for="" | |||||
| case $1 in | |||||
| -h|--h|--help) | |||||
| echo "usage: $0 [command] | |||||
| for arg in "$@";do | |||||
| case "$arg" in | |||||
| -h|--h|--help) | |||||
| echo "usage: $0 [command] | |||||
| -p Playback only with default number of channels | |||||
| -p <NUMBER> Number of playback channels | |||||
| -c Capture only with default number of channels | |||||
| -c <NUMBER> Number of capture channels | |||||
| -p, --play Playback mode only | |||||
| -h, --help Show this help menu | |||||
| --dummy Don't do anything, just create the needed files | |||||
| -h, --help Show this help menu | |||||
| --dummy Don't do anything, just create the needed files | |||||
| NOTE: | |||||
| When runned with no arguments, $(basename "$0") will | |||||
| activate PulseAudio with both playback and record modes with default number of channels. | |||||
| " | |||||
| exit | |||||
| ;; | |||||
| --dummy) | |||||
| exit | |||||
| ;; | |||||
| -c|--capture) | |||||
| arg_is_for="capture" | |||||
| wanted_capture_ports=-1 # -1 means default, if no (correct) argument is given. | |||||
| ;; | |||||
| -p|--play|--playback) | |||||
| arg_is_for="playback" | |||||
| wanted_playback_ports=-1 | |||||
| ;; | |||||
| * ) | |||||
| case "$arg_is_for" in | |||||
| "capture") | |||||
| [ "$arg" -ge 0 ] 2>/dev/null && wanted_capture_ports="$arg" | |||||
| ;; | |||||
| "playback") | |||||
| [ "$arg" -ge 0 ] 2>/dev/null && wanted_playback_ports="$arg" | |||||
| ;; | |||||
| esac | |||||
| ;; | |||||
| esac | |||||
| done | |||||
| NOTE: | |||||
| When runned with no arguments, pulse2jack will | |||||
| activate PulseAudio with both playback and record modes. | |||||
| " | |||||
| exit | |||||
| ;; | |||||
| --dummy) | |||||
| exit | |||||
| ;; | |||||
| if [ $wanted_capture_ports == 0 ] && [ $wanted_playback_ports == 0 ];then | |||||
| #no sense to want to start/bridge pulseaudio without ports, set as default | |||||
| capture_ports=-1 # -1 means default | |||||
| playback_ports=-1 # -1 means default | |||||
| fi | |||||
| -p|--p|--play) | |||||
| PLAY_ONLY="yes" | |||||
| FILE=$INSTALL_PREFIX/share/cadence/pulse2jack/play.pa | |||||
| ;; | |||||
| str_capture="channels=$wanted_capture_ports" #used for pulseaudio commands | |||||
| str_playback="channels=$wanted_playback_ports" ## | |||||
| *) | |||||
| FILE=$INSTALL_PREFIX/share/cadence/pulse2jack/play+rec.pa | |||||
| ;; | |||||
| esac | |||||
| [ $wanted_capture_ports == -1 ] && str_capture="" # -1 means default, no command channels=n | |||||
| [ $wanted_playback_ports == -1 ] && str_playback="" ## | |||||
| # ---------------------------------------------- | # ---------------------------------------------- | ||||
| @@ -88,40 +116,166 @@ IsPulseAudioRunning() | |||||
| fi | fi | ||||
| } | } | ||||
| if (IsPulseAudioRunning); then | |||||
| StartBridged() | |||||
| { | { | ||||
| if (`jack_lsp | grep "PulseAudio JACK Sink:" > /dev/null`); then | |||||
| { | |||||
| echo "PulseAudio is already running and bridged to JACK" | |||||
| } | |||||
| #write pulseaudio config file in a tmp file | |||||
| pa_file=$(mktemp --suffix .pa) | |||||
| echo .fail > $pa_file | |||||
| ### Automatically restore the volume of streams and devices | |||||
| echo load-module module-device-restore >> $pa_file | |||||
| echo load-module module-stream-restore >> $pa_file | |||||
| echo load-module module-card-restore >> $pa_file | |||||
| ### Load Jack modules | |||||
| [ $wanted_capture_ports != 0 ] && echo load-module module-jack-source $str_capture >> $pa_file | |||||
| [ $wanted_playback_ports != 0 ] && echo load-module module-jack-sink $str_playback >> $pa_file | |||||
| ### Load unix protocol | |||||
| echo load-module module-native-protocol-unix >> $pa_file | |||||
| ### Automatically restore the default sink/source when changed by the user | |||||
| ### during runtime | |||||
| ### NOTE: This should be loaded as early as possible so that subsequent modules | |||||
| ### that look up the default sink/source get the right value | |||||
| echo load-module module-default-device-restore >> $pa_file | |||||
| ### Automatically move streams to the default sink if the sink they are | |||||
| ### connected to dies, similar for sources | |||||
| echo load-module module-rescue-streams >> $pa_file | |||||
| ### Make sure we always have a sink around, even if it is a null sink. | |||||
| echo load-module module-always-sink >> $pa_file | |||||
| ### Make Jack default | |||||
| [ $wanted_capture_ports != 0 ] && echo set-default-source jack_in >> $pa_file | |||||
| [ $wanted_playback_ports != 0 ] && echo set-default-sink jack_out >> $pa_file | |||||
| if (`pulseaudio --daemonize --high-priority --realtime --exit-idle-time=-1 --file=$pa_file -n`); then | |||||
| echo "Initiated PulseAudio successfully!" | |||||
| else | else | ||||
| { | |||||
| echo "PulseAudio is already running, bridge it..." | |||||
| echo "Failed to initialize PulseAudio!" | |||||
| fi | |||||
| } | |||||
| if [ "$PLAY_ONLY" == "yes" ]; then | |||||
| { | |||||
| pactl load-module module-jack-sink > /dev/null | |||||
| pacmd set-default-source jack_in > /dev/null | |||||
| } | |||||
| else | |||||
| { | |||||
| pactl load-module module-jack-sink > /dev/null | |||||
| pactl load-module module-jack-source > /dev/null | |||||
| pacmd set-default-sink jack_out > /dev/null | |||||
| killReStart() | |||||
| { | |||||
| pulseaudio -k && StartBridged | |||||
| exit | |||||
| } | |||||
| JackNotRunning() | |||||
| { | |||||
| echo "JACK seems not running, start JACK before bridge PulseAudio" | |||||
| exit 1 | |||||
| } | |||||
| if (IsPulseAudioRunning); then | |||||
| { | |||||
| #count all Jack Audio Physical ports | |||||
| all_jack_lsp=$(jack_lsp -p -t) || JackNotRunning | |||||
| output_physical_lines=$(echo "$all_jack_lsp"|grep -n "output,physical,"|cut -d':' -f1) | |||||
| input_physical_lines=$( echo "$all_jack_lsp"|grep -n "input,physical," |cut -d':' -f1) | |||||
| audio_lines=$(echo "$all_jack_lsp" |grep -n " audio"|cut -d':' -f1) | |||||
| capture_physical_ports=0 | |||||
| playback_physical_ports=0 | |||||
| for out_phy_line in $output_physical_lines;do | |||||
| if echo "$audio_lines"|grep -q $(($out_phy_line + 1));then | |||||
| ((capture_physical_ports++)) | |||||
| fi | |||||
| done | |||||
| for in_phy_line in $input_physical_lines;do | |||||
| if echo "$audio_lines"|grep -q $(($in_phy_line + 1));then | |||||
| ((playback_physical_ports++)) | |||||
| fi | |||||
| done | |||||
| #count PulseAudio jack ports | |||||
| current_playback_ports=$(echo "$all_jack_lsp"|grep ^"PulseAudio JACK Sink:" |wc -l) | |||||
| current_capture_ports=$( echo "$all_jack_lsp"|grep ^"PulseAudio JACK Source:"|wc -l) | |||||
| #if number of pulseaudio ports equal to physical ports, consider pulseaudio module is running the default mode (no channels=n) | |||||
| [ $current_capture_ports == $capture_physical_ports ] && current_capture_ports=-1 | |||||
| [ $current_playback_ports == $playback_physical_ports ] && current_playback_ports=-1 | |||||
| [ $wanted_capture_ports == $capture_physical_ports ] && wanted_capture_ports=-1 | |||||
| [ $wanted_playback_ports == $playback_physical_ports ] && wanted_playback_ports=-1 | |||||
| if [ $wanted_capture_ports == $current_capture_ports ] && [ $wanted_playback_ports == $current_playback_ports ];then | |||||
| echo "PulseAudio is already started and bridged to Jack with $current_capture_ports inputs and $current_playback_ports outputs, nothing to do !" | |||||
| exit | |||||
| fi | |||||
| if [ $current_capture_ports != $wanted_capture_ports ];then | |||||
| if [ $current_capture_ports != 0 ];then | |||||
| echo "unload PulseAudio JACK Source" | |||||
| pactl unload-module module-jack-source > /dev/null || killReStart | |||||
| fi | |||||
| if [ $wanted_capture_ports != 0 ];then | |||||
| echo "load PulseAudio JACK Source $str_capture" | |||||
| pactl load-module module-jack-source $str_capture > /dev/null | |||||
| pacmd set-default-source jack_in > /dev/null | pacmd set-default-source jack_in > /dev/null | ||||
| } | |||||
| fi | fi | ||||
| echo "Done" | |||||
| } | |||||
| fi | |||||
| if [ $current_playback_ports != $wanted_playback_ports ];then | |||||
| if [ $current_playback_ports != 0 ];then | |||||
| echo "unload PulseAudio JACK Sink" | |||||
| pactl unload-module module-jack-sink > /dev/null || killReStart | |||||
| fi | |||||
| if [ $wanted_playback_ports != 0 ];then | |||||
| echo "load PulseAudio JACK Sink $str_playback" | |||||
| pactl load-module module-jack-sink $str_playback > /dev/null | |||||
| pactl set-default-sink jack_out > /dev/null | |||||
| fi | |||||
| fi | fi | ||||
| } | } | ||||
| else | else | ||||
| { | |||||
| if (`pulseaudio --daemonize --high-priority --realtime --exit-idle-time=-1 --file=$FILE -n`); then | |||||
| echo "Initiated PulseAudio successfully!" | |||||
| else | |||||
| echo "Failed to initialize PulseAudio!" | |||||
| fi | |||||
| { | |||||
| StartBridged | |||||
| # #write pulseaudio config file in a tmp file | |||||
| # pa_file=$(mktemp --suffix .pa) | |||||
| # echo .fail > $pa_file | |||||
| # | |||||
| # ### Automatically restore the volume of streams and devices | |||||
| # echo load-module module-device-restore >> $pa_file | |||||
| # echo load-module module-stream-restore >> $pa_file | |||||
| # echo load-module module-card-restore >> $pa_file | |||||
| # | |||||
| # ### Load Jack modules | |||||
| # [ $wanted_capture_ports != 0 ] && echo load-module module-jack-source $str_capture >> $pa_file | |||||
| # [ $wanted_playback_ports != 0 ] && echo load-module module-jack-sink $str_playback >> $pa_file | |||||
| # | |||||
| # ### Load unix protocol | |||||
| # echo load-module module-native-protocol-unix >> $pa_file | |||||
| # | |||||
| # ### Automatically restore the default sink/source when changed by the user | |||||
| # ### during runtime | |||||
| # ### NOTE: This should be loaded as early as possible so that subsequent modules | |||||
| # ### that look up the default sink/source get the right value | |||||
| # echo load-module module-default-device-restore >> $pa_file | |||||
| # | |||||
| # ### Automatically move streams to the default sink if the sink they are | |||||
| # ### connected to dies, similar for sources | |||||
| # echo load-module module-rescue-streams >> $pa_file | |||||
| # | |||||
| # ### Make sure we always have a sink around, even if it is a null sink. | |||||
| # echo load-module module-always-sink >> $pa_file | |||||
| # | |||||
| # ### Make Jack default | |||||
| # [ $wanted_capture_ports != 0 ] && echo set-default-source jack_in >> $pa_file | |||||
| # [ $wanted_playback_ports != 0 ] && echo set-default-sink jack_out >> $pa_file | |||||
| # | |||||
| # if (`pulseaudio --daemonize --high-priority --realtime --exit-idle-time=-1 --file=$pa_file -n`); then | |||||
| # echo "Initiated PulseAudio successfully!" | |||||
| # else | |||||
| # echo "Failed to initialize PulseAudio!" | |||||
| # fi | |||||
| } | } | ||||
| fi | fi | ||||
| @@ -7,7 +7,7 @@ | |||||
| <x>0</x> | <x>0</x> | ||||
| <y>0</y> | <y>0</y> | ||||
| <width>740</width> | <width>740</width> | ||||
| <height>564</height> | |||||
| <height>680</height> | |||||
| </rect> | </rect> | ||||
| </property> | </property> | ||||
| <property name="windowTitle"> | <property name="windowTitle"> | ||||
| @@ -544,7 +544,16 @@ | |||||
| <string>JACK Bridges</string> | <string>JACK Bridges</string> | ||||
| </property> | </property> | ||||
| <layout class="QGridLayout" name="gridLayout_5"> | <layout class="QGridLayout" name="gridLayout_5"> | ||||
| <property name="margin"> | |||||
| <property name="leftMargin"> | |||||
| <number>2</number> | |||||
| </property> | |||||
| <property name="topMargin"> | |||||
| <number>2</number> | |||||
| </property> | |||||
| <property name="rightMargin"> | |||||
| <number>2</number> | |||||
| </property> | |||||
| <property name="bottomMargin"> | |||||
| <number>2</number> | <number>2</number> | ||||
| </property> | </property> | ||||
| <item row="0" column="0"> | <item row="0" column="0"> | ||||
| @@ -572,8 +581,8 @@ | |||||
| <rect> | <rect> | ||||
| <x>0</x> | <x>0</x> | ||||
| <y>0</y> | <y>0</y> | ||||
| <width>360</width> | |||||
| <height>100</height> | |||||
| <width>435</width> | |||||
| <height>130</height> | |||||
| </rect> | </rect> | ||||
| </property> | </property> | ||||
| <attribute name="label"> | <attribute name="label"> | ||||
| @@ -720,8 +729,8 @@ | |||||
| <rect> | <rect> | ||||
| <x>0</x> | <x>0</x> | ||||
| <y>0</y> | <y>0</y> | ||||
| <width>360</width> | |||||
| <height>97</height> | |||||
| <width>435</width> | |||||
| <height>130</height> | |||||
| </rect> | </rect> | ||||
| </property> | </property> | ||||
| <attribute name="label"> | <attribute name="label"> | ||||
| @@ -854,8 +863,8 @@ | |||||
| <rect> | <rect> | ||||
| <x>0</x> | <x>0</x> | ||||
| <y>0</y> | <y>0</y> | ||||
| <width>360</width> | |||||
| <height>97</height> | |||||
| <width>435</width> | |||||
| <height>130</height> | |||||
| </rect> | </rect> | ||||
| </property> | </property> | ||||
| <attribute name="label"> | <attribute name="label"> | ||||
| @@ -916,6 +925,13 @@ | |||||
| </property> | </property> | ||||
| </widget> | </widget> | ||||
| </item> | </item> | ||||
| <item> | |||||
| <widget class="QPushButton" name="b_pulse_channels"> | |||||
| <property name="text"> | |||||
| <string>Channels</string> | |||||
| </property> | |||||
| </widget> | |||||
| </item> | |||||
| <item> | <item> | ||||
| <spacer name="horizontalSpacer_13"> | <spacer name="horizontalSpacer_13"> | ||||
| <property name="orientation"> | <property name="orientation"> | ||||
| @@ -956,13 +972,6 @@ | |||||
| </property> | </property> | ||||
| </widget> | </widget> | ||||
| </item> | </item> | ||||
| <item> | |||||
| <widget class="QToolButton" name="tb_pulse_options"> | |||||
| <property name="text"> | |||||
| <string>...</string> | |||||
| </property> | |||||
| </widget> | |||||
| </item> | |||||
| </layout> | </layout> | ||||
| </item> | </item> | ||||
| <item> | <item> | ||||
| @@ -1572,7 +1581,7 @@ | |||||
| <string>Audio Plugins PATH</string> | <string>Audio Plugins PATH</string> | ||||
| </property> | </property> | ||||
| <property name="textAlignment"> | <property name="textAlignment"> | ||||
| <set>AlignHCenter|AlignVCenter|AlignCenter</set> | |||||
| <set>AlignCenter</set> | |||||
| </property> | </property> | ||||
| <property name="flags"> | <property name="flags"> | ||||
| <set>ItemIsSelectable|ItemIsEnabled</set> | <set>ItemIsSelectable|ItemIsEnabled</set> | ||||
| @@ -1583,7 +1592,7 @@ | |||||
| <string>Default Applications</string> | <string>Default Applications</string> | ||||
| </property> | </property> | ||||
| <property name="textAlignment"> | <property name="textAlignment"> | ||||
| <set>AlignHCenter|AlignVCenter|AlignCenter</set> | |||||
| <set>AlignCenter</set> | |||||
| </property> | </property> | ||||
| <property name="flags"> | <property name="flags"> | ||||
| <set>ItemIsSelectable|ItemIsEnabled</set> | <set>ItemIsSelectable|ItemIsEnabled</set> | ||||
| @@ -1594,7 +1603,7 @@ | |||||
| <string>WineASIO</string> | <string>WineASIO</string> | ||||
| </property> | </property> | ||||
| <property name="textAlignment"> | <property name="textAlignment"> | ||||
| <set>AlignHCenter|AlignVCenter|AlignCenter</set> | |||||
| <set>AlignCenter</set> | |||||
| </property> | </property> | ||||
| <property name="flags"> | <property name="flags"> | ||||
| <set>ItemIsSelectable|ItemIsEnabled</set> | <set>ItemIsSelectable|ItemIsEnabled</set> | ||||
| @@ -1613,7 +1622,16 @@ | |||||
| </property> | </property> | ||||
| <widget class="QWidget" name="page_plugins"> | <widget class="QWidget" name="page_plugins"> | ||||
| <layout class="QGridLayout" name="gridLayout_6"> | <layout class="QGridLayout" name="gridLayout_6"> | ||||
| <property name="margin"> | |||||
| <property name="leftMargin"> | |||||
| <number>0</number> | |||||
| </property> | |||||
| <property name="topMargin"> | |||||
| <number>0</number> | |||||
| </property> | |||||
| <property name="rightMargin"> | |||||
| <number>0</number> | |||||
| </property> | |||||
| <property name="bottomMargin"> | |||||
| <number>0</number> | <number>0</number> | ||||
| </property> | </property> | ||||
| <item row="3" column="1"> | <item row="3" column="1"> | ||||
| @@ -1681,8 +1699,8 @@ | |||||
| <rect> | <rect> | ||||
| <x>0</x> | <x>0</x> | ||||
| <y>0</y> | <y>0</y> | ||||
| <width>416</width> | |||||
| <height>334</height> | |||||
| <width>413</width> | |||||
| <height>401</height> | |||||
| </rect> | </rect> | ||||
| </property> | </property> | ||||
| <attribute name="label"> | <attribute name="label"> | ||||
| @@ -1711,8 +1729,8 @@ | |||||
| <rect> | <rect> | ||||
| <x>0</x> | <x>0</x> | ||||
| <y>0</y> | <y>0</y> | ||||
| <width>94</width> | |||||
| <height>66</height> | |||||
| <width>96</width> | |||||
| <height>86</height> | |||||
| </rect> | </rect> | ||||
| </property> | </property> | ||||
| <attribute name="label"> | <attribute name="label"> | ||||
| @@ -1741,8 +1759,8 @@ | |||||
| <rect> | <rect> | ||||
| <x>0</x> | <x>0</x> | ||||
| <y>0</y> | <y>0</y> | ||||
| <width>94</width> | |||||
| <height>66</height> | |||||
| <width>96</width> | |||||
| <height>86</height> | |||||
| </rect> | </rect> | ||||
| </property> | </property> | ||||
| <attribute name="label"> | <attribute name="label"> | ||||
| @@ -1771,8 +1789,8 @@ | |||||
| <rect> | <rect> | ||||
| <x>0</x> | <x>0</x> | ||||
| <y>0</y> | <y>0</y> | ||||
| <width>94</width> | |||||
| <height>66</height> | |||||
| <width>96</width> | |||||
| <height>86</height> | |||||
| </rect> | </rect> | ||||
| </property> | </property> | ||||
| <attribute name="label"> | <attribute name="label"> | ||||
| @@ -1832,12 +1850,21 @@ | |||||
| </widget> | </widget> | ||||
| <widget class="QWidget" name="page_apps"> | <widget class="QWidget" name="page_apps"> | ||||
| <layout class="QGridLayout" name="gridLayout_7"> | <layout class="QGridLayout" name="gridLayout_7"> | ||||
| <property name="verticalSpacing"> | |||||
| <number>20</number> | |||||
| <property name="leftMargin"> | |||||
| <number>0</number> | |||||
| </property> | |||||
| <property name="topMargin"> | |||||
| <number>0</number> | |||||
| </property> | |||||
| <property name="rightMargin"> | |||||
| <number>0</number> | |||||
| </property> | </property> | ||||
| <property name="margin"> | |||||
| <property name="bottomMargin"> | |||||
| <number>0</number> | <number>0</number> | ||||
| </property> | </property> | ||||
| <property name="verticalSpacing"> | |||||
| <number>20</number> | |||||
| </property> | |||||
| <item row="1" column="0"> | <item row="1" column="0"> | ||||
| <widget class="QCheckBox" name="ch_app_image"> | <widget class="QCheckBox" name="ch_app_image"> | ||||
| <property name="text"> | <property name="text"> | ||||
| @@ -2063,7 +2090,16 @@ | |||||
| </widget> | </widget> | ||||
| <widget class="QWidget" name="page_wineasio"> | <widget class="QWidget" name="page_wineasio"> | ||||
| <layout class="QVBoxLayout" name="verticalLayout_17"> | <layout class="QVBoxLayout" name="verticalLayout_17"> | ||||
| <property name="margin"> | |||||
| <property name="leftMargin"> | |||||
| <number>0</number> | |||||
| </property> | |||||
| <property name="topMargin"> | |||||
| <number>0</number> | |||||
| </property> | |||||
| <property name="rightMargin"> | |||||
| <number>0</number> | |||||
| </property> | |||||
| <property name="bottomMargin"> | |||||
| <number>0</number> | <number>0</number> | ||||
| </property> | </property> | ||||
| <item> | <item> | ||||
| @@ -6,8 +6,8 @@ | |||||
| <rect> | <rect> | ||||
| <x>0</x> | <x>0</x> | ||||
| <y>0</y> | <y>0</y> | ||||
| <width>317</width> | |||||
| <height>72</height> | |||||
| <width>218</width> | |||||
| <height>124</height> | |||||
| </rect> | </rect> | ||||
| </property> | </property> | ||||
| <property name="windowTitle"> | <property name="windowTitle"> | ||||
| @@ -15,11 +15,60 @@ | |||||
| </property> | </property> | ||||
| <layout class="QVBoxLayout" name="verticalLayout"> | <layout class="QVBoxLayout" name="verticalLayout"> | ||||
| <item> | <item> | ||||
| <widget class="QCheckBox" name="cb_playback_only"> | |||||
| <property name="text"> | |||||
| <string>Playback Mode only</string> | |||||
| </property> | |||||
| </widget> | |||||
| <layout class="QGridLayout" name="gridLayout"> | |||||
| <item row="0" column="0"> | |||||
| <widget class="QLabel" name="labelPulseInputs"> | |||||
| <property name="text"> | |||||
| <string>Input Channels :</string> | |||||
| </property> | |||||
| <property name="alignment"> | |||||
| <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | |||||
| </property> | |||||
| </widget> | |||||
| </item> | |||||
| <item row="1" column="0"> | |||||
| <widget class="QLabel" name="labelPulseOutputs"> | |||||
| <property name="text"> | |||||
| <string>Output Channels :</string> | |||||
| </property> | |||||
| <property name="alignment"> | |||||
| <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | |||||
| </property> | |||||
| </widget> | |||||
| </item> | |||||
| <item row="0" column="1"> | |||||
| <widget class="QSpinBox" name="spinBoxPulseInputs"> | |||||
| <property name="specialValueText"> | |||||
| <string>Default</string> | |||||
| </property> | |||||
| <property name="minimum"> | |||||
| <number>-1</number> | |||||
| </property> | |||||
| <property name="maximum"> | |||||
| <number>10</number> | |||||
| </property> | |||||
| <property name="value"> | |||||
| <number>-1</number> | |||||
| </property> | |||||
| </widget> | |||||
| </item> | |||||
| <item row="1" column="1"> | |||||
| <widget class="QSpinBox" name="spinBoxPulseOutputs"> | |||||
| <property name="specialValueText"> | |||||
| <string>Default</string> | |||||
| </property> | |||||
| <property name="minimum"> | |||||
| <number>-1</number> | |||||
| </property> | |||||
| <property name="maximum"> | |||||
| <number>10</number> | |||||
| </property> | |||||
| <property name="value"> | |||||
| <number>-1</number> | |||||
| </property> | |||||
| </widget> | |||||
| </item> | |||||
| </layout> | |||||
| </item> | </item> | ||||
| <item> | <item> | ||||
| <widget class="QDialogButtonBox" name="buttonBox"> | <widget class="QDialogButtonBox" name="buttonBox"> | ||||
| @@ -116,10 +116,15 @@ XDG_APPLICATIONS_PATH = [ | |||||
| WINEASIO_PREFIX = "HKEY_CURRENT_USER\Software\Wine\WineASIO" | WINEASIO_PREFIX = "HKEY_CURRENT_USER\Software\Wine\WineASIO" | ||||
| # --------------------------------------------------------------------- | # --------------------------------------------------------------------- | ||||
| class PulseAudioJackBridgeValues(object): | |||||
| clientIdCapture = -1 | |||||
| clientIdPlayback = -1 | |||||
| portCaptureNumber = 0 | |||||
| portPlaybackNumber = 0 | |||||
| global jackClientIdALSA, jackClientIdPulse | |||||
| jackClientIdALSA = -1 | |||||
| jackClientIdPulse = -1 | |||||
| global jackClientIdALSA | |||||
| jackClientIdALSA = -1 | |||||
| pA_bridge_values = PulseAudioJackBridgeValues() | |||||
| # jackdbus indexes | # jackdbus indexes | ||||
| iGraphVersion = 0 | iGraphVersion = 0 | ||||
| @@ -333,8 +338,7 @@ def isPulseAudioStarted(): | |||||
| return bool("pulseaudio" in getProcList()) | return bool("pulseaudio" in getProcList()) | ||||
| def isPulseAudioBridged(): | def isPulseAudioBridged(): | ||||
| global jackClientIdPulse | |||||
| return bool(jackClientIdPulse != -1) | |||||
| return bool(pA_bridge_values.clientIdCapture != -1 or pA_bridge_values.clientIdPlayback != -1) | |||||
| def isDesktopFileInstalled(desktop): | def isDesktopFileInstalled(desktop): | ||||
| for X_PATH in XDG_APPLICATIONS_PATH: | for X_PATH in XDG_APPLICATIONS_PATH: | ||||
| @@ -581,10 +585,10 @@ class ForceRestartThread(QThread): | |||||
| # PulseAudio | # PulseAudio | ||||
| if GlobalSettings.value("Pulse2JACK/AutoStart", True, type=bool) and not isPulseAudioBridged(): | if GlobalSettings.value("Pulse2JACK/AutoStart", True, type=bool) and not isPulseAudioBridged(): | ||||
| if GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool): | |||||
| os.system("cadence-pulse2jack -p") | |||||
| else: | |||||
| os.system("cadence-pulse2jack") | |||||
| inputs = GlobalSettings.value("Pulse2JACK/CaptureChannels", -1, type=int) | |||||
| outputs = GlobalSettings.value("Pulse2JACK/PlaybackChannels", -1, type=int) | |||||
| os.system("cadence-pulse2jack -c %s -p %s" % (str(inputs), str(outputs))) | |||||
| self.progressChanged.emit(100) | self.progressChanged.emit(100) | ||||
| @@ -718,18 +722,24 @@ class ToolBarAlsaAudioDialog(QDialog, ui_cadence_tb_alsa.Ui_Dialog): | |||||
| self.close() | self.close() | ||||
| # Additional PulseAudio options | # Additional PulseAudio options | ||||
| class ToolBarPADialog(QDialog, ui_cadence_tb_pa.Ui_Dialog): | |||||
| class PAChannelsDialog(QDialog, ui_cadence_tb_pa.Ui_Dialog): | |||||
| def __init__(self, parent): | def __init__(self, parent): | ||||
| QDialog.__init__(self, parent) | QDialog.__init__(self, parent) | ||||
| self.setupUi(self) | self.setupUi(self) | ||||
| self.parent = parent | |||||
| self.spinBoxPulseInputs.setValue(GlobalSettings.value("Pulse2JACK/CaptureChannels", 2, type=int)) | |||||
| self.spinBoxPulseOutputs.setValue(GlobalSettings.value("Pulse2JACK/PlaybackChannels", 2, type=int)) | |||||
| self.cb_playback_only.setChecked(GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool)) | |||||
| self.accepted.connect(self.slot_setOptions) | |||||
| self.accepted.connect(self.slot_updateChannels) | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_setOptions(self): | |||||
| GlobalSettings.setValue("Pulse2JACK/PlaybackModeOnly", self.cb_playback_only.isChecked()) | |||||
| def slot_updateChannels(self): | |||||
| GlobalSettings.setValue("Pulse2JACK/CaptureChannels", self.spinBoxPulseInputs.value()) | |||||
| GlobalSettings.setValue("Pulse2JACK/PlaybackChannels", self.spinBoxPulseOutputs.value()) | |||||
| if isPulseAudioBridged(): | |||||
| self.parent.slot_PulseAudioBridgeStart() | |||||
| def done(self, r): | def done(self, r): | ||||
| QDialog.done(self, r) | QDialog.done(self, r) | ||||
| @@ -739,8 +749,10 @@ class ToolBarPADialog(QDialog, ui_cadence_tb_pa.Ui_Dialog): | |||||
| class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | ||||
| DBusJackServerStartedCallback = pyqtSignal() | DBusJackServerStartedCallback = pyqtSignal() | ||||
| DBusJackServerStoppedCallback = pyqtSignal() | DBusJackServerStoppedCallback = pyqtSignal() | ||||
| DBusJackClientAppearedCallback = pyqtSignal(int, str) | |||||
| DBusJackClientAppearedCallback = pyqtSignal(int, str) | |||||
| DBusJackClientDisappearedCallback = pyqtSignal(int) | DBusJackClientDisappearedCallback = pyqtSignal(int) | ||||
| DBusJackPortAppearedCallback = pyqtSignal(int) | |||||
| DBusJackPortDisappearedCallback = pyqtSignal(int) | |||||
| DBusA2JBridgeStartedCallback = pyqtSignal() | DBusA2JBridgeStartedCallback = pyqtSignal() | ||||
| DBusA2JBridgeStoppedCallback = pyqtSignal() | DBusA2JBridgeStoppedCallback = pyqtSignal() | ||||
| @@ -1066,6 +1078,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| self.systray.addMenu("pulse", self.tr("PulseAudio Bridge")) | self.systray.addMenu("pulse", self.tr("PulseAudio Bridge")) | ||||
| self.systray.addMenuAction("pulse", "pulse_start", self.tr("Start")) | self.systray.addMenuAction("pulse", "pulse_start", self.tr("Start")) | ||||
| self.systray.addMenuAction("pulse", "pulse_stop", self.tr("Stop")) | self.systray.addMenuAction("pulse", "pulse_stop", self.tr("Stop")) | ||||
| self.systray.addMenuAction("pulse", "pulse_channels", self.tr("Channels")) | |||||
| self.systray.setActionIcon("jack_start", "media-playback-start") | self.systray.setActionIcon("jack_start", "media-playback-start") | ||||
| self.systray.setActionIcon("jack_stop", "media-playback-stop") | self.systray.setActionIcon("jack_stop", "media-playback-stop") | ||||
| @@ -1076,6 +1089,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| self.systray.setActionIcon("a2j_stop", "media-playback-stop") | self.systray.setActionIcon("a2j_stop", "media-playback-stop") | ||||
| self.systray.setActionIcon("pulse_start", "media-playback-start") | self.systray.setActionIcon("pulse_start", "media-playback-start") | ||||
| self.systray.setActionIcon("pulse_stop", "media-playback-stop") | self.systray.setActionIcon("pulse_stop", "media-playback-stop") | ||||
| self.systray.setActionIcon("pulse_channels", "audio-card") | |||||
| self.systray.connect("jack_start", self.slot_JackServerStart) | self.systray.connect("jack_start", self.slot_JackServerStart) | ||||
| self.systray.connect("jack_stop", self.slot_JackServerStop) | self.systray.connect("jack_stop", self.slot_JackServerStop) | ||||
| @@ -1086,6 +1100,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| self.systray.connect("a2j_stop", self.slot_A2JBridgeStop) | self.systray.connect("a2j_stop", self.slot_A2JBridgeStop) | ||||
| self.systray.connect("pulse_start", self.slot_PulseAudioBridgeStart) | self.systray.connect("pulse_start", self.slot_PulseAudioBridgeStart) | ||||
| self.systray.connect("pulse_stop", self.slot_PulseAudioBridgeStop) | self.systray.connect("pulse_stop", self.slot_PulseAudioBridgeStop) | ||||
| self.systray.connect("pulse_channels", self.slot_PulseAudioBridgeChannels) | |||||
| self.systray.addMenu("tools", self.tr("Tools")) | self.systray.addMenu("tools", self.tr("Tools")) | ||||
| self.systray.addMenuAction("tools", "app_catarina", "Catarina") | self.systray.addMenuAction("tools", "app_catarina", "Catarina") | ||||
| @@ -1128,9 +1143,10 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| self.b_a2j_start.clicked.connect(self.slot_A2JBridgeStart) | self.b_a2j_start.clicked.connect(self.slot_A2JBridgeStart) | ||||
| self.b_a2j_stop.clicked.connect(self.slot_A2JBridgeStop) | self.b_a2j_stop.clicked.connect(self.slot_A2JBridgeStop) | ||||
| self.b_pulse_start.clicked.connect(self.slot_PulseAudioBridgeStart) | self.b_pulse_start.clicked.connect(self.slot_PulseAudioBridgeStart) | ||||
| self.b_pulse_stop.clicked.connect(self.slot_PulseAudioBridgeStop) | self.b_pulse_stop.clicked.connect(self.slot_PulseAudioBridgeStop) | ||||
| self.tb_pulse_options.clicked.connect(self.slot_PulseAudioBridgeOptions) | |||||
| self.b_pulse_channels.clicked.connect(self.slot_PulseAudioBridgeChannels) | |||||
| self.pic_catia.clicked.connect(self.func_start_catia) | self.pic_catia.clicked.connect(self.func_start_catia) | ||||
| self.pic_claudia.clicked.connect(self.func_start_claudia) | self.pic_claudia.clicked.connect(self.func_start_claudia) | ||||
| @@ -1182,6 +1198,8 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| # org.jackaudio.JackPatchbay | # org.jackaudio.JackPatchbay | ||||
| self.DBusJackClientAppearedCallback.connect(self.slot_DBusJackClientAppearedCallback) | self.DBusJackClientAppearedCallback.connect(self.slot_DBusJackClientAppearedCallback) | ||||
| self.DBusJackClientDisappearedCallback.connect(self.slot_DBusJackClientDisappearedCallback) | self.DBusJackClientDisappearedCallback.connect(self.slot_DBusJackClientDisappearedCallback) | ||||
| self.DBusJackPortAppearedCallback.connect(self.slot_DBusJackPortAppearedCallback) | |||||
| self.DBusJackPortDisappearedCallback.connect(self.slot_DBusJackPortDisappearedCallback) | |||||
| # org.gna.home.a2jmidid.control | # org.gna.home.a2jmidid.control | ||||
| self.DBusA2JBridgeStartedCallback.connect(self.slot_DBusA2JBridgeStartedCallback) | self.DBusA2JBridgeStartedCallback.connect(self.slot_DBusA2JBridgeStartedCallback) | ||||
| @@ -1230,9 +1248,12 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| if group_name == "alsa2jack": | if group_name == "alsa2jack": | ||||
| global jackClientIdALSA | global jackClientIdALSA | ||||
| jackClientIdALSA = group_id | jackClientIdALSA = group_id | ||||
| elif group_name == "PulseAudio JACK Source": | |||||
| pA_bridge_values.clientIdCapture = group_id | |||||
| pA_bridge_values.portCaptureNumber = len(ports) | |||||
| elif group_name == "PulseAudio JACK Sink": | elif group_name == "PulseAudio JACK Sink": | ||||
| global jackClientIdPulse | |||||
| jackClientIdPulse = group_id | |||||
| pA_bridge_values.clientIdPlayback = group_id | |||||
| pA_bridge_values.portPlaybackNumber = len(ports) | |||||
| self.jackStarted() | self.jackStarted() | ||||
| @@ -1298,6 +1319,10 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| self.DBusJackClientAppearedCallback.emit(args[iJackClientId], args[iJackClientName]) | self.DBusJackClientAppearedCallback.emit(args[iJackClientId], args[iJackClientName]) | ||||
| elif kwds['member'] == "ClientDisappeared": | elif kwds['member'] == "ClientDisappeared": | ||||
| self.DBusJackClientDisappearedCallback.emit(args[iJackClientId]) | self.DBusJackClientDisappearedCallback.emit(args[iJackClientId]) | ||||
| elif kwds['member'] == "PortAppeared": | |||||
| self.DBusJackPortAppearedCallback.emit(args[iJackClientId]) | |||||
| elif kwds['member'] == "PortDisappeared": | |||||
| self.DBusJackPortDisappearedCallback.emit(args[iJackClientId]) | |||||
| elif kwds['interface'] == "org.gna.home.a2jmidid.control": | elif kwds['interface'] == "org.gna.home.a2jmidid.control": | ||||
| if DEBUG: print("org.gna.home.a2jmidid.control", kwds['member']) | if DEBUG: print("org.gna.home.a2jmidid.control", kwds['member']) | ||||
| @@ -1378,10 +1403,12 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| if gDBus.a2j: | if gDBus.a2j: | ||||
| self.b_a2j_start.setEnabled(False) | self.b_a2j_start.setEnabled(False) | ||||
| self.systray.setActionEnabled("a2j_start", False) | self.systray.setActionEnabled("a2j_start", False) | ||||
| global jackClientIdALSA, jackClientIdPulse | |||||
| jackClientIdALSA = -1 | |||||
| jackClientIdPulse = -1 | |||||
| global jackClientIdALSA | |||||
| jackClientIdALSA = -1 | |||||
| pA_bridge_values.clientIdCapture = -1 | |||||
| pA_bridge_values.clientIdPlayback = -1 | |||||
| if haveDBus: | if haveDBus: | ||||
| self.checkAlsaAudio() | self.checkAlsaAudio() | ||||
| @@ -1484,7 +1511,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| self.b_pulse_stop.setEnabled(True) | self.b_pulse_stop.setEnabled(True) | ||||
| self.systray.setActionEnabled("pulse_start", False) | self.systray.setActionEnabled("pulse_start", False) | ||||
| self.systray.setActionEnabled("pulse_stop", True) | self.systray.setActionEnabled("pulse_stop", True) | ||||
| self.label_bridge_pulse.setText(self.tr("PulseAudio is started and bridged to JACK")) | |||||
| self.label_bridge_pulse.setText(self.tr("PulseAudio is started and bridged to JACK with %s inputs/%s outputs") % (pA_bridge_values.portCaptureNumber, pA_bridge_values.portPlaybackNumber)) | |||||
| else: | else: | ||||
| jackRunning = bool(gDBus.jack and gDBus.jack.IsStarted()) | jackRunning = bool(gDBus.jack and gDBus.jack.IsStarted()) | ||||
| self.b_pulse_start.setEnabled(jackRunning) | self.b_pulse_start.setEnabled(jackRunning) | ||||
| @@ -1620,21 +1647,46 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| global jackClientIdALSA | global jackClientIdALSA | ||||
| jackClientIdALSA = group_id | jackClientIdALSA = group_id | ||||
| self.checkAlsaAudio() | self.checkAlsaAudio() | ||||
| elif group_name == "PulseAudio JACK Source": | |||||
| pA_bridge_values.clientIdCapture = group_id | |||||
| self.checkPulseAudio() | |||||
| elif group_name == "PulseAudio JACK Sink": | elif group_name == "PulseAudio JACK Sink": | ||||
| global jackClientIdPulse | |||||
| jackClientIdPulse = group_id | |||||
| pA_bridge_values.clientIdPlayback = group_id | |||||
| self.checkPulseAudio() | self.checkPulseAudio() | ||||
| @pyqtSlot(int) | @pyqtSlot(int) | ||||
| def slot_DBusJackClientDisappearedCallback(self, group_id): | def slot_DBusJackClientDisappearedCallback(self, group_id): | ||||
| global jackClientIdALSA, jackClientIdPulse | |||||
| global jackClientIdALSA | |||||
| if group_id == jackClientIdALSA: | if group_id == jackClientIdALSA: | ||||
| jackClientIdALSA = -1 | jackClientIdALSA = -1 | ||||
| self.checkAlsaAudio() | self.checkAlsaAudio() | ||||
| elif group_id == jackClientIdPulse: | |||||
| jackClientIdPulse = -1 | |||||
| elif group_id == pA_bridge_values.clientIdCapture: | |||||
| pA_bridge_values.clientIdCapture = -1 | |||||
| pA_bridge_values.portCaptureNumber = 0 | |||||
| self.checkPulseAudio() | self.checkPulseAudio() | ||||
| elif group_id == pA_bridge_values.clientIdPlayback: | |||||
| pA_bridge_values.clientIdPlayback = -1 | |||||
| pA_bridge_values.portPlaybackNumber = 0 | |||||
| self.checkPulseAudio() | |||||
| @pyqtSlot(int) | |||||
| def slot_DBusJackPortAppearedCallback(self, group_id): | |||||
| if group_id == pA_bridge_values.clientIdCapture: | |||||
| pA_bridge_values.portCaptureNumber+=1 | |||||
| self.checkPulseAudio() | |||||
| elif group_id == pA_bridge_values.clientIdPlayback: | |||||
| pA_bridge_values.portPlaybackNumber+=1 | |||||
| self.checkPulseAudio() | |||||
| @pyqtSlot(int) | |||||
| def slot_DBusJackPortDisappearedCallback(self, group_id): | |||||
| if group_id == pA_bridge_values.clientIdCapture: | |||||
| pA_bridge_values.portCaptureNumber+=1 | |||||
| self.checkPulseAudio() | |||||
| elif group_id == pA_bridge_values.clientIdPlayback: | |||||
| pA_bridge_values.portPlaybackNumber+=1 | |||||
| self.checkPulseAudio() | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_DBusA2JBridgeStartedCallback(self): | def slot_DBusA2JBridgeStartedCallback(self): | ||||
| self.a2jStarted() | self.a2jStarted() | ||||
| @@ -1788,18 +1840,18 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW): | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_PulseAudioBridgeStart(self): | def slot_PulseAudioBridgeStart(self): | ||||
| if GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool): | |||||
| os.system("cadence-pulse2jack -p") | |||||
| else: | |||||
| os.system("cadence-pulse2jack") | |||||
| inputs = GlobalSettings.value("Pulse2JACK/CaptureChannels", 2, type=int) | |||||
| outputs = GlobalSettings.value("Pulse2JACK/PlaybackChannels", 2, type=int) | |||||
| os.system("cadence-pulse2jack -c %s -p %s" % (str(inputs), str(outputs))) | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_PulseAudioBridgeStop(self): | def slot_PulseAudioBridgeStop(self): | ||||
| os.system("pulseaudio -k") | os.system("pulseaudio -k") | ||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_PulseAudioBridgeOptions(self): | |||||
| ToolBarPADialog(self).exec_() | |||||
| def slot_PulseAudioBridgeChannels(self): | |||||
| PAChannelsDialog(self).exec_() | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_handleCrash_jack(self): | def slot_handleCrash_jack(self): | ||||