#!/usr/bin/perl

use strict;
use warnings;

my $OS = $^O;

sub Error {
   my ($str) = @_;

   print STDERR "Error: $str\n";

   exit (0 << 1);
}

sub mixer_levels_get {
   my ($left, $right) = @_;
   my $pipe_cmd = "";

   if ($OS eq "openbsd" || $OS eq "netbsd")
     {
        $pipe_cmd = "mixerctl outputs.master|";
     }
   elsif ($OS eq "freebsd" || $OS eq "dragonfly")
     {
        $pipe_cmd = "mixer vol|";
     }
   elsif ($OS eq "darwin")
     {
        $pipe_cmd = "osascript -e 'get volume settings'|";
     }
   elsif ($OS eq "linux")
     {
        $pipe_cmd = "amixer get Master|";
     }

   open P, "$pipe_cmd" || die "Unable to determine mixer!\n";
   my @lines = <P>;
   close P;

   my $have_mixer = 0;

   foreach my $line (@lines)
     {
        if ($line =~ m/Left:.*\[(\d+)%\]/)
          {
             $$left = $1;
             $have_mixer = 1;
          }

        if ($line =~ m/Right:.*\[(\d+)%\]/)
          {
             $$right = $1;
             $have_mixer = 1;
          }

        if ($line =~ m/\Aoutput\svolume:(\d+),/)
          {
             $$left = $$right = $1;
             return 1;
          }
        elsif ($line =~ m/(\d+),(\d+)/ || $line =~ m/(\d+):(\d+)/)
          {
             $$left = $1;
             $$right = $2;
             return 1;
          }
     }

   return $have_mixer;
}

sub mixer_levels_set {
   my ($new_left, $new_right) = @_;
   my $cmd = "";

   close (STDOUT);

   if ($OS eq "openbsd" || $OS eq "netbsd")
     {
        $cmd = "mixerctl outputs.master=$new_left,$new_right";
     }
   elsif ($OS eq "freebsd" || $OS eq "dragonfly")
     {
        $cmd = "mixer $new_left:$new_right"
     }
   elsif ($OS eq "darwin")
     {
        my $greatest = $new_left > $new_right ? $new_left : $new_right;
        my $ratio = 7 / 100;
        my $volume = $greatest * $ratio;
        $cmd = "osascript -e 'set volume $volume'";
     }
   elsif ($OS eq "linux")
     {
        my $greatest = $new_left > $new_right ? $new_left : $new_right;
        $cmd = "amixer set \"Master\" $greatest%";
     }

   return system($cmd);
}

sub main {
   my (@args) = @_;
   my $argc = scalar(@args);
   my ($inc, $dec) = (0, 0);
   my ($left, $right) = (0, 0);

   for (my $i = 0; $i < $argc; $i++)
     {
        if ($args[$i] =~ /\+(\d+)/)
          {
             $inc = $1;
          }

        if ($args[$i] =~ /\-(\d+)/)
          {
	     $dec = $1
          }
     }

   if (!mixer_levels_get(\$left, \$right))
     {
        Error("couldn't get current volumes");
     }

   $left -= $dec; $right -= $dec;
   $left += $inc; $right += $inc;

   if ($OS eq "linux" || $OS eq "darwin" || $OS eq "freebsd" || $OS eq "dragonfly")
     {
        if ($left < 0) { $left = 0; };
        if ($left > 100) { $left = 100; };
        if ($right < 0) { $right = 0; };
        if ($right > 100) { $right = 100 };
     }

   return mixer_levels_set($left, $right);
}

exit(main(@ARGV));

