更改音量的脚本

更改音量的脚本

我有一个 ruby​​ 脚本,可以让我使用 bash 脚本调整音量。

该脚本已经运行多年,但现在时有时无。

这是我尝试过的。

2018 年 1 月 26 日我找到了另一种调节音量的方法。

$ amixer set Master 50% 
amixer: Unable to find simple control 'Master',0

$ pactl set-sink-volume 0 60%
$ pactl set-sink-volume 0 60%
$ amixer -c 2 sset Master 50%
amixer: Unable to find simple control 'Master',0

以下是评论中提到的脚本内容:

40_VOL.sh

#!/bin/bash
# Ubuntu_Mate
# REQUIRES THAT RUBY BE INSTALLED AND THAT VOL BE IN THE PATH !!
# See notes in vol !!
volume.rb 40

volume.rb

#!/usr/bin/ruby
# 10/6/17 version
#
# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
# Unported License. To view a copy of this license, visit
# http://creativecommons.org/licenses/by-sa/3.0/.
#
# Forked/derived from original by Jasper Van der Jeugt (jaspervdj);
# large chunks rewritten by Steven Saus (uriel1998)
# This is designed to set your pulseaudio volume settings, muting, and
# default sink from the command line.  It will even switch currently
# running streams to the new sink when you switch it!
# Usage will be largely for folks who are using keybinds for volume, etc.
# Originally wrote this to work with ALSA cards - that's what I have.
# (see line 46) but the code at line 45 *should* work for anything
# that's set up as a device in PulseAudio.  This is written to work
# with the version of PulseAudio I have on my system - 0.9.22.
# By perusing the online PulseAudio documentation, it looks like this
# *should* still work just fine for later versions.  Please ping me one
# way or another so I can properly document/fix it...

# To do:   -Set toggle (like the q toggle) so that actions only impact
#           current default sink
#          -Add in toggle so simple output available for notify-osd
# 20140716:uriel1998: Whoops. Fixed output so it presents right info 
# 20140629:uriel1998: Fixed catching of soundcard by name instead of id 
#                     number, added termwidth cap for output, merged in
#                     commit from xentac, and yes, I called awk.
# 20121114:uriel1998: Added introduction/description above
# 20121114:uriel1998: Standardized indentations
# 20121114:uriel1998: Rewrote if/else statements into case statements
# 20121114:uriel1998: Added usage instructions when no arguments given
# 20121114:uriel1998: Added quiet option
# 20121114:uriel1998: Added explicit setting of volume
# 20121114:uriel1998: Added explicit muting/unmuting instead of just
#                     toggling mute
# 20121114:uriel1998: Formatted output to be somewhat more human-
#                     readable, including padding & volume percentages
# 20121114:uriel1998: Added function to allow changing default sink
# 20121114:uriel1998: Added code to switch playing streams to new sink.
# 20121114:uriel1998: Rewrote array; arranged by sink id instead of name
# 20120210:uriel1998: Changed bit of code toggling mute
# 20120210:uriel1998: Added output, so it could be piped to a notify-osd
#                     or somesuch if desired. (superceded 20121114)
# 20120210:uriel1998: Original fork from https://gist.github.com/814634


# Function to test if argument is number, from
#http://stackoverflow.com/questions/5661466/test-if-string-is-a-number-in-ruby-on-rails
class String
        def is_number?
                true if Float(self) rescue false
        end
end

