A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.
1 #!/usr/bin/perl 2 # 3 # Perl Audio Converter 4 # 5 # Copyright (C) 2005-2021 Philip Lyons (vorzox@gmail.com) 6 # 7 # This program is free software; you can redistribute it and/or modify 8 # it under the terms of the GNU General Public License as published by 9 # the Free Software Foundation; either version 3 of the License, or 10 # (at your option) any later version. 11 # 12 # This program is distributed in the hope that it will be useful, 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # GNU General Public License for more details. 16 # 17 # You should have received a copy of the GNU General Public License 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 19 20 use strict; 21 use warnings; 22 use Getopt::Long; 23 use File::Basename; 24 use File::Find; 25 use File::Spec::Functions qw(rel2abs); 26 use Parallel::ForkManager; 27 use String::ShellQuote; 28 29 use feature qw(switch say); 30 31 no if $] >= 5.018, warnings => "experimental::smartmatch"; 32 33 # Tagging modules 34 use MP3::Tag; 35 use Audio::FLAC::Header; 36 use Audio::Scan; 37 38 # CDDB module 39 use CDDB_get qw(get_cddb); 40 41 # non-encoder/decoder related options 42 my 43 ( 44 $to, 45 $recursive, 46 $preserve, 47 $rip, 48 $help, 49 $longhelp, 50 $verbose, 51 $verinfo, 52 $dryrun, 53 $delete, 54 $keep, 55 $overwrite, 56 $formats, 57 $topdir, 58 $only, 59 $first_run, 60 61 @file, 62 @dir, 63 64 %run, 65 %lang, 66 ); 67 68 my $silent = "> /dev/null 2>&1"; 69 70 # tagging options 71 my 72 ( 73 $title, 74 $track, 75 $artist, 76 $album, 77 $comment, 78 $year, 79 $genre, 80 $taginfo, 81 ); 82 83 # name and version 84 my $name = "Perl Audio Converter"; 85 my $version = "6.1.3"; 86 87 # If these options are toggled, messages/errors will be displayed 88 # via kdialog or zenity/notify-send (depending on environment) 89 my ($gui, $kde, $gnome); 90 91 # Debugging (for developer use only) 92 my $debug = 0; 93 94 # default configuration. 95 my %config = ( 96 97 IMPORTM => 0, 98 JOBS => 4, 99 100 DEFOPTS => 1, 101 EOPTS => '', 102 DOPTS => '', 103 NOPTS => '', 104 105 BITRATE => 128, 106 FREQ => 44100, 107 CHANNELS => 2, 108 EFFECT => '', 109 FCOMP => 2, 110 PCOMP => 3, 111 ACOMP => 3000, 112 OGGQUAL => 3, 113 SPXQUAL => 8, 114 AACQUAL => 100, 115 MPCQUAL => 'radio', 116 OFMODE => 'normal', 117 OFOPT => 'fast', 118 BRATIO => 2, 119 BQUANL => 1.0, 120 BPSIZE => 128, 121 122 USE_CDDB => 1, 123 CDDB_HOST => 'freedb.freedb.org', 124 CDDB_PORT => 8880, 125 CDDB_MODE => 'cddb', 126 CDDB_INPUT => 1, 127 DEVICE => '/dev/dvd', 128 NSCHEME => '%ar - %ti', 129 130 ZEN_DIR => 1, 131 ZEN_OPTS => 1, 132 KDE_DIR => 1, 133 KDE_OPTS => 1, 134 135 ); 136 137 # location of configuration file 138 my $conf_path = "@sysconfdir@/pacpl"; 139 my $po_dir = "@pkgdatadir@/locale"; 140 my $mod_dir = "$conf_path/modules"; 141 142 my $conf_file; 143 144 # Icon path 145 my $icon_path = "$conf_path/pacpl.png"; 146 147 # load the appropriate locale file 148 load_lang(); 149 150 # try to load configuration file in this order... 151 my @conf_locations = ( 152 "$ENV{HOME}/.pacplrc", # Local 153 "$conf_path/pacpl.conf", # Global 154 "$ENV{PWD}/pacpl.conf", # Current Directory 155 ); 156 157 # try to load conf file from one of the above locations 158 foreach my $i (@conf_locations) { 159 if (not $conf_file and -e $i) { 160 $conf_file = $i; 161 say "$lang{debug} $lang{loaded_config} $conf_file" if $debug == 1; 162 } 163 } 164 165 say "$lang{no_config}" if not $conf_file; 166 167 # open config file. 168 if ($conf_file and -e $conf_file) { 169 170 open(CONF, "$conf_file") or die "$lang{opening_file} $conf_file - $!\n"; 171 172 my @conf_opts = <CONF>; 173 @conf_opts = grep(!/^#|^$/, @conf_opts); 174 175 close(CONF); 176 177 # now read config file options and change default values accordingly. 178 foreach (@conf_opts) { 179 chomp; 180 my ($k, $v) = split(/\s*=\s*/); 181 $config{$k} = $v if exists($config{$k}) and length($v); 182 say "$lang{debug} $k = $v" if $debug == 1 and exists($config{$k}); 183 } 184 } 185 186 my $codecs_conf = "$conf_path/codecs.conf"; 187 188 # set default encoders/decoders 189 sub load_codecs { 190 191 open(CODECS, "$codecs_conf") or die "$lang{opening_file} $codecs_conf - $!\n"; 192 193 my @codecs = <CODECS>; 194 @codecs = grep(!/^$|^#/, @codecs); 195 @codecs = grep(s/^\s*|\s*$//, @codecs); 196 197 close(CODECS); 198 199 foreach (@codecs) { 200 201 chomp; 202 my ($k, $v) = split(/\s*=\s*/); 203 my ($e, $d) = split(/,/, $v); 204 205 $k =~ tr/A-Z/a-z/; 206 207 $run{$k}{DEFAULT_ENCODER} = $e if (exists($run{$k}{DEFAULT_ENCODER})); 208 $run{$k}{DEFAULT_DECODER} = $d if (exists($run{$k}{DEFAULT_DECODER})); 209 } 210 } 211 212 # load po file and store in %lang hash 213 sub load_lang { 214 215 my $po = "$po_dir/$ENV{LANG}.po"; 216 $po =~ s/\.UTF-8//i if $po =~ /UTF-8/i; 217 $po =~ s/\.utf8//i if $po =~ /utf8/i; 218 $po =~ s/_\w+// if not -e $po; 219 $po = "$po_dir/en_US.po" if not -e $po; 220 221 open(LANG, "< $po") or die "error: could not open - $po\n$!\n"; 222 223 my @data = <LANG>; 224 @data = grep(!/^#|^$/, @data); 225 226 close(LANG); 227 228 foreach (@data) { 229 chomp; 230 s/=/__EQ__/; 231 my ($k, $v) = split(/\s*__EQ__\s*/, $_); 232 $lang{$k} = $v; 233 } 234 235 } 236 237 my $banner = 1; 238 239 # print error messages 240 sub perror { 241 my ($key, $msg) = @_; 242 say "$name - $version\n"; 243 say "$lang{error}: $lang{$key} $msg" . "\n"; 244 system("kdialog --title \"$name\" --error \"$lang{error}: $lang{$key} $msg\" &") if $gui and $kde; 245 system("zenity --title \"$name\" --error \"$lang{error}: $lang{$key} $msg\" &") if $gui and $gnome; 246 die "$lang{seek_help}\n"; 247 } 248 249 # print notices/warnings 250 sub pnotice { 251 252 my ($key, $msg, $nm) = @_; 253 254 say "$name - $version\n" if $banner == 1; 255 print "$lang{$key} $msg"; 256 say '' if $nm == 1; 257 say "\n" if $nm == 2; 258 259 $banner = 0; 260 } 261 262 # defaults for user variables. 263 my $outfile; 264 my $outdir; 265 my $defopts = $config{DEFOPTS}; 266 my $eopts = $config{EOPTS}; 267 my $dopts = $config{DOPTS}; 268 my $nopts = $config{NOPTS}; 269 my $normalize = $config{NOPTS}; 270 my $bitrate = $config{BITRATE}; 271 my $freq = $config{FREQ}; 272 my $channels = $config{CHANNELS}; 273 my $effect = $config{EFFECT}; 274 my $fcomp = $config{FCOMP}; 275 my $acomp = $config{ACOMP}; 276 my $oggqual = $config{OGGQUAL}; 277 my $spxqual = $config{SPXQUAL}; 278 my $aacqual = $config{AACQUAL}; 279 my $mpcqual = $config{MPCQUAL}; 280 my $ofmode = $config{OFMODE}; 281 my $ofopt = $config{OFOPT}; 282 my $bratio = $config{BRATIO}; 283 my $bquanl = $config{BQUANL}; 284 my $bpsize = $config{BPSIZE}; 285 286 my $cdinfo; 287 my $nocddb; 288 my $noinput; 289 my $device = $config{DEVICE}; 290 my $nscheme = $config{NSCHEME}; 291 my $my_encoder; 292 my $my_decoder; 293 my $encoder; 294 my $decoder; 295 296 my $jobs = $config{JOBS}; 297 298 # command line options 299 GetOptions 300 ( 301 't|to=s' => \$to, 302 'r|recursive' => \$recursive, 303 'p|preserve' => \$preserve, 304 'h|help' => \$help, 305 'l|longhelp' => \$longhelp, 306 'v|verbose' => \$verbose, 307 'f|formats' => \$formats, 308 'o|only=s' => \$only, 309 'k|keep' => \$keep, 310 'j|jobs=n' => \$jobs, 311 312 'taginfo' => \$taginfo, 313 314 'version' => \$verinfo, 315 'dryrun' => \$dryrun, 316 'delete' => \$delete, 317 'overwrite' => \$overwrite, 318 'normalize' => \$normalize, 319 'encoder=s' => \$my_encoder, 320 'decoder=s' => \$my_decoder, 321 322 'title=s' => \$title, 323 'track=n' => \$track, 324 'artist=s' => \$artist, 325 'album=s' => \$album, 326 'comment=s' => \$comment, 327 'year=n' => \$year, 328 'genre=s' => \$genre, 329 330 'gui' => \$gui, 331 'kde' => \$kde, 332 'gnome' => \$gnome, 333 334 'eopts=s' => \$eopts, 335 'dopts=s' => \$dopts, 336 'defopts=n' => \$defopts, 337 'nopts=s' => \$nopts, 338 'outfile=s' => \$outfile, 339 'outdir=s' => \$outdir, 340 341 'bitrate=n' => \$bitrate, 342 'freq=n' => \$freq, 343 'channels=n' => \$channels, 344 'effect=s' => \$effect, 345 'fcomp=n' => \$fcomp, 346 'acomp=n' => \$acomp, 347 'oggqual=n' => \$oggqual, 348 'spxqual=n' => \$spxqual, 349 'aacqual=n' => \$aacqual, 350 'mpcqual=s' => \$mpcqual, 351 'ofmode=s' => \$ofmode, 352 'ofopt=s' => \$ofopt, 353 'bratio=n' => \$bratio, 354 'bquanl=n' => \$bquanl, 355 'bpsize=n' => \$bpsize, 356 357 'rip=s' => \$rip, 358 'nocddb' => \$nocddb, 359 'noinput' => \$noinput, 360 'device=s' => \$device, 361 'nscheme=s' => \$nscheme, 362 'cdinfo' => \$cdinfo, 363 ); 364 365 if (defined($preserve) && !defined($outdir)) { 366 die "You must specify --outdir when you use --preserve option. See man page.\n"; 367 } 368 369 $silent = '' if $verbose; 370 371 my $opts; 372 my $total_converted = 0; 373 my $total_failed = 0; 374 375 # Initialize the fork manager with a count set through pacpl.conf or via the command line 376 my $pm = Parallel::ForkManager->new($jobs); 377 378 # conversion options. when adding a new format, 379 # wild card %i = input file and %o = output file 380 %run = ( 381 382 '3g2' => { 383 384 DEFAULT_ENCODER => 'ffmpeg', 385 DEFAULT_DECODER => 'ffmpeg', 386 387 ENCODER => { 388 ffmpeg => { 389 NAME => 'ffmpeg', 390 ESTR => sub { 391 $opts = "-ar 8000 -ac 1" if $defopts == 1; 392 $opts = '' if $defopts == 0; 393 "-y -i %i $eopts $opts %o" 394 }, 395 396 PROMPT => { NONE => 0, }, 397 }, 398 399 avconv => { 400 NAME => 'avconv', 401 ESTR => sub { 402 $opts = "-ar 8000 -ac 1" if $defopts == 1; 403 $opts = '' if $defopts == 0; 404 "-y -i %i $eopts $opts %o" 405 }, 406 407 PROMPT => { NONE => 0, }, 408 }, 409 410 }, 411 412 DECODER => { 413 ffmpeg => { 414 NAME => 'ffmpeg', 415 DSTR => sub { "-y -i %o $dopts %o" }, 416 }, 417 418 avconv => { 419 NAME => 'avconv', 420 DSTR => sub { "-y -i %o %dopts %o" }, 421 }, 422 }, 423 424 TAGS => { 425 READ => 0, 426 WRITE => 0, 427 MODULE => undef, 428 }, 429 430 }, 431 432 '3gp' => { 433 434 DEFAULT_ENCODER => 'ffmpeg', 435 DEFAULT_DECODER => 'ffmpeg', 436 437 ENCODER => { 438 ffmpeg => { 439 NAME => 'ffmpeg', 440 ESTR => sub { 441 $opts = "-ar 8000 -ac 1" if $defopts == 1; 442 $opts = '' if $defopts == 0; 443 "-y -i %i $eopts $opts %o" 444 }, 445 446 PROMPT => { NONE => 0, }, 447 }, 448 449 avconv => { 450 NAME => 'avconv', 451 ESTR => sub { 452 $opts = "-ar 8000 -ac 1" if $defopts == 1; 453 $opts = '' if $defopts == 0; 454 "-y -i %i $eopts $opts %o" 455 }, 456 457 PROMPT => { NONE => 0, }, 458 }, 459 460 }, 461 462 DECODER => { 463 ffmpeg => { 464 NAME => 'ffmpeg', 465 DSTR => sub { "-y -i %o $dopts %o" }, 466 }, 467 468 avconv => { 469 NAME => 'avconv', 470 DSTR => sub { "-y -i %o %dopts %o" }, 471 }, 472 }, 473 474 TAGS => { 475 READ => 0, 476 WRITE => 0, 477 MODULE => undef, 478 }, 479 480 }, 481 482 aac => { 483 484 DEFAULT_ENCODER => "faac", 485 DEFAULT_DECODER => "faad", 486 487 ENCODER => { 488 faac => { 489 NAME => "faac", 490 ESTR => sub { 491 $opts = "-q $aacqual" if $defopts == 1; 492 $opts = '' if $defopts == 0; 493 "$eopts $opts %i -o %o" 494 }, 495 PROMPT => { AACQUAL => 1 }, 496 }, 497 498 ffmpeg => { 499 NAME => 'ffmpeg', 500 ESTR => sub { 501 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 502 $opts = '' if $defopts == 0; 503 "-y -i %i $eopts $opts %o" 504 }, 505 506 PROMPT => { 507 BITRATE => 1, 508 FREQ => 1, 509 CHANNELS => 1, 510 }, 511 }, 512 513 avconv => { 514 NAME => 'avconv', 515 ESTR => sub { 516 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 517 $opts = '' if $defopts == 1, 518 }, 519 520 PROMPT => { 521 BITRATE => 1, 522 FREQ => 1, 523 CHANNELS => 1, 524 }, 525 }, 526 }, 527 528 DECODER => { 529 faad => { 530 NAME => "faad", 531 DSTR => sub { "$dopts -o %i %o" }, 532 }, 533 534 ffmpeg => { 535 NAME => "ffmpeg", 536 DSTR => sub { "$dopts -y -i %i %o" }, 537 }, 538 539 avconv => { 540 NAME => 'avconv', 541 DSTR => sub { "$dopts -y -i %i %o" }, 542 }, 543 544 mplayer => { 545 NAME => "mplayer", 546 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 547 }, 548 }, 549 550 TAGS => { 551 READ => 0, 552 WRITE => 0, 553 MODULE => undef, 554 }, 555 }, 556 557 ac3 => { 558 559 DEFAULT_ENCODER => "ffmpeg", 560 DEFAULT_DECODER => "ffmpeg", 561 562 ENCODER => { 563 ffmpeg => { 564 NAME => "ffmpeg", 565 ESTR => sub { 566 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 567 $opts = '' if $defopts == 0; 568 "-y -i %i $eopts $opts %o" 569 }, 570 571 PROMPT => { 572 BITRATE => 1, 573 FREQ => 1, 574 CHANNELS => 1, 575 }, 576 }, 577 578 avconv => { 579 NAME => "avconv", 580 ESTR => sub { 581 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 582 $opts = '' if $defopts == 0; 583 "-y -i %i $eopts $opts %o" 584 }, 585 PROMPT => { 586 BITRATE => 1, 587 FREQ => 1, 588 CHANNELS => 1, 589 }, 590 }, 591 592 aften => { 593 NAME => "aften", 594 ESTR => sub { 595 $opts = "-v 1 -q $bitrate -2" if $defopts == 1; 596 $opts = '' if $defopts == 0; 597 "$eopts $opts %i %o" 598 }, 599 600 PROMPT => { 601 BITRATE => 1, 602 }, 603 }, 604 605 }, 606 607 DECODER => { 608 mplayer => { 609 NAME => "mplayer", 610 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 611 }, 612 613 ffmpeg => { 614 NAME => "ffmpeg", 615 DSTR => sub { "$dopts -y -i %i %o" }, 616 }, 617 618 avconv => { 619 NAME => "avconv", 620 DSTR => sub { "$dopts -y -i %i %o" }, 621 }, 622 }, 623 624 TAGS => { 625 READ => 0, 626 WRITE => 0, 627 MODULE => undef, 628 }, 629 }, 630 631 adts => { 632 633 DEFAULT_ENCODER => 'ffmpeg', 634 DEFAULT_DECODER => 'ffmpeg', 635 636 ENCODER => { 637 ffmpeg => { 638 NAME => 'ffmpeg', 639 ESTR => sub { 640 $opts = "-ab $bitrate.k -ar $freq -ac $channels -codec:a libfaac" if $defopts == 1; 641 $opts = '' if $defopts == 0; 642 "-y -i %i $opts $eopts -strict -2 %o" 643 }, 644 PROMPT => { 645 BITRATE => 1, 646 FREQ => 1, 647 CHANNELS => 1, 648 }, 649 }, 650 651 avconv => { 652 NAME => 'avconv', 653 ESTR => sub { 654 $opts = "-ab $bitrate.k -ar $freq -ac $channels -codec:a libfaac" if $defopts == 1; 655 $opts = '' if $defopts == 0; 656 "-y -i %i $opts $eopts %o" 657 }, 658 659 PROMPT => { 660 BITRATE => 1, 661 FREQ => 1, 662 CHANNELS => 1, 663 }, 664 }, 665 }, 666 667 DECODER => { 668 ffmpeg => { 669 NAME => 'ffmpeg', 670 DSTR => "$dopts -y -i %i %o", 671 }, 672 673 avconv => { 674 NAME => 'avconv', 675 DSTR => "$dopts -y -i %i %o", 676 }, 677 }, 678 679 TAGS => { 680 READ => 0, 681 WRITE => 0, 682 MODULE => undef, 683 }, 684 }, 685 686 ape => { 687 688 DEFAULT_ENCODER => "mac", 689 DEFAULT_DECODER => "mac", 690 691 ENCODER => { 692 mac => { 693 NAME => "mac", 694 ESTR => sub { 695 $opts = "-c$acomp" if $defopts == 1; 696 $opts = '' if $defopts == 0; 697 "%i %o $opts $eopts" 698 }, 699 700 PROMPT => { ACOMP => 1 }, 701 }, 702 }, 703 704 DECODER => { 705 mac => { 706 NAME => "mac", 707 DSTR => sub { "%i %o -d $dopts" }, 708 }, 709 710 ffmpeg => { 711 NAME => 'ffmpeg', 712 DSTR => sub { "-y -i %i %dopts %o" }, 713 }, 714 715 avconv => { 716 NAME => 'avconv', 717 DSTR => sub { "-y -i %i $dopts %o" }, 718 }, 719 }, 720 721 TAGS => { 722 READ => 1, 723 WRITE => 0, 724 MODULE => "Audio::Scan", 725 }, 726 }, 727 728 amr => { 729 730 DEFAULT_ENCODER => "ffmpeg", 731 DEFAULT_DECODER => "ffmpeg", 732 733 ENCODER => { 734 ffmpeg => { 735 NAME => "ffmpeg", 736 ESTR => sub { 737 $opts = "-ar 8000 -ac 1" if $defopts == 1; 738 $opts = '' if $defopts == 0; 739 "-y -i %i $eopts $opts %o" 740 }, 741 742 PROMPT => { NONE => 0, }, 743 }, 744 745 avconv => { 746 NAME => "avconv", 747 ESTR => sub { 748 $opts = "-ar 8000 -ac 1" if $defopts == 1; 749 $opts = '' if $defopts == 0; 750 "-y -i %i $eopts $opts %o" 751 }, 752 753 PROMPT => { NONE => 0, }, 754 }, 755 756 }, 757 758 DECODER => { 759 ffmpeg => { 760 NAME => 'ffmpeg', 761 DSTR => sub { "-y -i %i $dopts %o" }, 762 }, 763 764 avconv => { 765 NAME => 'ffmpeg', 766 DSTR => sub { "-y -i %i %dopts %o" }, 767 }, 768 }, 769 770 TAGS => { 771 READ => 0, 772 WRITE => 0, 773 MODULE => undef, 774 }, 775 776 }, 777 778 bonk => { 779 780 DEFAULT_ENCODER => "bonk", 781 DEFAULT_DECODER => "bonk", 782 783 ENCODER => { 784 bonk => { 785 NAME => "bonk", 786 ESTR => sub { 787 $opts = "-q $bquanl -b $bratio -s $bpsize" if $defopts == 1; 788 $opts = '' if $defopts == 0; 789 "encode $eopts $opts %i -o %o" 790 }, 791 792 PROMPT => { 793 BQUANL => 1, 794 BRATIO => 1, 795 BPSIZE => 1, 796 }, 797 }, 798 }, 799 800 DECODER => { 801 bonk => { 802 NAME => "bonk", 803 DSTR => sub { "decode %i -o %o" }, 804 }, 805 }, 806 807 TAGS => { 808 READ => 0, 809 WRITE => 0, 810 MODULE => undef, 811 }, 812 }, 813 814 dsf => { 815 816 DEFAULT_ENCODER => undef, 817 DEFAULT_DECODER => "sacd", 818 819 DECODER => { 820 821 sacd => { 822 NAME => "sacd", 823 DSTR => sub { "-i %i" }, 824 }, 825 }, 826 827 TAGS => { 828 READ => 1, 829 WRITE => 0, 830 MODULE => "Audio::Scan", 831 }, 832 }, 833 834 dts => { 835 836 DEFAULT_ENCODER => 'ffmpeg', 837 DEFAULT_DECODER => 'ffmpeg', 838 839 ENCODER => { 840 ffmpeg => { 841 NAME => 'ffmpeg', 842 ESTR => sub { 843 $opts = '' if $defopts == 1; 844 $opts = '' if $defopts == 0; 845 "-y -i %i $opts $eopts -strict -2 -codec:a libfaac %o" 846 }, 847 848 PROMPT => { NONE => 0, }, 849 }, 850 851 avconv => { 852 NAME => 'avconv', 853 ESTR => sub { 854 $opts = '' if $defopts == 1 or $defopts == 0; 855 "-y -i %i $opts $eopts -codec:a libfaac %o", 856 }, 857 PROMPT => { NONE => 0, }, 858 }, 859 860 dcaenc => { 861 NAME => 'dcaenc', 862 ESTR => sub { 863 $opts = "$bitrate" if $defopts == 0; 864 $opts = '' if $defopts == 1; 865 "%i %o $opts" 866 }, 867 868 PROMPT => { NONE => 0, }, 869 }, 870 }, 871 872 DECODER => { 873 ffmpeg => { 874 NAME => 'ffmpeg', 875 DSTR => "$dopts -y -i %i %o", 876 }, 877 878 avconv => { 879 NAME => 'avconv', 880 DSTR => "$dopts -y -i %i %o", 881 }, 882 }, 883 884 TAGS => { 885 READ => 0, 886 WRITE => 0, 887 MODULE => undef, 888 }, 889 }, 890 891 flac => { 892 893 DEFAULT_ENCODER => "flac", 894 DEFAULT_DECODER => "flac", 895 896 ENCODER => { 897 flac => { 898 NAME => "flac", 899 ESTR => sub { 900 $opts = "-$fcomp" if $defopts == 1; 901 $opts = '' if $defopts == 0; 902 "$eopts -f $opts %i -o %o" 903 }, 904 PROMPT => { FCOMP => 1 }, 905 }, 906 907 flake => { 908 NAME => "flake", 909 ESTR => sub { 910 $opts = "-$fcomp" if $defopts == 1; 911 $opts = '' if $defopts == 0; 912 "$eopts $opts %i -o %o" 913 }, 914 PROMPT => { FCOMP => 1 }, 915 }, 916 917 ffmpeg => { 918 NAME => "ffmpeg", 919 ESTR => sub { 920 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 921 $opts = '' if $defopts == 0; 922 "-y -i %i $eopts $opts %o" 923 }, 924 925 PROMPT => { 926 BITRATE => 1, 927 FREQ => 1, 928 CHANNELS => 1, 929 }, 930 }, 931 932 avconv => { 933 NAME => 'avconv', 934 ESTR => sub { 935 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 936 $opts = '' if $defopts == 1; 937 "-y -i %i $eopts $opts %o" 938 }, 939 PROMPT => { 940 BITRATE => 1, 941 FREQ => 1, 942 CHANNELS => 1, 943 }, 944 }, 945 }, 946 947 DECODER => { 948 flac => { 949 NAME => "flac", 950 DSTR => sub { "$dopts -f -d %i -o %o" }, 951 }, 952 953 ffmpeg => { 954 NAME => "ffmpeg", 955 DSTR => sub { "$dopts -y -i %i %o" }, 956 }, 957 958 avconv => { 959 NAME => 'avconv', 960 DSTR => sub { "$dopts -y -i %i %o" }, 961 }, 962 963 mplayer => { 964 NAME => "mplayer", 965 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 966 }, 967 }, 968 969 TAGS => { 970 READ => 1, 971 WRITE => 1, 972 MODULE => "Audio::FLAC::Header", 973 }, 974 }, 975 976 fla => { 977 978 DEFAULT_ENCODER => "flac", 979 DEFAULT_DECODER => "flac", 980 981 ENCODER => { 982 flac => { 983 NAME => "flac", 984 ESTR => sub { 985 $opts = "-$fcomp" if $defopts == 1; 986 $opts = '' if $defopts == 0; 987 "$eopts -f $opts %i -o %o" 988 }, 989 PROMPT => { FCOMP => 1 }, 990 }, 991 }, 992 993 DECODER => { 994 flac => { 995 NAME => "flac", 996 DSTR => sub { "$dopts -f -d %i -o %o" }, 997 }, 998 999 mplayer => { 1000 NAME => "mplayer", 1001 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 1002 }, 1003 }, 1004 1005 TAGS => { 1006 READ => 1, 1007 WRITE => 1, 1008 MODULE => "Audio::FLAC::Header", 1009 }, 1010 }, 1011 1012 la => { 1013 1014 DEFAULT_ENCODER => "la", 1015 DEFAULT_DECODER => "la", 1016 1017 ENCODER => { 1018 la => { 1019 NAME => "la", 1020 ESTR => sub { "-overwrite $eopts %i %o" }, 1021 PROMPT => { NONE => 0, }, 1022 }, 1023 }, 1024 1025 DECODER => { 1026 la => { 1027 NAME => "la", 1028 ESTR => sub { "-console $dopts %i > %o" }, 1029 }, 1030 }, 1031 1032 TAGS => { 1033 READ => 0, 1034 WRITE => 0, 1035 MODULE => undef, 1036 }, 1037 }, 1038 1039 mp2 => { 1040 1041 DEFAULT_ENCODER => "ffmpeg", 1042 DEFAULT_DECODER => "ffmpeg", 1043 1044 ENCODER => { 1045 ffmpeg => { 1046 NAME => 'ffmpeg', 1047 ESTR => sub { 1048 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 1049 $opts = '' if $defopts == 0; 1050 "-y -i %i $eopts $opts %o" 1051 }, 1052 1053 PROMPT => { 1054 BITRATE => 1, 1055 FREQ => 1, 1056 CHANNELS => 1, 1057 }, 1058 }, 1059 1060 avconv => { 1061 NAME => 'avconv', 1062 ESTR => sub { 1063 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 1064 $opts = '' if $defopts == 0; 1065 "-y -i %i $eopts $opts %o" 1066 }, 1067 PROMPT => { 1068 BITRATE => 1, 1069 FREQ => 1, 1070 CHANNELS => 1, 1071 }, 1072 }, 1073 1074 toolame => { 1075 NAME => 'toolame', 1076 ESTR => sub { 1077 $opts = "-b $bitrate" if $defopts == 1; 1078 $opts = '' if $defopts == 0; 1079 "$eopts $opts %i %o" 1080 }, 1081 1082 PROMPT => { 1083 BITRATE => 1, 1084 }, 1085 }, 1086 1087 twolame => { 1088 NAME => 'twolame', 1089 ESTR => sub { 1090 $opts = "-b $bitrate -s $freq" if $defopts == 1; 1091 $opts = '' if $defopts == 0; 1092 "$eopts $opts %i %o" 1093 }, 1094 1095 PROMPT => { 1096 BITRATE => 1, 1097 FREQ => 1, 1098 }, 1099 }, 1100 1101 sox => { 1102 NAME => 'sox', 1103 ESTR => sub { 1104 $opts = "-c $channels -r $bitrate" if $defopts == 1; 1105 $opts = '' if $defopts == 0; 1106 "%i $eopts $opts %o" 1107 }, 1108 1109 PROMPT => { 1110 BITRATE => 1, 1111 CHANNELS => 1, 1112 }, 1113 }, 1114 }, 1115 1116 DECODER => { 1117 1118 ffmpeg => { 1119 NAME => 'ffmpeg', 1120 DSTR => "$dopts -y -i %i %o", 1121 }, 1122 1123 avconv => { 1124 NAME => 'avconv', 1125 DSTR => "%dopts -y -i %i %o", 1126 }, 1127 1128 mplayer => { 1129 NAME => 'mplayer', 1130 DSTR => "-vc null -vo null -ao pcm:file=%o %i", 1131 }, 1132 }, 1133 1134 TAGS => { 1135 READ => 0, 1136 WRITE => 0, 1137 MODULE => undef, 1138 }, 1139 }, 1140 1141 mp3 => { 1142 1143 DEFAULT_ENCODER => "lame", 1144 DEFAULT_DECODER => "lame", 1145 1146 ENCODER => { 1147 lame => { 1148 NAME => "lame", 1149 ESTR => sub { 1150 $opts = "--resample $freq -b $bitrate -h" if $defopts == 1; 1151 $opts = '' if $defopts == 0; 1152 "$eopts $opts %i %o" 1153 }, 1154 1155 PROMPT => { 1156 BITRATE => 1, 1157 FREQ => 1, 1158 }, 1159 }, 1160 1161 bladeenc => { 1162 NAME => "bladeenc", 1163 ESTR => sub { 1164 $opts = "-br $bitrate" if $defopts == 1; 1165 $opts = '' if $defopts == 0; 1166 "$eopts $opts %i %o" 1167 }, 1168 PROMPT => { BITRATE => 1 }, 1169 }, 1170 1171 ffmpeg => { 1172 NAME => "ffmpeg", 1173 ESTR => sub { 1174 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 1175 $opts = '' if $defopts == 0; 1176 "$eopts -y -i %i $opts %o" 1177 }, 1178 1179 PROMPT => { 1180 BITRATE => 1, 1181 FREQ => 1, 1182 CHANNELS => 1, 1183 }, 1184 }, 1185 1186 avconv => { 1187 NAME => 'avconv', 1188 ESTR => sub { 1189 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 1190 $opts = '' if $defopts == 0; 1191 "-y -i %i $eopts $opts %o" 1192 }, 1193 PROMPT => { 1194 BITRATE => 1, 1195 FREQ => 1, 1196 CHANNELS => 1, 1197 }, 1198 }, 1199 1200 sox => { 1201 NAME => "sox", 1202 ESTR => sub { 1203 $opts = "-r $freq -c $channels" if $defopts == 1; 1204 $opts = '' if $defopts == 0; 1205 "%i $eopts $opts %o" 1206 }, 1207 1208 PROMPT => { 1209 FREQ => 1, 1210 CHANNELS => 1, 1211 }, 1212 }, 1213 }, 1214 1215 DECODER => { 1216 lame => { 1217 NAME => "lame", 1218 DSTR => sub { "$dopts --decode %i %o" }, 1219 }, 1220 1221 ffmpeg => { 1222 NAME => "ffmpeg", 1223 DSTR => sub { "$dopts -y -i %i %o" }, 1224 }, 1225 1226 avconv => { 1227 NAME => 'avconv', 1228 DSTR => sub { "$dopts -y -i %i %O" }, 1229 }, 1230 1231 mplayer => { 1232 NAME => "mplayer", 1233 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 1234 }, 1235 1236 sox => { 1237 NAME => "sox", 1238 DSTR => sub { "%i $dopts %o" }, 1239 }, 1240 }, 1241 1242 TAGS => { 1243 READ => 1, 1244 WRITE => 1, 1245 MODULE => "MP3::Tag", 1246 }, 1247 }, 1248 1249 mp3hd => { 1250 1251 DEFAULT_ENCODER => "mp3hdEncoder", 1252 DEFAULT_DECODER => "mp3hdDecoder", 1253 1254 ENCODER => { 1255 mp3hdEncoder => { 1256 NAME => "mp3hdEncoder", 1257 ESTR => sub { 1258 $opts = "-br $bitrate" if $defopts == 1; 1259 $opts = '' if $defopts == 0; 1260 "$eopts $opts -if %i -of %o" 1261 }, 1262 PROMPT => { BITRATE => 1 }, 1263 }, 1264 }, 1265 1266 DECODER => { 1267 mp3hdDecoder => { 1268 NAME => "mp3hdDecoder", 1269 DSTR => sub { "$dopts -if %i -of %o" }, 1270 }, 1271 }, 1272 1273 TAGS => { 1274 WRITE => 1, 1275 READ => 1, 1276 MODULE => "MP3::Tag", 1277 }, 1278 }, 1279 1280 mp4 => { 1281 1282 DEFAULT_ENCODER => "faac", 1283 DEFAULT_DECODER => "faad", 1284 1285 ENCODER => { 1286 1287 faac => { 1288 NAME => "faac", 1289 ESTR => sub { 1290 $opts = "-q $aacqual" if $defopts == 1; 1291 $opts = '' if $defopts == 0; 1292 "$eopts -w $opts %i -o %o" 1293 }, 1294 PROMPT => { AACQUAL => 1 }, 1295 }, 1296 1297 ffmpeg => { 1298 NAME => "ffmpeg", 1299 ESTR => sub { 1300 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 1301 $opts = '' if $defopts == 0; 1302 "-y -i %i $eopts $opts %o" 1303 }, 1304 1305 PRIMPT => { 1306 BITRATE => 1, 1307 FREQ => 1, 1308 CHANNELS => 1, 1309 }, 1310 }, 1311 1312 avconv => { 1313 NAME => 'avconv', 1314 ESTR => sub { 1315 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 1316 $opts = '' if $defopts == 0; 1317 "-y -i %i $eopts $opts %o" 1318 }, 1319 1320 PROMPT => { 1321 BITRATE => 1, 1322 FREQ => 1, 1323 CHANNELS => 1, 1324 }, 1325 }, 1326 }, 1327 1328 DECODER => { 1329 1330 faad => { 1331 NAME => "faad", 1332 DSTR => sub { "$dopts -o %o %i" }, 1333 }, 1334 1335 ffmpeg => { 1336 NAME => "ffmpeg", 1337 DSTR => sub { "$dopts -y -i %i %o" }, 1338 }, 1339 1340 avconv => { 1341 NAME => 'avconv', 1342 DSTR => sub { "$dopts -y -i %i %o" }, 1343 }, 1344 1345 mplayer => { 1346 NAME => "mplayer", 1347 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 1348 }, 1349 }, 1350 1351 TAGS => { 1352 READ => 1, 1353 WRITE => 1, 1354 MODULE => "Audio::Scan", 1355 }, 1356 }, 1357 1358 # m4a container with AAC codec 1359 mp4a => { 1360 1361 DEFAULT_ENCODER => "faac", 1362 DEFAULT_DECODER => "faad", 1363 1364 ENCODER => { 1365 1366 faac => { 1367 NAME => "faac", 1368 ESTR => sub { 1369 $opts = "-q $aacqual" if $defopts == 1; 1370 $opts = '' if $defopts == 0; 1371 "$eopts -w $opts %i -o %o" 1372 }, 1373 PROMPT => { AACQUAL => 1 }, 1374 }, 1375 1376 ffmpeg => { 1377 NAME => "ffmpeg", 1378 ESTR => sub { 1379 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 1380 $opts = '' if $defopts == 0; 1381 "$eopts -y -i %i $opts %o" 1382 }, 1383 1384 PROMPT => { 1385 BITRATE => 1, 1386 FREQ => 1, 1387 CHANNELS => 1, 1388 }, 1389 }, 1390 1391 avconv => { 1392 NAME => 'avconv', 1393 ESTR => sub { 1394 $opts = "-ab $bitrate.k -ar $freq -ac $channels" if $defopts == 1; 1395 $opts = '' if $defopts == 0; 1396 "-y -i %i $eopts $opts %o" 1397 }, 1398 1399 PROMPT => { 1400 BITRATE => 1, 1401 FREQ => 1, 1402 CHANNELS => 1, 1403 }, 1404 }, 1405 }, 1406 1407 DECODER => { 1408 1409 faad => { 1410 NAME => "faad", 1411 DSTR => sub { "$dopts -o %o %i" }, 1412 }, 1413 1414 ffmpeg => { 1415 NAME => "ffmpeg", 1416 DSTR => sub { "$dopts -y -i %i %o" }, 1417 }, 1418 1419 avconv => { 1420 NAME => 'avconv', 1421 DSTR => sub { "$dopts -y -i %i %o" }, 1422 }, 1423 1424 mplayer => { 1425 NAME => "mplayer", 1426 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 1427 }, 1428 1429 }, 1430 1431 ESTR => sub { "$eopts -w -q $aacqual %i -o %o" }, 1432 1433 TAGS => { 1434 READ => 1, 1435 WRITE => 1, 1436 MODULE => "Audio::Scan", 1437 }, 1438 }, 1439 1440 # m4a container with ALAC codec 1441 alac => { 1442 1443 DEFAULT_ENCODER => undef, 1444 DEFAULT_DECODER => "alac-decoder", 1445 1446 DECODER => { 1447 1448 'alac-decoder' => { 1449 NAME => "alac-decoder", 1450 DSTR => sub { "$dopts -f %o %i" }, 1451 }, 1452 1453 ffmpeg => { 1454 NAME => "ffmpeg", 1455 DSTR => sub { "$dopts -y -i %i %o" }, 1456 }, 1457 1458 avconv => { 1459 NAME => 'avconv', 1460 DSTR => sub { "$dopts -y -i %i %o" }, 1461 }, 1462 1463 mplayer => { 1464 NAME => "mplayer", 1465 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 1466 }, 1467 1468 }, 1469 1470 TAGS => { 1471 READ => 1, 1472 WRITE => 0, 1473 MODULE => "Audio::Scan", 1474 }, 1475 }, 1476 1477 m4b => { 1478 1479 DEFAULT_ENCODER => undef, 1480 DEFAULT_DECODER => "faad", 1481 1482 DECODER => { 1483 faad => { 1484 NAME => "faad", 1485 DSTR => sub { "$dopts -o %o %i" }, 1486 }, 1487 1488 mplayer => { 1489 NAME => "mplayer", 1490 DSTR => sub { "$dopts -vc null -vo null -ao pcm:file=%o %i" }, 1491 }, 1492 1493 ffmpeg => { 1494 NAME => 'ffmpeg', 1495 DSTR => sub { "$dopts -y -i %i %o" }, 1496 }, 1497 1498 avconv => { 1499 NAME => 'avconv', 1500 DSTR => sub { "$dopts -y -i %i %o" }, 1501 }, 1502 }, 1503 1504 TAGS => { 1505 READ => 0, 1506 WRITE => 1, 1507 MODULE => undef, 1508 }, 1509 }, 1510 1511 mpc => { 1512 1513 DEFAULT_ENCODER => "mpcenc", 1514 DEFAULT_DECODER => "mpcdec", 1515 1516 ENCODER => { 1517 1518 mpcenc => { 1519 NAME => "mpcenc", 1520 ESTR => sub { 1521 $opts = "--$mpcqual" if $defopts == 1; 1522 $opts = '' if $defopts == 0; 1523 "$eopts --overwrite $opts %i %o" 1524 }, 1525 PROMPT => { MPCQUAL => 1 }, 1526 }, 1527 }, 1528 1529 DECODER => { 1530 1531 mpcdec => { 1532 NAME => "mpcdec", 1533 DSTR => sub { "$dopts %i %o" }, 1534 }, 1535 1536 ffmpeg => { 1537 NAME => 'ffmpeg', 1538 DSTR => sub { "$dopts -y -i %i %o" }, 1539 }, 1540 1541 avconv => { 1542 NAME => 'avconv', 1543 DSTR => sub { "$dopts -y -i %i %o" }, 1544 }, 1545 1546 mplayer => { 1547 NAME => "mplayer", 1548 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 1549 }, 1550 }, 1551 1552 TAGS => { 1553 READ => 1, 1554 WRITE => 1, 1555 MODULE => "Audio::Scan", 1556 }, 1557 1558 PROMPT => { 1559 MPCQUAL => 1, 1560 }, 1561 }, 1562 1563 mpp => { 1564 1565 DEFAULT_ENCODER => "mpcenc", 1566 DEFAULT_DECODER => "mpcdec", 1567 1568 ENCODER => { 1569 1570 mpcenc => { 1571 NAME => "mpcenc", 1572 ESTR => sub { 1573 $opts = "--$mpcqual" if $defopts == 1; 1574 $opts = '' if $defopts == 0; 1575 "$eopts --overwrite $opts %i %o" 1576 }, 1577 PROMPT => { MPCQUAL => 1 }, 1578 }, 1579 }, 1580 1581 DECODER => { 1582 1583 mpcdec => { 1584 NAME => "mpcdec", 1585 DSTR => sub { "$dopts %i %o" }, 1586 }, 1587 1588 ffmpeg => { 1589 NAME => 'ffmpeg', 1590 DSTR => sub { "$dopts -y -i %i %o" }, 1591 }, 1592 1593 avconv => { 1594 NAME => 'avconv', 1595 DSTR => sub { "$dopts -y -i %i %o" }, 1596 }, 1597 1598 mplayer => { 1599 NAME => "mplayer", 1600 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 1601 }, 1602 }, 1603 1604 TAGS => { 1605 READ => 1, 1606 WRITE => 1, 1607 MODULE => "Audio::Scan", 1608 }, 1609 }, 1610 1611 off => { 1612 DEFAULT_ENCODER => 'off', 1613 DEFAULT_DECODER => 'off', 1614 1615 ENCODER => { 1616 off => { 1617 NAME => 'off', 1618 ESTR => sub { 1619 $opts = "--mode $ofmode --optimize $ofopt" if $defopts == 1; 1620 $opts = '' if $defopts == 0; 1621 "$eopts --overwrite $opts %i --output %o" 1622 }, 1623 1624 PROMPT => { 1625 OFMODE => 1, 1626 OFOPT => 1, 1627 }, 1628 }, 1629 }, 1630 1631 DECODER => { 1632 off => { 1633 NAME => 'off', 1634 DSTR => sub { "$dopts --overwrite --decode %i --output %o" }, 1635 }, 1636 }, 1637 1638 TAGS => { 1639 READ => 0, 1640 WRITE => 0, 1641 MODULE => undef, 1642 }, 1643 }, 1644 1645 ofr => { 1646 1647 DEFAULT_ENCODER => "ofr", 1648 DEFAULT_DECODER => "ofr", 1649 1650 ENCODER => { 1651 ofr => { 1652 NAME => "ofr", 1653 ESTR => sub { 1654 $opts = "--mode $ofmode --optimize $ofopt" if $defopts == 1; 1655 $opts = '' if $defopts == 0; 1656 "$eopts --overwrite $opts %i --output %o" 1657 }, 1658 1659 PROMPT => { 1660 OFMODE => 1, 1661 OFOPT => 1, 1662 }, 1663 }, 1664 }, 1665 1666 DECODER => { 1667 ofr => { 1668 NAME => "ofr", 1669 DSTR => sub { "$dopts --overwrite --decode %i --output %o" }, 1670 }, 1671 }, 1672 1673 TAGS => { 1674 READ => 0, 1675 WRITE => 0, 1676 MODULE => undef, 1677 }, 1678 }, 1679 1680 ofs => { 1681 1682 DEFAULT_ENCODER => "ofs", 1683 DEFAULT_DECODER => "ofs", 1684 1685 ENCODER => { 1686 ofs => { 1687 NAME => "ofs", 1688 ESTR => sub { 1689 $opts = "--mode $ofmode --optimize $ofopt" if $defopts == 1; 1690 $opts = '' if $defopts == 0; 1691 "$eopts --overwrite $opts %i --output %o" 1692 }, 1693 1694 PROMPT => { 1695 OFMODE => 1, 1696 OFOPT => 1, 1697 }, 1698 }, 1699 }, 1700 1701 DECODER => { 1702 ofs => { 1703 NAME => "ofs", 1704 DSTR => sub { "$dopts --overwrite --decode %i --output %o" }, 1705 }, 1706 }, 1707 1708 TAGS => { 1709 READ => 0, 1710 WRITE => 0, 1711 MODULE => undef, 1712 }, 1713 }, 1714 1715 1716 oga => { 1717 DEFAULT_ENCODER => 'oggenc', 1718 DEFAULT_DECODER => 'oggdec', 1719 1720 ENCODER => { 1721 oggenc => { 1722 NAME => 'oggenc', 1723 ESTR => sub { 1724 $opts = "--resample $freq -q $oggqual" if $defopts == 1; 1725 $opts = '' if $defopts == 0; 1726 "$eopts $opts %i %o" 1727 }, 1728 PROMPT => { 1729 FREQ => 1, 1730 OGGQUAL => 1, 1731 }, 1732 }, 1733 1734 ffmpeg => { 1735 NAME => "ffmpeg", 1736 ESTR => sub { 1737 $opts = "-ab $bitrate.k -ar $freq -ac $channels -codec:a libvorbis" if $defopts == 1; 1738 $opts = '' if $defopts == 0; 1739 "-y -i %i $eopts $opts %o" 1740 }, 1741 1742 PROMPT => { 1743 BITRATE => 1, 1744 FREQ => 1, 1745 CHANNELS => 1, 1746 }, 1747 }, 1748 1749 avconv => { 1750 NAME => 'avconv', 1751 ESTR => sub { 1752 $opts = "-ab $bitrate.k -ar $freq -ac $channels -codec:a libvorbis" if $defopts == 1; 1753 $opts = '' if $defopts == 0; 1754 "-y -i %i $eopts $opts %o" 1755 }, 1756 1757 PROMPT => { 1758 BITRATE => 1, 1759 FREQ => 1, 1760 CHANNELS => 1, 1761 }, 1762 }, 1763 1764 sox => { 1765 NAME => "sox", 1766 ESTR => sub { 1767 $opts = "-r $freq -c $channels" if $defopts == 1; 1768 $opts = '' if $defopts == 0; 1769 "%i $eopts $opts %o" 1770 }, 1771 1772 PROMPT => { 1773 FREQ => 1, 1774 CHANNELS => 1, 1775 }, 1776 }, 1777 }, 1778 1779 DECODER => { 1780 oggdec => { 1781 NAME => "oggdec", 1782 DSTR => sub { "$dopts %i --output %o" }, 1783 }, 1784 1785 ffmpeg => { 1786 NAME => "ffmpeg", 1787 DSTR => sub { "$dopts -y -i %i %o" }, 1788 }, 1789 1790 avconv => { 1791 NAME => 'avconv', 1792 DSTR => sub { "$dopts -y -i %i %o" }, 1793 }, 1794 1795 mplayer => { 1796 NAME => "mplayer", 1797 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 1798 }, 1799 1800 sox => { 1801 NAME => "sox", 1802 DSTR => sub { "%i $dopts %o" }, 1803 }, 1804 }, 1805 1806 TAGS => { 1807 READ => 1, 1808 WRITE => 1, 1809 MODULE => "vorbiscomment", 1810 }, 1811 }, 1812 1813 ogg => { 1814 1815 DEFAULT_ENCODER => "oggenc", 1816 DEFAULT_DECODER => "oggdec", 1817 1818 ENCODER => { 1819 oggenc => { 1820 NAME => "oggenc", 1821 ESTR => sub { 1822 $opts = "--resample $freq -q $oggqual" if $defopts == 1; 1823 $opts = '' if $defopts == 0; 1824 "$eopts $opts %i -o %o" 1825 }, 1826 1827 PROMPT => { 1828 FREQ => 1, 1829 OGGQUAL => 1, 1830 }, 1831 }, 1832 1833 ffmpeg => { 1834 NAME => "ffmpeg", 1835 ESTR => sub { 1836 $opts = "-ab $bitrate.k -ar $freq -ac $channels -codec:a libvorbis" if $defopts == 1; 1837 $opts = '' if $defopts == 0; 1838 "-y -i %i $eopts $opts %o" 1839 }, 1840 1841 PROMPT => { 1842 BITRATE => 1, 1843 FREQ => 1, 1844 CHANNELS => 1, 1845 }, 1846 }, 1847 1848 avconv => { 1849 NAME => 'avconv', 1850 ESTR => sub { 1851 $opts = "-ab $bitrate.k -ar $freq -ac $channels -codec:a libvorbis" if $defopts == 1; 1852 $opts = '' if $defopts == 0; 1853 "-y -i %i $eopts $opts %o" 1854 }, 1855 1856 PROMPT => { 1857 BITRATE => 1, 1858 FREQ => 1, 1859 CHANNELS => 1, 1860 }, 1861 }, 1862 1863 sox => { 1864 NAME => "sox", 1865 ESTR => sub { 1866 $opts = "-r $freq -c $channels" if $defopts == 1; 1867 $opts = '' if $defopts == 0; 1868 "%i $eopts $opts %o" 1869 }, 1870 1871 PROMPT => { 1872 FREQ => 1, 1873 CHANNELS => 1, 1874 }, 1875 }, 1876 }, 1877 1878 DECODER => { 1879 oggdec => { 1880 NAME => "oggdec", 1881 DSTR => sub { "$dopts %i --output %o" }, 1882 }, 1883 1884 ffmpeg => { 1885 NAME => "ffmpeg", 1886 DSTR => sub { "$dopts -y -i %i %o" }, 1887 }, 1888 1889 avconv => { 1890 NAME => 'avconv', 1891 DSTR => sub { "$dopts -y -i %i %o" }, 1892 }, 1893 1894 mplayer => { 1895 NAME => "mplayer", 1896 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 1897 }, 1898 1899 sox => { 1900 NAME => "sox", 1901 DSTR => sub { "%i $dopts %o" }, 1902 }, 1903 }, 1904 1905 TAGS => { 1906 READ => 1, 1907 WRITE => 1, 1908 MODULE => "vorbiscomment", 1909 }, 1910 }, 1911 1912 opus => { 1913 1914 DEFAULT_ENCODER => "opusenc", 1915 DEFAULT_DECODER => "opusdec", 1916 1917 ENCODER => { 1918 opusenc => { 1919 NAME => 'opusenc', 1920 ESTR => sub { 1921 $opts = "--bitrate $bitrate" if $defopts == 1; 1922 $opts = '' if $defopts == 0; 1923 "$eopts $opts %i %o" 1924 }, 1925 PROMTP => { 1926 BITRATE => 1, 1927 }, 1928 }, 1929 }, 1930 1931 DECODER => { 1932 opusdec => { 1933 NAME => 'opusdec', 1934 DSTR => sub { "--force-wav %i %o" }, 1935 PROMPT => { NONE => 0 }, 1936 }, 1937 }, 1938 1939 TAGS => { 1940 READ => 0, 1941 WRITE => 0, 1942 MODULE => undef, 1943 }, 1944 }, 1945 1946 raw => { 1947 1948 DEFAULT_ENCODER => "sox", 1949 DEFAULT_DECODER => "sox", 1950 1951 ENCODER => { 1952 sox => { 1953 NAME => 'sox', 1954 ESTR => sub { 1955 $opts = "-r $freq -c $channels" if $defopts == 1; 1956 $opts = '' if $defopts == 0; 1957 "%i $opts $eopts %o $effect" 1958 }, 1959 1960 PROMPT => { 1961 FREQ => 1, 1962 CHANNELS => 1, 1963 }, 1964 }, 1965 }, 1966 1967 DECODER => { 1968 sox => { 1969 NAME => 'sox', 1970 DSTR => sub { "-w -s -r $freq -c $channels $dopts %i %o" }, 1971 }, 1972 }, 1973 1974 TAGS => { 1975 READ => 0, 1976 WRITE => 0, 1977 MODULE => undef, 1978 }, 1979 }, 1980 1981 rm => { 1982 1983 DEFAULT_ENCODER => 'ffmpeg', 1984 DEFAULT_DECODER => 'ffmpeg', 1985 1986 ENCODER => { 1987 ffmpeg => { 1988 NAME => 'ffmpeg', 1989 ESTR => sub { 1990 $opts = "-ar $freq -ac $channels" if $defopts == 1; 1991 $opts = '' if $defopts == 0; 1992 "-y -i %i $eopts $opts %o" 1993 }, 1994 1995 PROMPT => { 1996 FREQ => 1, 1997 CHANNELS => 1, 1998 }, 1999 }, 2000 2001 avconv => { 2002 NAME => 'avconv', 2003 ESTR => sub { 2004 $opts = "-ar $freq -ac $channels" if $defopts == 1; 2005 $opts = '' if $defopts == 0; 2006 "-y -i %i $eopts $opts %o" 2007 }, 2008 2009 PROMPT => { 2010 FREQ => 1, 2011 CHANNELS => 1, 2012 }, 2013 }, 2014 }, 2015 2016 DECODER => { 2017 mplayer => { 2018 NAME => 'mplayer', 2019 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 2020 }, 2021 2022 ffmpeg => { 2023 NAME => 'ffmpeg', 2024 DSTR => sub { "$dopts -y -i %i %o" }, 2025 }, 2026 2027 avconv => { 2028 NAME => 'avconv', 2029 DSTR => sub { "$dopts -y -i %i %o" }, 2030 }, 2031 }, 2032 2033 TAGS => { 2034 READ => 0, 2035 WRITE => 0, 2036 MODULE => undef, 2037 }, 2038 }, 2039 2040 shn => { 2041 2042 DEFAULT_ENCODER => "shorten", 2043 DEFAULT_DECODER => "shorten", 2044 2045 ENCODER => { 2046 shorten => { 2047 NAME => "shorten", 2048 ESTR => sub { 2049 $opts = "-c $channels" if $defopts == 1; 2050 $opts = '' if $defopts == 0; 2051 "$eopts $opts %i %o" 2052 }, 2053 PROMPT => { CHANNELS => 1 }, 2054 }, 2055 }, 2056 2057 DECODER => { 2058 shorten => { 2059 NAME => "shorten", 2060 DSTR => sub { "-x %i %o" }, 2061 }, 2062 }, 2063 2064 TAGS => { 2065 READ => 0, 2066 WRITE => 0, 2067 MODULE => undef, 2068 }, 2069 }, 2070 2071 spx => { 2072 2073 DEFAULT_ENCODER => "speexenc", 2074 DEFAULT_DECODER => "speexdec", 2075 2076 ENCODER => { 2077 speexenc => { 2078 NAME => "speexenc", 2079 ESTR => sub { 2080 $opts = "--quality $spxqual" if $defopts == 1; 2081 $opts = '' if $defopts == 0; 2082 "$eopts $opts %i %o" 2083 }, 2084 PROMPT => { SPXQUAL => 1 }, 2085 }, 2086 2087 ffmpeg => { 2088 NAME => 'ffmpeg', 2089 ESTR => sub { 2090 $opts = "--bitrate $bitrate.k" if $defopts == 1; 2091 $opts = '' if $defopts == 0; 2092 "-y -i %i $eopts $opts %o" 2093 }, 2094 2095 PROMPT => { 2096 BITRATE => 1, 2097 }, 2098 }, 2099 2100 avconv => { 2101 NAME => 'avconv', 2102 ESTR => sub { 2103 $opts = "--bitrate $bitrate.k" if $defopts == 1; 2104 $opts = '' if $defopts == 0; 2105 "-y -i $eopts $opts %o" 2106 }, 2107 PROMPT => { 2108 BITRATE => 1, 2109 }, 2110 }, 2111 }, 2112 2113 DECODER => { 2114 speexdec => { 2115 NAME => "speexdec", 2116 DSTR => sub { "$dopts %i %o" }, 2117 }, 2118 2119 ffmpeg => { 2120 NAME => 'ffmpeg', 2121 DSTR => sub { "$dopts -y -i %i %o" }, 2122 }, 2123 2124 avconv => { 2125 NAME => 'avconv', 2126 DSTR => sub { "$dopts -y -i %i %o" }, 2127 }, 2128 }, 2129 2130 TAGS => { 2131 READ => 1, 2132 WRITE => 1, 2133 MODULE => undef, 2134 }, 2135 }, 2136 2137 tta => { 2138 2139 DEFAULT_ENCODER => "ttaenc", 2140 DEFAULT_DECODER => "ttaenc", 2141 2142 ENCODER => { 2143 ttaenc => { 2144 NAME => "ttaenc", 2145 ESTR => sub { "$eopts -e %i -o %o" }, 2146 PROMPT => { NONE => 0, }, 2147 }, 2148 }, 2149 2150 DECODER => { 2151 ttaenc => { 2152 NAME => "ttaenc", 2153 DSTR => sub { "$dopts -d %i -o %o" }, 2154 }, 2155 2156 ffmpeg => { 2157 NAME => "ffmpeg", 2158 DSTR => sub { "$dopts -y -i %i %o" }, 2159 }, 2160 2161 avconv => { 2162 NAME => 'avconv', 2163 DSTR => sub { "$dopts -y -i %i %o" }, 2164 }, 2165 2166 mplayer => { 2167 NAME => "mplayer", 2168 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 2169 }, 2170 }, 2171 2172 TAGS => { 2173 READ => 0, 2174 WRITE => 0, 2175 MODULE => undef, 2176 }, 2177 }, 2178 2179 wav => { 2180 2181 DEFAULT_ENCODER => "mv", 2182 DEFAULT_DECODER => "cp", 2183 2184 ENCODER => { 2185 mv => { 2186 NAME => "mv", 2187 ESTR => sub { "%i %o" }, 2188 PROMPT => { NONE => 0, }, 2189 }, 2190 }, 2191 2192 DECODER => { 2193 cp => { 2194 NAME => "cp", 2195 DSTR => sub { "%i %o" }, 2196 } 2197 }, 2198 2199 TAGS => { 2200 READ => 0, 2201 WRITE => 0, 2202 MODULE => undef, 2203 }, 2204 }, 2205 2206 wv => { 2207 2208 DEFAULT_ENCODER => "wavpack", 2209 DEFAULT_DECODER => "wvunpack", 2210 2211 ENCODER => { 2212 wavpack => { 2213 NAME => "wavpack", 2214 ESTR => sub { "$eopts -h -y %i -o %o" }, 2215 PROMPT => { NONE => 0, }, 2216 }, 2217 2218 ffmpeg => { 2219 NAME => 'ffmpeg', 2220 ESTR => sub { "-y -i %i $eopts %o" }, 2221 PROMPT => { NONE => 0, }, 2222 }, 2223 2224 avconv => { 2225 NAME => 'avconv', 2226 ESTR => sub { "-y -i %i $eopts %o" }, 2227 PROMPT => { NONE => 0, }, 2228 }, 2229 }, 2230 2231 DECODER => { 2232 wvunpack => { 2233 NAME => "wvunpack", 2234 DSTR => sub { "$dopts -y %i -o %o" }, 2235 }, 2236 2237 ffmpeg => { 2238 NAME => "ffmpeg", 2239 DSTR => sub { "$dopts -y -i %i %o" }, 2240 }, 2241 2242 avconv => { 2243 NAME => 'avconv', 2244 DSTR => sub { "$dopts -y -i %i %o" }, 2245 }, 2246 2247 mplayer => { 2248 NAME => "mplayer", 2249 DSTR => sub { "-vc null -vo null -ao pcm:file=%o %i" }, 2250 }, 2251 }, 2252 2253 TAGS => { 2254 READ => 1, 2255 WRITE => 1, 2256 MODULE => "Audio::Scan", 2257 }, 2258 }, 2259 ); 2260 2261 # supported ffmpeg/avconv formats (decode only) 2262 my @ffmpeg_codecs = ( "mmf", "ra", "wma" ); 2263 my @ffmpeg_forks = ( "avconv", "ffmpeg" ); 2264 2265 foreach my $fork (@ffmpeg_forks) { 2266 2267 foreach my $codec (@ffmpeg_codecs) { 2268 2269 $run{$codec}{DEFAULT_ENCODER} = $fork; 2270 $run{$codec}{DEFAULT_DECODER} = $fork; 2271 $run{$codec}{ENCODER}{$fork}{NAME} = $fork; 2272 $run{$codec}{DECODER}{$fork}{NAME} = $fork; 2273 $run{$codec}{DECODER}{$fork}{DSTR} = sub {"-y -i %i $dopts %o"}; 2274 $run{$codec}{ENCODER}{$fork}{ESTR} = sub {"-y -i %i $eopts -ab $bitrate.k -ar $freq -ac $channels %o"}; 2275 $run{$codec}{TAGS}{READ} = 0; 2276 $run{$codec}{TAGS}{WRITE} = 0; 2277 $run{$codec}{TAGS}{MODULE} = undef; 2278 } 2279 2280 } 2281 2282 # support reading of WMA tags via Audio::Scan 2283 $run{wma}{TAGS}{READ} = 1; 2284 $run{wma}{TAGS}{MODULE} = "Audio::Scan"; 2285 2286 # supported video to audio types 2287 my @movie_codecs = ( 2288 "rv", "asf", "avi", "divx", 2289 "mkv", "mpg", "mpeg", "mov", 2290 "ogm", "qt", "vcd", "vob", 2291 "wmv", "flv", "svcd", "m4v", 2292 "nsv", "nuv", "psp", "smk", 2293 "ogv", "webm", "vp9", "mpeg4", 2294 2295 # decode only audio formats 2296 "vqf", "tak", 2297 ); 2298 2299 foreach (@movie_codecs) { 2300 $run{$_}{DEFAULT_ENCODER} = undef; 2301 $run{$_}{DEFAULT_DECODER} = "ffmpeg"; 2302 $run{$_}{DECODER}{mplayer}{NAME} = "mplayer"; 2303 $run{$_}{DECODER}{ffmpeg}{NAME} = "ffmpeg"; 2304 $run{$_}{DECODER}{mplayer}{DSTR} = sub { "$dopts -vc null -vo null -ao pcm:file=%o %i" }; 2305 $run{$_}{DECODER}{ffmpeg}{DSTR} = sub { "$dopts -i %i %o"; }; 2306 $run{$_}{TAGS}{READ} = 0; 2307 $run{$_}{TAGS}{WRITE} = 0; 2308 $run{$_}{TAGS}{MODULE} = undef; 2309 } 2310 2311 # supported sndfile-convert formats 2312 my @sndfile = ( 2313 "pvf", "caf", "sf", "paf", "fap", "sd2", 2314 "mat4", "mat5", "mat", "ircam", "w64", "nist", 2315 "rf64", 2316 ); 2317 2318 foreach (@sndfile) { 2319 2320 $run{$_}{DEFAULT_ENCODER} = "sndfile-convert"; 2321 $run{$_}{DEFAULT_DECODER} = "sndfile-convert"; 2322 $run{$_}{ENCODER}{"sndfile-convert"}{NAME} = "sndfile-convert"; 2323 $run{$_}{DECODER}{"sndfile-convert"}{NAME} = "sndfile-convert"; 2324 $run{$_}{ENCODER}{"sndfile-convert"}{ESTR} = sub { "$eopts %i %o" }; 2325 $run{$_}{DECODER}{"sndfile-convert"}{DSTR} = sub { "$dopts %i %o" }; 2326 $run{$_}{TAGS}{READ} = 0; 2327 $run{$_}{TAGS}{WRITE} = 0; 2328 $run{$_}{TAGS}{MODULE} = undef; 2329 } 2330 2331 # supported sox formats 2332 my @sox_codecs = ( 2333 "aiff", "aif", "au", "snd", "voc", 2334 "smp", "avr", "cdr", "8svx", "amb", 2335 "dat", "dvms", "f32", "f64", "fssd", 2336 "gsrt", "hcom", "txw", "vms", "al", 2337 "sou", "ima", "prc", "cvu", 2338 "maud", 2339 ); 2340 2341 foreach (@sox_codecs) { 2342 2343 $run{$_}{DEFAULT_ENCODER} = "sox"; 2344 $run{$_}{DEFAULT_DECODER} = "sox"; 2345 $run{$_}{ENCODER}{sox}{NAME} = "sox"; 2346 $run{$_}{DECODER}{sox}{NAME} = "sox"; 2347 $run{$_}{ENCODER}{sox}{ESTR} = sub { "%i -r $freq -c $channels $eopts %o $effect" }; 2348 $run{$_}{DECODER}{sox}{DSTR} = sub { "%i $dopts %o" }; 2349 $run{$_}{TAGS}{READ} = 0; 2350 $run{$_}{TAGS}{WRITE} = 0; 2351 $run{$_}{TAGS}{MODULE} = undef; 2352 2353 $run{$_}{ENCODER}{sox}{PROMPT}{FREQ} = 1; 2354 $run{$_}{ENCODER}{sox}{PROMPT}{CHANNELS} = 1; 2355 2356 } 2357 2358 # load codecs.conf file 2359 load_codecs() if -e $codecs_conf; 2360 2361 my $out_name = $outfile; 2362 my $out_dir = $outdir; 2363 my $first_message = 1; 2364 my %files; 2365 my $number = 0; 2366 2367 # process all files and directories 2368 sub proc_input { 2369 2370 $to =~ tr/A-Z/a-z/; 2371 2372 perror("bad_input","") unless(exists($run{$to})); 2373 2374 proc_preserve_dir($dir[0]) if @dir and $preserve; # process recursive directory preservation (sends to proc_files 2375 proc_dirs() if @dir and not $preserve; # process directories including recursively (sends to proc_files) 2376 proc_files() if @file; # process all files 2377 fork_files(); # start the conversion process. 2378 } 2379 2380 # process all files (all roads lead to rome) 2381 sub proc_files { 2382 2383 if (@file) { 2384 2385 foreach my $i (sort(@file)) { 2386 2387 my ($file, $dir, $ext) = fileparse("$i", qr/\.[^.]*/); 2388 2389 $ext =~ s/^\.//; 2390 $dir = rel2abs($dir); 2391 $outdir = $dir if not defined($out_dir) and not $preserve; 2392 $outdir = $out_dir if $preserve; 2393 2394 my $if = $ext; 2395 $if =~ tr/A-Z/a-z/; 2396 2397 $only =~ tr/A-Z/a-z/ if $only; 2398 2399 next if $only and $if ne $only; 2400 2401 $encoder = $my_encoder if defined($my_encoder); 2402 $decoder = $my_decoder if defined($my_decoder); 2403 2404 $encoder = $run{$to}{DEFAULT_ENCODER} if not $my_encoder; 2405 my $codec = ( $if eq "m4a" ? Audio::Scan->scan_info($i)->{info}->{tracks}[0]->{encoding} : $if ); 2406 $decoder = $run{$codec}{DEFAULT_DECODER} if not $my_decoder; 2407 2408 if (-e "$dir/$file.$to" and not $overwrite) { 2409 pnotice("overwrite","$file.$to",1); 2410 $total_failed++; 2411 next; 2412 } 2413 2414 if (check_input($file,$dir,$codec) == 0) { 2415 2416 pnotice("unk_encoder","$file.$ext",1), next unless(exists($run{$to}{ENCODER}{$encoder})); 2417 pnotice("unk_decoder","$file.$ext",1), next unless(exists($run{$codec}{DECODER}{$decoder})); 2418 2419 get_visual_opts($to,$outdir) if $gui and not defined($first_run); 2420 2421 $first_run = 1; 2422 2423 perror("multi_out","") if (defined($out_name) and $#file gt 0 or defined($out_name) and @dir); 2424 perror("no_outdir","") if (not -e $outdir and not -d $outdir); 2425 2426 $outfile = "$file" if not $out_name; 2427 2428 if ($keep and $if eq $to) { 2429 my $source_q = shell_quote "$dir/$file.$ext"; 2430 my $dest_q = shell_quote "$outdir/$outfile.$ext"; 2431 system("cp -v $source_q $dest_q") if $outdir ne $dir and not -e "$outdir/$outfile.$ext"; 2432 next if $outdir eq $dir; 2433 } 2434 2435 else { 2436 $files{"FILE$number"}{FILE} = "$dir/$file"; 2437 $files{"FILE$number"}{OUTF} = "$outdir/$outfile"; 2438 $files{"FILE$number"}{EXT} = "$ext"; 2439 $files{"FILE$number"}{CODEC} = "$codec"; 2440 $files{"FILE$number"}{NAME} = "$file"; 2441 $files{"FILE$number"}{OUTD} = "$outfile"; 2442 $files{"FILE$number"}{DECODER} = "$decoder"; 2443 2444 $number++; 2445 } 2446 2447 } 2448 } 2449 } 2450 undef(@file); 2451 } 2452 2453 # process directories and push all to @file arrary 2454 sub proc_dirs { 2455 2456 if (@dir) { 2457 2458 my @tmp_dir = @dir; 2459 undef(@dir); 2460 $topdir = $tmp_dir[0]; 2461 2462 if (not $recursive) { 2463 2464 undef(@file); 2465 2466 foreach my $d (@tmp_dir) { 2467 2468 opendir(DIR, "$d") or perror("opening_dir","$d: $!"); 2469 my @dir_files = readdir(DIR); 2470 closedir(DIR); 2471 perror("empty_dir","$d") if $#dir_files <= 1; 2472 2473 foreach my $f (@dir_files) { 2474 2475 if (not -d $f and not -d "$d/$f") { 2476 push(@file, "$d/$f"); 2477 undef($out_name); 2478 } 2479 } 2480 } 2481 2482 proc_files(); 2483 return 0; 2484 2485 } 2486 2487 elsif ($recursive) { 2488 2489 if (not $preserve) { 2490 2491 undef(@file); 2492 2493 foreach my $r (@tmp_dir) { 2494 2495 $r = rel2abs($r); 2496 2497 find ( sub { 2498 my $rfile = $File::Find::name; 2499 push(@file, $rfile) if not -d $rfile; 2500 }, $r 2501 ); 2502 } 2503 2504 proc_files(); 2505 return 0; 2506 2507 } 2508 } 2509 2510 } 2511 } 2512 2513 # preserve directory structuer (revised 10-7-2013) 2514 my $out_dir_original = rel2abs($outdir) if $outdir and -d $outdir; 2515 2516 sub proc_preserve_dir { 2517 2518 $topdir = rel2abs($dir[0]); 2519 2520 perror("no_outdir","") if not defined($out_dir_original); 2521 perror("no_outdir","") if not -d $out_dir_original; 2522 2523 undef(@file); # clear the array before we begin. 2524 2525 find ( sub { 2526 my $val = $File::Find::name; 2527 $val =~ s/(\$)/\\\$/g; 2528 2529 if ($val ne $topdir) { 2530 2531 $val =~ s/$topdir\///; 2532 2533 # create mirrored directories in output directory 2534 if (not -f fileparse("$topdir/$val") and not -d "$out_dir_original/$val") { 2535 say "creating directory $out_dir_original/$val" if not -f "$topdir/$val" and $verbose; 2536 mkdir("$out_dir_original/$val", 0755) if not -f "$topdir/$val"; 2537 } 2538 2539 # this will list all files in their original directories 2540 if (-f "$topdir/$val") { 2541 say "$lang{debug} pushing to \@file: $topdir/$val" if $debug == 1; 2542 push(@file, "$topdir/$val"); 2543 } 2544 2545 # set $out_dir to the 2546 $out_dir = "$out_dir_original/" . dirname($val) if -f "$topdir/$val"; 2547 2548 # send file, and output dir to proc_files(); 2549 proc_files(); 2550 } 2551 2552 }, $topdir 2553 ); 2554 } 2555 2556 # convert input to destination format 2557 sub convert { 2558 2559 my ($inf, $outf, $infmt, $iname, $oname, $codec, $dec) = @_; 2560 2561 my $if = $infmt; 2562 $if =~ tr/A-Z/a-z/; 2563 2564 clear_tag_hash() if not $rip; 2565 2566 # check to see if encoder/decoder exists. if not, see if we have one 2567 # that supports the desired input/output formats. 2568 $decoder = $dec; 2569 check_encoder(); 2570 check_decoder($codec); 2571 2572 my $wavf = "$outf.$$.wav"; 2573 my $wavf_q = shell_quote $wavf; 2574 my $decode_string = $run{$codec}{DECODER}{$decoder}{DSTR}->(); 2575 my $inf_q = shell_quote "$inf.$infmt"; 2576 $decode_string =~ s/%i/$inf_q/; 2577 if ( $decode_string =~ m/%o/ ) { 2578 $decode_string =~ s/%o/$wavf_q/; 2579 } else { 2580 $wavf = "$outf.wav"; 2581 $wavf_q = shell_quote $wavf; 2582 } 2583 2584 pnotice("debug","\n$run{$codec}{DECODER}{$decoder}{NAME} $decode_string", 2) if $dryrun; 2585 2586 # catch ^C. will have to be pressed repeatedly to exit the process. 2587 $SIG{INT} = sub { 2588 unlink("$wavf"); 2589 kill 9, $$; 2590 }; 2591 2592 # decode input file to temporary wav 2593 system("$run{$codec}{DECODER}{$decoder}{NAME} $decode_string $silent") if not $dryrun; 2594 2595 # remove temporary wav file and die if decode fails 2596 if ($? > 0) { 2597 unlink("$wavf") if -e "$wavf"; 2598 say ""; 2599 $banner = 0; 2600 pnotice("decode_failed","$inf.$infmt: try with --verbose",1); 2601 return 1; 2602 } 2603 2604 # normalize wav file before encoding to output format 2605 perror("no_app","normalize") if $normalize and not `which normalize 2>/dev/null`; 2606 system("normalize $nopts $wavf_q") if $normalize; 2607 2608 # copy meta-data from input file to %tag_name 2609 read_tags("$inf.$infmt", "$codec") if $run{$codec}{TAGS}{READ} == 1 and not $dryrun; 2610 2611 my $tag_opts = format_tags($to); # tag options for mp4/m4a/m4b/mpc/mpp/bonk/spx/wv 2612 2613 my $outf_q = shell_quote "$outf.$to"; 2614 my $encode_string = $run{$to}{ENCODER}{$encoder}{ESTR}->(); 2615 $encode_string =~ s/%i/$tag_opts $wavf_q/ if $to =~ /mpc|mpp|mp4|m4a/ and $encoder eq "faac" or $encoder eq "mpcenc"; 2616 $encode_string =~ s/%i/$wavf_q $tag_opts/ if $to =~ /mpc|mpp|mp4|m4a/ and $encoder eq "ffmpeg" or $encoder eq "avconv"; 2617 $encode_string =~ s/%i/$wavf_q/ if $to !~ /mpc|mpp|mp4|m4a/; 2618 $encode_string =~ s/%o/$tag_opts $outf_q/ if $tag_opts ne " " and $to !~ /mpc|mpp|mp4|m4a/; 2619 $encode_string =~ s/%o/$outf_q/ if $tag_opts eq " " or $to =~ /mpc|mpp|mp4|m4a/; 2620 2621 # read tag options from command line if present 2622 get_user_tags(); 2623 2624 pnotice("debug","\n$run{$to}{ENCODER}{$encoder}{NAME} $encode_string", 2) if $dryrun; 2625 2626 # encode temporary WAV to desired output format. 2627 system("$run{$to}{ENCODER}{$encoder}{NAME} $encode_string $silent") if not $dryrun; 2628 2629 # remove partially encoded output file and temporary wav if encoding fails 2630 if ($? > 0) { 2631 unlink("$outf.$to") if -e "$outf.$to"; 2632 unlink("$wavf") if -e "$wavf"; 2633 say ""; 2634 $banner = 0; 2635 pnotice("encode_failed","$outf.$to: $?",1); 2636 return 1; 2637 } 2638 2639 # write meta-data to output file from %tag_name hash 2640 write_tags("$outf.$to", "$to") if $run{$to}{TAGS}{WRITE} == 1 and $tag_opts eq " " and not $dryrun; 2641 2642 unlink("$wavf") if not $dryrun; 2643 unlink("$inf.$infmt") if $delete and not $dryrun; 2644 2645 pnotice("removed_tmp","$wavf","2") if $verbose; 2646 pnotice("removed_src","$inf.$infmt", "2") if $delete and $verbose; 2647 } 2648 2649 $pm->run_on_finish 2650 ( sub { 2651 my $pid = shift; 2652 my $exit_code = shift; 2653 my $ident = shift; 2654 2655 if (-e "$ident.$to") { 2656 $total_converted++; 2657 } 2658 say "$lang{debug} PID: $pid EXIT_CODE: $exit_code IDENTITY: \"$ident.$to\"" if $debug == 1; 2659 } 2660 ); 2661 2662 # convert all files that have been placed in the %files hash through various procs* 2663 sub fork_files { 2664 2665 say "\n$name - $version\n" if not $gui and $banner == 1; 2666 2667 foreach (sort(keys(%files))) 2668 { 2669 $pm->start($files{$_}{OUTF}) and next; 2670 my $msg = "$lang{converting}" . " " . basename($files{$_}{FILE}) . ".$files{$_}{EXT} -> $to"; 2671 say "$msg" if not $gui; 2672 system("kdialog --icon $icon_path --title \"$name\" --passivepopup \"$msg\" 10 &") if $gui and $kde; 2673 system("notify-send \"$name\" \"$msg\" -t 35 -i $icon_path &") if $gui and $gnome; 2674 convert("$files{$_}{FILE}","$files{$_}{OUTF}","$files{$_}{EXT}","$files{$_}{NAME}","$files{$_}{OUTD}","$files{$_}{CODEC}","$files{$_}{DECODER}"); 2675 $pm->finish; 2676 } 2677 2678 $pm->wait_all_children; 2679 $total_failed = $number - $total_converted if $total_converted < $number; 2680 2681 my $finished_msg = "\n$lang{total_converted} $total_converted, $lang{failed} $total_failed\n"; 2682 2683 say "$finished_msg" if not $gui; 2684 system("kdialog --icon $icon_path --title \"$name\" --passivepopup \"$finished_msg\" 10 &") if $gui and $kde; 2685 system("notify-send \"$name\" \"$finished_msg\" -t 35 -i $icon_path &") if $gui and $gnome; 2686 2687 } 2688 2689 # if the default encoder does not exist, cycle through the supported 2690 # encoders until we find one that does. 2691 sub check_encoder { 2692 2693 if (not `which $encoder 2>/dev/null`) { 2694 my $first_encoder = $encoder; 2695 foreach (keys %{$run{$to}{ENCODER}}) { $encoder = $_ and return if `which $_ 2>/dev/null`; } 2696 perror("no_encode_app","$to") if $encoder eq $first_encoder; 2697 } 2698 2699 else { return 0; } 2700 } 2701 2702 # if the default decoder does not exist, cycle through the supported 2703 # decoders until we find one that does. 2704 sub check_decoder { 2705 2706 my $from = shift; 2707 2708 if (not `which $decoder 2>/dev/null`) { 2709 my $first_decoder = $decoder; 2710 foreach (keys %{$run{$from}{DECODER}}) { $decoder = $_ and return if `which $_ 2>/dev/null`; } 2711 perror("no_decode_app","$from") if $decoder eq $first_decoder; 2712 } 2713 2714 else { return 0; } 2715 } 2716 2717 # make sure encoding/decoding is supported. 2718 sub check_input { 2719 2720 my $file = shift; 2721 my $dir = shift; 2722 my $codec = shift; 2723 2724 perror("no_encoder","$to") unless(defined($run{$to}{ENCODER})); 2725 2726 unless(defined($run{$codec}{DECODER})) { 2727 pnotice("no_decoder","$codec",2) if $verbose or not $only; 2728 $total_failed++; 2729 return 1; 2730 } 2731 2732 return 0; 2733 } 2734 2735 ######################################## 2736 # GUI options for KDE & Gnome Plugins # 2737 ######################################## 2738 2739 my $kdialog = "kdialog --title \"$name\""; 2740 my $zenity = "zenity --title \"$name\" --list --radiolist --width 100 --height 300 --column '' --column "; 2741 2742 sub get_visual_opts { 2743 2744 my ($to_fmt,$od) = @_; 2745 2746 # escape illegal characters in output directory name 2747 $od =~ s/( |'|\(|\)|"|\\)/\\$1/g; 2748 2749 $outdir = `kdialog --getexistingdirectory $od` if $config{KDE_DIR} == 1 and $kde; 2750 $outdir = `zenity --title \"$lang{gui_outdir}\" --file-selection --directory --filename=\`pwd\`` if $config{ZEN_DIR} == 1 and $gnome; 2751 2752 chomp($outdir); 2753 $out_dir = $outdir; 2754 exit(1) if not $outdir; 2755 2756 if ($config{KDE_OPTS} == 1 or $config{ZEN_OPTS} == 1) { 2757 foreach (keys %{$run{$to_fmt}{ENCODER}{$encoder}{PROMPT}}) { 2758 prompt_user($_); 2759 } 2760 } 2761 } 2762 2763 sub prompt_user { 2764 2765 my $opt = shift; 2766 2767 given ($opt) { 2768 2769 when (/^BITRATE/) { 2770 $bitrate = `$kdialog --default $bitrate --combobox \"$lang{gui_bitrate}\" 56 112 128 160 192 256 320` if $kde; 2771 $bitrate = `$zenity \"$lang{gui_bitrate}\" FALSE 56 FALSE 112 FALSE 128 FALSE 160 TRUE 192 FALSE 256 FALSE 320` if $gnome; 2772 chomp($bitrate); 2773 exit(1) if not $bitrate; 2774 } 2775 2776 when (/^FREQ/) { 2777 $freq = `$kdialog --default $freq --combobox \"$lang{gui_freq}\" 32000 44100 48000` if $kde; 2778 $freq = `$zenity \"$lang{gui_freq}\" FALSE 32000 TRUE 44100 FALSE 48000` if $gnome; 2779 chomp($freq); 2780 exit(1) if not $freq; 2781 } 2782 2783 when (/^CHANNELS/) { 2784 $channels = `$kdialog --default $channels --combobox \"$lang{gui_chans}\" 1 2` if $kde; 2785 $channels = `$zenity \"$lang{gui_chans}\" FALSE 1 TRUE 2` if $gnome; 2786 chomp($channels); 2787 exit(1) if not $channels; 2788 } 2789 2790 when (/^FCOMP/) { 2791 $fcomp = `$kdialog --default $fcomp --combobox \"$lang{gui_fcomp}\" 0 1 2 3 4 5 6 7 8` if $kde; 2792 $fcomp = `$zenity \"$lang{gui_fcomp}\" FALSE 0 FALSE 1 TRUE 2 FALSE 3 FALSE 4 FALSE 5 FALSE 6 FALSE 7 FALSE 8` if $gnome; 2793 chomp($fcomp); 2794 exit(1) if not $fcomp; 2795 } 2796 2797 when (/^ACOMP/) { 2798 $acomp = `$kdialog --default $acomp --combobox \"$lang{gui_acomp}\" 1000 2000 3000 4000 5000` if $kde; 2799 $acomp = `$zenity \"$lang{gui_acomp}\" FALSE 1000 FALSE 2000 TRUE 3000 FALSE 4000 FALSE 5000` if $gnome; 2800 chomp($acomp); 2801 exit(1) if not $acomp; 2802 } 2803 2804 when (/^OGGQUAL/) { 2805 $oggqual = `$kdialog --default $oggqual --combobox \"$lang{gui_oggqual}\" 0 1 2 3 4 5 6 7 8 9 10` if $kde; 2806 $oggqual = `$zenity \"$lang{gui_oggqual}\" FALSE 0 FALSE 1 FALSE 2 TRUE 3 FALSE 4 FALSE 5 FALSE 6 FALSE 7 FALSE 8 FALSE 9 FALSE 10` if $gnome; 2807 chomp($oggqual); 2808 exit(1) if not $oggqual; 2809 } 2810 2811 when (/^SPXQUAL/) { 2812 $spxqual = `$kdialog --default $spxqual --combobox \"$lang{gui_spxqual}\" 0 1 2 3 4 5 6 7 8 9 10` if $kde; 2813 $spxqual = `$zenity \"$lang{gui_spxqual}\" FALSE 0 FALSE 1 FALSE 2 FALSE 3 FALSE 4 FALSE 5 FALSE 6 FALSE 7 TRUE 8 FALSE 9 FALSE 10` if $gnome; 2814 chomp($spxqual); 2815 exit(1) if not $spxqual; 2816 } 2817 2818 when (/^AACQUAL/) { 2819 $aacqual = `$kdialog --default $aacqual --combobox \"$lang{gui_aacqual}\" 100 200 300 400 500` if $kde; 2820 $aacqual = `$zenity \"$lang{gui_aacqual}\" TRUE 100 FALSE 200 FALSE 300 FALSE 400 FALSE 500` if $gnome; 2821 chomp($aacqual); 2822 exit(1) if not $aacqual; 2823 } 2824 2825 when (/^MPCQUAL/) { 2826 $mpcqual = `$kdialog --default $mpcqual --combobox \"$lang{gui_mpcqual}\" thumb radio standard xtreme insane braindead` if $kde; 2827 $mpcqual = `$zenity \"$lang{gui_mpcqual}\" FALSE thumb TRUE radio FALSE standard FALSE xtreme FALSE insane FALSE braindead` if $gnome; 2828 chomp($mpcqual); 2829 exit(1) if not $mpcqual; 2830 } 2831 2832 when (/^OFMODE/ ) { 2833 $ofmode = `$kdialog --default $ofmode --combobox \"$lang{gui_ofmode}\" fast normal high extra best highnew extranew bestnew` if $kde; 2834 $ofmode = `$zenity \"$lang{gui_ofmode}\" FALSE fast TRUE normal FALSE high FALSE extra FALSE best FALSE highnew FALSE extranew FALSE bestnew` if $gnome; 2835 chomp($ofmode); 2836 exit(1) if not $ofmode; 2837 } 2838 2839 when (/^OFOPT/) { 2840 $ofopt = `$kdialog --default $ofopt --combobox \"$lang{gui_ofopt}\" none fast normal high best` if $kde; 2841 $ofopt = `$zenity \"$lang{gui_ofopt}\" FALSE none TRUE fast FALSE normal FALSE high FALSE best` if $gnome; 2842 chomp($ofopt); 2843 exit(1) if not $ofopt; 2844 } 2845 2846 when (/^BRATIO/) { 2847 $bratio = `$kdialog --default $bratio --combobox \"$lang{gui_bratio}\" 1 2 3 4 5` if $kde; 2848 $bratio = `$zenity \"$lang{gui_bratio}\" FALSE 1 TRUE 2 FALSE 3 FALSE 4 FALSE 5` if $gnome; 2849 chomp($bratio); 2850 exit(1) if not $bratio; 2851 } 2852 2853 when (/^BQUANL/) { 2854 $bquanl = `$kdialog --default $bquanl --combobox \"$lang{gui_bquanl}\" 1.00 1.25 1.50 1.75 2.00` if $kde; 2855 $bquanl = `$zenity \"$lang{gui_bquanl}\" TRUE 1.00 FALSE 1.25 FALSE 1.50 FALSE 1.75 FALSE 2.00` if $gnome; 2856 chomp($bquanl); 2857 exit(1) if not $bquanl; 2858 } 2859 2860 when (/^BPSIZE/) { 2861 $bpsize = `$kdialog --default $bpsize --combobox \"$lang{gui_bpsize}\" 10 128` if $kde; 2862 $bpsize = `$zenity \"$lang{gui_bpsize}\" FALSE 10 TRUE 128` if $gnome; 2863 chomp($bpsize); 2864 exit(1) if not $bpsize; 2865 } 2866 2867 default { return 0; } 2868 } 2869 2870 } 2871 2872 # all copied tags will be stored here for furture use 2873 my %tag_name = 2874 ( 2875 title => undef, 2876 track => undef, 2877 artist => undef, 2878 album => undef, 2879 comment => undef, 2880 year => undef, 2881 genre => undef, 2882 ); 2883 2884 # override tags read from input file if any of the tagging 2885 # options are specified by the user during conversion. 2886 sub get_user_tags 2887 { 2888 $tag_name{title} = $title if $title; 2889 $tag_name{track} = $track if $track; 2890 $tag_name{artist} = $artist if $artist; 2891 $tag_name{album} = $album if $album; 2892 $tag_name{comment} = $comment if $comment; 2893 $tag_name{year} = $year if $year; 2894 $tag_name{genre} = $genre if $genre; 2895 } 2896 2897 # the formats MP4/M4A/M4B/MPC/MPP/WV/BONK have no tag writing module. 2898 # tags therefore have to be written during encode via various 2899 # command line args. 2900 sub format_tags { 2901 2902 my $type = shift; 2903 2904 given ($type) { 2905 2906 when (/^mp4$|^m4a$|^m4b$/) { 2907 2908 if ($run{$to}{ENCODER}{$encoder}{NAME} eq "ffmpeg" or $run{$to}{ENCODER}{$encoder}{NAME} eq "avconv") { 2909 2910 $tag_name{track} = 0 if not $tag_name{track}; 2911 $tag_name{year} = 0 if not $tag_name{year}; 2912 2913 return "-metadata TITLE=\"$tag_name{title}\" -metadata TRACK=\"$tag_name{track}\" -metadata ARTIST=\"$tag_name{artist}\" -metadata ALBUM=\"$tag_name{album}\" -metadata COMMENT=\"$tag_name{comment}\" -metadata YEAR=\"$tag_name{year}\" -metadata GENRE=\"$tag_name{genre}\""; 2914 2915 } else { 2916 2917 return "--title \"$tag_name{title}\" --track \"$tag_name{track}\" --artist \"$tag_name{artist}\" --album \"$tag_name{album}\" --comment \"$tag_name{comment}\" --year \"$tag_name{year}\" --genre \"$tag_name{genre}\""; 2918 2919 } 2920 } 2921 2922 when (/^mpc$|^mpp$/) { return "--artist \"$tag_name{artist}\" --title \"$tag_name{title}\" --album \"$tag_name{album}\" --track \"$tag_name{track}\" --genre \"$tag_name{genre}\" --year \"$tag_name{year}\" --comment \"$tag_name{comment}\""; } 2923 when (/^wv$/) { return "-w \"Title=$tag_name{title}\" -w \"Track=$tag_name{track}\" -w \"Artist=$tag_name{artist}\" -w \"Album=$tag_name{album}\" -w \"Comment=$tag_name{comment}\" -w \"Year=$tag_name{year}\" -w \"Genre=$tag_name{genre}\""; } 2924 when (/^bonk$/) { return "-t \"$tag_name{title}\" -a \"$tag_name{artist}\" -c \"$tag_name{comment}\""; } 2925 when (/^spx$/) { return "--author \"$tag_name{artist}\" --title \"$tag_name{title}\" --comment \"year=$tag_name{year}\" --comment \"tracknumber=$tag_name{track}\" --comment \"album=$tag_name{album}\" --comment \"genre=$tag_name{genre}\" --comment \"comment=$tag_name{comment}\""; } 2926 2927 default { return " "; } 2928 } 2929 } 2930 2931 # meta-data is read based on input file extension. 2932 # all tags which are present will be copied to 2933 # the %tag_name hash. 2934 sub read_tags { 2935 2936 my $in_file = shift; 2937 my $in_format = shift; 2938 2939 my $tag_module = $run{$in_format}{TAGS}{MODULE}; 2940 2941 given ($in_format) { 2942 2943 when (/^mp3$|^mp3hd$/) { 2944 my $mp3tag = $tag_module->new($in_file); 2945 my @tags = $mp3tag->autoinfo(); 2946 2947 $tag_name{title} = "$tags[0]" if $tags[0]; 2948 $tag_name{track} = "$tags[1]" if $tags[1]; 2949 $tag_name{artist} = "$tags[2]" if $tags[2]; 2950 $tag_name{album} = "$tags[3]" if $tags[3]; 2951 $tag_name{comment} = "$tags[4]" if $tags[4]; 2952 $tag_name{year} = "$tags[5]" if $tags[5]; 2953 $tag_name{genre} = "$tags[6]" if $tags[6]; 2954 2955 return 0; 2956 } 2957 2958 when (/^ogg$|^oga$/) { 2959 my $ogg_tag = Audio::Scan->scan_tags($in_file)->{tags}; 2960 2961 $tag_name{title} = $ogg_tag->{TITLE} if $ogg_tag->{TITLE}; 2962 $tag_name{track} = $ogg_tag->{TRACKNUMBER} if $ogg_tag->{TRACKNUMBER}; 2963 $tag_name{artist} = $ogg_tag->{ARTIST} if $ogg_tag->{ARTIST}; 2964 $tag_name{album} = $ogg_tag->{ALBUM} if $ogg_tag->{ALBUM}; 2965 $tag_name{comment} = $ogg_tag->{COMMENT} if $ogg_tag->{COMMENT}; 2966 $tag_name{year} = $ogg_tag->{YEAR} if $ogg_tag->{YEAR}; 2967 $tag_name{genre} = $ogg_tag->{GENRE} if $ogg_tag->{GENRE}; 2968 2969 return 0; 2970 } 2971 2972 when (/^spx$/) { 2973 my $pid = open(SPX, "speexdec \"$in_file\" tmp1-$$.wav 2>&1 |") or perror("opening_file","$in_file"); 2974 my @data = <SPX>; 2975 @data = grep(!/^$|^#/, @data); 2976 2977 close(SPX); 2978 2979 foreach (@data) { 2980 2981 next unless /=/; 2982 chomp; 2983 2984 my ($k, $v) = split /=/; 2985 $k =~ tr/A-Z/a-z/; 2986 $tag_name{$k} = $v if exists($tag_name{$k}); 2987 $tag_name{artist} = $v if $k =~ /^author/i; 2988 $tag_name{track} = $v if $k =~ /^tracknumber/i; 2989 } 2990 2991 unlink("tmp-$$.wav"); 2992 return 0; 2993 } 2994 2995 when (/^flac$|^fla$/) { 2996 my $flac_file = Audio::FLAC::Header->new($in_file); 2997 my $flac_tag = $flac_file->tags(); 2998 2999 $tag_name{title} = $flac_tag->{TITLE} if $flac_tag->{TITLE}; 3000 $tag_name{track} = $flac_tag->{TRACKNUMBER} if $flac_tag->{TRACKNUMBER}; 3001 $tag_name{artist} = $flac_tag->{ARTIST} if $flac_tag->{ARTIST}; 3002 $tag_name{album} = $flac_tag->{ALBUM} if $flac_tag->{ALBUM}; 3003 $tag_name{comment} = $flac_tag->{COMMENT} if $flac_tag->{COMMENT}; 3004 $tag_name{year} = $flac_tag->{DATE} if $flac_tag->{DATE}; 3005 $tag_name{genre} = $flac_tag->{GENRE} if $flac_tag->{GENRE}; 3006 3007 return 0; 3008 } 3009 3010 when (/^(mp4|m4b|alac|mp4a)$/) { 3011 my $mp4_tag = $tag_module->scan_tags($in_file)->{tags}; 3012 3013 $tag_name{title} = $mp4_tag->{NAM} if $mp4_tag->{NAM}; 3014 $tag_name{track} = $mp4_tag->{TRKN} if $mp4_tag->{TRKN}; 3015 $tag_name{artist} = $mp4_tag->{ART} if $mp4_tag->{ART}; 3016 $tag_name{album} = $mp4_tag->{ALB} if $mp4_tag->{ALB}; 3017 $tag_name{comment} = $mp4_tag->{CMT} if $mp4_tag->{CMT}; 3018 $tag_name{year} = $mp4_tag->{DAY} if $mp4_tag->{DAY}; 3019 $tag_name{genre} = $mp4_tag->{GNRE} if $mp4_tag->{GNRE}; 3020 3021 return 0; 3022 } 3023 3024 when (/^dsf$/) { 3025 my $dsf_tag = $tag_module->scan_tags($in_file)->{tags}; 3026 3027 $tag_name{title} = $dsf_tag->{TIT2} if $dsf_tag->{TIT2}; 3028 $tag_name{track} = $dsf_tag->{TRCK} if $dsf_tag->{TRCK}; 3029 $tag_name{artist} = $dsf_tag->{TPE1} if $dsf_tag->{TPE1}; 3030 $tag_name{album} = $dsf_tag->{TALB} if $dsf_tag->{TALB}; 3031 $tag_name{comment} = $dsf_tag->{COMM} if $dsf_tag->{COMM}; 3032 $tag_name{year} = $dsf_tag->{TYER} if $dsf_tag->{TYER}; 3033 $tag_name{genre} = $dsf_tag->{TCON} if $dsf_tag->{TCON}; 3034 3035 return 0; 3036 } 3037 3038 when (/^ape$|^mpc$|^mpp$|^wv$/) { 3039 my $audio_tag = $tag_module->scan_tags($in_file)->{tags}; 3040 3041 $tag_name{title} = $audio_tag->{TITLE} if $audio_tag->{TITLE}; 3042 $tag_name{track} = $audio_tag->{TRACK} if $audio_tag->{TRACK}; 3043 $tag_name{artist} = $audio_tag->{ARTIST} if $audio_tag->{ARTIST}; 3044 $tag_name{album} = $audio_tag->{ALBUM} if $audio_tag->{ALBUM}; 3045 $tag_name{comment} = $audio_tag->{COMMENT} if $audio_tag->{COMMENT}; 3046 $tag_name{year} = $audio_tag->{YEAR} if $audio_tag->{YEAR}; 3047 $tag_name{genre} = $audio_tag->{GENRE} if $audio_tag->{GENRE}; 3048 3049 return 0; 3050 } 3051 3052 when (/^wma$/) { 3053 my $wma_tag = $tag_module->scan_tags($in_file)->{tags}; 3054 3055 $tag_name{title} = $wma_tag->{Title} if $wma_tag->{Title}; 3056 $tag_name{track} = $wma_tag->{'WM/TrackNumber'} if $wma_tag->{'WM/TrackNumber'}; 3057 $tag_name{artist} = $wma_tag->{'WM/AlbumArtist'} if $wma_tag->{'WM/AlbumArtist'}; 3058 $tag_name{album} = $wma_tag->{'WM/AlbumTitle'} if $wma_tag->{'WM/AlbumTitle'}; 3059 $tag_name{comment} = $wma_tag->{'WM/Description'} if $wma_tag->{'WM/Description'}; 3060 $tag_name{year} = $wma_tag->{'WM/Year'} if $wma_tag->{'WM/Year'}; 3061 $tag_name{genre} = $wma_tag->{'WM/Genre'} if $wma_tag->{'WM/Genre'}; 3062 3063 return 0; 3064 } 3065 3066 default { return 1; } 3067 } 3068 } 3069 3070 # write meta-data stored in %tag_name to output file. 3071 sub write_tags { 3072 3073 my $out_file = shift; 3074 my $out_format = shift; 3075 3076 my $tag_m; 3077 3078 given ($out_format) { 3079 3080 when (/^mp3$|^mp3hd$/) { 3081 $tag_m = MP3::Tag->new("$out_file"); 3082 3083 # ID3v2 Tags 3084 unless(exists($tag_m->{ID3v2})) { $tag_m->new_tag("ID3v2"); } 3085 3086 $tag_m->{ID3v2}->add_frame("TIT2", "$tag_name{title}") if defined($tag_name{title}); 3087 $tag_m->{ID3v2}->add_frame("TRCK", "$tag_name{track}") if defined($tag_name{track}); 3088 $tag_m->{ID3v2}->add_frame("TPE1", "$tag_name{artist}") if defined($tag_name{artist}); 3089 $tag_m->{ID3v2}->add_frame("TALB", "$tag_name{album}") if defined($tag_name{album}); 3090 $tag_m->{ID3v2}->comment("$tag_name{comment}") if defined($tag_name{comment}); 3091 $tag_m->{ID3v2}->add_frame("TYER", "$tag_name{year}") if defined($tag_name{year}); 3092 $tag_m->{ID3v2}->add_frame("TCON", "$tag_name{genre}") if defined($tag_name{genre}); 3093 3094 $tag_m->{ID3v2}->write_tag; 3095 3096 # ID3v1 Tags 3097 unless(exists($tag_m->{ID3v1})) { $tag_m->new_tag("ID3v1"); } 3098 3099 $tag_m->{ID3v1}->title("$tag_name{title}") if defined($tag_name{title}); 3100 $tag_m->{ID3v1}->track("$tag_name{track}") if defined($tag_name{track}); 3101 $tag_m->{ID3v1}->artist("$tag_name{artist}") if defined($tag_name{artist}); 3102 $tag_m->{ID3v1}->album("$tag_name{album}") if defined($tag_name{album}); 3103 $tag_m->{ID3v1}->comment("$tag_name{comment}") if defined($tag_name{comment}); 3104 $tag_m->{ID3v1}->year("$tag_name{year}") if defined($tag_name{year}); 3105 $tag_m->{ID3v1}->genre("$tag_name{genre}") if defined($tag_name{genre}); 3106 3107 $tag_m->{ID3v1}->write_tag; 3108 3109 return 0; 3110 3111 } 3112 3113 when (/^ogg$|^oga$/) { 3114 $tag_m = ''; 3115 3116 $tag_m = "$tag_m -t \"TITLE=$tag_name{title}\"" if $tag_name{title}; 3117 $tag_m = "$tag_m -t \"TRACKNUMBER=$tag_name{track}\"" if $tag_name{track}; 3118 $tag_m = "$tag_m -t \"ARTIST=$tag_name{artist}\"" if $tag_name{artist}; 3119 $tag_m = "$tag_m -t \"ALBUM=$tag_name{album}\"" if $tag_name{album}; 3120 $tag_m = "$tag_m -t \"COMMENT=$tag_name{comment}\"" if $tag_name{comment}; 3121 $tag_m = "$tag_m -t \"YEAR=$tag_name{year}\"" if $tag_name{year}; 3122 $tag_m = "$tag_m -t \"GENRE=$tag_name{genre}\"" if $tag_name{genre}; 3123 3124 my $out_file_q = shell_quote $out_file; 3125 system("vorbiscomment -w $tag_m $out_file_q") if $tag_m ne ''; 3126 3127 return 0; 3128 } 3129 3130 when (/^fla$|^flac$/) { 3131 $tag_m = Audio::FLAC::Header->new("$out_file"); 3132 my $tag_i = $tag_m->tags(); 3133 3134 $tag_i->{TITLE} = "$tag_name{title}" if $tag_name{title}; 3135 $tag_i->{TRACKNUMBER} = "$tag_name{track}" if $tag_name{track}; 3136 $tag_i->{ARTIST} = "$tag_name{artist}" if $tag_name{artist}; 3137 $tag_i->{ALBUM} = "$tag_name{album}" if $tag_name{album}; 3138 $tag_i->{COMMENT} = "$tag_name{comment}" if $tag_name{comment}; 3139 $tag_i->{DATE} = "$tag_name{year}" if $tag_name{year}; 3140 $tag_i->{GENRE} = "$tag_name{genre}" if $tag_name{genre}; 3141 3142 $tag_m->write(); 3143 3144 return 0; 3145 } 3146 3147 default { perror("no_write_tag","$out_file"); } 3148 } 3149 3150 } 3151 3152 # this is necessary when converting multiple files. 3153 # it prevents old tags from the previous file being 3154 # copied over to the next file in line. 3155 sub clear_tag_hash { 3156 foreach (keys(%tag_name)) { 3157 $tag_name{$_} = ''; 3158 } 3159 } 3160 3161 # display meta-data for selected file(s) 3162 sub show_taginfo { 3163 3164 perror("no_input","") if $#file < 0; 3165 3166 foreach my $i (@file) { 3167 3168 my ($file, $dir, $ext) = fileparse("$i", qr/\.[^.]*/); 3169 3170 $ext =~ s/^\.//; 3171 3172 my $from = $ext; 3173 $from =~ tr/A-Z/a-z/; 3174 3175 if ($run{$from}{TAGS}{READ} == 1) { 3176 3177 clear_tag_hash(); 3178 read_tags("$dir/$file.$ext","$from"); 3179 3180 say ''; 3181 3182 pnotice("tag_info","$file.$ext",2); 3183 3184 say " Artist: $tag_name{artist}"; 3185 say " Title: $tag_name{title}"; 3186 say " Album: $tag_name{album}"; 3187 say " Track: $tag_name{track}"; 3188 say "Comment: $tag_name{comment}"; 3189 say " Year: $tag_name{year}"; 3190 say " Genre: $tag_name{genre}"; 3191 3192 say ''; 3193 3194 } else { pnotice("no_read_tag","$file.$ext",2); } 3195 } 3196 } 3197 3198 # write tags to file supplied by the user 3199 sub write_user_tags { 3200 3201 perror("no_input","") if $#file < 0; 3202 3203 say ''; 3204 say "$name - $version\n"; 3205 3206 foreach (@file) { 3207 3208 my ($file, $dir, $ext) = fileparse("$_", qr/\.[^.]*/); 3209 3210 $ext =~ s/^\.//; 3211 my $from = $ext; 3212 $from =~ tr/A-Z/a-z/; 3213 3214 if ($run{$from}{TAGS}{WRITE} == 1) { 3215 3216 clear_tag_hash(); 3217 read_tags("$dir/$file.$ext","$from"); 3218 3219 $tag_name{title} = $title if $title; 3220 $tag_name{track} = $track if $track; 3221 $tag_name{artist} = $artist if $artist; 3222 $tag_name{album} = $album if $album; 3223 $tag_name{comment} = $comment if $comment; 3224 $tag_name{year} = $year if $year; 3225 $tag_name{genre} = $genre if $genre; 3226 3227 write_tags("$dir/$file.$ext","$from"); 3228 say "$lang{write_tag_i} $file.$ext"; 3229 3230 } else { perror("no_write_tag","$file.$ext"); } 3231 } 3232 say ''; 3233 } 3234 3235 # print out list of supported encode & decode formats 3236 sub show_formats { 3237 3238 say "\n$name - $version\n"; 3239 say "EXT E D ENCODER DECODER TAG-READ TAG-WRITE"; 3240 say "----------------------------------------------------------------------"; 3241 3242 my $enc_count = 0; 3243 my $dec_count = 0; 3244 3245 foreach (sort(keys(%run))) { 3246 3247 my $e = "N"; $e = "Y" if defined($run{$_}{DEFAULT_ENCODER}); 3248 my $d = "N"; $d = "Y" if defined($run{$_}{DEFAULT_DECODER}); 3249 my $r = "N"; $r = "Y" if $run{$_}{TAGS}{READ} == 1; 3250 my $w = "N"; $w = "Y" if $run{$_}{TAGS}{WRITE} == 1; 3251 3252 my $enc = ''; $enc = $run{$_}{DEFAULT_ENCODER} if defined($run{$_}{DEFAULT_ENCODER}); 3253 my $dec = ''; $dec = $run{$_}{DEFAULT_DECODER} if defined($run{$_}{DEFAULT_DECODER}); 3254 3255 printf("%-9s %-3s %-3s %-15s %-18s %-10s %s\n", $_, $e, $d, $enc, $dec, $r, $w); 3256 3257 ++$enc_count if $enc ne ''; 3258 ++$dec_count if $dec ne ''; 3259 3260 } 3261 3262 say "\n$lang{enc_fmts} $enc_count --- $lang{dec_fmts} $dec_count\n"; 3263 3264 } 3265 3266 # show encoders for output format 3267 sub show_encoders { 3268 say "\n$name - $version\n\n$lang{show_encoders}: $my_encoder\n"; 3269 foreach (sort(keys %{$run{$my_encoder}{ENCODER}})) { 3270 print "$_ -> "; 3271 print "installed" if `which $_ 2>/dev/null`; 3272 print "not found" if not `which $_ 2>/dev/null`; 3273 print " (default)" if $_ eq $run{$my_encoder}{DEFAULT_ENCODER}; 3274 say ''; 3275 } 3276 say ''; 3277 } 3278 3279 # show decoders for input format 3280 sub show_decoders { 3281 say "\n$name - $version\n\n$lang{show_decoders}: $my_decoder\n"; 3282 foreach (sort(keys %{$run{$my_decoder}{DECODER}})) { 3283 print "$_ -> "; 3284 print "installed" if `which $_ 2>/dev/null`; 3285 print " (default)" if $_ eq $run{$my_decoder}{DEFAULT_DECODER}; 3286 say ''; 3287 } 3288 say ''; 3289 } 3290 3291 ################# 3292 # cd ripping... # 3293 ################# 3294 3295 # get total number of tracks from cdparanoia query 3296 sub get_total_tracks { 3297 3298 open(CDINFO, "cdparanoia -Q 2>&1 |") or die "can't fork: $!\n"; 3299 my @cdquery = <CDINFO>; 3300 close(CDINFO); 3301 3302 my $fmt_tracks = $cdquery[-3]; 3303 $fmt_tracks =~ s/\s//g; 3304 3305 my @ttracks = split(/\./, $fmt_tracks); 3306 3307 return "$ttracks[0]"; 3308 3309 } 3310 3311 my (%cd, %ripconfig, @cdtrack, $track_total); 3312 3313 # setup the cddb config 3314 sub get_cddb_config { 3315 3316 $config{USE_CDDB} = 0 && return if $nocddb; 3317 3318 $config{CDDB_INPUT} = 0 if $noinput; 3319 3320 $ripconfig{CDDB_HOST} = $config{CDDB_HOST}; 3321 $ripconfig{CDDB_PORT} = $config{CDDB_PORT}; 3322 $ripconfig{CDDB_MODE} = $config{CDDB_MODE}; 3323 $ripconfig{DEVICE} = $device; 3324 $ripconfig{CDDB_INPUT} = $config{CDDB_INPUT}; 3325 3326 print $ripconfig{CDDB_HOST}; 3327 3328 %cd = get_cddb(\%ripconfig); 3329 3330 if (not $cd{title}) { 3331 pnotice("no_cddb","",2); 3332 $config{USE_CDDB} = 0; 3333 } 3334 else { 3335 @cdtrack = @{$cd{track}}; 3336 $track_total = $cd{tno}; 3337 } 3338 3339 } 3340 3341 # check to see if a disc is present 3342 sub query_disc { 3343 system("cdparanoia -q -d $device -Q > /dev/null 2>&1"); 3344 perror("no_disc","$device") if $? > 0; 3345 } 3346 3347 # set tag info from cddb 3348 sub tag_track { 3349 3350 my $tno = shift; 3351 3352 $tag_name{artist} = $cd{artist} if $cd{artist}; 3353 $tag_name{title} = $cdtrack[$tno-1] if $cdtrack[$tno-1]; 3354 $tag_name{genre} = $cd{cat} if $cd{cat}; 3355 $tag_name{track} = $tno; 3356 $tag_name{album} = $cd{title} if $cd{title}; 3357 $tag_name{year} = $cd{year} if $cd{year}; 3358 $tag_name{comment} = ''; 3359 3360 } 3361 3362 # process and convert ripped track 3363 sub rip_cd { 3364 3365 my ($on,$tno) = @_; 3366 3367 $outdir = $ENV{HOME}; 3368 $to =~ tr/A-Z/a-z/; 3369 3370 get_visual_opts($to,$out_dir) if $gui and not defined($first_run); 3371 $first_run = 1; 3372 pnotice("ripping_track","$tno",2); 3373 3374 $on =~ s/\//_/g; 3375 3376 say "\ncdparanoia -d $device $tno $on.wav\n" if $dryrun; 3377 my $on_q = shell_quote "$on.wav"; 3378 system("cdparanoia -d $device $tno $on_q >/dev/null 2>&1") if not $dryrun; 3379 3380 if ($to !~ /wav/i) { 3381 3382 push(@file, "$on.wav"); 3383 tag_track($tno); 3384 proc_input(); 3385 clear_tag_hash(); 3386 undef(@file); 3387 unlink("$on.wav") if not $dryrun; 3388 pnotice("removed_tmp","$on.wav",2) if $verbose; 3389 3390 } 3391 } 3392 3393 # rip selected tracks or all from disc 3394 sub proc_cd { 3395 3396 perror("no_app","cdparanoia") if not `which cdparanoia 2>/dev/null`; 3397 3398 query_disc(); 3399 get_cddb_config(); 3400 3401 my $total_tracks = get_total_tracks(); 3402 3403 if ($rip eq "all") { 3404 3405 if ($config{USE_CDDB} ne 1) { 3406 3407 for(my $i=1;$i<=$total_tracks;$i++) { 3408 rip_cd($i, $i); 3409 } 3410 3411 } elsif ($config{USE_CDDB} eq 1) { 3412 3413 my $n = 1; 3414 3415 foreach my $i (@cdtrack) { 3416 3417 my $out_string = $nscheme; 3418 3419 chomp($cdtrack[$n-1]); 3420 3421 $out_string =~ s/%ar/$cd{artist}/; 3422 $out_string =~ s/%ti/$cdtrack[$n-1]/; 3423 $out_string =~ s/%tr/$n/; 3424 $out_string =~ s/%ab/$cd{title}/; 3425 $out_string =~ s/%yr/$cd{year}/; 3426 3427 rip_cd($out_string, $n); 3428 3429 ++$n; 3430 } 3431 } 3432 3433 } else { 3434 3435 my @tracks = split(/,/, $rip); 3436 3437 foreach my $i (@tracks) { 3438 3439 next if $i > $total_tracks or $i < 1; 3440 3441 my $out_string = $nscheme; 3442 3443 $out_string =~ s/%ar/$cd{artist}/; 3444 $out_string =~ s/%ti/$cdtrack[$i-1]/; 3445 $out_string =~ s/%tr/$i/; 3446 $out_string =~ s/%ab/$cd{title}/; 3447 $out_string =~ s/%yr/$cd{year}/; 3448 3449 rip_cd($out_string, $i) if $config{USE_CDDB} == 1; 3450 rip_cd($i, $i) if $config{USE_CDDB} == 0; 3451 } 3452 } 3453 } 3454 3455 # get/print cddb information from disc 3456 sub cdinfo { 3457 3458 query_disc(); 3459 get_cddb_config(); 3460 3461 say "$name - $version\n"; 3462 3463 say "Artist = $cd{artist}"; 3464 say "Album = $cd{title}"; 3465 say "Genre = $cd{genre}"; 3466 say "Tracks = $cd{tno}"; 3467 say "Year = $cd{year}\n"; 3468 3469 my $n = 1; 3470 3471 foreach (@cdtrack) { 3472 say "Track $n: $_"; 3473 ++$n; 3474 } 3475 3476 exit(0); 3477 } 3478 3479 # version / license information 3480 sub version { 3481 3482 say " 3483 $name - $version 3484 3485 Copyright (C) 2005-2021 Philip Lyons 3486 3487 This is free software. You may redistribute copies of it under the terms of 3488 the GNU General Public License <http://www.gnu.org/licenses/gpl.html>. 3489 There is NO WARRANTY, to the extent permitted by law. 3490 "; 3491 3492 } 3493 3494 # help & longhelp menu 3495 sub help_menu { 3496 3497 say "\n$name - $version"; 3498 3499 say " 3500 -t, --to $lang{to} 3501 -r, --recursive $lang{recursive} 3502 -p, --preserve $lang{preserve} 3503 -f, --formats $lang{formats} 3504 -o, --only $lang{only} 3505 -k, --keep $lang{keep} 3506 -j, --jobs $lang{jobs} 3507 -h, --help $lang{help} 3508 -l, --longhelp $lang{longhelp} 3509 -v, --verbose $lang{verbose} 3510 "; 3511 3512 say "$lang{user_opts} 3513 3514 --defopts $lang{defopts} 3515 --eopts $lang{eopts} 3516 --dopts $lang{dopts} 3517 --nopts $lang{nopts} 3518 --outfile $lang{outfile} 3519 --outdir $lang{outdir} 3520 --dryrun $lang{dryrun} 3521 --overwrite $lang{overwrited} 3522 --normalize $lang{normalize} 3523 --delete $lang{delete} 3524 --encoder $lang{encoder} 3525 --decoder $lang{decoder} 3526 --version $lang{version} 3527 3528 $lang{enc_opts} 3529 3530 --bitrate $lang{bitrate} 3531 --freq $lang{freq} 3532 --channels $lang{channels} 3533 --effect $lang{effect} 3534 --fcomp $lang{fcomp} 3535 --acomp $lang{acomp} 3536 --oggqual $lang{oggqual} 3537 --spxqual $lang{spxqual} 3538 --aacqual $lang{aacqual} 3539 --mpcqual $lang{mpcqual} 3540 --ofmode $lang{ofmode} 3541 --ofopt $lang{ofopt} 3542 --bratio $lang{bratio} 3543 --bquanl $lang{bquanl} 3544 --bpsize $lang{bpsize} 3545 3546 $lang{tag_opts} 3547 3548 --artist $lang{artist} 3549 --title $lang{title} 3550 --track $lang{track} 3551 --year $lang{year} 3552 --album $lang{album} 3553 --genre $lang{genre} 3554 --comment $lang{comment} 3555 --taginfo $lang{taginfo} 3556 3557 $lang{tag_usage} 3558 3559 $lang{rip_opts} 3560 3561 --rip $lang{rip} 3562 --nocddb $lang{nocddb} 3563 --noinput $lang{noinput} 3564 --nscheme $lang{nscheme} 3565 --cdinfo $lang{cdinfo} 3566 --device $lang{device} 3567 3568 $lang{rip_usage}" if $longhelp; 3569 3570 say "\n$lang{usage}\n"; 3571 3572 } 3573 3574 sub load_module { 3575 my ($file) = @_; 3576 my $return; 3577 unless($return = do $file) { 3578 perror("opening_file","$file: $@ $!") if $@ or !defined($return) or not !$return; 3579 } 3580 } 3581 3582 sub import_module { 3583 my ($format_ref) = @_; 3584 my $format_name=$format_ref->{NAME}; 3585 $run{$format_name} = $format_ref; 3586 } 3587 3588 # load all user modules 3589 sub load_user_modules { 3590 my @imported_mods; 3591 opendir(DIR, "$mod_dir") or perror("opening_dir","$mod_dir: $!"); 3592 foreach (readdir(DIR)) { 3593 load_module("$mod_dir/$_") if $_ !~ /^\./; 3594 push(@imported_mods, $_) if $_ !~ /^\./; 3595 } 3596 closedir(DIR); 3597 say "$lang{imported} @imported_mods"; 3598 } 3599 3600 # place files/directories in their respective arrays 3601 if (@ARGV) { 3602 foreach (@ARGV) { 3603 if (-f $_) { push(@file,$_); print "$lang{debug} adding $_ to \@file\n" if $debug == 1; } 3604 elsif (-d $_) { push(@dir, $_); print "$lang{debug} adding $_ to \@dir\n" if $debug == 1; } 3605 else { perror("no_infile","$_"); } 3606 } 3607 } 3608 3609 load_user_modules() if $config{IMPORTM} == 1; 3610 3611 if ($to and @ARGV and not $rip) { proc_input(); exit $total_failed; } 3612 3613 elsif ($to and $rip) { proc_cd(); } 3614 elsif ($my_encoder and not $to) { show_encoders(); } 3615 elsif ($my_decoder and not $to) { show_decoders(); } 3616 elsif ($verinfo) { version(); } 3617 elsif ($longhelp) { help_menu(); } 3618 elsif ($formats) { show_formats(); } 3619 elsif ($cdinfo) { cdinfo(); } 3620 elsif ($taginfo and not $to) { show_taginfo(); } 3621 elsif ($title or $track or $artist or $album or $comment or $year or $genre) { write_user_tags(); } 3622 3623 else { help_menu(); } 3624 3625 __END__ 3626 3627 =head1 NAME 3628 3629 pacpl - Perl Audio Converter, a multi purpose converter/ripper/tagger 3630 3631 =head1 SYNOPSIS 3632 3633 pacpl --to <format> <options> [file(s)/directory(s)] 3634 3635 =head1 DESCRIPTION 3636 3637 Perl Audio Converter 3638 3639 A Linux CLI tool for converting multiple audio types from one format to another. 3640 3641 It supports the following audio formats: 3642 3643 ======================================== 3644 3645 3G2, 3GP, 8SVX, AAC, AC3, ADTS, AIFF, AL, AMB, AMR, APE, AU, 3646 AVR, BONK, CAF, CDR, CVU, DAT, DSF, DTS, DVMS, F32, F64, FAP, FLA, 3647 FLAC, FSSD, GSRT, HCOM, IMA, IRCAM, LA, MAT, MAUD, MAT4, MAT5, 3648 M4A, MP2, MP3, MP4, MPC, MPP, NIST, OFF, OFR, OFS, OPUS, OGA, 3649 OGG, PAF, PRC, PVF, RA, RAM, RAW, RF64, SD2, SF, SHN, SMP, SND, 3650 SOU, SPX, SRN, TAK, TTA, TXW, VOC, VMS, VQF, W64, WAV, WMA, 3651 and WV. 3652 3653 It can also extract audio from the following video extensions: 3654 3655 ============================================================== 3656 3657 RM, RV, ASF, DivX, MPG, MKV, MPEG, AVI, MOV, OGM, OGV, QT, VCD, 3658 SVCD, M4V, NSV, NUV, PSP, SMK, VOB, FLV, WEBM and WMV. 3659 3660 Parallel Processing, a CD ripping function with CDDB support, batch conversion, 3661 tag preservation for most supported formats, independent tag reading & writing, 3662 service menus for KDE Dolphin/Konqueror, GNOME Nautilus script, and action 3663 scripts for Nemo/Thunar are also provided. 3664 3665 =head1 OPTIONS 3666 3667 B<-t, --to> I<format> 3668 3669 set encode format for the input file(s) or directory(ies). you can see a 3670 complete list of supported encode formats by using the B<--formats> option. 3671 3672 B<-r, --recursive> 3673 3674 recursively scan and convert input folder(s) to destination format. 3675 3676 B<-p, --preserve> 3677 3678 when recursively converting a directory, preserve the input folders directory 3679 structure in the specified output directory. such as: 3680 3681 pacpl --to ogg -r -p /home/mp3s --outdir /home/oggs 3682 3683 in the example above, let's assume the directory structure was: 3684 3685 =over 21 3686 3687 =item /home/mp3s/Alternative 3688 3689 =item /home/mp3s/Alternative/New 3690 3691 =item /home/mp3s/Rap 3692 3693 =item /home/mp3s/Country 3694 3695 =item /home/mp3s/Techno/ 3696 3697 =back 3698 3699 the output directory will now contain: 3700 3701 =over 4 3702 3703 =item /home/oggs/Alternative 3704 3705 =item /home/oggs/Alternative/New 3706 3707 =item /home/oggs/Rap 3708 3709 =item /home/oggs/Country 3710 3711 =item /home/oggs/Techno 3712 3713 =back 3714 3715 with all files in each sub-folder converted to ogg. 3716 3717 B<-o, --only> I<format> 3718 3719 only convert files matching extension. this option is useful when you have 3720 a directory or batch of files with mixed audio types and only need to 3721 convert one specific type. 3722 3723 B<-k, --keep> 3724 3725 do not re-encode files with extensions matching the destination extension. 3726 instead...copy them to the output folder, or skip to the next file. 3727 3728 B<-j, --jobs> 3729 3730 number of simultanious jobs to run at once. the default limit 3731 is set to 4 in pacpl.conf. You can modify this value on the fly 3732 using --jobs=<num> or set it perminately in the configuration file 3733 3734 =over 4 3735 3736 =item B<-f, --formats> show a list of supported encode/decode formats. 3737 3738 =item B<-h, --help> show the short help menu. 3739 3740 =item B<-l, --longhelp> display the complete list of options. 3741 3742 =item B<--version> show version and licensing information. 3743 3744 =back 3745 3746 =head1 USER OPTIONS 3747 3748 B<--defopts> I<1/0> 3749 3750 to turn off default encoder options use --defopts 0. this option gives you 3751 more control when using the --eopts command. 3752 3753 defopts is set to 1 by default. you can also toggle this option in 3754 /etc/pacpl/pacpl.conf. 3755 3756 B<--eopts> I<options> 3757 3758 this option allows you to use encoder options not implemented by pacpl. 3759 an example would be: 3760 3761 pacpl --to mp4 --eopts="-c 44100 -I 1,2" YourFile.mp3 3762 3763 B<--dopts> I<options> 3764 3765 this option allows you to use decoder options not implemented by pacpl. 3766 an example would be: 3767 3768 pacpl --to mpc --dopts="--start 60" YourFile.ogg 3769 3770 B<--outfile> I<name> 3771 3772 set the output file name to I<name>. 3773 3774 B<--outdir> I<directory> 3775 3776 place all encoded files in I<directory>. 3777 3778 B<--dryrun> 3779 3780 show what would be done without actually converting anything. this is a 3781 good way to trouble shoot, or to see what would be done without actually 3782 touching your files. 3783 3784 B<--overwrite> 3785 3786 replace the output file if it already exists. 3787 3788 B<--normalize> 3789 3790 adjusts volume levels of audio files. 3791 3792 B<--nopts> I<options> 3793 3794 this allows you to specify normalize options not implemented by pacpl 3795 3796 B<--delete> 3797 3798 remove source/input file after the conversion process has finished. 3799 3800 B<--encoder> I<encoder> 3801 3802 specify an alternate encoder for the selected output file(s) 3803 3804 you can see a list of supported encoders by using the following: 3805 3806 pacpl --encoder I<format> 3807 3808 B<--decoder> I<decoder> 3809 3810 specify an alternate decoder for the selected input file(s) 3811 3812 you can see a list of supported decoders by using the following: 3813 3814 pacpl --decoder I<format> 3815 3816 B<-v, --verbose> 3817 3818 show detailed information about the encoding process and what's actually 3819 being done. 3820 3821 =head1 ENCODER OPTIONS 3822 3823 B<--bitrate> I<num> 3824 3825 set the bitrate to I<num>. default is 128. this option does not apply 3826 to all formats. 3827 3828 B<--freq> I<num> 3829 3830 set the frequency to I<num>. default is 44100. this option does not apply 3831 to all formats. 3832 3833 B<--channels> I<num> 3834 3835 set the number of audio channels in the output file to I<num>. this option 3836 does not apply to all formats. 3837 3838 B<--effect> I<str> 3839 3840 see B<sox>(1). this option only applies to the following: 3841 3842 AIFF, AU, SND, RAW, VOC, SMP, AVR, and CDR 3843 3844 B<--fcomp> I<num> 3845 3846 set flac compression level to I<num>. fastest -0, highest -8, default -2 3847 3848 =over 4 3849 3850 =item 1 = fast 3851 3852 =item 2 = simple 3853 3854 =item 3 = medium (default) 3855 3856 =item 4 = high 3857 3858 =item 5 = extra high, 3859 3860 =back 3861 3862 B<--acomp> I<num> 3863 3864 set ape compression level to I<num>. 3865 3866 =over 4 3867 3868 =item 1000 = fast 3869 3870 =item 2000 = normal 3871 3872 =item 3000 = high (default) 3873 3874 =item 4000 = extra high 3875 3876 =item 5000 = insane 3877 3878 =back 3879 3880 B<--oggqual> I<num> 3881 3882 set ogg quality level to I<num>. -1, very low and 10 very high, default 3 3883 3884 B<--spxqual> I<num> 3885 3886 set speex quality level to I<num>. 0-10, default 8 (use --bitrate <num> when using ffmpeg/avconv as encoder) 3887 3888 B<--aacqual> I<num> 3889 3890 set aac, mp4, m4a, or m4b quality level to I<num>. default 300 3891 3892 B<--mpcqual> I<str> 3893 3894 set mpc/mpp quality level to I<str>. 3895 3896 =over 4 3897 3898 =item thumb low quality/internet, (typ. 58... 86 kbps) 3899 3900 =item radio medium (MP3) quality, (typ. 112...152 kbps - default) 3901 3902 =item standard high quality (dflt), (typ. 142...184 kbps) 3903 3904 =item xtreme extreme high quality, (typ. 168...212 kbps) 3905 3906 =back 3907 3908 B<--ofmode> I<str> 3909 3910 set off/ofr/ofs compression mode to I<str>. normal, extra, and extranew modes 3911 are recommended for general use. available options are: 3912 3913 =over 4 3914 3915 =item fast 3916 3917 =item normal (default) 3918 3919 =item high 3920 3921 =item extra 3922 3923 =item best 3924 3925 =item highnew 3926 3927 =item extranew 3928 3929 =item bestnew 3930 3931 =back 3932 3933 B<--ofopt> I<str> 3934 3935 set off/ofr/ofs optimization level to I<str>. 3936 3937 specify the optimization level in the engine. In order to achieve 3938 optimal compression at all sample types, sample rates, and audio 3939 content, the core compression engine has the possibility to find the 3940 optimal values for its parameters, at the cost of slightly increased 3941 compression time only. The default recommended value is fast. 3942 do not use normal (or even high or best) for this parameter unless 3943 encoding time does not matter and you want to obtain the smallest 3944 possible file for a given compression mode. The difference between 3945 the optimize levels fast and best (which is up to three times slower 3946 than fast) is very small, generally under 0.05%, but may be also 3947 larger in some rare cases. Note that the none optimize level is 3948 forced by the encoder to fast optimize level for the extra, best, 3949 highnew, extranew, and bestnew modes. 3950 3951 available options are: 3952 3953 =over 4 3954 3955 =item none 3956 3957 =item fast (default) 3958 3959 =item normal 3960 3961 =item high 3962 3963 =item best 3964 3965 =back 3966 3967 B<--bratio> I<num> 3968 3969 set bonk down sampling ratio. default 2 3970 3971 B<--bquanl> I<num> 3972 3973 set bonk quantanization level. default 1.0 3974 3975 B<--bpsize> I<num> 3976 3977 set bonk predictor size. default 128 3978 3979 =head1 TAGGING OPTIONS 3980 3981 B<note:> 3982 3983 tagging outside of the encoding process can only be performed on the 3984 following audio types: 3985 3986 =over 4 3987 3988 =item MP3 3989 3990 =item OGG 3991 3992 =item FLA 3993 3994 =item FLAC 3995 3996 =back 3997 3998 B<--artist> I<str> 3999 4000 set artist information to I<str>. 4001 4002 B<--title> I<str> 4003 4004 set title information to I<str>. 4005 4006 B<--track> I<num> 4007 4008 set track information to I<num>. 4009 4010 B<--year> I<num> 4011 4012 set year/date information to I<num>. 4013 4014 B<--album> I<str> 4015 4016 set album information to I<str>. 4017 4018 B<--genre> I<str> 4019 4020 set genre information to I<str>. 4021 4022 B<--comment> I<str> 4023 4024 set comment information to I<str>. 4025 4026 B<--taginfo> I<file> 4027 4028 show tagging information for I<file>. multiple files can be specified 4029 at once. 4030 4031 =head1 RIPPING OPTIONS 4032 4033 B<--rip> I<num/all> 4034 4035 rip selected tracks separated by comma or all from current disc. 4036 4037 =over 4 4038 4039 =item pacpl --rip all --to flac 4040 4041 =item pacpl --rip 1,3,9,15 --to flac 4042 4043 =back 4044 4045 B<--nocddb> 4046 4047 disable cddb. use this option if you do not want tagging based on cddb. 4048 4049 B<--noinput> 4050 4051 disable cddb interactivity. this is enabled by default. 4052 4053 B<--nscheme> I<str> 4054 4055 set naming scheme to I<str>. default is %ar - %ti 4056 4057 available options are: 4058 4059 =over 4 4060 4061 =item %ar = artist 4062 4063 =item %ti = song title 4064 4065 =item %tr = track 4066 4067 =item %yr = year 4068 4069 =item %ab = album 4070 4071 =back 4072 4073 B<eg:> --nscheme="(%tr)-%ti" 4074 4075 B<--device> I<device> 4076 4077 set device to I<device>. default is /dev/dvd 4078 4079 B<--cdinfo> 4080 4081 show cddb information for current disc. 4082 4083 =head1 SEE ALSO 4084 4085 =over 4 4086 4087 =item B<sox>(1) B<ffmpeg>(1) B<lame>(1) B<oggenc>(1) B<oggdec>(1) 4088 4089 =item B<flac>(1) B<shorten>(1) B<faac>(1) B<faad>(1) B<mpcenc>(1) 4090 4091 =item B<mpcdec>(1) B<mplayer>(1) B<speexenc>(1) B<speexdec>(1) 4092 4093 =item B<sndfile-convert>(1) B<normalize>(1) B<cdparanoia>(1) 4094 4095 =item B<opusenc>(1) B<opusdec>(1) B<wavpack>(1) B<ffmpeg>(1) 4096 4097 =item B<mplayer>(1) B<avconv>(1) 4098 4099 =back 4100 4101 =head1 BUGS 4102 4103 Report all bugs to Philip Lyons (vorzox@gmail.com) 4104 4105 =head1 LICENSING 4106 4107 This program is free software; you can redistribute it and/or modify 4108 it under the terms of the GNU General Public License as published by 4109 the Free Software Foundation; either version 3 of the License, or 4110 (at your option) any later version. 4111 4112 This program is distributed in the hope that it will be useful, 4113 but WITHOUT ANY WARRANTY; without even the implied warranty of 4114 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 4115 GNU General Public License for more details. 4116 4117 You should have received a copy of the GNU General Public License 4118 along with this program. If not, see <http://www.gnu.org/licenses/>. 4119 4120 =head1 AUTHOR 4121 4122 <<<<<<< HEAD 4123 Copyright (C) 2005-2021 Philip Lyons (vorzox@gmail.com) 4124 ======= 4125 Copyright (C) 2005-2019 Philip Lyons (vorzox@gmail.com) 4126 >>>>>>> cc4eb189828ef15228da02c14a39e484294126ec