ALSA Volume Script

From Superk

Jump to: navigation, search
#! /usr/bin/perl -w
#
# Adjust ALSA master volume up/down or report current volume.  Can also 
# mute or unmute the volume.
#
# Written by Ewen McNeill <ewen@naos.co.nz>, 2003/10/11
#---------------------------------------------------------------------------

use strict;

my $MIXER='/usr/bin/amixer';
my $UNMUTE="numid=1,iface=MIXER,name='Master Playback Switch'";
my $VOLUME="numid=2,iface=MIXER,name='Master Playback Volume'";

my %ACTION_DECODE =
(
  'up'     => 'up',
  '+1'     => 'up',
  '+'      => 'up',

  'down'   => 'down',
  '-1'     => 'down',
  '-'      => 'down',

  'mute'   => 'mute',
  '0'      => 'mute',

  'unmute' => 'unmute',
  '1'      => 'unmute',

  'toggle' => 'toggle',

  'show'   => 'show'
);

my $USAGE="$0 {up|down|mute|unmute|toggle|show}";

#---------------------------------------------------------------------------
# Get existing mixer settings
#
# Input: path to a (complex) mixer setting
#
# Returns: minimum value, maximum value, current value (left then right, 
#          or one value for mono)
#
# NOTE: Boolean values are cooerced into 0 or 1 (true/false)
#
# Example output from mixer command:
#
# $ amixer cget numid=1,iface=MIXER,name='Master Playback Switch'
# numid=1,iface=MIXER,name='Master Playback Switch'
#   ; type=BOOLEAN,access=rw---,values=1
#   : values=on
#
# $ amixer cget numid=2,iface=MIXER,name='Master Playback Volume'
# numid=2,iface=MIXER,name='Master Playback Volume'
#   ; type=INTEGER,access=rw---,values=2,min=0,max=31,step=0
#   : values=24,23
#
sub get_mixer_value
{
  my ($control)=@_;
  return undef unless defined($control);

  open(MIXER, "$MIXER cget $control|") or
    do { warn "Cannot run $MIXER!\n";  return undef; };

  my ($min, $max, $left, $right);

  while(<MIXER>)
  {
    # Boolean
    if (/^\s*:.*values=on/)            { $left=1; $min=0; $max=1; }
    if (/^\s*:.*values=off/)           { $left=0; $min=0; $max=1; }
  
    # Integer
    if (/^\s*;.*min=(\d+)/)            { $min=$1; }
    if (/^\s*;.*max=(\d+)/)            { $max=$1; }
    if (/^\s*:.*values=(\d+),(\d+)/)   { ($left,$right)=($1,$2); next; }
    if (/^\s*:.*values=(\d+)/)         { ($left)=($1); next; }
  }

  close(MIXER);
 
  return ($min, $max, $left, $right);
}

#---------------------------------------------------------------------------
# Set a mixer value
# 
# Input: name of (complex) mixer control, value(s) to set
#
sub set_mixer_value
{
  my ($control,@values) = @_;
  return undef unless (defined($control) && defined($values[0]));

# warn ("$MIXER cset $control " . join(",", @values) . ">/dev/null\n");
  system("$MIXER cset $control " . join(",", @values) . " >/dev/null");

  return 1;
}

#---------------------------------------------------------------------------
# Mainline
#
my ($mmin, $mmax, $mleft, $mright) = get_mixer_value($UNMUTE);
my ($vmin, $vmax, $vleft, $vright) = get_mixer_value($VOLUME);
#
my $action=$ARGV[0];
   $action=$ACTION_DECODE{$action} if (defined($action));

if (defined($action))
{
  if ($action eq 'up')
  {
    set_mixer_value($VOLUME, $vleft+1, $vright+1);
    set_mixer_value($UNMUTE, 1);
  }

  if ($action eq 'down')
  {
    set_mixer_value($VOLUME, (($vleft-1  > 0) ? ($vleft-1)  : 0), 
                             (($vright-1 > 0) ? ($vright-1) : 0));
    set_mixer_value($UNMUTE, 1);
  }

  if ($action eq 'mute')
  {
    set_mixer_value($UNMUTE, 0);
  }

  if ($action eq 'unmute')
  {
    set_mixer_value($UNMUTE, 1);
  }

  if ($action eq 'toggle')
  {
    set_mixer_value($UNMUTE, (! $mleft));
  }

  # Reload mixer values after changes
  ($mmin, $mmax, $mleft, $mright) = get_mixer_value($UNMUTE);
  ($vmin, $vmax, $vleft, $vright) = get_mixer_value($VOLUME);
}
elsif (defined($ARGV[0]))
{
  warn "Unrecognised option: $ARGV[0]\n$USAGE\n";
}
#
printf "Master Volume: left: %d (%d%%);  right: %d (%d%%)%s\n",
       $vleft,  int(($vleft-$vmin)*100/($vmax-$vmin)),
       $vright, int(($vright-$vmin)*100/($vmax-$vmin)),
       ($mleft ? "" : "  (*MUTED*)");
Personal tools