# Pulseaudio volume control
class Pulse
  attr_reader :volumes, :mutes

  # Constructor
  def initialize
        dump = `pacmd dump`.lines
        @volumes = {}
        @mutes = {}
        @names = {}
        @id = {}
        @outputs = {}
        $longname = 0

        dump.each do |line|
        args = line.split

        #We are using the id to actually enumerate this bloody array.
        if !args[2].nil? and args[2].include? "device_id" then # this should work for any recognized device
        #if args[1] == "module-alsa-card" then  # this works if you only have ALSA cards.
                s1 = args[2].sub("device_id=\"","")
                      s2 = s1.sub("\"","")
                      number = s2.to_i
                        @id[number] = number
                      crapstring = args[3].sub("name=\"","")
                      @names[number] = crapstring.sub("\"","")
                      if @names[number].length > $longname
                                $longname = @names[number].length
                      end
        else
                if @names.keys.length > 0   # we already have something in the array
                        @names.keys.each do |sink|
                                if !args[1].nil? and args[1].include? @names[sink]   # and if it's a sink we recognize AND not nil...
                                        result = case args[0]
                                                when "set-default-sink" then $defaultsink = args[1].sub("alsa_output.","")  # static variable
                                                when "set-sink-volume" then @volumes[@id[sink]] = args[2].hex
                                                when "set-sink-mute" then @mutes[@id[sink]] = args[2]
                                                when "set-card-profile" then @outputs[@id[sink]] = ` echo "#{args[2]}" |awk -F ':' '{ print $2 }' | awk -F '+' '{ print $1 }' `.chomp
                                        end
                                end
                        end
                end
          end
  end

  # Adjust the volume with the given increment for every sink
  def volume_set_relative(increment)
        @volumes.keys.each do |sink|
                volume = @volumes[sink] + increment
                volume = [[0, volume].max, 0x10000].min
                @volumes[sink] = volume
                `pacmd set-sink-volume #{sink} #{"0x%x" % volume}`
        end
  end

  # Adjust the volume with the given increment for every sink
  def volume_set_absolute(setvol)
    if setvol < 100.1
            @volumes.keys.each do |sink|
                volume = setvol * 65536 / 100
                @volumes[sink] = volume
                `pacmd set-sink-volume #{sink} #{"0x%x" % volume}`
        end
    end
  end

  # Toggle the mute setting for every sink
  def mute_toggle
        @mutes.keys.each do |sink|
                if @mutes[sink] == "yes"
                        `pacmd set-sink-mute #{sink} no`
                else
                        `pacmd set-sink-mute #{sink} yes`
                end
            end
  end
  def mute(setting)
        @mutes.keys.each do |sink|
                `pacmd set-sink-mute #{sink} #{setting}`
            end
  end

  # give me that sweet percentage value.
  def percentage(vol)
          return vol * 100 / 65536 unless vol.nil?
          return 0
  end

  def setdefault
        puts "Which sink shall be set as default (enter the number)"
        scratch = STDIN.gets.chomp
        newdefault = scratch.to_i
        @names.keys.each do |sink|
                if newdefault.eql? @id[sink]
                        puts "Switching to #{@names[sink]}..."
                        system ("pacmd set-default-sink alsa_output.#{@names[sink]}.#{@outputs[sink]}")
                        puts "Moving current playing inputs..."
                        dump2 = `pacmd list-sink-inputs`.lines
                        @inputs = {}
                        counter = 0
                        dump2.each do |line|
                                args = line.split
                                if args[0] == "index:"  # We need to find the item index for each playing stream
                                        @inputs[counter] = args[1]
                                        counter += 1
                                end
                        end
                        # And now to shift them all to the new sink.
                        count2 = 0
                        while count2 < counter
                                `pacmd move-sink-input #{@inputs[count2]} alsa_output.#{@names[sink]}.#{@outputs[sink]}`
                                count2 += 1
                        end
               end
        end
  end


  # so we can have nice things.
  def padstring(strlen)
        dyncounter = 0
        counter = $longname.to_i - strlen.to_i
        padder = " "
        while dyncounter < counter do
                padder << " "
                dyncounter += 1
        end
        return padder
  end

  # Report out settings for each sink.
  def status
        # needed to get new values
        initialize
        termwidth=`/usr/bin/env tput cols`.to_i
        termwidth=termwidth-1
        puts "##Current status##############################################################################".slice! 0..termwidth
        puts "ID D  M  Vol Sink Name#{padstring(10)}   Output".slice! 0..termwidth
        @id.keys.each do |sink|
                # making volume into a percentage for humans
                # Not sure why I have to pass to a subprocess to make it do, but...
                volpercent = percentage(@volumes[sink])
                isdefault = $defaultsink.include? @names[sink]
                puts "#{@id[sink]}. #{isdefault ? '*' : ' '} #{@mutes[sink] || 'no'} #{volpercent}% #{@names[sink]}#{padstring(@names[sink].length)} #{@outputs[sink]} ".slice! 0..termwidth
        end
        puts "##############################################################################################".slice! 0..termwidth
  end

  # Report out settings for default sink
  def simple
        # needed to get new values
        initialize
        @id.keys.each do |sink|
                if $defaultsink.include? @names[sink]
                        volpercent = percentage(@volumes[sink])
                        puts "#{volpercent}#{@mutes[sink] == 'no' ? '%' : 'M'}"
                end
        end
  end
end

# Control code
p = Pulse.new
# Always give us the results, unless simple is desired
        if ARGV.include? "s"
                p.simple
        end
        unless ARGV.length > 0
                p.status
                puts "\nUsage: ruby volume.rb [0-100|up|down|toggle|mute|unmute|default] [q] [s]\n[0-100] - set percentage of max volume for all sinks\nup|down - Increases volume on all sinks\ntoggle|mute|unmute - Sets mute on all sinks\ndefault - Select default sink from commandline\nq - quiet; no status output\ns - simple status output\n"
        else
                if ARGV.first.is_number?
                        absvolume = ARGV.first.to_i
                        p.volume_set_absolute(absvolume)
                else
                        result = case ARGV.first
                                when "up" then p.volume_set_relative 0x1000
                                when "down" then p.volume_set_relative -0x1000
                                when "toggle" then p.mute_toggle
                                when "mute" then p.mute("yes")
                                when "unmute" then p.mute("no")
                                when "default" then p.status;p.setdefault
                        end
                end
                                if !ARGV.include? "q" and !ARGV.include? "s"
                                    p.status
                                end                                # status not needed; it's included

        end
end

相关内容