#!/usr/bin/perl
require 5.008;                 # require minimum Perl version 5.8 - support for Unicode.                
use Gtk2 -init;                # load the Gtk-Perl module - see <man Gtk2>
use Glib qw(filename_from_unicode filename_to_unicode filename_display_name);
use Gtk2::Pango;               # to change fonts
use strict;                    # a good idea for all non-trivial Perl programs
use warnings;                  # force print warnings
use File::Find;                # similar to the Unix find command, see <man File::Find>

use Encode qw(encode decode is_utf8 _utf8_on _utf8_off); # see <man Encode>.
use Unicode::Normalize qw(NFKD); # combining accent
		   
# use Fcntl;                   # for gnormalize::cdplay

# See <man waitpid>, perlipc and Programming Perl, 3a Ed., Chap.16
# waitpid Child_PID,FLAGS : "Waits for a particular child process to terminate and returns
#                            the pid of the deceased process, or "-1" if there is no such child process."
# waitpid(-1, WNOHANG) < 0 ; -1 : meaning wait for any child process. WNOHANG : return immediately if no child has exited.
use POSIX  qw(:sys_wait_h fmod floor ceil);    # ':sys_wait_h' is used on sub 'change_count'

# set_locale Gtk2;             # internationalize

# use POSIX qw(locale_h);      # internationalize: see <man setlocale> POSIX, perlunicode and perllocale
# Usage: POSIX::setlocale(category, locale = 0)
# setlocale( LC_CTYPE, 'C');   # for regular expression matching, character classification,  conversion,  
                               # case-sensitive  comparison,  and  wide character functions
# setlocale( LC_NUMERIC, 'C'); # for number formatting (such as the decimal point and  the  thousands separator).
# setlocale( LC_ALL, 'iso-8859-1'); 

$SIG{CHLD} = "IGNORE";         # kill zombies ; see man perlfunc and perlfork

$|++;                          # Disable buffering by setting the perl-filehandle variable $| to a true value

my $false = 0; my $true = 1;   # convenience variables for true and false
my $id3tag_character = 'iso-8859-1'; # Latin1 for id3tag mp3 files.

# use open IO => ":encoding(iso-8859-1)"; # set PerlIO layers for Input and Output. See 'man PerlIO'
# BEGIN { $ENV{LC_ALL} = $ENV{LANG} = 'pt_BR' } # man perluniintro
# use open OUT => ':locale';

#------------------------- perl module: CDDB_get -----------------------------#
# To get informations from audio cds - See <man CDDB_get>
sub modules_cddb_get {
   if (eval "use CDDB_get qw(get_cddb get_discids); 1;"){ return $true;}
   else { warn  "\n\n  Not found CDDB_get perl module in your system.\n  gnormalize will uses internal CDDB_get (version 2.27).\n"; }
   return $false;
}
my $use_external_cddbget = modules_cddb_get();

#------------------------- perl module: MP3::Info ----------------------------#
sub modules_mp3info { # Suggestions from Perl Cookbook, 2nd Edition, chapter 12.2 .
   if (eval "use MP3::Info qw(:all); 1;"){ return $true;}
   else { warn  "\n\n  Not found MP3::Info perl module in your system.\n  gnormalize will uses internal MP3::Info (version 1.20).\n"; }
   return $false;
}
my $use_external_MP3Info = modules_mp3info();
use_winamp_genres() if $use_external_MP3Info;

#------------------------- perl module: Audio::CD ----------------------------#
# Imports "Audio::CD" into current package if it exist 
my $use_audiocd = $false;
sub modules_audio_cd { # suggestions from Perl Cookbook.
   if (eval "use Audio::CD; 1;"){ $use_audiocd = $true;}
   # else{ warn "Could not use Audio::CD \n $@";   }
   return $use_audiocd;
}
modules_audio_cd();

sub audio_cd_have_current_track { # return true if Audio::CD have current_track and $frames
   my $audiodevice = shift;
   if ( $use_audiocd eq $false ){ return $false; }
   
   # umount the audio cd drive if possible. This is need to play EXTRA CD.      
   
   exec_cmd_system2('umount', "$audiodevice");
   
   my $audiocd = Audio::CD->init("$audiodevice");
   my $info = $audiocd->stat;
   
   # See eval in perlfunc.
   eval { $info->current_track; };
   if ($@) { 
      warn "\n   Can't find the function \"current_track\".".
           "\n   You must install the perl module \"Audio-CD-0.04-changed.tar.gz\".\n";
      return $false; 
   }
   my ($minutes, $seconds, $frames) = $info->time;
   if (not defined($frames)){
      warn "\n   Can't find the function \"my (\$minutes, \$seconds, \$frames) = \$info->time\".".
           "\n   You must install the perl module \"Audio-CD-0.04-changed.tar.gz\".\n";
      return $false;   
   }   
   return $true;
}

sub check_minimum_version {
   my $gtk2_version = Gtk2->CHECK_VERSION (2, 6, 0); # boolean
   my $gtk2_Perl_version = $Gtk2::VERSION;      
   if ( $gtk2_Perl_version < 1.100 or not $gtk2_version ) {
      print "\n\$gtk2_Perl_version = $gtk2_Perl_version \n";
      print "\nYou need a gtk2_Perl_version more recent!\n";
      return $true;    
   }
}
check_minimum_version();

#-----------------------------------------------------------------------------#		   

# gtk+2.0 - 2.4.9 -9mdk  and  perl-Glib-1.080
# examples: perl /usr/share/doc/perl-Gtk2-doc/gtk-demo/main.pl &
# See:  man perl, perlfunc, perlintro, Gtk2, Gtk2::Window, Gtk2::index, ...

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.

# "Free Software, since you might like to learn a bit in the
# process by looking at the code (or teach the author of the program how
# to write better programs...)."

# Copyright 2005/2008 - Claudio Fernandes de Souza Rodrigues
# email: claudiofsr@yahoo.com

# DISCLAIMER
# The author assumes no responsibility for correct function, appropriate use, or misuse 
# of this program, and any damage its function, use or misuse may cause.

# Pensamento filosfico:
# "A calcinha pode no ser a melhor coisa do mundo, mas est bem perto!"

##########------------Global-Variables------------##########
###------------------------------------------------------###

my $VERSION = "0.63";
my $AUTHOR = "Claudio Fernandes de Souza Rodrigues";
my $EMAIL = "claudiofsr\@yahoo.com";
my $DATE = "Jul 10 2008";
my $HOMEPAGE = "http://gnormalize.sourceforge.net";

#----------------------------------------------------------#
## ------- default path used by the cdrom drive --------- ##
my $audiodevice_path ="/dev/cdrom";
#----------------------------------------------------------#
#----------------------------------------------------------#
my $home = filename_to_unicode "$ENV{HOME}"; my $os;
#my $datey = system("date +%Y");
my $window; my $window_width = 860; my $window_height = 580;
my $tooltips = Gtk2::Tooltips->new; #$tooltips->set_delay( 1000 ); # wait for 1s
my $check_button_tooltips; my $show_all_tooltips = $true;
my $notebook; my $notebook2; my $button; my $spinner;my $spinner_q; my $spinner_bitrate_mp3; 
my $spinner_bitrate_ogg; my $spinner_bitrate_mp4; my $spinner_Vmp4;
my $vbox_up; my $vbox1; my $vbox2; my $button_save_tag;
my $frame1; my $frame_prog_bar; my $have_current_track = $false;
my $table1; my $table_down;
my $norm_type = "Track"; my $num_d;
my $file_dialog; my $button_clear;
my $label_type; my $label_VB; my $entry_f; my $entry_dir_input;
my $spinner_V; my $spinner_Vogg; my $spinner_Vmpc;
my $label_mp3b; my $combo; my $show_tux_animation = $true; my $check_button_animation;
my $label_Min; my $ComboBox_Min; my $vb_Min=64;
my $label_Max; my $ComboBox_Max; my $vb_Max=320;
my $ComboBox_rip; my $ComboBox_char;
my $ComboBox_encode_type; my $ComboBox_const_bitrate;
my $file_mp3=""; my $file_ogg=""; my $file_mpc=""; my $file_ape=""; 
my $file_flac=""; my $file_cda=""; my $file_wav=""; my $file_mp4="";
my $spinner_compress; my $label_comp; my $button_quit;
my $spinner_compress_flac; my $fileSize = 0; my $directory;
my $directory_final; my $directory_output = $home; my $directory_base; 
my $recursively = $true; my $check_button_recursively; my $check;  my $label;
my $pbar; my $pbar_n; my $pbar_encode; my $progbar_files_info; my $label_pct; my $da;
my $symbol; my $align; my $separator; my $table;
my $orientation; my $new_val; my $ripper = 'cdparanoia';
my $entry_l; my $entry_n; my $ComboBox_mode; my $ComboBox_freq; my $entry;
my $status_bar; my $context_id = 0; my $adjust; 
my @files_info = (); my @music_sector; my @length = (); # array with music length of audio cd
my %albums_already_played;   # hash whose key is only the played album name
my %artists_already_played;  # hash whose key is only the played artist name
my $already_normalized; my $extension_input = 'other'; my $extension_output = 'mp3'; 
my $bitrate_nominal; # for ogg
my $bitrate_constant = 160; my $bitrate_avr_mp3 = 160; my $bitrate_avr_mp4 = 160;
my $quality = 3; # encoder algorithms process for lame. 
my $bitrate_avr_ogg = 160; my $bitrate_original; my $bitrate_average = $true; 
my $pid_lame_decode = -1; my $pid_lame_encode = -1; my $pid_rip_cda = -1;
my $pid_mpc_decode = -1; my $pid_mpc_encode = -1; my $pid_cdpar_rip = -1;
my $pid_normalize = -1; my $pid_ogg_decode = -1; my $pid_ogg_encode = -1;
my $pid_ape = -1; my $pid_flac_decode = -1; my $pid_player;
my $audio_cd_volume = 80; my $button_volume;
my $V = 4; my $Vogg = 4; my $Vmpc = 5; my $Vmp4 = 200; my $encode="average";# constant, average or variable
my @array_wav; my @array_ogg; my @array_of_files; #array of mp3/ogg/wav 
my $textview; my $scrolled; my $buffer; my $iter; my $track;
my $vbox_text; my $hbox_text; my $frame_debug;
my $count = 0; my $timer; my $window_font_name = 'Sans 10'; my $button_font;
my %encode_type; $encode_type{'mp3'} = 'average'; $encode_type{'mp4'} = 'average';
$encode_type{'mpc'} = 'variable'; $encode_type{'ogg'} = 'average';

my %options = ( mp3 => { encode_type => 'average', # not used yet!
                              player => 'mpg321',                        
                       },
		mp4 => { encode_type => 'average',
                              player => 'mplayer',                        
                       },
		mpc => { encode_type => 'variable',
                              player => 'mpg321',                        
                       },
		ogg => { encode_type => 'average',
                              player => 'mplayer',                        
                       },
		ape => { encode_type => 'average',
                              player => 'mplayer',                        
                       },
	       flac => { encode_type => 'variable',
                              player => 'mpg321',                        
                       },
		wav => { encode_type => 'average',
                              player => 'mplayer',                        
                       },
		tag => {      artist => '',
		               album => '',  
		       }       
	      );	         

my $check_button_del_wav; my $check_button_cddb; my $spinner_pri;
my $go_back = $false; my $go_forward = $false; my $delete_wave = $true; 
my $discDB = $true; my $entry_CDDB_server; my $CDDB_server = 'freedb.freedb.org';
my $spinner_cddb_port; my $cddb_port = 8880; my $cddb_transport = 'cddb';
my $priority = 15; my $change_properties = $false;
my $check_change_properties; my $check_button_overwrite; my $check_button_overwrite_cddb;
my $overwrite_cddb = $false; my $entry_format_cda; my $file_format_cda_rip = "%b/%n-%a-%t";
my $overwrite = $false; my $entry_def_comment; my $comment_tag = "gnormalize - gain=%gain";
my $gain = 0.00; my $insensibility = 0.3; my $spinner_sensi;
my $mode = 'joint stereo'; my $freq = 44100; my $comp_ape = 2000; my $comp_flac = 3;
my $entry_cda; my $button_cdda1; my $button_cdda2; my $button_cdda3;
my $paranoia = $true; my $paranoia_disable = $false; my $paranoia_no_verify = $false;	
my $change_fonte = $true; my $change_fonte_norm = $true;
my $change_font_layout = $true; my $change_font_rand = $true;
my $additional_command_mp3 = ""; my $additional_command_mp4 = ""; my $additional_command_mpc = "";
my $additional_command_ogg = ""; my $additional_command_ape = ""; my $additional_command_flac = "";
my $entry_command_mp3; my $entry_command_mp4; my $entry_command_mpc;
my $entry_command_ogg; my $entry_command_ape; my $entry_command_flac;
my $renderer_track; my $renderer_artist; my $renderer_title; my $renderer_album; my $renderer_length;
my $button_info_type = 1; my $notebook_page_num = 0; my $notebook_page_num2 = 0;
my $scrolling_text_speed = 45; # 45 milliseconds
my $scrolling_text_incremental = 1; # 1 pixel
my $scrolling_type = "random"; my $scrolling_text_orientation = 1;
#---cdparanoia options
my $disable_paranoia = $false; my $disable_extra_paranoia = $false;
my $abort_on_skip = $false; my $never_skip_repair = $false; 
my $audio_cd_channel; my $audio_cd_total_time; my $audio_cd_fileSize;
my $button_noia1; my $button_noia2; my $button_noia3; my $button_noia4;
# The paths are automatically found.
my $lame_path; my $oggenc_path; my $mpcenc_path; my $ape_path; my $flac_path;
my $metaflac_path; my $wavegain_path; my $oggdec_path; my $mpcdec_path;
my $cdparanoia_path; my $cdda2wav_path; my $faac_path; my $faad_path;
my $mpg123_path; my $mpg321_path;  my $ogg123_path; my $flac123_path; 
my $mplayer_path; my $madplay_path; my $amixer_path; my $play_path;
my $aplay_path; my $vorbiscomment_path; my $nice_path; my $audiocd;
my $cdcd_path; my $cdplayer = "Audio::CD";
#---mp3/ogg tag
my $mode_channel; my $Frequency = 0; my $Time_Min_Sec; my $Technical_Info;
my $Title; my $Comment; my $Genre; my $Artist; my $Track_Number; my $Total_Track; my $Album; my $Year; 
my %metadata = ();  # hash with metadata (tag) and technical information
# ---- More global variables ---- cdrom player #
my $window_cd_player; my $window_cd_player_width = 252; my $window_cd_player_height = 56;
my $notebook_cd_player_num = 0;
my $color_bg_cdplay = '#839975'; my $color_cdplayer_shadow = '#839975'; 
my $color_cdplayer_arrows = '#651DB6'; my $color_cdplayer_shadow_motion = '#651DB6';
my $color_cdplayer_arrows_motion = '#839975'; my $color_cdplayer_digit = '#651DB6';
my $color_cdplayer_digit_remaining = '#FFA500';
my $force_unselect_all_tracks = $false;
my $show_cdplayer_skin = $false; my $show_cdplayer_border = $true; my $show_cdplayer_keep_above = $true;
my $show_time_remaining = $false; my $show_time_abs = $false;
my $playing_music = $false;
my $selected_row = 0; # default audio track
my $total_time = 0;
my @rows_already_played = ();
my $play_random = $false; my $loop_tracks = $false;
my @start_sector; my $pause = $false; my $toc_audiocd;
my $column_show_extension = $false; my $column_show_filepath = $false; my $column_show_filename = $false; 
my $column_show_frequency = $false; my $column_show_bitrate = $true; my $column_show_year = $false;
my $column_show_artist = $true; my $column_show_album = $false; my $column_show_track = $true;
my $column_show_file = $true; my $column_show_play_count = $true;

my $use_filter = $false; my $ComboBox_player_with_filter;  

#---player---#
my $device_path = "/dev/audio"; my $device_type = "alsa"; 
my $player_mp3  = "mpg321";  my %all_mp3_player; 
my $player_mp4  = "mplayer"; my %all_mp4_player; 
my $player_mpc  = "mplayer"; my %all_mpc_player;
my $player_ogg  = "mplayer"; my %all_ogg_player;
my $player_ape  = "mplayer"; my %all_ape_player;
my $player_flac = "mplayer"; my %all_flac_player;
my $player_wav  = "mplayer"; my %all_wav_player; 
#--languages--#
my $language = 'English'; my $ComboBox_Lang_5a; my %all_language; # Hash of all the different languages
my $ComboBox_Names;  my $Names_Active_Num = 0;

#-----------------------------------------------------#

my $setting_file = "$home/.config/gnormalize/config";
my $lang_dir     = "$home/.config/gnormalize/language"; 
my %settings;    # Hash of all the different options that can be saved

if ( not -d filename_from_unicode $lang_dir ){
   my @cmd = ( 'mkdir', '-p', $lang_dir ); # create the directory	      
   exec_cmd_system2(@cmd);   
}

sub read_settings { # not yet used
   my $file = shift;
   if ( !-e filename_from_unicode $file ) { return; }
   open( INPUT, '<:utf8', filename_from_unicode $file ) or die "Can't open <$file>: $!, stopped";
   while (my $line = <INPUT>) {
      chomp($line);
      next if ( $line !~ /=/ );
      (my $key, my $value) = split(/=/, $line);
      $settings{$key} = $value;
   }
   close( INPUT );
   #foreach my $key ( sort keys %settings ) { print $key, '=', $settings{$key}, "\n"; }
}
# read_settings($setting_file);

sub save_settings { # not yet used
   #$lang_dir/language.txt
   $settings{'cdrom'} = $entry_cda->get_text;

   my $key;
   open( OUTPUT, '>:utf8', $setting_file ) or die "Couldn't open $setting_file for writing: $!\n";
   foreach $key ( sort keys %settings ) { print OUTPUT $key, '=', $settings{$key}, "\n"; }
   close( OUTPUT );
}

#######------------- Read the config file -----------#######

sub read_config {
	my $config = filename_to_unicode $setting_file;
	
	if( -r filename_from_unicode $config ) {
	   my $file_number = 1;	
	   # read config file
	   open(CONFIG, '<:utf8', $config ); 
	   while( <CONFIG> ) 
	   {   
	      if ($_ =~ /^cdrom=(.*)/){ $audiodevice_path = $1; }
	      if ($_ =~ /^recursively=(.*)/){ $recursively = $1; } 
	      if ($_ =~ /^extension_output=(.*)/){ $extension_output = $1; }	      
	      if ($_ =~ /^directory_output=(.*)/){ $directory_output = $1; }
	      if ($_ =~ /^normalization_type=(Track|Album|None)$/){ $norm_type = $1; } 
	      if ($_ =~ /^gain=(.*)/){ $gain = $1; } 
	      if ($_ =~ /^insensibility=(.*)/){ $insensibility = $1; } 	      	      
	      if ($_ =~ /^delete_wave=(.*)/){ $delete_wave = $1; } 
	      if ($_ =~ /^discDB=(.*)/){ $discDB = $1; } 
	      if ($_ =~ /^overwrite_cddb=(.*)/){ $overwrite_cddb = $1; } 
	      if ($_ =~ /^CDDB_server=(.*)/){ $CDDB_server = $1; } 
	      if ($_ =~ /^cddb_port=(\d+)/){ $cddb_port = $1; } 
	      if ($_ =~ /^cddb_transport=(.*)/){ $cddb_transport = $1; }    
	      if ($_ =~ /^priority=(.*)/){ $priority = $1; } 
	      if ($_ =~ /^change_properties=(.*)/){ $change_properties = $1; }	      
	      if ($_ =~ /^show_all_tooltips=([01])/){ $show_all_tooltips = $1; }	      
	      if ($_ =~ /^file_format_cda_rip=(.*)/){ $file_format_cda_rip = $1; }
	      if ($_ =~ /^overwrite=(.*)/){ $overwrite = $1; } 
	      if ($_ =~ /^comment_tag=(.*)/){ $comment_tag = $1; }	      	      
	      if ($_ =~ /^additional_command_mp3=(.*)/){ $additional_command_mp3 = $1; } 
	      if ($_ =~ /^additional_command_mp4=(.*)/){ $additional_command_mp4 = $1; } 
	      if ($_ =~ /^additional_command_mpc=(.*)/){ $additional_command_mpc = $1; }
	      if ($_ =~ /^additional_command_ogg=(.*)/){ $additional_command_ogg = $1; } 
	      if ($_ =~ /^additional_command_ape=(.*)/){ $additional_command_ape = $1; } 
	      if ($_ =~ /^additional_command_flac=(.*)/){ $additional_command_flac = $1; }	      
	      if ($_ =~ /^character=(.*)/){ $id3tag_character = $1; }
	      if ($_ =~ /^cdplayer=(.*)/){ $cdplayer = $1; }	      
	      if ($_ =~ /^window_font_name=(.*)/){ $window_font_name = $1; }	     	      
	      if ($_ =~ /^ripper=(.*)/){ $ripper = $1; }
	      if ($_ =~ /^language=(.*)/){ $language = $1; }
	      if ($_ =~ /^Names_Active_Num=(\d+)/){ $Names_Active_Num = $1; }	      	      
	      if ($_ =~ /^encode=(.*)/){ $encode = $1; }	      
	      if ($_ =~ /^encode_remember_mp3=(.*)/){ $encode_type{mp3} = $1; } 
	      if ($_ =~ /^encode_remember_mp4=(.*)/){ $encode_type{mp4} = $1; } 
	      if ($_ =~ /^encode_remember_mpc=(.*)/){ $encode_type{mpc} = $1; } 
	      if ($_ =~ /^encode_remember_ogg=(.*)/){ $encode_type{ogg} = $1; }	      
	      if ($_ =~ /^bitrate=(.*)/){ $bitrate_constant = $1; } 
	      if ($_ =~ /^bitrate_avr_mp3=(.*)/){ $bitrate_avr_mp3 = $1; }
	      if ($_ =~ /^bitrate_avr_mp4=(.*)/){ $bitrate_avr_mp4 = $1; }
	      if ($_ =~ /^bitrate_avr_ogg=(.*)/){ $bitrate_avr_ogg = $1; }
	      if ($_ =~ /^bitrate_vrb_mp3=(.*)/){ $V = $1; }
	      if ($_ =~ /^bitrate_vrb_mp4=(.*)/){ $Vmp4 = $1; }	  
	      if ($_ =~ /^bitrate_vrb_ogg=(.*)/){ $Vogg = $1; }
	      if ($_ =~ /^bitrate_vrb_mpc=(.*)/){ $Vmpc = $1; }	      
	      if ($_ =~ /^comp_ape=(.*)/){ $comp_ape = $1; }
	      if ($_ =~ /^comp_flac=(.*)/){ $comp_flac = $1; }	             	      
	      if ($_ =~ /^mode=(.*)/){ $mode = $1; }	      
	      if ($_ =~ /^Min=(.*)/){ $vb_Min = $1; }
	      if ($_ =~ /^Max=(.*)/){ $vb_Max = $1; }
	      if ($_ =~ /^freq=(8000|11025|12000|16000|22050|24000|32000|44100|48000)$/){ $freq = $1; }      
	      if ($_ =~ /^quality=(.*)/){ $quality = $1; }        	      
	      if ($_ =~ /^disable_paranoia=(.*)/){ $disable_paranoia = $1; }
	      if ($_ =~ /^never_skip_repair=(.*)/){ $never_skip_repair = $1; }
	      if ($_ =~ /^disable_extra_paranoia=(.*)/){ $disable_extra_paranoia = $1; }
	      if ($_ =~ /^abort_on_skip=(.*)/){ $abort_on_skip = $1; } 	      
	      if ($_ =~ /^paranoia=(.*)/){ $paranoia = $1; }
	      if ($_ =~ /^paranoia_disable=(.*)/){ $paranoia_disable = $1; }
	      if ($_ =~ /^paranoia_no_verify=(.*)/){ $paranoia_no_verify = $1; } 
	      if ($_ =~ /^play_random=(.*)/){ $play_random = $1; } 
	      if ($_ =~ /^loop_tracks=(.*)/){ $loop_tracks = $1; }	  
	      if ($_ =~ /^audio_cd_volume=(\d*)/){ $audio_cd_volume = $1; }	      
	      if ($_ =~ /^window_width=(\d+)/){ $window_width = $1; }
	      if ($_ =~ /^window_height=(\d+)/){ $window_height = $1; }	           	      	      
	      if ($_ =~ /^window_cd_player_width=(\d+)/){ $window_cd_player_width = $1; }
	      if ($_ =~ /^window_cd_player_height=(\d+)/){ $window_cd_player_height = $1; } 	      	      
	      if ($_ =~ /^show_tux_animation=([01])/){ $show_tux_animation = $1; }	      
	      if ($_ =~ /^color_bg_cdplay=(#[ABCDEFabcdef\d]{6})/){ $color_bg_cdplay = $1; } 
	      if ($_ =~ /^color_cdplayer_shadow=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_shadow = $1; }      
	      if ($_ =~ /^color_cdplayer_arrows=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_arrows = $1; } 
	      if ($_ =~ /^color_cdplayer_shadow_motion=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_shadow_motion = $1; }  
	      if ($_ =~ /^color_cdplayer_arrows_motion=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_arrows_motion = $1; } 
	      if ($_ =~ /^color_cdplayer_digit=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_digit = $1; }
	      if ($_ =~ /^color_cdplayer_digit_remaining=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_digit_remaining = $1; }	      
	      if ($_ =~ /^scrolling_text_speed=(\d+)/){ $scrolling_text_speed = $1 if ($1>=10); }		      
	      if ($_ =~ /^scrolling_text_incremental=(\d+)/){ $scrolling_text_incremental = $1; }	     
	      if ($_ =~ /^scrolling_type=(.*)/){ $scrolling_type = $1; }	      
	      if ($_ =~ /^scrolling_text_orientation=((-1|1))/){ $scrolling_text_orientation = $1; }	         	            
	      if ($_ =~ /^show_cdplayer_skin=([01])/){ $show_cdplayer_skin = $1; }	      
	      if ($_ =~ /^show_cdplayer_border=([01])/){ $show_cdplayer_border = $1; }
	      if ($_ =~ /^show_cdplayer_keep_above=([01])/){ $show_cdplayer_keep_above = $1; }    
	      if ($_ =~ /^player_mp3=(madplay|mpg123|mpg321|mplayer)$/){ $player_mp3 = $1; }
	      if ($_ =~ /^player_mp4=(mplayer)$/){ $player_mp4 = $1; }
	      if ($_ =~ /^player_mpc=(mpcdec|mplayer)$/){ $player_mpc = $1; }
	      if ($_ =~ /^player_ogg=(ogg123|mplayer)$/){ $player_ogg = $1; }
	      if ($_ =~ /^player_ape=(mac|mplayer|aplay)$/){ $player_ape = $1; }	      	      
	      if ($_ =~ /^player_flac=(flac123|mplayer)$/){ $player_flac = $1; }
	      if ($_ =~ /^player_wav=(mplayer|aplay|play)$/){ $player_wav = $1; }
	      if ($_ =~ /^device_path=(.*)/){ $device_path = $1; }
	      if ($_ =~ /^device_type=(.*)/){ $device_type = $1; }	      
	      if ($_ =~ /^use_filter=(\d+)/){ $use_filter = $1; }	      	      
	      if ($_ =~ /^column_show_file=(0|1)/){ $column_show_file = $1; }
	      if ($_ =~ /^column_show_artist=(0|1)/){ $column_show_artist = $1; }	
	      if ($_ =~ /^column_show_album=(0|1)/){ $column_show_album = $1; }
	      if ($_ =~ /^column_show_track=(0|1)/){ $column_show_track = $1; }	  
	      if ($_ =~ /^column_show_extension=(0|1)/){ $column_show_extension = $1; }	      
	      if ($_ =~ /^column_show_play_count=(0|1)/){ $column_show_play_count = $1; }	      
	      if ($_ =~ /^column_show_filepath=(0|1)/){ $column_show_filepath = $1; }
	      if ($_ =~ /^column_show_filename=(0|1)/){ $column_show_filename = $1; }
	      if ($_ =~ /^column_show_frequency=(0|1)/){ $column_show_frequency = $1; }
	      if ($_ =~ /^column_show_bitrate=(0|1)/){ $column_show_bitrate = $1; }
	      if ($_ =~ /^column_show_year=(0|1)/){ $column_show_year = $1; }	      
	      if ($_ =~ /^button_info_type=(\d)/){ $button_info_type = $1; }	      
	      if ($_ =~ /^notebook_page_num=(\d+)/){ $notebook_page_num = $1; }
	      if ($_ =~ /^notebook_page_num2=(\d+)/){ $notebook_page_num2 = $1; }
	      if ($_ =~ /^notebook_cd_player_num=(\d+)/){ $notebook_cd_player_num = $1; }
	      	      	      
	      # read the music list
	      if ($_ =~ /^checked=(0|1):::file=(\d+):::track=(.*):::artist=(.*):::title=(.*):::album=(.*):::length=(.*):::bitrate=(\d+):::year=(.*):::frequency=(\d+):::genre=(.*):::filepath=(.*):::directory_remain=(.*):::filename=(.*):::extension_input=(.*)$/){ 
                 my $filepath = $12; # print "\$filepath = $filepath\n";	 
		 		 
		 eval { if (not -e filename_from_unicode $filepath){warn filename_from_unicode "\nCould not find <$filepath>: $!"; next;} };		 		 
		 
		 push @files_info, {   # fill the array of array references
                                       rip         => $1,
	                               file        => $file_number, # file_number = row - 1
			               track       => $3,
			               artist      => $4,
			               title       => $5,
			               album       => $6,
			               length      => $7,
			               bitrate     => $8,
				       year        => $9,
				       frequency   => $10,
				       genre       => $11,
				       
				       filepath          => $filepath,  # $12,				       				       
				       directory_remain  => $13,				       				       
				       filename          => $14,				       	  
			               extension_input   => $15,
                                   };
	         $file_number += 1; 		        
	      }	            	         	      	       
	}
	close(CONFIG);
	$extension_input = $files_info[0]{extension_input} if ( defined $files_info[0]{extension_input} );	
     }
     $gain = number_value($gain);    
     return;     
}		  

#######------------- Save the config file -----------#######

# save configurations only when quit the program
sub save_config {
	my $config = $setting_file;
	if ( not -e filename_from_unicode $config ){ print "Save configuration file: $config\n"; }
	
	# test_expr ? if_true_expr : if_false_expr	
	open(CONFIG, '>:utf8',  filename_from_unicode $config ) or die "Can not write to <$config>: $!";
	  print CONFIG "   gnormalize - $VERSION\n";
	  print CONFIG "author: $AUTHOR\n";
	  print CONFIG "homepage: $HOMEPAGE\n\n";
	  print CONFIG "cdrom=",$entry_cda->get_text,"\n";
	  print CONFIG "recursively=$recursively\n";	  
	  print CONFIG "extension_output=$extension_output\n";
	  print CONFIG "directory_output=$directory_output\n";	  	  
	  print CONFIG "normalization_type=$norm_type\n";
	  print CONFIG "gain=",$spinner->get_value,"\n";
	  print CONFIG "insensibility=",$spinner_sensi->get_value,"\n";
	  print CONFIG "delete_wave=",$check_button_del_wav->get_active?1:0,"\n";
	  print CONFIG "discDB=",$check_button_cddb->get_active?1:0,"\n";
	  print CONFIG "overwrite_cddb=",$check_button_overwrite_cddb->get_active?1:0,"\n";
	  print CONFIG "CDDB_server=",$entry_CDDB_server->get_text,"\n"; 
	  print CONFIG "cddb_port=",$spinner_cddb_port->get_value,"\n";  
	  print CONFIG "cddb_transport=$cddb_transport\n";		   
	  print CONFIG "priority=",$spinner_pri->get_value,"\n";
	  print CONFIG "change_properties=",$check_change_properties->get_active?1:0,"\n";	  
	  print CONFIG "show_all_tooltips=",$check_button_tooltips->get_active?1:0,"\n";
	  print CONFIG "file_format_cda_rip=",$entry_format_cda->get_text,"\n";
	  print CONFIG "overwrite=",$check_button_overwrite->get_active?1:0,"\n";
	  print CONFIG "comment_tag=",$entry_def_comment->get_text,"\n";	  	  
	  print CONFIG "additional_command_mp3=",$entry_command_mp3->get_text,"\n"; 
	  print CONFIG "additional_command_mp4=",$entry_command_mp4->get_text,"\n"; 
	  print CONFIG "additional_command_mpc=",$entry_command_mpc->get_text,"\n"; 
	  print CONFIG "additional_command_ogg=",$entry_command_ogg->get_text,"\n"; 
	  print CONFIG "additional_command_ape=",$entry_command_ape->get_text,"\n"; 
	  print CONFIG "additional_command_flac=",$entry_command_flac->get_text,"\n";  
	  print CONFIG "character=",$id3tag_character,"\n";
	  print CONFIG "cdplayer=",$cdplayer,"\n";	  
	  print CONFIG "window_font_name=",$button_font->get_label,"\n";	  	
	  print CONFIG "ripper=",$ripper,"\n";  
	  print CONFIG "language=",$ComboBox_Lang_5a->get_active_text,"\n";
	  print CONFIG "Names_Active_Num=",$ComboBox_Names->get_active,"\n";	  
	  print CONFIG "encode=",$ComboBox_encode_type->get_active_text,"\n";	  
	  print CONFIG "encode_remember_mp3=$encode_type{mp3}\n";
	  print CONFIG "encode_remember_mp4=$encode_type{mp4}\n";
	  print CONFIG "encode_remember_mpc=$encode_type{mpc}\n";
	  print CONFIG "encode_remember_ogg=$encode_type{ogg}\n";	  		  	  	  
	  print CONFIG "bitrate=$bitrate_constant\n";
	  print CONFIG "bitrate_avr_mp3=$bitrate_avr_mp3\n";
	  print CONFIG "bitrate_avr_mp4=$bitrate_avr_mp4\n";
	  print CONFIG "bitrate_avr_ogg=$bitrate_avr_ogg\n";
	  print CONFIG "bitrate_vrb_mp3=",$spinner_V->get_value,"\n";
	  print CONFIG "bitrate_vrb_mp4=",$spinner_Vmp4->get_value,"\n";
	  print CONFIG "bitrate_vrb_ogg=", number_value(sprintf("%.1f", $spinner_Vogg->get_value)) ,"\n";
	  print CONFIG "bitrate_vrb_mpc=",$spinner_Vmpc->get_value,"\n";  
	  print CONFIG "comp_ape=",$spinner_compress->get_value,"\n";
	  print CONFIG "comp_flac=",$spinner_compress_flac->get_value,"\n";	 	  
	  print CONFIG "mode=",$ComboBox_mode->get_active_text,"\n";	  
	  print CONFIG "Min=",$ComboBox_Min->get_active_text,"\n";
	  print CONFIG "Max=",$ComboBox_Max->get_active_text,"\n";
	  print CONFIG "freq=",$ComboBox_freq->get_active_text,"\n";		  
	  print CONFIG "quality=$quality\n";	   	  		  
	  print CONFIG "\n---cdparanoia options:\n";
	  print CONFIG "disable_paranoia=",$button_noia1->get_active?1:0,"\n";
	  print CONFIG "never_skip_repair=",$button_noia2->get_active?1:0,"\n";
	  print CONFIG "disable_extra_paranoia=",$button_noia3->get_active?1:0,"\n";
	  print CONFIG "abort_on_skip=",$button_noia4->get_active?1:0,"\n";
	  print CONFIG "\n---cdda2wav options:\n";	  
	  print CONFIG "paranoia=",$button_cdda1->get_active?1:0,"\n";
	  print CONFIG "paranoia_disable=",$button_cdda2->get_active?1:0,"\n";
	  print CONFIG "paranoia_no_verify=",$button_cdda3->get_active?1:0,"\n\n";
	  print CONFIG "play_random=$play_random\n"; 
	  print CONFIG "loop_tracks=$loop_tracks\n";
	  print CONFIG "audio_cd_volume=$audio_cd_volume\n";
	  print CONFIG "\n---window size:\n";
	  # see resize_window() subroutine
	  print CONFIG "window_width=",int($window->allocation->width),"\n";
	  print CONFIG "window_height=",$button_info_type != 2 ? 
	               int($window->allocation->height) : int($window->allocation->height - $frame_debug->allocation->height) ,"\n";	  
	  print CONFIG "window_cd_player_width=$window_cd_player_width\n";
	  print CONFIG "window_cd_player_height=$window_cd_player_height\n";	       
	  print CONFIG "show_tux_animation=",$check_button_animation->get_active?1:0,"\n";
	  print CONFIG "\n---cd player color:\n";	  
	  print CONFIG "color_bg_cdplay=$color_bg_cdplay\n";  
	  print CONFIG "color_cdplayer_shadow=$color_cdplayer_shadow\n";
	  print CONFIG "color_cdplayer_arrows=$color_cdplayer_arrows\n";
	  print CONFIG "color_cdplayer_shadow_motion=$color_cdplayer_shadow_motion\n";
	  print CONFIG "color_cdplayer_arrows_motion=$color_cdplayer_arrows_motion\n";	  
	  print CONFIG "color_cdplayer_digit=$color_cdplayer_digit\n";
	  print CONFIG "color_cdplayer_digit_remaining=$color_cdplayer_digit_remaining\n";
	  print CONFIG "scrolling_text_speed=$scrolling_text_speed\n";	  
	  print CONFIG "scrolling_text_incremental=$scrolling_text_incremental\n";	  
	  print CONFIG "scrolling_type=$scrolling_type\n";	  
	  print CONFIG "scrolling_text_orientation=$scrolling_text_orientation\n";	   	  	  
	  print CONFIG "show_cdplayer_skin=",$show_cdplayer_skin?1:0,"\n";	  
	  print CONFIG "show_cdplayer_border=",$show_cdplayer_border?1:0,"\n";
	  print CONFIG "show_cdplayer_keep_above=",$show_cdplayer_keep_above?1:0,"\n";
	  print CONFIG "\n---players:\n";
	  print CONFIG "player_mp3=$player_mp3\n";
	  print CONFIG "player_mp4=$player_mp4\n";
	  print CONFIG "player_mpc=$player_mpc\n";
	  print CONFIG "player_ogg=$player_ogg\n";
	  print CONFIG "player_ape=$player_ape\n";
	  print CONFIG "player_flac=$player_flac\n";
	  print CONFIG "player_wav=$player_wav\n";
	  print CONFIG "device_path=$device_path\n";	
	  print CONFIG "device_type=$device_type\n";	  
	  print CONFIG "use_filter=$use_filter\n";	  	  
	  print CONFIG "\n---columns:\n";
	  print CONFIG "column_show_file=",$column_show_file?1:0,"\n";
	  print CONFIG "column_show_artist=",$column_show_artist?1:0,"\n";
	  print CONFIG "column_show_album=",$column_show_album?1:0,"\n";
	  print CONFIG "column_show_track=",$column_show_track?1:0,"\n";
	  print CONFIG "column_show_extension=",$column_show_extension?1:0,"\n";	  
	  print CONFIG "column_show_play_count=",$column_show_play_count?1:0,"\n";	  
	  print CONFIG "column_show_filepath=",$column_show_filepath?1:0,"\n";
	  print CONFIG "column_show_filename=",$column_show_filename?1:0,"\n";
	  print CONFIG "column_show_frequency=",$column_show_frequency?1:0,"\n";
	  print CONFIG "column_show_bitrate=",$column_show_bitrate?1:0,"\n";
	  print CONFIG "column_show_year=",$column_show_year?1:0,"\n";	  
	  print CONFIG "button_info_type=",$button_info_type,"\n";	  	  
	  print CONFIG "notebook_page_num=",$notebook->get_current_page,"\n";
	  print CONFIG "notebook_page_num2=",$notebook2->get_current_page,"\n";
	  print CONFIG "notebook_cd_player_num=$notebook_cd_player_num\n"; 	  	  	  
	  
	  print CONFIG "\n---music list:\n";
	  	  
	  # save list store            
          foreach my $d (@files_info) {    # print "\$d->{file} = $d->{file} ; n = ",$#files_info+1,"\n";
	     return if not defined $files_info[0]{artist};
	     next if ($d->{extension_input} eq 'cda' or $d->{remove});
             print CONFIG "checked=$d->{rip}:::file=$d->{file}:::track=$d->{track}:::artist=$d->{artist}:::".
	                  "title=$d->{title}:::album=$d->{album}:::length=$d->{length}:::bitrate=$d->{bitrate}:::".
			  "year=$d->{year}:::frequency=$d->{frequency}:::genre=$d->{genre}:::filepath=$d->{filepath}:::".
			  "directory_remain=$d->{directory_remain}:::filename=$d->{filename}:::extension_input=$d->{extension_input}\n";	   
          }	  	  	  	    	       
	close CONFIG;
}

read_config(); 
#save_config(); # save when quit; see 'sub Quit'
#print "extension_output = $extension_output \n";

#######------------------- Icon --------------------########

# from /usr/share/doc/perl-Gtk2-1.054/gtk-demo/main.pl
sub set_icon {
  my $icon_path = shift || "/usr/share/icons/gnormalize.png";
  my $pixbuf;
  eval { $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file($icon_path); };
  #eval { $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file("/usr/share/icons/wolf.png"); };
  # "/usr/share/icons/sound_section.png"
  if ($pixbuf) {
    # The icon has a white background, make it transparent 
    my $transparent = $pixbuf->add_alpha ($true, 0xff, 0xff, 0xff);

    # only one item on the parameter list, but the parameter list is a list
    Gtk2::Window->set_default_icon_list ($transparent);
    #Gtk2::Window->set_default_icon_list ($pixbuf);
  }
}

set_icon ();  

#######---------------- Tranlation -----------------########

my %langs; # Hash of all names, tabs, tips and messages

# All defined language - hash of all the different languages
$all_language{'English'}    = $true;
$all_language{'Portugus'}  = $true;
$all_language{'Franais'}   = $true;
$all_language{'Nederlands'} = $true;
$all_language{'Espagol'}   = $true;
$all_language{'Deutsch'}    = $true;
#$all_language{'new_language'}    = $true;  # <-- add a new language here

read_new_langs();

$language = 'English' if not defined $all_language{"$language"}; # standard language

sub set_language {

   if ( $language eq 'English' )
   {
   $langs{all_tab01} = "Data";
   $langs{all_tab02} = "Configuration";
   $langs{all_tab03} = "Information";
   $langs{all_tab04} = "Rip/Play";
   $langs{all_tab05} = "Translations";
   $langs{all_tab06} = "About";
   $langs{all_tab07} = "Option1";
   $langs{all_tab08} = "Option2";
   $langs{all_tab09} = "CDDB";
   $langs{all_tab10} = "Ripper";   
   $langs{all_tab11} = "Colors";
   $langs{all_tab12} = "Players";
   $langs{all_tab13} = "Columns";
   $langs{all_tab14} = "Skins";
   
   $langs{name001} = "Normalization Type";
   $langs{name002} = "Insensibility";
   $langs{name003} = "Selected File";
   $langs{name004} = "Input Directory";
   $langs{name005} = "Output: Lossy Compression";
   $langs{name006} = "Output: Lossless Compression";
   $langs{name106} = "Output: Uncompressed";   
   
   $langs{name007} = "File";
   $langs{name008} = "Recursively";
   $langs{name009} = "Delete Wav Files";
   $langs{name010} = "Change Properties";
   $langs{name011} = "Overwrite";
   $langs{name012} = "Priority";
   $langs{name013} = "Add Command";
   $langs{name014} = "Filename Rip";
   $langs{name015} = "Character";
   $langs{name016} = "Language";
   $langs{name017} = "Font";
   $langs{name018} = "Read CDDB";
   $langs{name019} = "Overwrite CDDB";
   $langs{name020} = "CDDB Server";
   $langs{name021} = "Port";
   $langs{name022} = "Transport";
   $langs{name023} = "Disable Paranoia";
   $langs{name024} = "Disable Extra Paranoia";
   $langs{name025} = "Abort on Skip";
   $langs{name026} = "Never Skip Repair";
   $langs{name027} = "Paranoia No-Verify";
   $langs{name028} = "Paranoia Disable";
   $langs{name029} = "Ripper";
   $langs{name030} = "Encode Type";
   $langs{name031} = "Mode";
   $langs{name032} = "Encode Quality";
   $langs{name033} = "Variable";
   $langs{name034} = "Title";
   $langs{name035} = "Artist";
   $langs{name036} = "Album"; ## <<<-----
   $langs{name037} = "Comment";
   $langs{name038} = "Year";
   $langs{name039} = "Track Number";
   $langs{name040} = "Genre";
   $langs{name041} = "Frequency";
   $langs{name042} = "Time";
   $langs{name043} = "Channels";
   $langs{name044} = "Length";
   $langs{name045} = "Track";
   $langs{name046} = "Artist";
   $langs{name047} = "Title";
   $langs{name048} = "Size";
   $langs{name049} = "Year";
   $langs{name050} = "Filepath";
   $langs{name051} = "Extension";
   $langs{name052} = "Output Directory";
   $langs{name053} = "Album"; ## <<<-----
   $langs{name054} = "Play Count";
   $langs{name055} = "Animation";
   $langs{name056} = "Filename";
   $langs{name057} = "Show Tooltips";
   $langs{name058} = "Guidance Language";
   $langs{name059} = "Current Translation";  
   $langs{name060} = "Improve The Currente Language Translation";
   $langs{name061} = "Add New Language";
   $langs{name062} = "Add new language here and then press save buton.";
   $langs{name063} = "Normalize";
   $langs{name064} = "CD Player";
   $langs{name065} = "Play";
   
   $langs{name429} = 'Play Tracks Without Any Filters';
   $langs{name430} = 'Play Tracks From Different Albums';
   $langs{name431} = 'Play Tracks From Different Artists';
   $langs{name432} = 'Play Tracks From Different Genres';
   $langs{name433} = 'Play Tracks From Different Years';    
   
   $langs{tip101}  = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n";
   $langs{tip101} .= "None: no normalization is done.\n";
   $langs{tip101} .= "---*---\n";
   $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n";
   $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files.";
   $langs{tip102}  = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. ";
   $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n";
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n";   
   $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n";
   $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 
   $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n";  
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n";
   $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude.";  
   $langs{tip103}  = "Insensibility of normalize. Only not re-encode if:\n";
   $langs{tip103} .= "1) the extension of input file is the same of output file;\n";
   $langs{tip103} .= "2) and \"$langs{name010}\" button is not active;\n";
   $langs{tip103} .= "3) and adjust of normalize is less than insensibility value.";
   $langs{tip104}  = "Select one directory with supported file.";
   $langs{tip105}  = "Choose the directory where all the files will be saved.";
   $langs{tip106}  = "Normalize/Convert all supported files inside the directory (recursively or not).\n"; 
   $langs{tip107}  = "Select a directory including subdirectories: descende recursively into the directory preserving the same structure.";                 
   $langs{tip108}  = "After normalize, the output format will be mp3. \nPlay it with mpg123, mpg321 or madplay."; 
   $langs{tip109}  = "After normalize, the output format will be mp4 (also know as m4a) or aac. \nPlay it with mplayer.";   
   $langs{tip110}  = "After normalize, the output format will be mpc (also know as mpp or mp+). \nPlay it with mppdec or mplayer.";   
   $langs{tip111}  = "After normalize, the output format will be ogg. \nPlay it with ogg123.";   
   $langs{tip112}  = "After normalize, the output format will be ape. \nPlay it with the command:\n   mac \"song.ape\"  - -d | play -t wav - ";     
   $langs{tip113}  = "After normalize, the output format will be flac. \nPlay it with flac123 or mplayer.\nRequired flac version >= \"1.1.1\".";
   $langs{tip114}  = "This is suitable to make an audio cd.\nWav is an uncompressed audio format.";
   $langs{tip115}  = "NOTE:\n";
   $langs{tip115} .= "This compression technique is known as 'Lossy Compression' whereby during the compression data can be lost. ";
   $langs{tip115} .= "The degree of loss varies upon settings. Although data loss does occur, it is minimal and certainly not noticable ";
   $langs{tip115} .= "when using good settings.\nExamples of Lossy compression audio: Mp3, Mp4, Mpc and Ogg.";         
   $langs{tip116}  = "NOTE:\n";
   $langs{tip116} .= "This compression technique is known as 'Lossless Compression' in which all of the information in the original ";
   $langs{tip116} .= "data is preserved, and the original data may be recovered in form identical to its original form.\n";
   $langs{tip116} .= "Examples of Lossless compression audio: Ape and Flac.";
   $langs{tip117}  = "Show the progress bar.";
   $langs{tip118}  = "Hide the progress bar.";
   $langs{tip119}  = "Show the command line and others info.";
   $langs{tip120}  = "Hide the command line and others info.";
   $langs{tip121}  = "Quit.";
   $langs{tip122}  = "Clear all messages.";
   
   $langs{tip201}  = "After the normalize process, the temporary wav files will be deleted.";     
   $langs{tip202}  = "After normalize the files, you can change its encode properties by determining the encode type, the bitrate of all ";
   $langs{tip202} .= "output files, etc. Otherwise, the bitrate of each input file and others properties will be conserved.";
   $langs{tip203}  = "The normalized file will be saved in the same directory of input. If it already exist then overwrite the original file.";
   $langs{tip204}  = "Show the hints and informations.";
   $langs{tip205}  = "Show the Tux and others penguins animations.";
   $langs{tip206}  = "Modify scheduling priority: 0 (highest priority) to 19 (lowest)";
   $langs{tip207}  = "Output filename format used only for rip Audio CD:\n";
   $langs{tip207} .= "   %a - artist\n";
   $langs{tip207} .= "   %b - album\n";
   $langs{tip207} .= "   %t - song title\n";
   $langs{tip207} .= "   %n - track number\n";
   $langs{tip207} .= "   %y - year\n";
   $langs{tip207} .= "   %g - genre";
   $langs{tip208}  = "Advised font: Sans 10.";
   $langs{tip209}  = "Read the CDDB info for Audio CD in your drive from CDDB server \"$CDDB_server\" or from files saved into $home/.cddd/.";
   $langs{tip210}  = "Always get CDDB info from server and overwrite the CDDB file saved at $home/.cddd/";
   $langs{tip211}  = "Some servers:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880";
   $langs{tip212}  = "Choose the port number.";
   $langs{tip213}  = "Disable all data verification and correction features. Consequently the extraction/rip is more fast. ";
   $langs{tip213} .= "This option implies that -Y is active. See cdparanoia (option -Z).";
   $langs{tip214}  = "Do not accept any skips; retry forever if needed. See cdparanoia (option -z).";
   $langs{tip215}  = "Disables intra-read data verification; only overlap checking at read boundaries is performed. Not recommended. See cdparanoia (option -Y).\n";
   $langs{tip215} .= "Boundaries are spaces/limit inter tracks of an audio cd. cdparanoia reads this boundaries carefully when rip on track.";
   $langs{tip216}  = "If the read skips due to imperfect data, a scratch, whatever, abort reading this track. See cdparanoia (option -X).";
   $langs{tip217}  = "Use the paranoia library instead of cdda2wav's routines for reading. See cdda2wav (option -paranoia).";
   $langs{tip218}  = "Disables paranoia mode. Paranoia is still being used. See cdda2wav (option -paraopts=help).";   
   $langs{tip219}  = "Switches verify off, and overlap on.";
   $langs{tip220}  = "Choose a targeted average bitrate. Sets encoding to the bitrate closest to this value (in Kb/s).";
   $langs{tip221}  = "Adjust the quality of mp3; 9 is the worst quality, 0 is the best quality with more Kb/s. See: man lame (option: -V).";
   $langs{tip222}  = "Adjust the quality of encode for ogg; 10 is the best quality with more Kb/s used, -1 is the worst quality. See: man oggenc.";
   $langs{tip223}  = "Adjust the quality of lame encoder for mp3 files: 0 is the best quality with maximum ";
   $langs{tip223} .= "algorithms process; 9 is the worst quality but more fast. See: man lame (option: -q).";
   $langs{tip224}  = "Set default variable bitrate (VBR) quantizer quality in percent for mp4 format; 500 is the best ";
   $langs{tip224} .= "quality with more Kb/s used; 10 is the worst quality. See: <faac --help>.";
   $langs{tip225}  =  "Adjust the quality of encode for mpc using profiles; 8 (braindead) is the best quality with more Kb/s used,";
   $langs{tip225} .= " 2 (telephone) is the worst quality. See: mppenc --longhelp\n";
   $langs{tip225} .= " q=2 --telephone - lowest quality,       (32... 48 kbps)\n";
   $langs{tip225} .= " q=3 --thumb     - low quality/internet, (58... 86 kbps)\n";
   $langs{tip225} .= " q=4 --radio     - medium (MP3) quality, (112...152 kbps)\n";
   $langs{tip225} .= " q=5 --standard  - high quality (dflt),  (142...184 kbps)\n";
   $langs{tip225} .= " q=6 --xtreme    - extreme high quality, (168...212 kbps)\n";
   $langs{tip225} .= " q=7 --insane    - extreme high quality, (232...268 kbps)\n";
   $langs{tip225} .= " q=8 --braindead - extreme high quality, (232...278 kbps)";
   $langs{tip226}  = "Compression level:\n  fast: 1000\n  normal: 2000\n  high: 3000\n  extra high: 4000\n  insane: 5000\n";
   $langs{tip226} .= "\nMore compression level \nresults small files.\nSee the help: mac";
   $langs{tip227}  = "Compression level:\n  fast: 0\n  normal: 5\n  best: 8\nSee <man flac>.";
   $langs{tip228}  = "Put here the additional command line used to encode this files.";
   $langs{tip229}  = "Used to encode ID3v2.3.0 Tag for MP3 files.";   
   $langs{tip250}  = "If this entry is empty, the original comment tag will be preserved. ";
   $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value.";   
   
   
   $langs{tip301}  = "If there is more than one artist, use:\nArtist1 & Artist2 & Artist3 & ...";
   $langs{tip302}  = "Track number";
   $langs{tip303}  = "Total track number";
   $langs{tip304}  = "Save changes of tag.";
   $langs{tip305}  = "Save changes of tag to $home/.cddb directory.";
   
   $langs{tip401}  = "Try /dev/cdrom, /dev/dvd, /dev/hdc or ...\nSee \"/etc/fstab\" file.";
   $langs{tip402}  = "Refresh the cdrom drive and erase the playlist.";
   $langs{tip403}  = "Unselect all tracks.";
   $langs{tip404}  = "Select all tracks.";
   $langs{tip405}  = "Add more files to play.";
   $langs{tip406}  = "Close the gnormalize player config.";       
   $langs{tip407}  = "Choose the interval in milliseconds that the text will be redrawed.";
   $langs{tip408}  = "Choose the step incremental in pixels.";
   $langs{tip409}  = "Scrolling text orientation: up/down or left/right.";
   $langs{tip410}  = "Show the xTunes like skin.\nTo take effect, change the display mode.";
   $langs{tip411}  = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode.";   
   $langs{tip429}  = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. ";   
   $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. ";
   $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. ";   
   $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. ";
   
   $langs{tip501}  = "All tabs, messages, names and tips used by gnormalize.";
   $langs{tip502}  = "You need to restart the Gnormalize to make the changes.";
   $langs{tip503}  = "Guidance Language only used to help the translations.\nRead Only.";
   $langs{tip504}  = "Save the translations and new languages inside the directory: $lang_dir.";
   $langs{tip505}  = "Improve this translation or use it as base for a new Language.";                                            

   
   $langs{msg001}  = "Supported Files into the directory (recursively):";
   $langs{msg002}  = "Supported Files into the directory (not recursively):";      
   $langs{msg003}  = " Choose a mp3/mp4/mpc/ogg/ape/flac/wav/cda file to normalize!";
   $langs{msg004}  = " Dependence not satisfied!";
   $langs{msg005}  = "If Same Extension, Overwrite file";
   $langs{msg006}  = "Analyzing with ReplayGain normalization algorithms ...";
   
   $langs{msg012} = ": read only!";
   $langs{msg013} = " Select at least one track to rip!";
   $langs{msg014} = " Success! Rip finished.";
   $langs{msg015} = " Rip stopped!";    
   $langs{msg016} = " Success!";       
   $langs{msg017} = " Success! File converted.";
   $langs{msg018} = " Success! File normalized.";
   $langs{msg019} = "stop ripping";
   $langs{msg020} = " Get info from ";
   $langs{msg021} = " Please, wait. cdparanoia is reading the cdrom ...";
   $langs{msg022} = " Please, select at least one track to play.";
   $langs{msg023} = "Can't find \"";
   $langs{msg024} = "\" in executable path.";
   $langs{msg025} = "The output can't be \"mp3\" format.";
   $langs{msg026} = "The output can't be \"ogg\" format.";
   $langs{msg027} = "The output can't be \"mpc\" format.";
   $langs{msg028} = "The output can't be \"ape\" format.";
   $langs{msg029} = "The output can't be \"flac\" format.";
   $langs{msg030} = "The output can't be \"mp4\" format.";
   $langs{msg031} = "The wav files can't be normalized.";
   $langs{msg032} = "The input can't be \"ogg\" format.";
   $langs{msg033} = "The input can't be \"mpc\" format.";
   $langs{msg034} = "The input can't be \"mp4\" format.";
   $langs{msg035} = "cdcd is a Command Driven CD player.";
   $langs{msg036} = "First run \"cdcd\" in command line to make the config file .cdcdrc";
   $langs{msg037} = "Choose \"n\" for the question:  Are you connected to a network (y/n) [y]?";
   $langs{msg038} = "Can't use the perl module \"";
   $langs{msg039} = "Can't play audio CD."; 
   $langs{msg040}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert ";
   $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV.";   
   $langs{msg041}  = "This file will not be normalized!";
   $langs{msg042} = "According to insensibility, not normalize";
   $langs{msg043} = "Not normalize because adjustment ";
   $langs{msg044} = " is less than insensibility value.";
   $langs{msg045} = " not normalize ";
   $langs{msg046} = "Don't need encode";
   $langs{msg047} = " already normalized ";
   $langs{msg048} = "This file is already normalized.";
   $langs{msg049} = " Stop normalizing!";
   $langs{msg050} = "Applying adjustment of ";
   $langs{msg051} = " normalizing: adjustment of ";
   $langs{msg052} = "Computing levels...";
   $langs{msg053} = " normalized with adjustment of ";
   $langs{msg054} = " ripping audio to wav";
   $langs{msg055} = " Stop ripping!";
   $langs{msg056} = "copy maked.";
   $langs{msg057} = " Stop lame decoding!";
   $langs{msg058} = " Stop lame encoding!";      
   $langs{msg061} = " This informations will be saved on normalized file.";   
   $langs{msg062} = " tag saved.";
   $langs{msg063} = "Select a mp3/mp4/mpc/ogg/ape/flac/wav file.";
   $langs{msg064} = "Homepage: $HOMEPAGE\nThis software is available under GNU General Public Licence.";
   $langs{msg065} = " output: ";
   $langs{msg066} = "file selected - $langs{all_tab03} can be edited.";
   $langs{msg067} = " Unable to open cdrom drive ";
   $langs{msg068} = " Getting information from cddb ...";
   $langs{msg069} = " none cddb information.";
   $langs{msg070} = " Press save button on \"$langs{all_tab03}\" tab to save this changes.";
   $langs{msg071} = " Not connected, using ";
   $langs{msg072} = " cddb: can't connect to internet!";
   $langs{msg073} = " Can't rip audio CD! cdparanoia not found.";
   $langs{msg074} = " Can't rip audio CD! cdda2wav not found.";
   $langs{msg075} = "Select a mp3, mp4, mpc, ogg, ape, flac, or wav file";   
   $langs{msg077} = "settings";
   $langs{msg078} = "Selected file";
   $langs{msg079} = "Recomended minimum version:";
   $langs{msg080} = " Invalid option!";
   $langs{msg081} = " Press the \"Refresh the cdrom\" button and type again the changes.";   
   $langs{msg082} = "Not found CDDB_get perl module in your system.\n gnormalize will uses internal CDDB_get (version 2.27).";
   $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20).";   
   $langs{msg084}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg085}  = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. ";
   $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV.";   
   $langs{msg086} = "Selected Directory (recursively)";
   $langs{msg087} = "Select a directory containing mp3, mp4, mpc, ogg, ape, flac, or wav file.";
   $langs{msg088} = "Selected Directory (not recursively)";
   $langs{msg089} = "Removing temporary file:";
   $langs{msg090} = "Can not find no supported file inside of directory!";
   $langs{msg092} = "remove this music from list";  
   $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; So Paulo - Brasil";
   $langs{msg094} = "Translation to English: Claudio Fernandes de Souza Rodrigues.";
   $langs{msg095} = "You must add new language name to translate!";
   }

   if ( $language eq 'Portugus' )
   {
   $langs{all_tab01} = "Arquivos";
   $langs{all_tab02} = "Configurao";
   $langs{all_tab03} = "Informao";
   $langs{all_tab04} = "Rip/Play";
   $langs{all_tab05} = "Tradues";
   $langs{all_tab06} = "Sobre";
   $langs{all_tab07} = "Opo1";
   $langs{all_tab08} = "Opo2";
   $langs{all_tab09} = "CDDB";
   $langs{all_tab10} = "Ripper";
   $langs{all_tab11} = "Cores";
   $langs{all_tab12} = "Tocadores";
   $langs{all_tab13} = "Colunas";
   $langs{all_tab14} = "Visual";
   
   $langs{name001} = "Tipo de Normalizao";
   $langs{name002} = "Insensibilidade";
   $langs{name003} = "Arquivo Selecionado";
   $langs{name004} = "Diretrio de Entrada";   
   $langs{name005} = "Sada: Compresso Com Perdas";
   $langs{name006} = "Sada: Compresso Sem Perdas";
   $langs{name106} = "Sada: Sem Compresso";
   
   $langs{name007} = "Arquivo";
   $langs{name008} = "Recursivamente";
   $langs{name009} = "Remover Wav";
   $langs{name010} = "Alterar Propriedades";
   $langs{name011} = "Sobrescrever";
   $langs{name012} = "Prioridade";
   $langs{name013} = "Adicionar Comando";
   $langs{name014} = "Arquivo Rip";
   $langs{name015} = "Caracteres";
   $langs{name016} = "Idioma";
   $langs{name017} = "Fonte";
   $langs{name018} = "Ler CDDB";
   $langs{name019} = "Sobrescrever CDDB";
   $langs{name020} = "CDDB Servidor";
   $langs{name021} = "Porta";
   $langs{name022} = "Transporte";
   $langs{name023} = "Desativar Paranoia";
   $langs{name024} = "Desativar Extra Paranoia";
   $langs{name025} = "Abortar no Caso de Arranho";
   $langs{name026} = "Reler Indefinidamente";
   $langs{name027} = "Paranoia no Verificar";
   $langs{name028} = "Desativar Paranoia";
   $langs{name029} = "Extrator";
   $langs{name030} = "Tipo de Codificao";
   $langs{name031} = "Modo";
   $langs{name032} = "Qualidade";
   $langs{name033} = "Varivel";
   $langs{name034} = "Ttulo";
   $langs{name035} = "Artista";
   $langs{name036} = "lbum";
   $langs{name037} = "Comentrio";
   $langs{name038} = "Ano";
   $langs{name039} = "Nmero";
   $langs{name040} = "Gnero";
   $langs{name041} = "Freqncia";
   $langs{name042} = "Durao";
   $langs{name043} = "Canais";
   $langs{name044} = "Durao";
   $langs{name045} = "Faixa";
   $langs{name046} = "Artista";
   $langs{name047} = "Ttulo";
   $langs{name048} = "Tamanho";
   $langs{name049} = "Ano";
   $langs{name050} = "Arquivo";
   $langs{name051} = "Extenso";
   $langs{name052} = "Diretrio de Sada";
   $langs{name053} = "lbum";
   $langs{name054} = "Play Count";
   $langs{name055} = "Animao";
   $langs{name056} = "Nome do Arquivo";
   $langs{name057} = "Exibir Lembretes";
   $langs{name058} = "Idioma Usado como Parmetro";
   $langs{name059} = "Atual Traduo";
   $langs{name060} = "Melhorar a Atual Traduo";
   $langs{name061} = "Adicionar Novo Idioma";
   $langs{name062} = "Adicione Aqui Novo Idioma e Pressione o Boto para Salvar.";
   $langs{name063} = "Normalizao"; 
   $langs{name064} = "CD Player";
   $langs{name065} = "Tocar";
   
   $langs{name429} = 'Tocar Arquivos Sem Qualquer Filtro';	
   $langs{name430} = 'Tocar Arquivos De Diferentes lbuns';
   $langs{name431} = 'Tocar Arquivos De Diferentes Artistas';
   $langs{name432} = 'Tocar Arquivos De Diferentes Gneros';
   $langs{name433} = 'Tocar Arquivos De Diferentes Anos';      
   
   $langs{tip101}  = "Track: usa o ajuste ReplayGain considerando uma nica Faixa.\nAlbum: ainda no implementado!\n";
   $langs{tip101} .= "None: nenhuma normalizao  realizada.\n";
   $langs{tip101} .= "---*---\n";
   $langs{tip101} .= "gnormalize utiliza o wavegain para normalizar os arquivos wave.\n";
   $langs{tip101} .= "wavegain  um programa que aplica o algortimo ReplayGain de normalizao diretamente aos arquivos wave.";   
   $langs{tip102}  = "Aplica ganhos adicionais ao audio em decibis entre -12.0 e +12.0. ";
   $langs{tip102} .= "Gain = 0.00dB corresponde ao valor de referncia de 89dB.\n";
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "Idias bsicas do algortmo de normalizao ReplayGain:\n";
   $langs{tip102} .= "1. Calcular a Raiz da Mdia do Quadrados da amplitude RMS(A) a cada intervalo de 50ms;\n";
   $langs{tip102} .= "2. Ordenar em ordem crescente os valores RMS(A) e escolher aquele que representa 95% dos volumes percebidos;\n";
   $langs{tip102} .= "3. Ajustar a energia do sinal digital ao valor de referncia de 89dB.\n"; 
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) corresponde a Raiz da Mdia dos Quadrados da amplitude sonora A.\n";
   $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), tal que A  a amplitude medida e A0  a amplitude de referncia.";
   $langs{tip103}  = "Insensibilidade do normalize. Apenas no re-codifica se:\n";
   $langs{tip103} .= "1) a extenso do arquivo de entrada for a mesma da sada;\n";
   $langs{tip103} .= "2) e o boto \"$langs{name010}\" no estiver ativo;\n";
   $langs{tip103} .= "3) e o ajuste do normalize for menor que o valor de insensibilidade.";
   $langs{tip104}  = "Selecione um diretrio com arquivo suportado.";
   $langs{tip105}  = "Escolha o diretrio onde todos os arquivos sero copiados.";
   $langs{tip106}  = "Normaliza/converte todos os arquivos suportados dentro do diretrio (recursivamente ou no).";   
   $langs{tip107}  = "Selecione um diretrio incluindo subdiretrios: desce recursivamente dentro do diretrio preservando a mesma estrutura.";                            
   $langs{tip108}  = "Depois de normalizar, o formato de sada ser mp3. \nPara ouvir arquivos mp3 utilize o mpg123, mpg321 ou madplay.";  
   $langs{tip109}  = "Depois de normalizar, o formato de sada ser mp4 (tambm conhecido como m4a) ou acc. \n";
   $langs{tip109} .= "Para ouvir arquivos mp4 utilize o mplayer.";   
   $langs{tip110}  = "Depois de normalizar, o formato de sada ser mpc (tambm conhecido como mpp ou mp+). \n";
   $langs{tip110} .= "Para ouvir arquivos mpc utilize o comando mppdec ou o mplayer.";
   $langs{tip111}  = "Depois de normalizar, o formato de sada ser ogg. \nPara ouvir arquivos ogg utilize o ogg123."; 
   $langs{tip112}  = "Depois de normalizar, o formato de sada ser ape. \nPara ouvir arquivos ape use o comando:\n   mac \"song.ape\"  - -d | play -t wav - ";   
   $langs{tip113}  = "Depois de normalizar, o formato de sada ser flac. \nPara ouvir arquivos flac utilize o flac123 ou o mplayer.\nVerso do flac exigida >= \"1.1.1\".";   
   $langs{tip114}  = "Esta opo  conveniente para gravar um cd de audio.\nWav  um formato de audio sem compresso."; 
   $langs{tip115}  = "NOTE:\n";
   $langs{tip115} .= "Neste procedimento, conhecido por 'Lossy Compression', dados podem ser perdidos durante a compresso. ";
   $langs{tip115} .= "O grau de perda varia de acordo com os ajustes adotados e dependendo destes ajustes a perda  mnima e no perceptvel ";
   $langs{tip115} .= "ao ouvido humano.\nExemplos de audio com Lossy Compression: Mp3, Mp4, Mpc e Ogg.";            
   $langs{tip116}  = "NOTE:\n";
   $langs{tip116} .= "Este procedimento  conhecido por 'Lossless Compression' ou 'Livre de Perdas' em que toda informao  preservada ";
   $langs{tip116} .= "durante a compresso e todos os dados podem ser recuperados de forma idntica aos originais.\n";
   $langs{tip116} .= "Exemplos de audio com Lossless Compression: Ape e Flac.";
   $langs{tip117}  = "Exibir a barra de progresso.";
   $langs{tip118}  = "Omitir a barra de progresso.";
   $langs{tip119}  = "Exibir as linhas de comando e outras informaes.";
   $langs{tip120}  = "Omitir as linhas de comando e outras informaes.";
   $langs{tip121}  = "Sair.";
   $langs{tip122}  = "Apagar todas as mensagens.";
   
   $langs{tip201}  = "Depois do processo de normalizao, os arquivos temporrios wav sero removidos/apagados.";                   
   $langs{tip202}  = "Depois de normalizar os arquivos, voc pode alterar suas propriedades determinando o tipo de codificao, ";
   $langs{tip202} .= "o bitrate de todos os arquivos de sada, etc. Caso contrrio, o bitrate de cada arquivo de entrada e ";
   $langs{tip202} .= "outras propriedades sero conservados na medida do possvel.";
   $langs{tip203}  = "O arquivo normalizado ser salvo no mesmo diretrio da entrada e ocorrer sobrescrio (salvar por cima) se existir outro arquivo de mesmo nome.";   
   $langs{tip204}  = "Exibir sugestes e informaes.";
   $langs{tip205}  = "Mostrar a animao do Tux e de outros pingins.";
   $langs{tip206}  = "Modificar o gerenciamento de prioridade na execuo dos comandos. Seu valor varia de 0 (maior prioridade) at 19 (menor prioridade).";
   $langs{tip207}  = "Formato para o nome final do arquivo, usado apenas para ripar/extrair arquivos do CD de audio:\n";
   $langs{tip207} .= "   %a - artista\n";
   $langs{tip207} .= "   %b - album\n";
   $langs{tip207} .= "   %t  - ttulo da msica\n";
   $langs{tip207} .= "   %n - nmero da faixa\n";
   $langs{tip207} .= "   %y - ano\n";
   $langs{tip207} .= "   %g - gnero";
   $langs{tip208}  = "Fonte aconselhada: Sans 10.";
   $langs{tip209}  = "Carregar informaes para o CD de audio em seu drive a partir do servidor CDDB \"$CDDB_server\" ou do arquivo copiado em $home/.cddd/.";
   $langs{tip210}  = "Sempre buscar informaes do servidor CDDB e sobrescrever o arquivo existente em $home/.cddd/ .";
   $langs{tip211}  = "Alguns servidores:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880";
   $langs{tip212}  = "Escolha o nmero da porta.";
   $langs{tip213}  = "Desativar toda a verificao e correo de erros na leitura de dados. Consequentemente a extrao  mais rpida. ";
   $langs{tip213} .= "Esta opo tambm implica em (opo -Y) ativa. Veja cdparanoia (opo -Z).";
   $langs{tip214}  = "No aceita nenhuma omisso na leitura dos dados; ler indefinidamente se necessrio. Veja cdparanoia (opo -z).";
   $langs{tip215}  = "Desativa a verificao interna dos dados; apenas cobre e verifica a regio das fronteiras. No  recomendado. Veja cdparanoia (opo -Y).";
   $langs{tip216}  = "Se a leitura pula/salta devido a dados imperfeitos, arranhes, etc., abandonar a leitura desta faixa do CD. Veja cdparanoia (opo -X).";
   $langs{tip217}  = "Usar, para a leitura do CD, a biblioteca do paranoia ao invs das rotinas do cdda2wav. Veja cdda2wav (opo -paranoia).";   
   $langs{tip218}  = "Desativar o modo paranoia. Mas, paranoia ainda assim ser usado. Veja cdda2wav (opo -paraopts=help).";   
   $langs{tip219}  = "Desativa a verificao, mas habilita a leitura sobreposta da regio das fronteiras."; 
   $langs{tip220}  = "Escolha o valor do bitrate mdio. Ajusta o codificador/encoder a este valor o mas prximo possvel (in Kb/s). ";
   $langs{tip220} .= "Bitrate  a taxa de bits utilizada no arquivo por unidade de tempo.";
   $langs{tip221}  = "Ajusta a qualidade do mp3; 9  a pior qualidade, 0  a melhor qualidade com mais Kb/s usado. Veja: man lame (opo: -V).";
   $langs{tip222}  = "Ajusta a qualidade do ogg; 10  a melhor qualidade com mais Kb/s usado, -1  a pior qualidade. Veja: man oggenc.";
   $langs{tip223}  = "Ajusta a qualidade do codificador lame para os arquivos mp3: 0  a melhor qualidade com a mxima iterao no processo algortmo; ";
   $langs{tip223} .= "9  a pior qualidade, contudo muito mais rpido. Veja: man lame (opo: -q).";
   $langs{tip224}  = "Ajusta a qualidade do varivel bitrate (VBR) em porcentagem para o formato mp4; 500  a melhor ";
   $langs{tip224} .= "qualidade com mais Kb/s usado; 10  a pior qualidade. Veja: <faac --help>.";
   $langs{tip225}  = "Ajusta a qualidade de codificao para os arquivos mpc usando um conjunto de rotinas (profiles); ";
   $langs{tip225} .= "8 (braindead)  a melhor qualidade com mais Kb/s usado, 2 (telephone)  a pior qualidade. Veja: <mppenc --longhelp>.\n";
   $langs{tip225} .= " q=2 --telephone - pior qualidade,           (32... 48 kbps)\n";
   $langs{tip225} .= " q=3 --thumb     - baixa qualidade/internet, (58... 86 kbps)\n";
   $langs{tip225} .= " q=4 --radio     - qualidade mdia (MP3),    (112...152 kbps)\n";
   $langs{tip225} .= " q=5 --standard  - qualidade alta (padro),  (142...184 kbps)\n";
   $langs{tip225} .= " q=6 --xtreme    - qualidade muito alta, (168...212 kbps)\n";
   $langs{tip225} .= " q=7 --insane    - qualidade muito alta, (232...268 kbps)\n";
   $langs{tip225} .= " q=8 --braindead - qualidade altssima,         (232...278 kbps)";
   $langs{tip226}  = "Nvel de Compresso:\n  fast (rpida): 1000\n  normal: 2000\n  high (alta): 3000\n  extra high: 4000\n  insane: 5000\n";
   $langs{tip226} .= "\nMaior nvel de compresso resulta \nem arquivos menores.\nVeja o comando: mac";
   $langs{tip227}  = "Nvel de Compresso:\n  fast (rpida): 0\n  normal: 5\n  best (mxima): 8\nVeja <man flac>.";
   $langs{tip228}  = "Coloque aqui linha de comando adicional usada para codificar estes arquivos.";
   $langs{tip229}  = "Usado para codificar o ID3v2.3.0 Tag em arquivos MP3.";   
   $langs{tip250}  = "Se esta entrada estiver vazia, o comentrio original do Tag ser preservado. ";
   $langs{tip250} .= "O comentrio padro  \"gnormalize - gain=%gain\" com %gain substitudo pelo seu valor.";
      
   $langs{tip301}  = "Se houver mais de um artista, use:\nArtista1 & Artista2 & Artista3 & ...";
   $langs{tip302}  = "Nmero da msica.";
   $langs{tip303}  = "Nmero total de msicas.";
   $langs{tip304}  = "Salvar alteraes do tag.";
   $langs{tip305}  = "Salvar alteraes do tag no diretrio $home/.cddb .";
   
   $langs{tip401}  = "Tente /dev/cdrom, /dev/dvd, /dev/hdc ou ...\nVeja o arquivo \"/etc/fstab\".";
   $langs{tip402}  = "Atualiza o drive do cdrom e apaga a lista de msicas.";
   $langs{tip403}  = "Selecionar nenhuma msica.";
   $langs{tip404}  = "Selecionar todas as msicas.";
   $langs{tip405}  = "Adicionar mais arquivos para tocar.";
   $langs{tip406}  = "Fechar a configurao do gnormalize player.";          
   $langs{tip407}  = "Escolha o intervalo em milisegundos que o texto ser redesenhado.";
   $langs{tip408}  = "Escolha o incremento no deslocamento do texto em pixels.";
   $langs{tip409}  = "Orientao no deslocamento do texto: cima/baixo ou esquerda/direita.";
   $langs{tip410}  = "Exibir um visual semelhante ao xTunes.\nPara fazer efeito, altere o modo de exibio.";
   $langs{tip411}  = "Exibir Sempre: forar que este modo de exibio fique acima de outras janelas.\nPara fazer efeito, altere o modo de exibio.";   
   $langs{tip429}  = "Tocar arquivos que satisfazem determinados filtros pode ser mais coveniente ou agradvel que o mtodo aleatrio geral. ";   
   $langs{tip429} .= "Os filtros disponveis so 'Tocar Arquivos de Diferentes lbuns/Artistas/Gneros/Anos'.";   
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "Por exemplo, se o filtro escolhido for lbuns, ento sero tocados arquivos entre os diferentes lbuns. ";
   $langs{tip429} .= "Neste caso, todos os lbuns sero tocados antes de repetir algum outro lbum. ";   
   $langs{tip429} .= "Em outras palavras, at que um arquivo tenha sido tocado de cada lbum, um mesmo lbum no ser escolhido duas vezes.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "Ao tocar, os filtros podem ser usados considerando a ordem direta ou aleatria. ";   
   
   $langs{tip501}  = "Todas as abas, mensagens, nomes e lembretes usados pelo gnormalize.";
   $langs{tip502}  = "Voc precisa reiniciar o Gnormalize para efetuar as mudanas.";
   $langs{tip503}  = "Idioma usado apenas como parmetro para auxiliar na traduo.\nApenas para leitura.";
   $langs{tip504}  = "Salvar as alteraes e novas tradues dentro do diretrio: $lang_dir.";
   $langs{tip505}  = "Aperfeioe esta traduo ou use-a como base para um novo Idioma.";
                             
   
   $langs{msg001}  = "Arquivos suportados dentro do diretrio (recursivamente):";
   $langs{msg002}  = "Arquivos suportados dentro do diretrio (no recursivamente):";   
   $langs{msg003}  = " Escolha um arquivo mp3/mp4/mpc/ogg/ape/flac/wav/cda para normalizar!";
   $langs{msg004}  = " Dependncia no satisfeita!";
   $langs{msg005}  = "Se Mesma Extenso, Sobrescrever Arquivo";
   $langs{msg006}  = "Analisando com o algoritmo ReplayGain de normalizao ...";

   $langs{msg012} = ": apenas para leitura!";
   $langs{msg013} = " Selecione ao menos uma msica para ripar/extrair!";
   $langs{msg014} = " Sucesso! Extrao finalizada.";
   $langs{msg015} = " Extrao interrompida!";    
   $langs{msg016} = " Sucesso!";       
   $langs{msg017} = " Sucesso! Arquivo convertido.";
   $langs{msg018} = " Sucesso! Arquivo normalizado.";
   $langs{msg019} = "Interromper a extrao";
   $langs{msg020} = " Informao obtida de ";
   $langs{msg021} = " Favor esperar. cdparanoia est lendo o cdrom ...";
   $langs{msg022} = " Favor, selecione pelo menos uma msica para tocar.";
   
   $langs{msg023} = "No encontrado \"";
   $langs{msg024} = "\" nos diretrios executveis.";
   $langs{msg025} = "O formato de sada no pode ser \"mp3\".";
   $langs{msg026} = "O formato de sada no pode ser \"ogg\".";
   $langs{msg027} = "O formato de sada no pode ser \"mpc\".";
   $langs{msg028} = "O formato de sada no pode ser \"ape\".";
   $langs{msg029} = "O formato de sada no pode ser \"flac\".";
   $langs{msg030} = "O formato de sada no pode ser \"mp4\".";
   $langs{msg031} = "O arquivo wav no pode ser normalizado.";
   $langs{msg032} = "O formato de entrada no poder ser \"ogg\".";
   $langs{msg033} = "O formato de entrada no poder ser \"mpc\".";
   $langs{msg034} = "O formato de entrada no poder ser \"mp4\".";
   $langs{msg035} = "cdcd  um tocador de CD em linha de comando.";
   $langs{msg036} = "Primeiro execute \"cdcd\" em linha de comando para gerar o arquivo de configurao .cdcdrc";
   $langs{msg037} = "Escolha \"n\" para a questo:  Are you connected to a network (y/n) [y]?";
   $langs{msg038} = "No pode ser usado o mdulo perl \"";
   $langs{msg039} = "CD de audio no poder ser tocado.";     
   $langs{msg040}  = "gnormalize  um conversor e extractor de CDs de Audio com aplicao do algortimo ReplayGain de normalizao, um tocador de audio e um ";
   $langs{msg040} .= "editor de metadata (tag). gnormalize utiliza o 'wavegain' para normalizar arquivos WAV com a acurcia do cdigo gain_analysis.c do ReplayGain. "; 
   $langs{msg040} .= "gnormalize decodifica os arquivos para o formato WAV, normaliza os arquivos WAV e re-codifica-os. gnormalize suporta converso ";
   $langs{msg040} .= "entre os formatos de audio MP3, MP4, MPC, OGG, APE, FLAC e WAV.";    
   $langs{msg041}  = "Este arquivo no ser normalizado!";
   $langs{msg042} = "De acordo com a insensibilidade, no normalizar";
   $langs{msg043} = "No normalizar pois o ajuste ";
   $langs{msg044} = "  menor que o valor da insensibilidade.";
   $langs{msg045} = " no normalizar ";
   $langs{msg046} = "No necessita codificar/encodar";
   $langs{msg047} = " j normalizado ";
   $langs{msg048} = "Este arquivo j est normalizado.";
   $langs{msg049} = " Interromper a normalizao!";
   $langs{msg050} = "Aplicando ajuste de ";
   $langs{msg051} = " normalizando: ajuste de ";
   $langs{msg052} = "Calculando o ajuste ...";
   $langs{msg053} = " normalizado com ajuste de ";
   $langs{msg054} = " extraindo audio para wav";
   $langs{msg055} = " Interrompendo a extrao!";
   $langs{msg056} = "cpia realizada.";
   $langs{msg057} = " Parar decodificao lame!";
   $langs{msg058} = " Parar codificao lame!";     
   $langs{msg061} = " Estas informaes sero salvas no arquivo normalizado.";      
   $langs{msg062} = " tag alterado.";
   $langs{msg063} = "Selecione um arquivo mp3/mp4/mpc/ogg/ape/flac/wav .";
   $langs{msg064} = "Homepage: $HOMEPAGE\nEste software est disponvel sob a GNU General Public Licence.";
   $langs{msg065} = " sada: ";
   $langs{msg066} = "selecionado - $langs{all_tab03} pode ser editado.";
   $langs{msg067} = " No foi possvel ler o cdrom no drive ";
   $langs{msg068} = " Obtendo informao do cddb ...";
   $langs{msg069} = " nenhuma informao do cddb.";
   $langs{msg070} = " Pressione o boto Save (Salvar) em \"$langs{all_tab03}\" para salvar as alteraes.";
   $langs{msg071} = " No conectado, usando ";
   $langs{msg072} = " cddb: falha ao conectar-se  internet!";
   $langs{msg073} = " No pode extrair CD de audio! cdparanoia no encontrado.";
   $langs{msg074} = " No pode extrair CD de audio! cdda2wav no encontrado.";
   $langs{msg075} = "Selecione um arquivo mp3, mp4, mpc, ogg, ape, flac, ou wav.";   
   $langs{msg077} = "ajustes";
   $langs{msg078} = "Arquivo selecionado";
   $langs{msg079} = "Verso mnima recomendada:";
   $langs{msg080} = " Opo Invlida!";
   $langs{msg081} = " Pressione o boto \"Atualizar o cdrom\" e digite novamente as alteraes.";
   $langs{msg082} = "O perl mdulo CDDB_get no foi encontrado no seu sistema.\n gnormalize ir usar o CDDB_get (verso 2.27) interno.";     
   $langs{msg083} = "O perl mdulo MP3::Info no foi encontrado no seu sistema.\n gnormalize ir usar o MP3::Info (verso 1.20) interno.";    
   $langs{msg084}  = "gnormalize  um conversor e extractor de CDs de Audio com aplicao do algortimo ReplayGain de normalizao, um tocador de audio e um ";
   $langs{msg084} .= "editor de metadata (tag). gnormalize utiliza o 'wavegain' para normalizar arquivos WAV com a acurcia do cdigo gain_analysis.c do ReplayGain. "; 
   $langs{msg085}  = "gnormalize decodifica os arquivos para o formato WAV, normaliza os arquivos WAV e re-codifica-os. gnormalize suporta converso ";
   $langs{msg085} .= "entre os formatos de audio MP3, MP4, MPC, OGG, APE, FLAC e WAV.";    
   $langs{msg086} = "Diretrio selecionado (recursivamente)";   
   $langs{msg087} = "Selecione um diretrio contendo arquivo mp3, mp4, mpc, ogg, ape, flac, ou wav.";
   $langs{msg088} = "Diretrio selecionado (no recursivamente):";
   $langs{msg089} = "Removendo arquivo temporrio";
   $langs{msg090} = "Nenhum arquivo suportado foi encontrado dentro do diretrio!";   
   $langs{msg092} = "remove esta msica da lista";
   $langs{msg093} = "Autor: $AUTHOR\nEmail: $EMAIL\nData: $DATE ; So Paulo - Brasil";
   $langs{msg094} = "Traduo para o Portugus: Claudio Fernandes de Souza Rodrigues.";
   $langs{msg095} = "Voc deve adicionar o nome do novo Idioma para traduzir.";
   }

   if ( $language eq 'Franais' )
   {
   $langs{all_tab01} = "Fichiers";
   $langs{all_tab02} = "Configuration";
   $langs{all_tab03} = "Information";
   $langs{all_tab04} = "Rip/Play";
   $langs{all_tab05} = "Translations";
   $langs{all_tab06} = "De";
   $langs{all_tab07} = "Option1";
   $langs{all_tab08} = "Option2";
   $langs{all_tab09} = "CDDB";
   $langs{all_tab10} = "Ripper";
   $langs{all_tab11} = "Colors";
   $langs{all_tab12} = "Players";
   $langs{all_tab13} = "Columns";
   $langs{all_tab14} = "Skins";
 
   $langs{name001} = "Type de Normalisation";
   $langs{name002} = "Insensibilit";
   $langs{name003} = "Fichier choisi";
   $langs{name004} = "Rpertoire de dpart";
   $langs{name005} = "Output: Lossy Compression";
   $langs{name006} = "Output: Lossless Compression";
   $langs{name106} = "Output: Uncompressed";
   
   $langs{name007} = "Fichier";
   $langs{name008} = "Rcursivement";
   $langs{name009} = "Effacer les .wav";
   $langs{name010} = "Changer les Proprits";
   $langs{name011} = "Remplacer";
   $langs{name012} = "Proprit";
   $langs{name013} = "Ajoute la Commande";
   $langs{name014} = "Nom du Fichier Ripp";
   $langs{name015} = "Caractre";
   $langs{name016} = "Idiom";
   $langs{name017} = "Police";
   $langs{name018} = "Lire CDDB";
   $langs{name019} = "Remplacer CDDB";
   $langs{name020} = "Serveur CDDB";
   $langs{name021} = "Port";
   $langs{name022} = "Transport";
   $langs{name023} = "Dsactiver Paranoia";
   $langs{name024} = "Dsactiver Extra Paranoia";
   $langs{name025} = "Annuler si Saut";
   $langs{name026} = "Never Skip Repair";
   $langs{name027} = "Paranoia No-Verify";
   $langs{name028} = "Paranoia Dsative";
   $langs{name029} = "Ripper";
   $langs{name030} = "Type d\'encodage";
   $langs{name031} = "Mode";
   $langs{name032} = "Qualit d\'encodage";
   $langs{name033} = "Variable";
   $langs{name034} = "Titre";
   $langs{name035} = "Artiste";
   $langs{name036} = "Album";
   $langs{name037} = "Commentaire";
   $langs{name038} = "Anne";
   $langs{name039} = "Num. Piste";
   $langs{name040} = "Genre";
   $langs{name041} = "Frequency";
   $langs{name042} = "Temps";
   $langs{name043} = "Canaux";
   $langs{name044} = "Length";
   $langs{name045} = "Piste";
   $langs{name046} = "Artiste";
   $langs{name047} = "Titre";
   $langs{name048} = "Taille";
   $langs{name049} = "Anne";
   $langs{name050} = "Chemin";
   $langs{name051} = "Extension";
   $langs{name052} = "Rpertoire de Sortie";
   $langs{name053} = "Album";
   $langs{name054} = "Play Count";
   $langs{name055} = "Animation";
   $langs{name056} = "Nom de Fichier";
   $langs{name057} = "Show Tooltips";
   $langs{name058} = "Guidance Language";
   $langs{name059} = "Current Translation";
   $langs{name060} = "Improve The Currente Language Translation";
   $langs{name061} = "Add New Language";
   $langs{name062} = "Add new language here and then press save buton.";
   $langs{name063} = "Normaliser";
   $langs{name064} = "CD Player";
   $langs{name065} = "Play";
   
   $langs{name429} = 'Play Tracks Without Any Filters';
   $langs{name430} = 'Play Tracks From Different Albums';
   $langs{name431} = 'Play Tracks From Different Artists';
   $langs{name432} = 'Play Tracks From Different Genres';
   $langs{name433} = 'Play Tracks From Different Years';
   
   $langs{tip101}  = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n";
   $langs{tip101} .= "None: no normalization is done.\n";
   $langs{tip101} .= "---*---\n";
   $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n";
   $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files.";   
   $langs{tip102}  = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. ";
   $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n";
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n";
   $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n";
   $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 
   $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n";  
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n";
   $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude.";
   $langs{tip103}  = "Insensibilit de normalisation. Ne pas re-encoder si:\n";
   $langs{tip103} .= "1) l\'extension du fichier de sortie est identique  l\'entre;\n";
   $langs{tip103} .= "2) et que le bouton \"$langs{name010}\" n\'est pas actif;\n";
   $langs{tip103} .= "3) et l\'ajustement de normalisation est plus petit que la valeur d\'insensibilit.";
   $langs{tip104}  = "Slectionner un rpertoire avec fichier support.";
   $langs{tip105}  = "Choisir le rpertoire o les fichiers seront sauvs.";
   $langs{tip106}  = "Normaliser/Convertir tous les fichiers du rpertoire (rcursivement ou pas).";
   $langs{tip107}  = "Inclure les sous-rpertoires: la rcursivit prserve l'arborescence.";               
   $langs{tip108}  = "Aprs la normalisation, le format de sortie sera mp3. Ouvrez le avec mpg123, mpg321 ou le madplay.";
   $langs{tip109}  = "Aprs la normalisation, le format de sortie sera mp4 (aussi m4a) ou aac. Ouvrez le avec le mplayer.";
   $langs{tip110}  = "Aprs la normalisation, le format de sortie sera mpc (aussi mpp or mp+). Ouvrez le avec mppdec ou le mplayer.";
   $langs{tip111}  = "Aprs la normalisation, le format de sortie sera ogg. Ouvrez le avec ogg123.";
   $langs{tip112}  = "Aprs la normalisation, le format de sortie sera ape. Ouvrez le avec la commande:\n   mac \"song.ape\"  - -d | play -t wav - ";   
   $langs{tip113}  = "Aprs la normalisation, le format de sortie sera flac. Ouvrez le avec flac123 ou le mplayer.\nRequiert une version flac >= \"1.1.1\".";   
   $langs{tip114}  = "Ce qui convient pour faire un CD Audio.\nWav est un format audio non comprim.";
   $langs{tip115}  = "NOTE:\n";
   $langs{tip115} .= "Lossy Compression, certaines informations seront perdues, le format originel ne pourra tre retrouv ";
   $langs{tip115} .= "et sera sensiblement diffrent.\nExemples de compression audio avec perte: Mp3, Mp4, Mpc et Ogg.";   
   $langs{tip116}  = "NOTE:\n";
   $langs{tip116} .= "La compression devrait tre Lossless Compression, toutes les informations d\'origine seront prserves, ";
   $langs{tip116} .= "et les donnes peuvent tre remises en l'tat originel.\nExemples de compression audio sans perte: Ape et Flac.";
   $langs{tip117}  = "Montrer la progression.";
   $langs{tip118}  = "Cacher laprogression.";
   $langs{tip119}  = "Voir la ligne de commande et autres infos.";
   $langs{tip120}  = "Cacher la ligne de commande et autres infos.";
   $langs{tip121}  = "Quitter.";
   $langs{tip122}  = "Effacer tous les messages."; 
   
   $langs{tip201}  = "Aprs le processus de normalisation, les fichiers wav seront effacs.";                                 
   $langs{tip202}  = "Aprs normalisation, vous pouvez changer les proprits d\'encodage comme le type d\'encodage, le bitratede tous ";
   $langs{tip202} .= "les fichiers de sortie, etc. Autrement, les proprits de dpart seront conserves.";
   $langs{tip203}  = "Le fichier normalis sera sauv dans le mme rpertoire que celui de dpart. S'il existe dj, le remplacer.";
   $langs{tip204}  = "Show the hints and informations.";
   $langs{tip205}  = "Montrer les animations Tux et compagnie.";
   $langs{tip206}  = "Modifier la priorit: 0 (la plus forte) to 19 (la plus faible)";
   $langs{tip207}  = "Le formatage des noms de fichiers en sortie uniquement pour les rip de CD audio:\n";
   $langs{tip207} .= "   %a - artiste\n";
   $langs{tip207} .= "   %b - album\n";
   $langs{tip207} .= "   %t - titre chanson\n";
   $langs{tip207} .= "   %n - numro piste\n";
   $langs{tip207} .= "   %y - anne\n";
   $langs{tip207} .= "   %g - genre";
   $langs{tip208}  = "Police: Sans 10.";
   $langs{tip209}  = "Lire les infos CDDB pour les CD Audio depuis le serveur CDDB \"$CDDB_server\" ou depuis un fichier sauv dans $home/.cddd/.";
   $langs{tip210}  = "Toujours rcuprer les infos CDDB depuis le serveur et remplacer les infos CDDB sauvs dans $home/.cddd/";
   $langs{tip211}  = "Des serveurs:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880";
   $langs{tip212}  = "Choisir le numro de port.";
   $langs{tip213}  = "Dsactive toute vrification et correction de donnes. Le rip sera plus rapide. ";
   $langs{tip213} .= "Cette option implique que -Y est actif. Voir cdparanoia (option -Z).";
   $langs{tip214}  = "Ne pas accepter de saut d\'erreurs; toujours recommencer au besoin. Voir cdparanoia (option -z).";
   $langs{tip215}  = "Dsactiver la vrification interne; only overlap checking at read boundaries is performed. Non recommand. Voir cdparanoia (option -Y).";
   $langs{tip216}  = "Si les sauts d\'erreur rsultants de donnes endommages ou autres, annuler la lecture de cette piste. Voir cdparanoia (option -X).";
   $langs{tip217}  = "Utiliser la librairie paranoia au lieu des routines cdda2wav pour lire. Voir cdda2wav (option -paranoia).";
   $langs{tip218}  = "Dsactiver le mode paranoia. Paranoia est encore utilis. Voir cdda2wav (option -paraopts=help).";  
   $langs{tip219}  = "Passer  pas de vrification et saut d\'erreur.";
   $langs{tip220}  = "Choisir un bitrate moyen. L\'encodage sera le plus proche possible de cette valeur (en Kb/s).";
   $langs{tip221}  = "Ajuster la qualit mp3; 9 est la pire, 0 est la meilleure (en Kb/s). Voir: man lame (option: -V).";
   $langs{tip222}  = "Ajuster la qualit ogg; 10 est la meilleure (en Kb/s), -1 est la pire. Voir: man oggenc.";
   $langs{tip223}  = "Ajuster la qualit de l\'encodage lame pour les mp3: 0 est la meilleure avec le maximum d\' ";
   $langs{tip223} .= "algorithmes; 9 est la pire et la plus rapide. Voir: man lame (option: -q).";
   $langs{tip224}  = "Choisir la qualit du quantizer (VBR) en pourcentage pour le mp4; 500 est la meilleure ";
   $langs{tip224} .= "(en Kb/s utiliss); 10 est la pire. Voir: <faac --help>.";
   $langs{tip225}  =  "Ajuster la qualit de l\'encodage des mpc en utilisant les profiles; 8 (braindead) est la meilleure (en Kb/s),";
   $langs{tip225} .= " 2 (tlphone) la pire qualit. Voir: mppenc --longhelp\n";
   $langs{tip225} .= " q=2 --tlphone - plus basse qualit,       (32... 48 kbps)\n";
   $langs{tip225} .= " q=3 --thumb     - basse qualit/internet, (58... 86 kbps)\n";
   $langs{tip225} .= " q=4 --radio     - qualit moyenne (MP3), (112...152 kbps)\n";
   $langs{tip225} .= " q=5 --standard  - haute qualit (dflt),  (142...184 kbps)\n";
   $langs{tip225} .= " q=6 --xtreme    - extreme haute qualit, (168...212 kbps)\n";
   $langs{tip225} .= " q=7 --insane    - extreme haute qualit, (232...268 kbps)\n";
   $langs{tip225} .= " q=8 --braindead - extreme haute qualit, (232...278 kbps)";
   $langs{tip226}  = "Niveau de compression:\n  rapide: 1000\n  normal: 2000\n  lev: 3000\n  trs lev: 4000\n  le top: 5000\n";
   $langs{tip226} .= "\nPlus la compression est forte \nplus les fichiers seront petits.\nVoir l'aide: mac";
   $langs{tip227}  = "Niveau de compression:\n  rapide: 0\n  normal: 5\n  meilleur: 8\nVoir <man flac>.";
   $langs{tip228}  = "Ajouter ici votre ligne de commande additionnelle pour encoder les fichiers.";
   $langs{tip229}  = "Used to encode ID3v2.3.0 Tag for MP3 files.";
   $langs{tip250}  = "If this entry is empty, the original comment tag will be preserved. ";
   $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value.";
      
   $langs{tip301}  = "S\'il y a plus d'un artiste (compilation), utiliser:\nArtiste1 & Artiste2 & Artiste3 & ...";
   $langs{tip302}  = "Numro piste";
   $langs{tip303}  = "Nombre total pistes";
   $langs{tip304}  = "Sauver les changements de tag.";
   $langs{tip305}  = "Sauver les changements de tag vers $home/.cddb.";
   
   $langs{tip401}  = "Essayer /dev/cdrom, /dev/dvd, /dev/hdc ou ...\nVoir le fichier \"/etc/fstab\".";
   $langs{tip402}  = "Rafrachir les cdrom et effacer la liste de lecture.";
   $langs{tip403}  = "Slectionner aucune piste.";
   $langs{tip404}  = "Slectionner tout.";
   $langs{tip405}  = "Ajouter d\'autres fichiers  jouer.";
   $langs{tip406}  = "Fermer la configuration du player.";   
   $langs{tip407}  = "Choose the interval in milliseconds that the text will be redrawed.";
   $langs{tip408}  = "Choose the step incremental in pixels.";
   $langs{tip409}  = "Scrolling text orientation: up/down or left/right.";
   $langs{tip410}  = "Show the xTunes like skin.\nTo take effect, change the display mode.";
   $langs{tip411}  = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode.";   
   $langs{tip429}  = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. ";   
   $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. ";
   $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. ";
   $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. ";
   
   $langs{tip501}  = "All tabs, messages, names and tips used by gnormalize.";
   $langs{tip502}  = "Vous devez de nouveau dmarrer.";
   $langs{tip503}  = "Guidance Language only used to help the translations.\nRead Only.";
   $langs{tip504}  = "Save the translations and new languages inside the directory: $lang_dir.";
   $langs{tip505}  = "Improve this translation or use it as base for a new Language.";
   
   
   $langs{msg001}  = "Fichiers supports dans le rpertoire (rcursif):";
   $langs{msg002}  = "Fichiers supports dans le rpertoire (non rcursif):";      
   $langs{msg003}  = " Choisir un fichier mp3/mp4/mpc/ogg/ape/flac/wav/cda  normaliser!";
   $langs{msg004}  = " Dpendance non satisfaite!";
   $langs{msg005}  = "If Same Extension, Overwrite file";
   $langs{msg006}  = "Analyzing with ReplayGain normalization algorithms ...";

   $langs{msg012} = ": lecture seule!";
   $langs{msg013} = " Slectionner au moins une piste  ripper!";
   $langs{msg014} = " Succs! Rip fini.";
   $langs{msg015} = " Rip interrompu!";    
   $langs{msg016} = " Succs!";       
   $langs{msg017} = " Succs! Fichier converti.";
   $langs{msg018} = " Succs! Fichier normalis.";
   $langs{msg019} = "Arrter le rip";
   $langs{msg020} = " Rcuprer les infos de ";
   $langs{msg021} = " Attendez SVP. cdparanoia lit le cdrom ...";
   $langs{msg022} = " SVP, slectionnez au moins une piste  jouer.";
   $langs{msg023} = "Ne peut trouver \"";
   $langs{msg024} = "\" dans le chemin d'excution.";
   $langs{msg025} = "La sortie ne peut tre au format \"mp3\".";
   $langs{msg026} = "La sortie ne peut tre au format \"ogg\".";
   $langs{msg027} = "La sortie ne peut tre au format \"mpc\".";
   $langs{msg028} = "La sortie ne peut tre au format \"ape\".";
   $langs{msg029} = "La sortie ne peut tre au format \"flac\".";
   $langs{msg030} = "La sortie ne peut tre au format \"mp4\".";
   $langs{msg031} = "Les wav ne peuvent tre normaliss.";
   $langs{msg032} = "L\'entre ne peut tre au format \"ogg\"";
   $langs{msg033} = "L\'entre ne peut tre au format \"mpc\".";
   $langs{msg034} = "L\'entre ne peut tre au format \"mp4\".";
   $langs{msg035} = "cdcd est un player cd  la commande.";
   $langs{msg036} = "Premirement lancer \"cdcd\"  la console pour construire le fichier de configuration .cdcdrc";
   $langs{msg037} = "Choisir \"n\"  la question:  Etes-vous connect  un rseau (y/n) [y]?";
   $langs{msg038} = "Ne peut utiliser le module Perl \"";
   $langs{msg039} = "Ne peut lire les CD Audio.";
   $langs{msg040}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert ";
   $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 
   $langs{msg041}  = "Ce fichier ne sera pas normalis!";
   $langs{msg042} = "Non normalis en accord avec l\'insensibilit";
   $langs{msg043} = "Non normalis car l\'ajustement ";
   $langs{msg044} = " est plus petit que la valeur d\'insensibilit.";
   $langs{msg045} = " ne pas normaliser ";
   $langs{msg046} = "Encodage non ncessaire";
   $langs{msg047} = " dj normalis ";
   $langs{msg048} = "ce fichier est dj normalis.";
   $langs{msg049} = " Arrter la normalisation!";
   $langs{msg050} = "Appliquer les ajustements de ";
   $langs{msg051} = " normalisation: ajustement de ";
   $langs{msg052} = "Niveaux de calculs...";
   $langs{msg053} = " normalis avec ajustement de ";
   $langs{msg054} = " rip audio vers wav";
   $langs{msg055} = " Arrter le rip!";
   $langs{msg056} = "copie faite.";
   $langs{msg057} = " Stopper dcodage lame!";
   $langs{msg058} = " Stopper encodage lame!";   
   $langs{msg061} = " Ces informations seront sauves dans le fichier normalis.";   
   $langs{msg062} = " tag sauv.";
   $langs{msg063} = "Slectionner un ficchier mp3/mp4/mpc/ogg/ape/flac/wav.";
   $langs{msg064} = "Homepage: $HOMEPAGE\nCe logiciel est disponible sous Licence Publique Gnrale GNU.";
   $langs{msg065} = " sortie: ";
   $langs{msg066} = "fichier slectionn - $langs{all_tab03} ditable.";
   $langs{msg067} = " Impossible d\'ouvrir le cdrom ";
   $langs{msg068} = " Rcupre l\'information de cddb ...";
   $langs{msg069} = " aucune information cddb.";
   $langs{msg070} = " presser le bouton sauver dans l'onglet \"$langs{all_tab03}\" pour sauver ces changements.";
   $langs{msg071} = " Non connect, en utilisant ";
   $langs{msg072} = " cddb: internet inaccessible!";
   $langs{msg073} = " Ne peut ripper le CD Audio! cdparanoia introuvable.";
   $langs{msg074} = " Ne peut ripper le CD Audio! cdda2wav introuvable.";
   $langs{msg075} = "Slectionner un fichier mp3, mp4, mpc, ogg, ape, flac, ou wav";   
   $langs{msg077} = "rglages";
   $langs{msg078} = "Fichier slectionn";
   $langs{msg079} = "Version minimum recommande:";
   $langs{msg080} = " Option invalide!";
   $langs{msg081} = " Presser le bouton \"Rafrachir le cdrom\" et r-entrer les changements.";
   $langs{msg082} = "Aucune info cddb, installer le module perl \"CDDB_get\".";
   $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20)."; 
   $langs{msg084}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg085}  = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. ";
   $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV.";
   $langs{msg086} = "Rpertoire slectionn (rcursif)";
   $langs{msg087} = "Slectionner un rpertoire contenant un fichier mp3, mp4, mpc, ogg, ape, flac, ou wav.";
   $langs{msg088} = "Rpertoire slectionn (non rcursif)";
   $langs{msg089} = "Suppression des fichiers temporaires:";
   $langs{msg090} = "Ne peut pas trouver de rpertoire ou fichier support!";   
   $langs{msg092} = "Enlever cette musique de la liste";
   $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; So Paulo - Brasil";
   $langs{msg094} = "Traduits vers franais: Yaen Pujol et finis par Roger Gabriels Antwerp (Essen) Belgium\n";
   $langs{msg095} = "You must add new language name to translate!";
   }
   
   if ( $language eq 'Nederlands' )
   {
   $langs{all_tab01} = "Data";
   $langs{all_tab02} = "Configuratie";
   $langs{all_tab03} = "Information";
   $langs{all_tab04} = "Rip/Play";
   $langs{all_tab05} = "Translations";
   $langs{all_tab06} = "Over";
   $langs{all_tab07} = "Option1";
   $langs{all_tab08} = "Option2";
   $langs{all_tab09} = "CDDB";
   $langs{all_tab10} = "Ripper";
   $langs{all_tab11} = "Colors";
   $langs{all_tab12} = "Players";
   $langs{all_tab13} = "Columns";
   $langs{all_tab14} = "Skins";

   $langs{name001} = "Normalizatie Type";
   $langs{name002} = "Gevoeligheid";
   $langs{name003} = "Geselecteerd Bestand of Map";
   $langs{name004} = "Selecteer Invoer";
   $langs{name005} = "Output: Lossy Compression";
   $langs{name006} = "Output: Lossless Compression";
   $langs{name106} = "Output: Uncompressed";
   
   $langs{name007} = "Bestand";
   $langs{name008} = "Recursief";
   $langs{name009} = "Delete Wav Files";
   $langs{name010} = "Change Properties";
   $langs{name011} = "Overwrite";
   $langs{name012} = "Priority";
   $langs{name013} = "Add Command";
   $langs{name014} = "Filename Rip";
   $langs{name015} = "Character";
   $langs{name016} = "Idiom";
   $langs{name017} = "Font";
   $langs{name018} = "Read CDDB";
   $langs{name019} = "Overwrite CDDB";
   $langs{name020} = "CDDB Server";
   $langs{name021} = "Port";
   $langs{name022} = "Transport";
   $langs{name023} = "disable paranoia";
   $langs{name024} = "disable extra paranoia";
   $langs{name025} = "abort on skip";
   $langs{name026} = "never skip repair";
   $langs{name027} = "paranoia no-verify";
   $langs{name028} = "paranoia disable";
   $langs{name029} = "ripper";
   $langs{name030} = "Encode Type";
   $langs{name031} = "Mode";
   $langs{name032} = "Encode Quality";
   $langs{name033} = "Variable";
   $langs{name034} = "Title";
   $langs{name035} = "Artist";
   $langs{name036} = "Album";
   $langs{name037} = "Comment";
   $langs{name038} = "Year";
   $langs{name039} = "Track Number";
   $langs{name040} = "Genre";
   $langs{name041} = "Frequency";
   $langs{name042} = "Time";
   $langs{name043} = "Channels";
   $langs{name044} = "Length";
   $langs{name045} = "Track";
   $langs{name046} = "Artist";
   $langs{name047} = "Title";
   $langs{name048} = "Size";
   $langs{name049} = "Year";
   $langs{name050} = "Filepath";
   $langs{name051} = "Extension";
   $langs{name052} = "Selecteer Uitvoer";
   $langs{name053} = "Album";
   $langs{name054} = "Play Count";
   $langs{name055} = "Animation";
   $langs{name056} = "Filename";
   $langs{name057} = "Show Tooltips";
   $langs{name058} = "Guidance Language";
   $langs{name059} = "Current Translation";
   $langs{name060} = "Improve The Currente Language Translation";
   $langs{name061} = "Add New Language";
   $langs{name062} = "Add new language here and then press save buton.";
   $langs{name063} = "Normaliseer";
   $langs{name064} = "CD Player";
   $langs{name065} = "Play";
   
   $langs{name429} = 'Play Tracks Without Any Filters';
   $langs{name430} = 'Play Tracks From Different Albums';
   $langs{name431} = 'Play Tracks From Different Artists';
   $langs{name432} = 'Play Tracks From Different Genres';
   $langs{name433} = 'Play Tracks From Different Years';
   
   $langs{tip101}  = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n";
   $langs{tip101} .= "None: no normalization is done.\n";
   $langs{tip101} .= "---*---\n";
   $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n";
   $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files.";   
   $langs{tip102}  = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. ";
   $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n";
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n";
   $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n";
   $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 
   $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n";  
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n";
   $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude.";
   $langs{tip103}  = "Insensibility of normalize. Only not re-encode if:\n";
   $langs{tip103} .= "1) the extension of input file is the same of output file;\n";
   $langs{tip103} .= "2) and \"$langs{name010}\" button is not active;\n";
   $langs{tip103} .= "3) and adjust of normalize is less than insensibility value.";
   $langs{tip104}  = "Select one directory with supported file.";
   $langs{tip105}  = "Choose the directory where all the files will be saved.";
   $langs{tip106}  = "Normalize/Convert all supported files inside the directory (recursively or not).";
   $langs{tip107}  = "Select a directory including subdirectories: descende recursively into the directory preserving the same structure.";              
   $langs{tip108}  = "After normalize, the output format will be mp3. Play it with mpg123, mpg321 or madplay.";
   $langs{tip109}  = "After normalize, the output format will be mp4 (also know as m4a) or aac. Play it with mplayer.";
   $langs{tip110}  = "After normalize, the output format will be mpc (also know as mpp or mp+). Play it with mppdec or xmms plugin.";
   $langs{tip111}  = "After normalize, the output format will be ogg. Play it with ogg123.";
   $langs{tip112}  = "After normalize, the output format will be ape. Play it with the command:\n   mac \"song.ape\"  - -d | play -t wav - ";  
   $langs{tip113}  = "After normalize, the output format will be flac. Play it with flac123 or xmms plugin.\nRequired flac version >= \"1.1.1\".";
   $langs{tip114}  = "This is suitable to make an audio cd.\nWav is an uncompressed audio format.";
   $langs{tip115}  = "NOTE:\n";
   $langs{tip115} .= "This compression technique is known as 'Lossy Compression' whereby during the compression data can be lost. ";
   $langs{tip115} .= "The degree of loss varies upon settings. Although data loss does occur, it is minimal and certainly not noticable ";
   $langs{tip115} .= "when using good settings.\nExamples of Lossy compression audio: Mp3, Mp4, Mpc and Ogg.";         
   $langs{tip116}  = "NOTE:\n";
   $langs{tip116} .= "This compression technique is known as 'Lossless Compression' in which all of the information in the original ";
   $langs{tip116} .= "data is preserved, and the original data may be recovered in form identical to its original form.\n";
   $langs{tip116} .= "Examples of Lossless compression audio: Ape and Flac.";
   $langs{tip117}  = "Show the progress bar.";
   $langs{tip118}  = "Hide the progress bar.";
   $langs{tip119}  = "Show the command line and others info.";
   $langs{tip120}  = "Hide the command line and others info.";
   $langs{tip121}  = "Quit.";
   $langs{tip122}  = "Clear all messages.";
   
   $langs{tip201}  = "After the normalize process, the temporary wav files will be deleted.";      
   $langs{tip202}  = "After normalize the files, you can change its encode properties by determining the encode type, the bitrate of all ";
   $langs{tip202} .= "output files, etc. Otherwise, the bitrate of each input file and others properties will be conserved.";
   $langs{tip203}  = "The normalized file will be saved in the same directory of input. If it already exist then overwrite the original file.";
   $langs{tip204}  = "Show the hints and informations.";
   $langs{tip205}  = "Show the Tux and others penguins animations.";
   $langs{tip206}  = "Modify scheduling priority: 0 (highest priority) to 19 (lowest)";
   $langs{tip207}  = "Output filename format used only for rip Audio CD:\n";
   $langs{tip207} .= "   %a - artist\n";
   $langs{tip207} .= "   %b - album\n";
   $langs{tip207} .= "   %t - song title\n";
   $langs{tip207} .= "   %n - track number\n";
   $langs{tip207} .= "   %y - year\n";
   $langs{tip207} .= "   %g - genre";
   $langs{tip208}  = "Advised font: Sans 10.";
   $langs{tip209}  = "Read the CDDB info for Audio CD in your drive from CDDB server \"$CDDB_server\" or from files saved into $home/.cddd/.";
   $langs{tip210}  = "Always get CDDB info from server and overwrite the CDDB file saved at $home/.cddd/";
   $langs{tip211}  = "Some servers:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880";
   $langs{tip212}  = "Choose the port number.";
   $langs{tip213}  = "Disable all data verification and correction features. Consequently the extraction/rip is more fast. ";
   $langs{tip213} .= "This option implies that -Y is active. See cdparanoia (option -Z).";
   $langs{tip214}  = "Do not accept any skips; retry forever if needed. See cdparanoia (option -z).";
   $langs{tip215}  = "Disables intra-read data verification; only overlap checking at read boundaries is performed. Not recommended. See cdparanoia (option -Y).\n";
   $langs{tip215} .= "Boundaries are spaces/limit inter tracks of an audio cd. cdparanoia reads this boundaries carefully when rip on track.";
   $langs{tip216}  = "If the read skips due to imperfect data, a scratch, whatever, abort reading this track. See cdparanoia (option -X).";
   $langs{tip217}  = "Use the paranoia library instead of cdda2wav's routines for reading. See cdda2wav (option -paranoia).";
   $langs{tip218}  = "Disables paranoia mode. Paranoia is still being used. See cdda2wav (option -paraopts=help).";  
   $langs{tip219}  = "Switches verify off, and overlap on.";
   $langs{tip220}  = "Choose a targeted average bitrate. Sets encoding to the bitrate closest to this value (in Kb/s).";
   $langs{tip221}  = "Adjust the quality of mp3; 9 is the worst quality, 0 is the best quality with more Kb/s. See: man lame (option: -V).";
   $langs{tip222}  = "Adjust the quality of encode for ogg; 10 is the best quality with more Kb/s used, -1 is the worst quality. See: man oggenc.";
   $langs{tip223}  = "Adjust the quality of lame encoder for mp3 files: 0 is the best quality with maximum ";
   $langs{tip223} .= "algorithms process; 9 is the worst quality but more fast. See: man lame (option: -q).";
   $langs{tip224}  = "Set default variable bitrate (VBR) quantizer quality in percent for mp4 format; 500 is the best ";
   $langs{tip224} .= "quality with more Kb/s used; 10 is the worst quality. See: <faac --help>.";
   $langs{tip225}  =  "Adjust the quality of encode for mpc using profiles; 8 (braindead) is the best quality with more Kb/s used,";
   $langs{tip225} .= " 2 (telephone) is the worst quality. See: mppenc --longhelp\n";
   $langs{tip225} .= " q=2 --telephone - lowest quality,       (32... 48 kbps)\n";
   $langs{tip225} .= " q=3 --thumb     - low quality/internet, (58... 86 kbps)\n";
   $langs{tip225} .= " q=4 --radio     - medium (MP3) quality, (112...152 kbps)\n";
   $langs{tip225} .= " q=5 --standard  - high quality (dflt),  (142...184 kbps)\n";
   $langs{tip225} .= " q=6 --xtreme    - extreme high quality, (168...212 kbps)\n";
   $langs{tip225} .= " q=7 --insane    - extreme high quality, (232...268 kbps)\n";
   $langs{tip225} .= " q=8 --braindead - extreme high quality, (232...278 kbps)";
   $langs{tip226}  = "Compression level:\n  fast: 1000\n  normal: 2000\n  high: 3000\n  extra high: 4000\n  insane: 5000\n";
   $langs{tip226} .= "\nMore compression level \nresults small files.\nSee the help: mac";
   $langs{tip227}  = "Compression level:\n  fast: 0\n  normal: 5\n  best: 8\nSee <man flac>.";
   $langs{tip228}  = "Put here the additional command line used to encode this files.";
   $langs{tip229}  = "Used to encode ID3v2.3.0 Tag for MP3 files.";
   $langs{tip250}  = "If this entry is empty, the original comment tag will be preserved. ";
   $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value.";
   
   $langs{tip301}  = "If there is more than one artist, use:\nArtist1 & Artist2 & Artist3 & ...";
   $langs{tip302}  = "Track number";
   $langs{tip303}  = "Total track number";
   $langs{tip304}  = "Save changes of tag.";
   $langs{tip305}  = "Save changes of tag to $home/.cddb directory.";
   
   $langs{tip401}  = "Try /dev/cdrom, /dev/dvd, /dev/hdc or ...\nSee \"/etc/fstab\" file.";
   $langs{tip402}  = "Refresh the cdrom drive and erase the playlist.";
   $langs{tip403}  = "Unselect all tracks.";
   $langs{tip404}  = "Select all tracks.";
   $langs{tip405}  = "Add more files to play.";
   $langs{tip406}  = "Close the gnormalize player config.";   
   $langs{tip407}  = "Choose the interval in milliseconds that the text will be redrawed.";
   $langs{tip408}  = "Choose the step incremental in pixels.";
   $langs{tip409}  = "Scrolling text orientation: up/down or left/right.";
   $langs{tip410}  = "Show the xTunes like skin.\nTo take effect, change the display mode.";
   $langs{tip411}  = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode.";
   $langs{tip429}  = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. ";   
   $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. ";
   $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. ";
   $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. ";
   
   $langs{tip501}  = "All tabs, messages, names and tips used by gnormalize.";
   $langs{tip502}  = "You need to restart the Gnormalize.";
   $langs{tip503}  = "Guidance Language only used to help the translations.\nRead Only.";
   $langs{tip504}  = "Save the translations and new languages inside the directory: $lang_dir.";
   $langs{tip505}  = "Improve this translation or use it as base for a new Language.";                         
      
   
   $langs{msg001}  = "Supported Files into the directory (recursively):";
   $langs{msg002}  = "Supported Files into the directory (not recursively):";      
   $langs{msg003}  = " Choose a mp3/mp4/mpc/ogg/ape/flac/wav/cda file to normalize!";
   $langs{msg004}  = " Dependence not satisfied!";
   $langs{msg005}  = "If Same Extension, Overwrite file";
   $langs{msg006}  = "Analyzing with ReplayGain normalization algorithms ...";

   $langs{msg012} = ": read only!";
   $langs{msg013} = " Select at least one track to rip!";
   $langs{msg014} = " Success! Rip finished.";
   $langs{msg015} = " Rip stopped!";    
   $langs{msg016} = " Success!";       
   $langs{msg017} = " Success! File converted.";
   $langs{msg018} = " Success! File normalized.";
   $langs{msg019} = "stop ripping";
   $langs{msg020} = " Get info from ";
   $langs{msg021} = " Please, wait. cdparanoia is reading the cdrom ...";
   $langs{msg022} = " Please, select at least one track to play.";
   $langs{msg023} = "Can't find \"";
   $langs{msg024} = "\" in executable path.";
   $langs{msg025} = "The output can't be \"mp3\" format.";
   $langs{msg026} = "The output can't be \"ogg\" format.";
   $langs{msg027} = "The output can't be \"mpc\" format.";
   $langs{msg028} = "The output can't be \"ape\" format.";
   $langs{msg029} = "The output can't be \"flac\" format.";
   $langs{msg030} = "The output can't be \"mp4\" format.";
   $langs{msg031} = "The wav files can't be normalized.";
   $langs{msg032} = "The input can't be \"ogg\" format.";
   $langs{msg033} = "The input can't be \"mpc\" format.";
   $langs{msg034} = "The input can't be \"mp4\" format.";
   $langs{msg035} = "cdcd is a Command Driven CD player.";
   $langs{msg036} = "First run \"cdcd\" in command line to make the config file .cdcdrc";
   $langs{msg037} = "Choose \"n\" for the question:  Are you connected to a network (y/n) [y]?";
   $langs{msg038} = "Can't use the perl module \"";
   $langs{msg039} = "Can't play audio CD.";
   $langs{msg040}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert ";
   $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV.";  
   $langs{msg041}  = "This file will not be normalized!";
   $langs{msg042} = "According to insensibility, not normalize";
   $langs{msg043} = "Not normalize because adjustment ";
   $langs{msg044} = " is less than insensibility value.";
   $langs{msg045} = " not normalize ";
   $langs{msg046} = "Don't need encode";
   $langs{msg047} = " already normalized ";
   $langs{msg048} = "This file is already normalized.";
   $langs{msg049} = " Stop normalizing!";
   $langs{msg050} = "Applying adjustment of ";
   $langs{msg051} = " normalizing: adjustment of ";
   $langs{msg052} = "Computing levels...";
   $langs{msg053} = " normalized with adjustment of ";
   $langs{msg054} = " ripping audio to wav";
   $langs{msg055} = " Stop ripping!";
   $langs{msg056} = "copy maked.";
   $langs{msg057} = " Stop lame decoding!";
   $langs{msg058} = " Stop lame encoding!";     
   $langs{msg061} = " This informations will be saved on normalized file.";   
   $langs{msg062} = " tag saved.";
   $langs{msg063} = "Select a mp3/mp4/mpc/ogg/ape/flac/wav file.";
   $langs{msg064} = "Homepage: $HOMEPAGE\nThis software is available under GNU General Public Licence.";
   $langs{msg065} = " output: ";
   $langs{msg066} = "file selected - $langs{all_tab03} can be edited.";
   $langs{msg067} = " Unable to open cdrom drive ";
   $langs{msg068} = " Getting information from cddb ...";
   $langs{msg069} = " none cddb information.";
   $langs{msg070} = " Press save button on \"$langs{all_tab03}\" tab to save this changes.";
   $langs{msg071} = " Not connected, using ";
   $langs{msg072} = " cddb: can't connect to internet!";
   $langs{msg073} = " Can't rip audio CD! cdparanoia not found.";
   $langs{msg074} = " Can't rip audio CD! cdda2wav not found.";
   $langs{msg075} = "Select a mp3, mp4, mpc, ogg, ape, flac, or wav file";   
   $langs{msg077} = "settings";
   $langs{msg078} = "Selected file";
   $langs{msg079} = "Recomended minimum version:";
   $langs{msg080} = " Invalid option!";
   $langs{msg081} = " Press the \"Refresh the cdrom\" button and type again the changes.";
   $langs{msg082} = "Not found CDDB_get perl module in your system.\n gnormalize will uses internal CDDB_get (version 2.27).";
   $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20).";
   $langs{msg084}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg085}  = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. ";
   $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV.";
   $langs{msg086} = "Selected Directory (recursively)";
   $langs{msg087} = "Select a directory containing mp3, mp4, mpc, ogg, ape, flac, or wav file.";
   $langs{msg088} = "Selected Directory (not recursively)";
   $langs{msg089} = "Removing temporary file:";
   $langs{msg090} = "Can not find no supported file inside of directory!";   
   $langs{msg092} = "remove this music from list";
   $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; So Paulo - Brasil";
   $langs{msg094}  = "Nederlandse vertaling door Roger Gabriels Antwerp (Essen) Belgium\n";
   $langs{msg094} .= "E-mail: normaliseer\@pcfreesoft.com | Homepage: htp://www.pcfreesoft.com";
   $langs{msg095} = "You must add new language name to translate!";
   }

   if ( $language eq 'Espagol' )
   {
   $langs{all_tab01} = "Datos";
   $langs{all_tab02} = "Configuracin";
   $langs{all_tab03} = "Information";
   $langs{all_tab04} = "Rip/Play";
   $langs{all_tab05} = "Translations";
   $langs{all_tab06} = "Sobre";
   $langs{all_tab07} = "Option1";
   $langs{all_tab08} = "Option2";
   $langs{all_tab09} = "CDDB";
   $langs{all_tab10} = "Ripper";
   $langs{all_tab11} = "Colors";
   $langs{all_tab12} = "Players";
   $langs{all_tab13} = "Columns";
   $langs{all_tab14} = "Skins";

   $langs{name001} = "Tipo de Normalizacin";
   $langs{name002} = "Insensibilidad";
   $langs{name003} = "Archivo Seleccionado";
   $langs{name004} = "Repertorio de Entrada";
   $langs{name005} = "Output: Lossy Compression";
   $langs{name006} = "Output: Lossless Compression";
   $langs{name106} = "Output: Uncompressed";
   
   $langs{name007} = "Archivo";
   $langs{name008} = "Recursivamente";
   $langs{name009} = "Delete Wav Files";
   $langs{name010} = "Change Properties";
   $langs{name011} = "Overwrite";
   $langs{name012} = "Priority";
   $langs{name013} = "Add Command";
   $langs{name014} = "Filename Rip";
   $langs{name015} = "Character";
   $langs{name016} = "Idiom";
   $langs{name017} = "Font";
   $langs{name018} = "Read CDDB";
   $langs{name019} = "Overwrite CDDB";
   $langs{name020} = "CDDB Server";
   $langs{name021} = "Port";
   $langs{name022} = "Transport";
   $langs{name023} = "disable paranoia";
   $langs{name024} = "disable extra paranoia";
   $langs{name025} = "abort on skip";
   $langs{name026} = "never skip repair";
   $langs{name027} = "paranoia no-verify";
   $langs{name028} = "paranoia disable";
   $langs{name029} = "ripper";
   $langs{name030} = "Encode Type";
   $langs{name031} = "Mode";
   $langs{name032} = "Encode Quality";
   $langs{name033} = "Variable";
   $langs{name034} = "Title";
   $langs{name035} = "Artist";
   $langs{name036} = "Album";
   $langs{name037} = "Comment";
   $langs{name038} = "Year";
   $langs{name039} = "Track Number";
   $langs{name040} = "Genre";
   $langs{name041} = "Frequency";
   $langs{name042} = "Time";
   $langs{name043} = "Channels";
   $langs{name044} = "Length";
   $langs{name045} = "Track";
   $langs{name046} = "Artist";
   $langs{name047} = "Title";
   $langs{name048} = "Size";
   $langs{name049} = "Year";
   $langs{name050} = "Filepath";
   $langs{name051} = "Extension";
   $langs{name052} = "Repertorio de Salida";
   $langs{name053} = "Album";
   $langs{name054} = "Play Count";
   $langs{name055} = "Animation";
   $langs{name056} = "Filename";
   $langs{name057} = "Show Tooltips";
   $langs{name058} = "Guidance Language";
   $langs{name059} = "Current Translation";
   $langs{name060} = "Improve The Currente Language Translation";
   $langs{name061} = "Add New Language";
   $langs{name062} = "Add new language here and then press save buton.";
   $langs{name063} = "Normalizacin";
   $langs{name064} = "CD Player";
   $langs{name065} = "Play";
   
   $langs{name429} = 'Play Tracks Without Any Filters';
   $langs{name430} = 'Play Tracks From Different Albums';
   $langs{name431} = 'Play Tracks From Different Artists';
   $langs{name432} = 'Play Tracks From Different Genres';
   $langs{name433} = 'Play Tracks From Different Years';
   
   $langs{tip101}  = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n";
   $langs{tip101} .= "None: no normalization is done.\n";
   $langs{tip101} .= "---*---\n";
   $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n";
   $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files.";   
   $langs{tip102}  = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. ";
   $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n";
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n";
   $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n";
   $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 
   $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n";  
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n";
   $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude.";
   $langs{tip103}  = "Insensibility of normalize. Only not re-encode if:\n";
   $langs{tip103} .= "1) the extension of input file is the same of output file;\n";
   $langs{tip103} .= "2) and \"$langs{name010}\" button is not active;\n";
   $langs{tip103} .= "3) and adjust of normalize is less than insensibility value.";
   $langs{tip104}  = "Select one directory with supported file.";
   $langs{tip105}  = "Choose the directory where all the files will be saved.";
   $langs{tip106}  = "Normalize/Convert all supported files inside the directory (recursively or not).";
   $langs{tip107}  = "Select a directory including subdirectories: descende recursively into the directory preserving the same structure.";               
   $langs{tip108}  = "After normalize, the output format will be mp3. Play it with mpg123, mpg321 or madplay.";
   $langs{tip109}  = "After normalize, the output format will be mp4 (also know as m4a) or aac. Play it with mplayer.";
   $langs{tip110}  = "After normalize, the output format will be mpc (also know as mpp or mp+). Play it with mppdec or xmms plugin.";
   $langs{tip111}  = "After normalize, the output format will be ogg. Play it with ogg123.";
   $langs{tip112}  = "After normalize, the output format will be ape. Play it with the command:\n   mac \"song.ape\"  - -d | play -t wav - "; 
   $langs{tip113}  = "After normalize, the output format will be flac. Play it with flac123 or xmms plugin.\nRequired flac version >= \"1.1.1\".";
   $langs{tip114}  = "Esta opcicn es muy corriente Para grabar un CD audio.\nWav no es un audio comprimido.";
   $langs{tip115}  = "NOTE:\n";
   $langs{tip115} .= "This compression technique is known as 'Lossy Compression' whereby during the compression data can be lost. ";
   $langs{tip115} .= "The degree of loss varies upon settings. Although data loss does occur, it is minimal and certainly not noticable ";
   $langs{tip115} .= "when using good settings.\nExamples of Lossy compression audio: Mp3, Mp4, Mpc and Ogg.";         
   $langs{tip116}  = "NOTE:\n";
   $langs{tip116} .= "This compression technique is known as 'Lossless Compression' in which all of the information in the original ";
   $langs{tip116} .= "data is preserved, and the original data may be recovered in form identical to its original form.\n";
   $langs{tip116} .= "Examples of Lossless compression audio: Ape and Flac.";
   $langs{tip117}  = "Show the progress bar.";
   $langs{tip118}  = "Hide the progress bar.";
   $langs{tip119}  = "Show the command line and others info.";
   $langs{tip120}  = "Hide the command line and others info.";
   $langs{tip121}  = "Quit.";
   $langs{tip122}  = "Clear all messages.";
   
   $langs{tip201}  = "After the normalize process, the temporary wav files will be deleted.";   
   $langs{tip202}  = "After normalize the files, you can change its encode properties by determining the encode type, the bitrate of all ";
   $langs{tip202} .= "output files, etc. Otherwise, the bitrate of each input file and others properties will be conserved.";
   $langs{tip203}  = "The normalized file will be saved in the same directory of input. If it already exist then overwrite the original file.";
   $langs{tip204}  = "Show the hints and informations.";
   $langs{tip205}  = "Show the Tux and others penguins animations.";
   $langs{tip206}  = "Modify scheduling priority: 0 (highest priority) to 19 (lowest)";
   $langs{tip207}  = "Output filename format used only for rip Audio CD:\n";
   $langs{tip207} .= "   %a - artist\n";
   $langs{tip207} .= "   %b - album\n";
   $langs{tip207} .= "   %t - song title\n";
   $langs{tip207} .= "   %n - track number\n";
   $langs{tip207} .= "   %y - year\n";
   $langs{tip207} .= "   %g - genre";
   $langs{tip208}  = "Advised font: Sans 10.";
   $langs{tip209}  = "Read the CDDB info for Audio CD in your drive from CDDB server \"$CDDB_server\" or from files saved into $home/.cddd/.";
   $langs{tip210}  = "Always get CDDB info from server and overwrite the CDDB file saved at $home/.cddd/";
   $langs{tip211}  = "Some servers:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880";
   $langs{tip212}  = "Choose the port number.";
   $langs{tip213}  = "Disable all data verification and correction features. Consequently the extraction/rip is more fast. ";
   $langs{tip213} .= "This option implies that -Y is active. See cdparanoia (option -Z).";
   $langs{tip214}  = "Do not accept any skips; retry forever if needed. See cdparanoia (option -z).";
   $langs{tip215}  = "Disables intra-read data verification; only overlap checking at read boundaries is performed. Not recommended. See cdparanoia (option -Y).\n";
   $langs{tip215} .= "Boundaries are spaces/limit inter tracks of an audio cd. cdparanoia reads this boundaries carefully when rip on track.";
   $langs{tip216}  = "If the read skips due to imperfect data, a scratch, whatever, abort reading this track. See cdparanoia (option -X).";
   $langs{tip217}  = "Use the paranoia library instead of cdda2wav's routines for reading. See cdda2wav (option -paranoia).";
   $langs{tip218}  = "Disables paranoia mode. Paranoia is still being used. See cdda2wav (option -paraopts=help).";   
   $langs{tip219}  = "Switches verify off, and overlap on.";
   $langs{tip220}  = "Choose a targeted average bitrate. Sets encoding to the bitrate closest to this value (in Kb/s).";
   $langs{tip221}  = "Adjust the quality of mp3; 9 is the worst quality, 0 is the best quality with more Kb/s. See: man lame (option: -V).";
   $langs{tip222}  = "Adjust the quality of encode for ogg; 10 is the best quality with more Kb/s used, -1 is the worst quality. See: man oggenc.";
   $langs{tip223}  = "Adjust the quality of lame encoder for mp3 files: 0 is the best quality with maximum ";
   $langs{tip223} .= "algorithms process; 9 is the worst quality but more fast. See: man lame (option: -q).";
   $langs{tip224}  = "Set default variable bitrate (VBR) quantizer quality in percent for mp4 format; 500 is the best ";
   $langs{tip224} .= "quality with more Kb/s used; 10 is the worst quality. See: <faac --help>.";
   $langs{tip225}  =  "Adjust the quality of encode for mpc using profiles; 8 (braindead) is the best quality with more Kb/s used,";
   $langs{tip225} .= " 2 (telephone) is the worst quality. See: mppenc --longhelp\n";
   $langs{tip225} .= " q=2 --telephone - lowest quality,       (32... 48 kbps)\n";
   $langs{tip225} .= " q=3 --thumb     - low quality/internet, (58... 86 kbps)\n";
   $langs{tip225} .= " q=4 --radio     - medium (MP3) quality, (112...152 kbps)\n";
   $langs{tip225} .= " q=5 --standard  - high quality (dflt),  (142...184 kbps)\n";
   $langs{tip225} .= " q=6 --xtreme    - extreme high quality, (168...212 kbps)\n";
   $langs{tip225} .= " q=7 --insane    - extreme high quality, (232...268 kbps)\n";
   $langs{tip225} .= " q=8 --braindead - extreme high quality, (232...278 kbps)";
   $langs{tip226}  = "Compression level:\n  fast: 1000\n  normal: 2000\n  high: 3000\n  extra high: 4000\n  insane: 5000\n";
   $langs{tip226} .= "\nMore compression level \nresults small files.\nSee the help: mac";
   $langs{tip227}  = "Compression level:\n  fast: 0\n  normal: 5\n  best: 8\nSee <man flac>.";
   $langs{tip228}  = "Put here the additional command line used to encode this files.";
   $langs{tip229}  = "Used to encode ID3v2.3.0 Tag for MP3 files.";
   $langs{tip250}  = "If this entry is empty, the original comment tag will be preserved. ";
   $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value.";
   
   $langs{tip301}  = "If there is more than one artist, use:\nArtist1 & Artist2 & Artist3 & ...";
   $langs{tip302}  = "Track number";
   $langs{tip303}  = "Total track number";
   $langs{tip304}  = "Save changes of tag.";
   $langs{tip305}  = "Save changes of tag to $home/.cddb directory.";
   
   $langs{tip401}  = "Try /dev/cdrom, /dev/dvd, /dev/hdc or ...\nSee \"/etc/fstab\" file.";
   $langs{tip402}  = "Refresh the cdrom drive and erase the playlist.";
   $langs{tip403}  = "Unselect all tracks.";
   $langs{tip404}  = "Select all tracks.";
   $langs{tip405}  = "Add more files to play.";
   $langs{tip406}  = "Close the gnormalize player config.";   
   $langs{tip407}  = "Choose the interval in milliseconds that the text will be redrawed.";
   $langs{tip408}  = "Choose the step incremental in pixels.";
   $langs{tip409}  = "Scrolling text orientation: up/down or left/right.";
   $langs{tip410}  = "Show the xTunes like skin.\nTo take effect, change the display mode.";
   $langs{tip411}  = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode.";
   $langs{tip429}  = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. ";   
   $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. ";
   $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. ";
   $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. ";
   
   $langs{tip501}  = "All tabs, messages, names and tips used by gnormalize.";
   $langs{tip502}  = "You need to restart the Gnormalize.";
   $langs{tip503}  = "Guidance Language only used to help the translations.\nRead Only.";
   $langs{tip504}  = "Save the translations and new languages inside the directory: $lang_dir.";
   $langs{tip505}  = "Improve this translation or use it as base for a new Language.";                              
   
   
   $langs{msg001}  = "Supported Files into the directory (recursively):";
   $langs{msg002}  = "Supported Files into the directory (not recursively):";      
   $langs{msg003}  = " Choose a mp3/mp4/mpc/ogg/ape/flac/wav/cda file to normalize!";
   $langs{msg004}  = " Dependence not satisfied!";
   $langs{msg005}  = "If Same Extension, Overwrite file";
   $langs{msg006}  = "Analyzing with ReplayGain normalization algorithms ...";

   $langs{msg012} = ": read only!";
   $langs{msg013} = " Select at least one track to rip!";
   $langs{msg014} = " Success! Rip finished.";
   $langs{msg015} = " Rip stopped!";    
   $langs{msg016} = " Success!";       
   $langs{msg017} = " Success! File converted.";
   $langs{msg018} = " Success! File normalized.";
   $langs{msg019} = "stop ripping";
   $langs{msg020} = " Get info from ";
   $langs{msg021} = " Please, wait. cdparanoia is reading the cdrom ...";
   $langs{msg022} = " Please, select at least one track to play.";
   $langs{msg023} = "Can't find \"";
   $langs{msg024} = "\" in executable path.";
   $langs{msg025} = "The output can't be \"mp3\" format.";
   $langs{msg026} = "The output can't be \"ogg\" format.";
   $langs{msg027} = "The output can't be \"mpc\" format.";
   $langs{msg028} = "The output can't be \"ape\" format.";
   $langs{msg029} = "The output can't be \"flac\" format.";
   $langs{msg030} = "The output can't be \"mp4\" format.";
   $langs{msg031} = "The wav files can't be normalized.";
   $langs{msg032} = "The input can't be \"ogg\" format.";
   $langs{msg033} = "The input can't be \"mpc\" format.";
   $langs{msg034} = "The input can't be \"mp4\" format.";
   $langs{msg035} = "cdcd is a Command Driven CD player.";
   $langs{msg036} = "First run \"cdcd\" in command line to make the config file .cdcdrc";
   $langs{msg037} = "Choose \"n\" for the question:  Are you connected to a network (y/n) [y]?";
   $langs{msg038} = "Can't use the perl module \"";
   $langs{msg039} = "Can't play audio CD.";
   $langs{msg040}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert ";
   $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 
   $langs{msg041}  = "This file will not be normalized!";
   $langs{msg042} = "According to insensibility, not normalize";
   $langs{msg043} = "Not normalize because adjustment ";
   $langs{msg044} = " is less than insensibility value.";
   $langs{msg045} = " not normalize ";
   $langs{msg046} = "Don't need encode";
   $langs{msg047} = " already normalized ";
   $langs{msg048} = "This file is already normalized.";
   $langs{msg049} = " Stop normalizing!";
   $langs{msg050} = "Applying adjustment of ";
   $langs{msg051} = " normalizing: adjustment of ";
   $langs{msg052} = "Computing levels...";
   $langs{msg053} = " normalized with adjustment of ";
   $langs{msg054} = " ripping audio to wav";
   $langs{msg055} = " Stop ripping!";
   $langs{msg056} = "copy maked.";
   $langs{msg057} = " Stop lame decoding!";
   $langs{msg058} = " Stop lame encoding!";     
   $langs{msg061} = " This informations will be saved on normalized file.";   
   $langs{msg062} = " tag saved.";
   $langs{msg063} = "Select a mp3/mp4/mpc/ogg/ape/flac/wav file.";
   $langs{msg064} = "Homepage: $HOMEPAGE\nThis software is available under GNU General Public Licence.";
   $langs{msg065} = " output: ";
   $langs{msg066} = "file selected - $langs{all_tab03} can be edited.";
   $langs{msg067} = " Unable to open cdrom drive ";
   $langs{msg068} = " Getting information from cddb ...";
   $langs{msg069} = " none cddb information.";
   $langs{msg070} = " Press save button on \"$langs{all_tab03}\" tab to save this changes.";
   $langs{msg071} = " Not connected, using ";
   $langs{msg072} = " cddb: can't connect to internet!";
   $langs{msg073} = " Can't rip audio CD! cdparanoia not found.";
   $langs{msg074} = " Can't rip audio CD! cdda2wav not found.";
   $langs{msg075} = "Select a mp3, mp4, mpc, ogg, ape, flac, or wav file";
   $langs{msg077} = "settings";
   $langs{msg078} = "Selected file";
   $langs{msg079} = "Recomended minimum version:";
   $langs{msg080} = " Invalid option!";
   $langs{msg081} = " Press the \"Refresh the cdrom\" button and type again the changes.";
   $langs{msg082} = "Not found CDDB_get perl module in your system.\n gnormalize will uses internal CDDB_get (version 2.27).";
   $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20)."; 
   $langs{msg084}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg085}  = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. ";
   $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV.";
   $langs{msg086} = "Selected Directory (recursively)";
   $langs{msg087} = "Select a directory containing mp3, mp4, mpc, ogg, ape, flac, or wav file.";
   $langs{msg088} = "Selected Directory (not recursively)";
   $langs{msg089} = "Removing temporary file:";
   $langs{msg090} = "Can not find no supported file inside of directory!";   
   $langs{msg092} = "remove this music from list";
   $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; So Paulo - Brasil";
   $langs{msg094}  = "Traduccin al Espagol: Victor Hugo Vidal conjuntamente con Roger Gabriels - Antwerp Belgium\n";
   $langs{msg094} .= "E-mail: normaliseer\@pcfreesoft.com | Homepage: http://www.pcfreesoft.com";
   $langs{msg095} = "You must add new language name to translate!";
   }

   if ( $language eq 'Deutsch' )
   {
   $langs{all_tab01} = "Daten";
   $langs{all_tab02} = "Konfiguration";
   $langs{all_tab03} = "Information";
   $langs{all_tab04} = "Rip/Play";
   $langs{all_tab05} = "Translations";
   $langs{all_tab06} = "ber";
   $langs{all_tab07} = "Option1";
   $langs{all_tab08} = "Option2";
   $langs{all_tab09} = "CDDB";
   $langs{all_tab10} = "Ripper";
   $langs{all_tab11} = "Colors";
   $langs{all_tab12} = "Players";
   $langs{all_tab13} = "Columns";
   $langs{all_tab14} = "Skins";

   $langs{name001} = "Normungstyp";
   $langs{name002} = "Unempfnglichkeit";
   $langs{name003} = "Selektierte Datei";
   $langs{name004} = "Importieren von Verzeichnis";
   $langs{name005} = "Output: Lossy Compression";
   $langs{name006} = "Output: Lossless Compression";
   $langs{name106} = "Output: Uncompressed";
   
   $langs{name007} = "Datei";
   $langs{name008} = "Zurckkehrend";
   $langs{name009} = "Delete Wav Files";
   $langs{name010} = "Change Properties";
   $langs{name011} = "Overwrite";
   $langs{name012} = "Priority";
   $langs{name013} = "Add Command";
   $langs{name014} = "Filename Rip";
   $langs{name015} = "Character";
   $langs{name016} = "Idiom";
   $langs{name017} = "Font";
   $langs{name018} = "Read CDDB";
   $langs{name019} = "Overwrite CDDB";
   $langs{name020} = "CDDB Server";
   $langs{name021} = "Port";
   $langs{name022} = "Transport";
   $langs{name023} = "disable paranoia";
   $langs{name024} = "disable extra paranoia";
   $langs{name025} = "abort on skip";
   $langs{name026} = "never skip repair";
   $langs{name027} = "paranoia no-verify";
   $langs{name028} = "paranoia disable";
   $langs{name029} = "ripper";
   $langs{name030} = "Encode Type";
   $langs{name031} = "Mode";
   $langs{name032} = "Encode Quality";
   $langs{name033} = "Variable";
   $langs{name034} = "Title";
   $langs{name035} = "Artist";
   $langs{name036} = "Album";
   $langs{name037} = "Comment";
   $langs{name038} = "Year";
   $langs{name039} = "Track Number";
   $langs{name040} = "Genre";
   $langs{name041} = "Frequency";
   $langs{name042} = "Time";
   $langs{name043} = "Channels";
   $langs{name044} = "Length";
   $langs{name045} = "Track";
   $langs{name046} = "Artist";
   $langs{name047} = "Title";
   $langs{name048} = "Size";
   $langs{name049} = "Year";
   $langs{name050} = "Filepath";
   $langs{name051} = "Extension";
   $langs{name052} = "Exportieren von Verzeichnis";
   $langs{name053} = "Album";
   $langs{name054} = "Play Count";
   $langs{name055} = "Animation";
   $langs{name056} = "Filename";
   $langs{name057} = "Show Tooltips";
   $langs{name058} = "Guidance Language";
   $langs{name059} = "Current Translation";
   $langs{name060} = "Improve The Currente Language Translation";
   $langs{name061} = "Add New Language";
   $langs{name062} = "Add new language here and then press save buton.";
   $langs{name063} = "Normalisieren";
   $langs{name064} = "CD Player";
   $langs{name065} = "Play";
   
   $langs{name429} = 'Play Tracks Without Any Filters';
   $langs{name430} = 'Play Tracks From Different Albums';
   $langs{name431} = 'Play Tracks From Different Artists';
   $langs{name432} = 'Play Tracks From Different Genres';
   $langs{name433} = 'Play Tracks From Different Years';
   
   $langs{tip101}  = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n";
   $langs{tip101} .= "None: no normalization is done.\n";
   $langs{tip101} .= "---*---\n";
   $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n";
   $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files.";   
   $langs{tip102}  = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. ";
   $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n";
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n";
   $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n";
   $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 
   $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n";  
   $langs{tip102} .= "---*---\n";
   $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n";
   $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude.";
   $langs{tip103}  = "Insensibility of normalize. Only not re-encode if:\n";
   $langs{tip103} .= "1) the extension of input file is the same of output file;\n";
   $langs{tip103} .= "2) and \"$langs{name010}\" button is not active;\n";
   $langs{tip103} .= "3) and adjust of normalize is less than insensibility value.";
   $langs{tip104}  = "Select one directory with supported file.";
   $langs{tip105}  = "Choose the directory where all the files will be saved.";
   $langs{tip106}  = "Normalize/Convert all supported files inside the directory (recursively or not).";
   $langs{tip107}  = "Select a directory including subdirectories: descende recursively into the directory preserving the same structure.";             
   $langs{tip108}  = "After normalize, the output format will be mp3. Play it with mpg123, mpg321 or madplay.";
   $langs{tip109}  = "After normalize, the output format will be mp4 (also know as m4a) or aac. Play it with mplayer.";
   $langs{tip110}  = "After normalize, the output format will be mpc (also know as mpp or mp+). Play it with mppdec or xmms plugin.";
   $langs{tip111}  = "After normalize, the output format will be ogg. Play it with ogg123.";
   $langs{tip112}  = "After normalize, the output format will be ape. Play it with the command:\n   mac \"song.ape\"  - -d | play -t wav - ";  
   $langs{tip113}  = "After normalize, the output format will be flac. Play it with flac123 or xmms plugin.\nRequired flac version >= \"1.1.1\".";
   $langs{tip114}  = "Es ist geeignet, Audio-Cds von wav-Dateien herzustellen.\nWav ist ein unkrompimiertes Audio Format.";
   $langs{tip115}  = "NOTE:\n";
   $langs{tip115} .= "This compression technique is known as 'Lossy Compression' whereby during the compression data can be lost. ";
   $langs{tip115} .= "The degree of loss varies upon settings. Although data loss does occur, it is minimal and certainly not noticable ";
   $langs{tip115} .= "when using good settings.\nExamples of Lossy compression audio: Mp3, Mp4, Mpc and Ogg.";         
   $langs{tip116}  = "NOTE:\n";
   $langs{tip116} .= "This compression technique is known as 'Lossless Compression' in which all of the information in the original ";
   $langs{tip116} .= "data is preserved, and the original data may be recovered in form identical to its original form.\n";
   $langs{tip116} .= "Examples of Lossless compression audio: Ape and Flac.";
   $langs{tip117}  = "Show the progress bar.";
   $langs{tip118}  = "Hide the progress bar.";
   $langs{tip119}  = "Show the command line and others info.";
   $langs{tip120}  = "Hide the command line and others info.";
   $langs{tip121}  = "Quit.";
   $langs{tip122}  = "Clear all messages.";
   
   $langs{tip201}  = "After the normalize process, the temporary wav files will be deleted.";     
   $langs{tip202}  = "After normalize the files, you can change its encode properties by determining the encode type, the bitrate of all ";
   $langs{tip202} .= "output files, etc. Otherwise, the bitrate of each input file and others properties will be conserved.";
   $langs{tip203}  = "The normalized file will be saved in the same directory of input. If it already exist then overwrite the original file.";
   $langs{tip204}  = "Show the hints and informations.";
   $langs{tip205}  = "Show the Tux and others penguins animations.";
   $langs{tip206}  = "Modify scheduling priority: 0 (highest priority) to 19 (lowest)";
   $langs{tip207}  = "Output filename format used only for rip Audio CD:\n";
   $langs{tip207} .= "   %a - artist\n";
   $langs{tip207} .= "   %b - album\n";
   $langs{tip207} .= "   %t - song title\n";
   $langs{tip207} .= "   %n - track number\n";
   $langs{tip207} .= "   %y - year\n";
   $langs{tip207} .= "   %g - genre";
   $langs{tip208}  = "Advised font: Sans 10.";
   $langs{tip209}  = "Read the CDDB info for Audio CD in your drive from CDDB server \"$CDDB_server\" or from files saved into $home/.cddd/.";
   $langs{tip210}  = "Always get CDDB info from server and overwrite the CDDB file saved at $home/.cddd/";
   $langs{tip211}  = "Some servers:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880";
   $langs{tip212}  = "Choose the port number.";
   $langs{tip213}  = "Disable all data verification and correction features. Consequently the extraction/rip is more fast. ";
   $langs{tip213} .= "This option implies that -Y is active. See cdparanoia (option -Z).";
   $langs{tip214}  = "Do not accept any skips; retry forever if needed. See cdparanoia (option -z).";
   $langs{tip215}  = "Disables intra-read data verification; only overlap checking at read boundaries is performed. Not recommended. See cdparanoia (option -Y).\n";
   $langs{tip215} .= "Boundaries are spaces/limit inter tracks of an audio cd. cdparanoia reads this boundaries carefully when rip on track.";
   $langs{tip216}  = "If the read skips due to imperfect data, a scratch, whatever, abort reading this track. See cdparanoia (option -X).";
   $langs{tip217}  = "Use the paranoia library instead of cdda2wav's routines for reading. See cdda2wav (option -paranoia).";
   $langs{tip218}  = "Disables paranoia mode. Paranoia is still being used. See cdda2wav (option -paraopts=help).";   
   $langs{tip219}  = "Switches verify off, and overlap on.";
   $langs{tip220}  = "Choose a targeted average bitrate. Sets encoding to the bitrate closest to this value (in Kb/s).";
   $langs{tip221}  = "Adjust the quality of mp3; 9 is the worst quality, 0 is the best quality with more Kb/s. See: man lame (option: -V).";
   $langs{tip222}  = "Adjust the quality of encode for ogg; 10 is the best quality with more Kb/s used, -1 is the worst quality. See: man oggenc.";
   $langs{tip223}  = "Adjust the quality of lame encoder for mp3 files: 0 is the best quality with maximum ";
   $langs{tip223} .= "algorithms process; 9 is the worst quality but more fast. See: man lame (option: -q).";
   $langs{tip224}  = "Set default variable bitrate (VBR) quantizer quality in percent for mp4 format; 500 is the best ";
   $langs{tip224} .= "quality with more Kb/s used; 10 is the worst quality. See: <faac --help>.";
   $langs{tip225}  =  "Adjust the quality of encode for mpc using profiles; 8 (braindead) is the best quality with more Kb/s used,";
   $langs{tip225} .= " 2 (telephone) is the worst quality. See: mppenc --longhelp\n";
   $langs{tip225} .= " q=2 --telephone - lowest quality,       (32... 48 kbps)\n";
   $langs{tip225} .= " q=3 --thumb     - low quality/internet, (58... 86 kbps)\n";
   $langs{tip225} .= " q=4 --radio     - medium (MP3) quality, (112...152 kbps)\n";
   $langs{tip225} .= " q=5 --standard  - high quality (dflt),  (142...184 kbps)\n";
   $langs{tip225} .= " q=6 --xtreme    - extreme high quality, (168...212 kbps)\n";
   $langs{tip225} .= " q=7 --insane    - extreme high quality, (232...268 kbps)\n";
   $langs{tip225} .= " q=8 --braindead - extreme high quality, (232...278 kbps)";
   $langs{tip226}  = "Compression level:\n  fast: 1000\n  normal: 2000\n  high: 3000\n  extra high: 4000\n  insane: 5000\n";
   $langs{tip226} .= "\nMore compression level \nresults small files.\nSee the help: mac";
   $langs{tip227}  = "Compression level:\n  fast: 0\n  normal: 5\n  best: 8\nSee <man flac>.";
   $langs{tip228}  = "Put here the additional command line used to encode this files.";
   $langs{tip229}  = "Used to encode ID3v2.3.0 Tag for MP3 files.";
   $langs{tip250}  = "If this entry is empty, the original comment tag will be preserved. ";
   $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value.";
   
   $langs{tip301}  = "If there is more than one artist, use:\nArtist1 & Artist2 & Artist3 & ...";
   $langs{tip302}  = "Track number";
   $langs{tip303}  = "Total track number";
   $langs{tip304}  = "Save changes of tag.";
   $langs{tip305}  = "Save changes of tag to $home/.cddb directory.";
   
   $langs{tip401}  = "Try /dev/cdrom, /dev/dvd, /dev/hdc or ...\nSee \"/etc/fstab\" file.";
   $langs{tip402}  = "Refresh the cdrom drive and erase the playlist.";
   $langs{tip403}  = "Unselect all tracks.";
   $langs{tip404}  = "Select all tracks.";
   $langs{tip405}  = "Add more files to play.";
   $langs{tip406}  = "Close the gnormalize player config.";   
   $langs{tip407}  = "Choose the interval in milliseconds that the text will be redrawed.";
   $langs{tip408}  = "Choose the step incremental in pixels.";
   $langs{tip409}  = "Scrolling text orientation: up/down or left/right.";
   $langs{tip410}  = "Show the xTunes like skin.\nTo take effect, change the display mode.";
   $langs{tip411}  = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode.";
   $langs{tip429}  = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. ";   
   $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. ";
   $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. ";
   $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice.";
   $langs{tip429} .= "\n---***---\n";
   $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. ";
   
   $langs{tip501}  = "All tabs, messages, names and tips used by gnormalize.";
   $langs{tip502}  = "Sie mssen den Gnormalize wiederanfangen.";
   $langs{tip503}  = "Guidance Language only used to help the translations.\nRead Only.";
   $langs{tip504}  = "Save the translations and new languages inside the directory: $lang_dir.";
   $langs{tip505}  = "Improve this translation or use it as base for a new Language.";                
     
   
   $langs{msg001}  = "Supported Files into the directory (recursively):";
   $langs{msg002}  = "Supported Files into the directory (not recursively):";      
   $langs{msg003}  = " Choose a mp3/mp4/mpc/ogg/ape/flac/wav/cda file to normalize!";
   $langs{msg004}  = " Dependence not satisfied!";
   $langs{msg005}  = "If Same Extension, Overwrite file";
   $langs{msg006}  = "Analyzing with ReplayGain normalization algorithms ...";

   $langs{msg012} = ": read only!";
   $langs{msg013} = " Select at least one track to rip!";
   $langs{msg014} = " Success! Rip finished.";
   $langs{msg015} = " Rip stopped!";    
   $langs{msg016} = " Success!";       
   $langs{msg017} = " Success! File converted.";
   $langs{msg018} = " Success! File normalized.";
   $langs{msg019} = "stop ripping";
   $langs{msg020} = " Get info from ";
   $langs{msg021} = " Please, wait. cdparanoia is reading the cdrom ...";
   $langs{msg022} = " Please, select at least one track to play.";
   $langs{msg023} = "Can't find \"";
   $langs{msg024} = "\" in executable path.";
   $langs{msg025} = "The output can't be \"mp3\" format.";
   $langs{msg026} = "The output can't be \"ogg\" format.";
   $langs{msg027} = "The output can't be \"mpc\" format.";
   $langs{msg028} = "The output can't be \"ape\" format.";
   $langs{msg029} = "The output can't be \"flac\" format.";
   $langs{msg030} = "The output can't be \"mp4\" format.";
   $langs{msg031} = "The wav files can't be normalized.";
   $langs{msg032} = "The input can't be \"ogg\" format.";
   $langs{msg033} = "The input can't be \"mpc\" format.";
   $langs{msg034} = "The input can't be \"mp4\" format.";
   $langs{msg035} = "cdcd is a Command Driven CD player.";
   $langs{msg036} = "First run \"cdcd\" in command line to make the config file .cdcdrc";
   $langs{msg037} = "Choose \"n\" for the question:  Are you connected to a network (y/n) [y]?";
   $langs{msg038} = "Can't use the perl module \"";
   $langs{msg039} = "Can't play audio CD.";
   $langs{msg040}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert ";
   $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 
   $langs{msg041}  = "This file will not be normalized!";
   $langs{msg042} = "According to insensibility, not normalize";
   $langs{msg043} = "Not normalize because adjustment ";
   $langs{msg044} = " is less than insensibility value.";
   $langs{msg045} = " not normalize ";
   $langs{msg046} = "Don't need encode";
   $langs{msg047} = " already normalized ";
   $langs{msg048} = "This file is already normalized.";
   $langs{msg049} = " Stop normalizing!";
   $langs{msg050} = "Applying adjustment of ";
   $langs{msg051} = " normalizing: adjustment of ";
   $langs{msg052} = "Computing levels...";
   $langs{msg053} = " normalized with adjustment of ";
   $langs{msg054} = " ripping audio to wav";
   $langs{msg055} = " Stop ripping!";
   $langs{msg056} = "copy maked.";
   $langs{msg057} = " Stop lame decoding!";
   $langs{msg058} = " Stop lame encoding!";      
   $langs{msg061} = " This informations will be saved on normalized file.";   
   $langs{msg062} = " tag saved.";
   $langs{msg063} = "Select a mp3/mp4/mpc/ogg/ape/flac/wav file.";
   $langs{msg064} = "Homepage: $HOMEPAGE\nThis software is available under GNU General Public Licence.";
   $langs{msg065} = " output: ";
   $langs{msg066} = "file selected - $langs{all_tab03} can be edited.";
   $langs{msg067} = " Unable to open cdrom drive ";
   $langs{msg068} = " Getting information from cddb ...";
   $langs{msg069} = " none cddb information.";
   $langs{msg070} = " Press save button on \"$langs{all_tab03}\" tab to save this changes.";
   $langs{msg071} = " Not connected, using ";
   $langs{msg072} = " cddb: can't connect to internet!";
   $langs{msg073} = " Can't rip audio CD! cdparanoia not found.";
   $langs{msg074} = " Can't rip audio CD! cdda2wav not found.";
   $langs{msg075} = "Select a mp3, mp4, mpc, ogg, ape, flac, or wav file";
   $langs{msg077} = "settings";
   $langs{msg078} = "Selected file";
   $langs{msg079} = "Recomended minimum version:";
   $langs{msg080} = " Invalid option!";
   $langs{msg081} = " Press the \"Refresh the cdrom\" button and type again the changes.";
   $langs{msg082} = "Not found CDDB_get perl module in your system.\n gnormalize will uses internal CDDB_get (version 2.27).";
   $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20)."; 
   $langs{msg084}  = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a ";
   $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. ";
   $langs{msg085}  = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. ";
   $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV.";
   $langs{msg086} = "Selected Directory (recursively)";
   $langs{msg087} = "Select a directory containing mp3, mp4, mpc, ogg, ape, flac, or wav file.";
   $langs{msg088} = "Selected Directory (not recursively)";
   $langs{msg089} = "Removing temporary file:";
   $langs{msg090} = "Can not find no supported file inside of directory!";   
   $langs{msg092} = "remove this music from list";
   $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; So Paulo - Brasil";
   $langs{msg094}  = "Deutsche bersetzung gemacht durch Roger Gabriels Antwerp (Essen) Belgium\n";
   $langs{msg094} .= "E-mail: normaliseer\@pcfreesoft.com | Homepage: htp://www.pcfreesoft.com";
   $langs{msg095} = "You must add new language name to translate!";
   }

   #if ( $language eq 'new_language' )
   #{
   # ...
   # ...
   #}

   read_new_langs();
   foreach my $lang ( sort keys %all_language ) { read_langs("$lang_dir/${lang}.txt") if ( $language eq $lang ); }

} # final of 'sub set_language'

set_language();

sub read_new_langs { # read new language inside $lang_dir
   return if ( ! -d filename_from_unicode $lang_dir );
   opendir(DIR, filename_from_unicode $lang_dir ) ;  #search for $lang_dir directory
      while (my $file = readdir(DIR)) {
         next if $file eq ".";
         next if $file eq "..";	
         if ( -w filename_from_unicode "$lang_dir/$file" ){ # -w  File is writable by effective uid/gid.
            ( my $lang = $file) =~ s/\.txt$//;
	    #print "\$file = $file ; \$lang = $lang \n";
	    $all_language{$lang} = $true; # Set New Language
         }
   }
   closedir(DIR);
}

sub read_langs {
   my $file = shift;
   return if ( ! -e filename_from_unicode $file );
   my $last_key = 'msg001';
   open( INPUT, '<:utf8', filename_from_unicode $file ) or die "Can't open <$file>: $!, stopped";
   while (my $line = <INPUT>) {  # regular expressions: see 'man perlre' and 'man perlretut'.
      chomp($line);              # avoid \n on last field      
      next if ( $line =~ /^$/ ); # remover linha vazia   # ^$ matches an empty string
      #$line =~ s/\n/\\n/sg; print "\$line =  $line\n";
      my $key; my $value;            
      
      #if ( $line =~ /^\$langs{(.*)}\s+=\s+"(.*)";/s){ $key = $1; $value = $2 }   # $langs{$key}=$value   
      if ( $line =~ /^(.*)<===>(.*)/s){ $key = $1; $value = $2 }                  # $langs{$key}=$value     
      
      #print "\$key = $key ; \$last_key = $last_key \n";      
      if ( not defined $key and defined $last_key and defined $line ) { $langs{$last_key} .= "\n$line"; next; }
      
      $langs{$key} = $value;
      $last_key = $key;
   }
   close( INPUT );
   #print "333-->\$language = $language \n";
}

#############----------Main--Window----------###############
#####--------------------------------------------------#####
#######-------------------Initial-------------------########

# main window - tela principal
$window = new Gtk2::Window( "toplevel" );  # principal janela
$window->signal_connect( "delete_event", \&Quit );
$window->set_border_width( 1 );
$window->set_decorated ($true);
# Realization is necessary when you want a widget to use 
# a GdkWindow to access the X server.
$window->realize; 
$window->set( 'resizable' => $true, 'allow-shrink' => $false, 'allow-grow' => $true);
# for set_uposition see <man Gtk2::Widget>
#$window->set_uposition (300,200); # (x,y) - window should be placed on the screen.
# 'center'; 'none'; 'mouse' ; 'center-on-parent', 'center-always' ; 
#$window->set_position ('center-always');
$window->set_title( "gnormalize - $VERSION" );
#Gtk2::Widget->set_size_request($widget, $width, $height);
#$window->set_size_request(520,450); #minimum required size, can't shrink for size less than this.
$window->resize($window_width, $window_height);
#my $color = Gtk2::Gdk::Color->parse ("#B8D3C1"); $window->modify_bg ('normal', $color);
$window->show;

###------------ vbox main -----------------###
# "Inside the window we need a vbox to arrange the widgets vertically
# $vbox = new Gtk2::VBox( $homogeneous, $spacing ); 
# $vbox->pack_start( $child, $expand, $fill, $padding ); 
# If the $expand  argument is a true value, then the widgets are laid out 
# in the box to fill in all the extra space in the box so the box is expanded 
# to fill the area allotted to it; otherwise the box is shrunk to just fit 
# the widgets. Setting expand to a false value will allow you to do right 
# and left justification of your widgets. Note that setting $homogeneous  
# to true on the VBox is the same as setting $expand to true for each widget."
 
my $vbox_main = new Gtk2::VBox( $false, 0 );
$vbox_main->set_border_width( 0 );
$window->add($vbox_main);
$vbox_main->show;

###-----------------vpaned-----------------###
###-----------------init-------------------###
# see <man Gtk2::Paned>
# Inside the $vbox_main we put vpaned
# and inside vpaned we put vbox_up and vbox_down

my $vpaned = Gtk2::VPaned->new;
$vpaned->set_border_width (0);
$vbox_main->pack_start( $vpaned, $true, $true, 0 ); 
$vpaned->show;

###--------------- vbox_up --------------------###
 
$vbox_up = new Gtk2::VBox( $false, 2 );
$vbox_up->set_border_width( 1 );
$vpaned->add1 ($vbox_up);
$vbox_up->show;

###------------ vbox_down ------------------###

my $vbox_down = new Gtk2::VBox( $false, 2 );
$vbox_down->set_border_width( 1 );
$vpaned->add2 ($vbox_down);
$vbox_down->show;

###-----------------------------------------###

# "child1_resize" determines whether the first child 
# should expand when $paned is resized.
$vpaned->child1_resize ($true);
$vpaned->child2_resize ($true);

# "If shrink is true, then that child can be made 
# smaller than its requisition by the user."
$vpaned->child1_shrink($false);
$vpaned->child2_shrink($false);

###-----------------final------------------###
###--------------- vpaned -----------------###


#------------------ tabs for notebook ---------------#

#criamos o vbox1 e o adicionamos dentro do notebook
$vbox1 = new Gtk2::VBox( $false, 2 );
$vbox1->set_border_width( 4 );
$vbox1->show();

#criamos o vbox2 e o adicionamos dentro do notebook
$vbox2 = new Gtk2::VBox( $false, 2 );
$vbox2->set_border_width( 4 );
$vbox2->show();

#criamos o vbox3 e o adicionamos dentro do notebook
my $vbox3 = new Gtk2::VBox( $false, 2 );
$vbox3->set_border_width( 4 );
$vbox3->show();

#criamos o vbox4 e o adicionamos dentro do notebook
my $vbox4 = new Gtk2::VBox( $false, 2 );
$vbox4->set_border_width( 4 );
$vbox4->show();

#criamos o vbox5 e o adicionamos dentro do notebook
my $vbox5 = new Gtk2::VBox( $false, 2 );
$vbox5->set_border_width( 4 );
$vbox5->show();

#criamos o vbox6 e o adicionamos dentro do notebook
my $vbox6 = new Gtk2::VBox( $false, 2 );
$vbox6->set_border_width( 4 );
$vbox6->show();

#------------------ icons for notebook ---------------#

sub DrawIcons {  # To show the icons correctely
   my ($stockid,$size) = @_;
   my $icon_image = Gtk2::Image->new_from_stock($stockid,$size);
   $icon_image->show;
   return $icon_image;
}

# widget = Gtk2::Image->new_from_stock ($stock_id, $size)
# $stock_id: see <man Gtk2::Stock>
# size : menu, small-toolbar, large-toolbar, button, dnd, dialog
my $tab_icon_size = 'small-toolbar';	 
my $label_data = Gtk2::Label->new($langs{all_tab01});
$label_data->show;
my $vbox_tab_data = Gtk2::VBox->new( $false, 1 );
$vbox_tab_data->add( DrawIcons('gtk-harddisk', $tab_icon_size) );
$vbox_tab_data->add($label_data);
$vbox_tab_data->show;

#my $notebook_color = Gtk2::Gdk::Color->parse ("blue"); # #B8D3C1 = 184 211 193 (RGB)
#$label_data->modify_fg ('normal', $notebook_color);

# for config notebook icon	 
my $label_config = Gtk2::Label->new($langs{all_tab02});
$label_config->show;
my $vbox_tab_config = Gtk2::VBox->new( $false, 1 );
$vbox_tab_config->add(DrawIcons('gtk-preferences', $tab_icon_size));
$vbox_tab_config->add($label_config);
$vbox_tab_config->show;

# for info notebook icon	 
my $label_info = Gtk2::Label->new($langs{all_tab03});
$label_info->show;
my $vbox_tab_info = Gtk2::VBox->new( $false, 1 );
$vbox_tab_info->add(DrawIcons('gtk-find-and-replace', $tab_icon_size));
$vbox_tab_info->add($label_info);
$vbox_tab_info->show;

# for rip notebook icon	 
my $label_rip = Gtk2::Label->new($langs{all_tab04});
$label_rip->show;
my $vbox_tab_rip = Gtk2::VBox->new( $false, 1 );
$vbox_tab_rip->add(DrawIcons('gtk-cdrom', $tab_icon_size));
$vbox_tab_rip->add($label_rip);
$vbox_tab_rip->show;

# for rip notebook icon	 
my $label_transl = Gtk2::Label->new($langs{all_tab05});
$label_transl->show;
my $vbox_tab_transl = Gtk2::VBox->new( $false, 1 );
$vbox_tab_transl->add(DrawIcons('gtk-spell-check', $tab_icon_size));
$vbox_tab_transl->add($label_transl);
$vbox_tab_transl->show;

# for about notebook icon	 
my $label_about = Gtk2::Label->new($langs{all_tab06});
$label_about->show;
my $vbox_tab_about = Gtk2::VBox->new( $false, 1 );
$vbox_tab_about->add(DrawIcons('gtk-dialog-info', $tab_icon_size));
$vbox_tab_about->add($label_about);
$vbox_tab_about->show;

#####-------------------Notebook-----------------#######
# we put vbox1, vbox2, vbox3, vbox4 and vbox6 inside notebook
# and we put notebook inside vbox_up

$notebook = Gtk2::Notebook->new;
$notebook->set( 'homogeneous' => $true, 'scrollable' => $true );
 
#$notebook->append_page_menu ($child, $tab_label, $menu_label)
$notebook->append_page_menu ( $vbox1,  $vbox_tab_data, undef );    # data
$notebook->append_page_menu ( $vbox2,  $vbox_tab_config, undef );  # config
$notebook->append_page_menu ( $vbox3,  $vbox_tab_info, undef );    # info
$notebook->append_page_menu ( $vbox4,  $vbox_tab_rip, undef );     # rip
$notebook->append_page_menu ( $vbox5,  $vbox_tab_transl, undef );  # Translation
$notebook->append_page_menu ( $vbox6,  $vbox_tab_about, undef );   # about
#$box->pack_start ($child, $expand, $fill, $padding)
$vbox_up->pack_start( $notebook, $true, $true, 0 );
#$notebook->signal_connect("switch-page", \&refresh_notebook_test);
#$vbox_up->add( $notebook );
$notebook->show;

#integer = $notebook->get_current_page;
#$notebook->set_current_page ($notebook_page_num); # see this command on the final 

#################------ItemFactory------################
# Inside the vbox1 we put frame1

###--------------frame1--------------------###
# Adicionamos este frame1 em vbox1
$frame1 = new Gtk2::Frame( $langs{name063} . ": mp3/mp4/mpc/ogg/ape/flac/wav");
# Set the frame's label
# Align the label at the right of the frame
$frame1->set_label_align( 1.0, 0.0 );
# Set the style of the frame
$frame1->set_shadow_type( 'etched_out' );
$vbox1->add($frame1);
$frame1->show();

#adicionamos uma tabela dentro do frame
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
$table1 = new Gtk2::Table (4, 6, 0); 
$table1->set_border_width (4);
$table1->set_row_spacings(4);
$table1->set_col_spacings(4);
$frame1->add( $table1 );
$table1->show;

# on hbox1 we put more two frames: frame11 and frame12
# Gtk2::HBox->new ($homogeneous=0, $spacing=5)
my $hbox1 = Gtk2::HBox->new ($true, 2);
$vbox1->add($hbox1);
$hbox1->show;

###--------------frame11--------------------###
# Adicionamos este frame11 em hbox1
my $frame11 = new Gtk2::Frame($langs{name005});
$frame11->set_label_align( 1.0, 0.0 );
$frame11->set_shadow_type( 'etched_out' );
$hbox1->add($frame11);
$frame11->show();

#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
my $table11 = new Gtk2::Table (2, 2, 0); 
$table11->set_border_width (4);
$table11->set_row_spacings(4);
$table11->set_col_spacings(0);
$frame11->add( $table11 );
$table11->show;

###--------------frame12--------------------###
# Adicionamos este frame12 em hbox1
my $frame12 = new Gtk2::Frame($langs{name006});
$frame12->set_label_align( 1.0, 0.0 );
$frame12->set_shadow_type( 'etched_out' );
$hbox1->add($frame12);
$frame12->show();

my $table12 = new Gtk2::Table (2, 2, 0); 
$table12->set_border_width (4);
$table12->set_row_spacings(6);
$table12->set_col_spacings(2);
$frame12->add( $table12 );
$table12->show;

###--------------frame13--------------------###

# Adicionamos este frame13 em hbox1
my $frame13 = new Gtk2::Frame($langs{name106});
$frame13->set_label_align( 1.0, 0.0 );
$frame13->set_shadow_type( 'etched_out' );
$hbox1->add($frame13);
$frame13->show();

my $table13 = new Gtk2::Table (2, 1, 0); 
$table13->set_border_width (4);
$table13->set_row_spacings(6);
$table13->set_col_spacings(2);
$frame13->add( $table13 );
$table13->show;

###--------------frame2--------------------###
# we put frame2 inside notebook2
my $frame2 = new Gtk2::Frame();
# Align the label at the right of the frame
$frame2->set_label_align( 1.0, 0.0 );
# Set the style of the frame
$frame2->set_shadow_type( 'etched_out' );
#$vbox2->add($frame2);
$frame2->show();

#adicionamos uma tabela dentro do frame
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
my $table2 = new Gtk2::Table (3, 4, 0); 
$table2->set_border_width (4);
$table2->set_row_spacings(4);
$table2->set_col_spacings(10);
$frame2->add( $table2 );
$table2->show;

###--------------frame202--------------------###
# we put frame202 inside notebook2
my $frame202 = new Gtk2::Frame();
$frame202->set_label_align( 1.0, 0.0 );
$frame202->set_shadow_type( 'etched_out' );
$frame202->show();

#adicionamos uma tabela dentro do frame
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
my $table202 = new Gtk2::Table (3, 4, 0); 
$table202->set_border_width (4);
$table202->set_row_spacings(4);
$table202->set_col_spacings(4);
$frame202->add( $table202 );
$table202->show;

###--------------frame203--------------------###
# we put frame203 inside notebook2
my $frame203 = new Gtk2::Frame();
$frame203->set_label_align( 1.0, 0.0 );
$frame203->set_shadow_type( 'etched_out' );
$frame203->show();

#adicionamos uma tabela dentro do frame
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
my $table203 = new Gtk2::Table (3, 4, 0); 
$table203->set_border_width (4);
$table203->set_row_spacings(4);
$table203->set_col_spacings(8);
$frame203->add( $table203 );
$table203->show;

###--------------frame204--------------------###
# we put frame204 inside notebook2
my $frame204 = new Gtk2::Frame("cdparanoia");
$frame204->set_label_align( 1.0, 0.0 );
$frame204->set_shadow_type( 'etched_out' );
$frame204->show();

#adicionamos uma tabela dentro do frame
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
my $table204 = new Gtk2::Table (3, 4, 0); 
$table204->set_border_width (4);
$table204->set_row_spacings(4);
$table204->set_col_spacings(8);
$frame204->add( $table204 );
$table204->show;

###--------------frame205--------------------###
# we put frame205 inside notebook2
my $frame205 = new Gtk2::Frame("cdda2wav");
$frame205->set_label_align( 1.0, 0.0 );
$frame205->set_shadow_type( 'etched_out' );
$frame205->show();

#adicionamos uma tabela dentro do frame
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
my $table205 = new Gtk2::Table (3, 4, 0); 
$table205->set_border_width (4);
$table205->set_row_spacings(4);
$table205->set_col_spacings(8);
$frame205->add( $table205 );
$table205->show;

#-------------------Notebook2----------------#
# we put frame2 inside notebook2
# and we put notebook2 inside vbox2
$notebook2 = Gtk2::Notebook->new; 
# position = 'left', 'right','top', 'bottom'
$notebook2->set( homogeneous => $true  ); # 'tab-hborder' => 20
$notebook2->set_tab_pos( 'left' );

#integer = $notebook2->get_current_page;
#$notebook2->set_current_page ($notebook_page_num2); # see this command on the final 

my $label_option1 = Gtk2::Label->new( $langs{all_tab07} );
my $label_option2 = Gtk2::Label->new( $langs{all_tab08} );
my $label_cddb = Gtk2::Label->new( $langs{all_tab09} );
my $label_ripper = Gtk2::Label->new( $langs{all_tab10} );
#$notebook->append_page_menu ($child, $tab_label, $menu_label)
$notebook2->append_page_menu ( $frame2,   $label_option1, undef );    # option1
$notebook2->append_page_menu ( $frame202, $label_option2, undef );    # option2
$notebook2->append_page_menu ( $frame203, $label_cddb,    undef );    # cddb
if ($ripper eq "cdparanoia"){ $notebook2->append_page_menu ( $frame204, $label_ripper, undef  ); }    # ripper
if ($ripper eq "cdda2wav"  ){ $notebook2->append_page_menu ( $frame205, $label_ripper, undef  ); }    # ripper

# $vbox->pack_start( $child, $expand, $fill, $padding ); 
$vbox2->pack_start( $notebook2, $true, $true, 0 );  
#$vbox2->add( $notebook2 );
$notebook2->show;

###--------------frame21--------------------###
# Adicionamos este frame21 em vbox2 (vbox2 est� dentro do notebook)
my $frame21 = new Gtk2::Frame("lame ".$langs{msg077} );
$frame21->set_label_align( 1.0, 0.0 );
$frame21->set_shadow_type( 'etched_out' );
# $vbox->pack_start( $child, $expand, $fill, $padding ); 
$vbox2->pack_start( $frame21, $true, $true, 0 );  
#$vbox2->add($frame21);
$frame21->show();

#adicionamos uma tabela21 dentro do frame21
my $table21 = new Gtk2::Table (3, 7, $false); 
$table21->set_border_width (4);
$table21->set_row_spacings(4);
$table21->set_col_spacings(4);
$frame21->add( $table21 );
$table21->show;

###----------------hpaned3-----------------###
###-----------------init-------------------###
# see <man Gtk2::Paned>
# Inside the vbox3 we put hpaned3
# and inside hpaned3 we put frame3 and frame31

my $hpaned3 = Gtk2::HPaned->new;
$vbox3->pack_start ($hpaned3, $true, $true, 0);
$hpaned3->set_border_width (0);
$hpaned3->show;

###--------------frame3--------------------###
my $frame3 = new Gtk2::Frame("Tag");
# Align the label at the right of the frame
$frame3->set_label_align( 1.0, 0.0 );
# Set the style of the frame
$frame3->set_shadow_type( 'etched_in' );
$hpaned3->add1 ($frame3);
$frame3->show();

#adicionamos uma tabela dentro do frame
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
my $table3 = new Gtk2::Table (6, 4, 0);
$table3->set_size_request( 350 ,-1 ); # width (70%), height; 
$table3->set_border_width (4);
$table3->set_row_spacings(6);
$table3->set_col_spacings(4);
$frame3->add( $table3 );
$table3->show;

###--------------frame31--------------------###
my $frame31 = new Gtk2::Frame("MP3 Info");
# Align the label at the right of the frame
$frame31->set_label_align( 1.0, 0.0 );
# Set the style of the frame
$frame31->set_shadow_type( 'etched_in' );
$hpaned3->add2 ($frame31);
$frame31->show();

#adicionamos uma tabela dentro do frame
my $table31 = new Gtk2::Table (6, 1, 0); 
#$table31->set_size_request( 144,-1 ); #width,height
$table31->set_border_width (2);
$table31->set_row_spacings(8);
$table31->set_col_spacings(2);
$frame31->add( $table31 );
$table31->show;

# "child1_resize" determines whether the first child 
# should expand when $paned is resized.
$hpaned3->child1_resize ($true);
$hpaned3->child2_resize ($true);

# "If shrink is true, then that child can be made 
# smaller than its requisition by the user."
$hpaned3->child1_shrink($false);
$hpaned3->child2_shrink($true);

###-----------------final------------------###
###----------------hpaned3-----------------###

###------------vpaned-playlist-------------###
###-----------------init-------------------###
# see <man Gtk2::Paned>
# Inside the window we put vpaned
# and inside vpaned we put vbox_up and vbox_down

my $vpaned_play_list = Gtk2::VPaned->new;
$vpaned_play_list->set_border_width (0); 
$vbox4->pack_start( $vpaned_play_list, $true, $true, 0 );  
$vpaned_play_list->show;

###------------ vbox_up playlist -----------###
 
my $vbox_up_play_list = new Gtk2::VBox( $false, 2 );
$vbox_up_play_list->set_border_width( 1 );
$vpaned_play_list->add1 ($vbox_up_play_list);
$vbox_up_play_list->show;

###----------- vbox_down playlist ----------###

#my $vbox_down_play_list = new Gtk2::VBox( $false, 2 );
#$vbox_down_play_list->set_border_width( 1 );
#$vpaned_play_list->add2 ($vbox_down_play_list);
#$vbox_down_play_list->show;

###-----------------------------------------###

# "child1_resize" determines whether the first child 
# should expand when $paned is resized.
$vpaned_play_list->child1_resize ($true);
$vpaned_play_list->child2_resize ($true);

# "If shrink is true, then that child can be made 
# smaller than its requisition by the user."
$vpaned_play_list->child1_shrink($true);
$vpaned_play_list->child2_shrink($true);

###-----------------final------------------###
###------------vpaned-playlist-------------###


###----------------hpaned-----------------###
###-----------------init-------------------###

my $hpaned_play_list = Gtk2::HPaned->new;
$vpaned_play_list->add2 ($hpaned_play_list);
$hpaned_play_list->set_border_width (0);
$hpaned_play_list->show;

###------------ vbox_left playlist -----------###
 
my $vbox_left_play_list = new Gtk2::VBox( $false, 2 );
$vbox_left_play_list->set_border_width( 1 );
$hpaned_play_list->add1 ($vbox_left_play_list);
$vbox_left_play_list->show;

###----------- vbox_right playlist ----------###

my $vbox_right_play_list = new Gtk2::VBox( $false, 2 );
$vbox_right_play_list->set_border_width( 1 );
$hpaned_play_list->add2 ($vbox_right_play_list);
$vbox_right_play_list->show;

###-----------------------------------------###

# "child1_resize" determines whether the first child 
# should expand when $paned is resized.
$hpaned_play_list->child1_resize ($true);
$hpaned_play_list->child2_resize ($true);

# "If shrink is true, then that child can be made 
# smaller than its requisition by the user."
$hpaned_play_list->child1_shrink($true);
$hpaned_play_list->child2_shrink($true);

#$paned->set_position ($position)
$hpaned_play_list->set_position ( int(44*$window_width/100) ); # 44% of $window_width

###-----------------final------------------###
###----------------hpaned3-----------------###


###--------------frame4--------------------###
# frame4 : rip and play Audio files
# Adicionamos este frame4 em vbox4 (vbox4 est dentro do notebook)

use constant COLUMN_RIP        => 0; # check play/rip files
use constant COLUMN_FILE       => 1; # file  = track = row + 1
use constant COLUMN_ARTIST     => 2;
use constant COLUMN_TITLE      => 3;
use constant COLUMN_ALBUM      => 4;
use constant COLUMN_TRACK      => 5; # this is the track number
use constant COLUMN_LENGTH     => 6;
use constant COLUMN_BITRATE    => 7;
use constant COLUMN_YEAR       => 8;
use constant COLUMN_FREQUENCY  => 9;
use constant COLUMN_FILEPATH   => 10;
use constant COLUMN_EXTENSION  => 11;
use constant COLUMN_FILENAME   => 12;
use constant COLUMN_PLAY_COUNT => 13;
use constant COLUMN_COLOR      => 14; # to color the music playing

my $color_row_playing = Gtk2::Gdk::Color->parse('#92D992');        # green
my $color_row_already_played = Gtk2::Gdk::Color->parse('#ADD8E6'); # cyan

# see: /usr/share/doc/perl-Gtk2-1.054/gtk-demo/list_store.pl
my $scrolled_window = Gtk2::ScrolledWindow->new (undef, undef);
$scrolled_window->set_shadow_type ('etched-in');
$scrolled_window->set_policy('automatic', 'always');
$scrolled_window->set_size_request( 100, 120 ); # width, height : minimun size
# $vbox->pack_start( $child, $expand, $fill, $padding ); 
$vbox_up_play_list->pack_start( $scrolled_window, $true, $true, 0 );  
$scrolled_window->show;

# create tree view ;; $treeview_play->get_selection is an Gtk2::TreeSelection 
my $treeview_play = Gtk2::TreeView->new( create_standard_model() ); # start with an empty array
$treeview_play->set ( 'rules-hint'    => $true,  # draw rows in alternating colors
                      'reorderable'   => $false,
		      'enable-search' => $true,
		      #'fixed-height-mode' => $true,
		      'search-column' => COLUMN_ARTIST,
		    );
$treeview_play->get_selection->set_mode ('multiple'); # single,multiple
$treeview_play->get_selection->signal_connect (changed => \&get_selection_tree, $treeview_play);
$treeview_play->signal_connect (button_press_event => \&button_press_event_treeview);
$treeview_play->signal_connect (row_activated => sub { # Double click one track to play it - 10Jun2008
                      my ($treeview, $path, $column) = @_;                      		      		     		      
		      
                      my $model = $treeview->get_model;
                      my $iter  = $model->get_iter ($path) if $path;
		      return unless $iter;
		      
		      if ( $files_info[$selected_row]{playing} ){   # if there are some row_playing, then change its color		      
		         push @rows_already_played, $selected_row;  # my $row_playing = $selected_row;		         		      
                         color_the_selected_tracks_and_scroll( select_color => 'played', scroll => $false, row => $selected_row );
		      }		      		                            
		      my $row = $model->get_value($iter,COLUMN_FILE) - 1;
		      #print "\$row = $row ; last \$selected_row = $selected_row \$treeview = $treeview ; \$path = $path ; \$column = $column\n"; 		      
		      $selected_row = $row;  # This $selected_row will be played.
		      
		      $go_forward = $true;  # See 'sub go_forward'
		      play_selection( skip => 0 );		                            
		      $go_forward = $false;		           
                });			
				
$treeview_play->set_search_equal_func ( sub {
                      my ($ListStore,$column,$search_name,$iter) = @_;		    
		      my $artist = $ListStore->get_value($iter,COLUMN_ARTIST);
		      my $row = $ListStore->get_value($iter,COLUMN_FILE) - 1;
		      #my $num = $ListStore->iter_n_children; # model size		    		    
		      if ( $artist =~ /$search_name/i ){
		         return $false; # to abandon the loop  	       
		      }
		      return $true; # to don't abandon the loop
		});
$treeview_play->columns_autosize;   # lost the performance
$treeview_play->show;												
	 
# add tree view to the ScrolledWindow
$scrolled_window->add ($treeview_play);

sub create_model_audio_cd {
   my @array = @_;
   @files_info = ();              # reset the array
   %albums_already_played = ();   # reset the hash whose key is only the played album name
   %artists_already_played = ();  # reset the hash whose key is only the played artist name
   $selected_row = 0;
	 
   # making array of array references - see <man perllol>
   for (my $i=0;$i<$#array+1;$i++){
      my $num = sprintf("%02d", $i+1);
      push @files_info, {
	                 rip    => $true,
			 file   => $num,
	                 track  => $num,
			 artist => "artist",
			 title  => "music title",		 
			 album  => "album",
			 comment     => '',	  	                 
			 year        => '',
			 total_track => $#array + 1,
			 genre       => "Other",
			 length      => "$array[$i]",
			 		 			 
			 #filepath    => "$audiodevice_path/$num".".cda", # mar2008			 
			 #directory_remain => "$audiodevice_path",			 
			 #filename    => "$num".".cda",
			 
			 # set all the 7 technical informations for cda:
			 technical_info  => "Audio CD",
			 bitrate         => "1411",
			 frequency       => "44100",
			 bitrate_average => $false,
			 mode            => $audio_cd_channel,
			 cda_total_time  => $audio_cd_total_time, # only for cda
			 fileSize        => $audio_cd_fileSize,			 
			 
			 extension_input => "cda",
			 editable  => $true,
			 show      => $true,
			 remove    => $false, #remove from playlist
			 playing   => $false,
			 played    => 0,			 
      };      
   }
     
   for (my $i=0;$i<$#array+1;$i++){ 
      $files_info[$i]{filepath} = make_filepath_format_for_cda($i);          
      $files_info[$i]{filename} = make_filename_format_for_cda($i);  
      $files_info[$i]{directory_remain} = remove_directory_base($audiodevice_path,$files_info[$i]{filepath});
   }   
   #my $model = create_standard_model(@files_info);
   my $model = create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@files_info );
   
   return $model;
}
   

sub make_filepath_format_for_cda {
   my $row = shift;
   
   # Filename format for rip Audio CD
   # %t = title of song; %a = artist; %b = album; %c = comment
   # %n = track number; %y = year; %g = genre 
   # $file_format = "%a-%n-%t";
   my $file_format = $entry_format_cda->get_text;
   
   if ($file_format !~ /(%t|%a|%b|%n|%y|%g)/ig){$file_format = "%n";}
   $file_format =~ s/%t/$files_info[$row]{title}/ig;
   $file_format =~ s/%a/$files_info[$row]{artist}/ig;
   $file_format =~ s/%b/$files_info[$row]{album}/ig;
   $file_format =~ s/%n/$files_info[$row]{track}/ig;
   $file_format =~ s/%y/$files_info[$row]{year}/ig;
   $file_format =~ s/%g/$files_info[$row]{genre}/ig;   
   
   my $filepath = '/' . $audiodevice_path . '/' . $file_format . '.cda';
   $filepath =~ s/\/{2,}/\//g;  # change two or more '//' character for one '/'
   
   $filepath = remove_9_chars_and_let_1($filepath); # Do not change the character '/'.
   
   return $filepath;
}

sub make_filename_format_for_cda {
   my $row = shift;
   
   # Filename format for rip Audio CD
   # %t = title of song; %a = artist; %b = album; %c = comment
   # %n = track number; %y = year; %g = genre 
   # $file_format = "%a-%n-%t";
   my $file_format = $entry_format_cda->get_text;
   
   if ($file_format !~ /(%t|%a|%b|%n|%y|%g)/ig){$file_format = "%n";}
   $file_format =~ s/%t/$files_info[$row]{title}/ig;
   $file_format =~ s/%a/$files_info[$row]{artist}/ig;
   $file_format =~ s/%b/$files_info[$row]{album}/ig;
   $file_format =~ s/%n/$files_info[$row]{track}/ig;
   $file_format =~ s/%y/$files_info[$row]{year}/ig;
   $file_format =~ s/%g/$files_info[$row]{genre}/ig;
   
   my $filename = $file_format . '.cda';
   $filename =~ s/\/{2,}/\//g;      # change two or more '//' character for one '/'
   $filename =~ s/(.*\/)(.*)/$2/g;  # (path/)(filename): copy (path/)(filename) and get (filename)
   
   $filename = remove_change_10_chars($filename);
   
   return $filename;
}

sub remove_change_10_chars { # 18Jun2008
   my $text = shift;
   return unless defined $text;
   
   # 9 Windows Prohibited Characters      :  \/:*?"<>|
   # 1 perl Prohibited Character          :  $
   # Some Permited Characters in filenames:  =^~;!@#%`   
   #$text = 'Testo/{`:claudiofsr@yahoo.com;"}!$!?[]<|>&#*.com\/=6/1/Sfigato'; # only to test

   $text =~ s/[\\\/:*?|\$\015]/_/g;   # replace the 7 characters \/:*?|$ with underscore _. See 'man perlretut'.
   $text =~ s/[`"]/'/g;                    # substitute the characters " or ` by '
   $text =~ tr/<>/[]/;                     # replace the characters <> with []. See 'man perlop'.
   
   #$text =~ s/[^[:print:]]/_/g;           # replace unprintable characters with underscores.   
   #print "remove_change_10_chars --> \$text = $text\n";   
   return $text;
}

sub remove_9_chars_and_let_1 { # 18Jun2008 - Do not change the character '/'.
   my $text = shift;
   return unless defined $text;
   
   # 9 Windows Prohibited Characters in filenames:  \/:*?"<>|
   # 1 perl Prohibited Character                 :  $
   # Remove/Change 9 Characters  \:*?"<>|$ in filenames and let 1 Characters /

   $text =~ s/[\\:*?|\$]/_/g;   # replace the 6 characters \:*?|$ with underscore _. See 'man perlretut'.
   $text =~ s/[`"]/'/g;         # substitute the characters " or ` by '
   $text =~ tr/<>/[]/;          # replace the characters <> with []. See 'man perlop'.
     
   return $text;
}

sub remove_directory_base {
    my ($dir_base,$file) = @_;    
    ( my $dir = $file ) =~ s/(.*\/)(.*)/$1/g;  # supose that $file = (/path1/path2/path3/path4/)(filename). So remove (filename) from full path.
    $dir =~ s/^\Q$dir_base\E//;                # supose that $directory_base = (/path1/path2), then directory_ramin = (/path3/path4/)
    
    # Caution with metacharacters: {}[]()^$.|*+?\ 
    # To match this metacharacters use the escape sequence "\Q"..."\E" (see man perlretut)
    return $dir;
}

sub create_model_files_to_be_played {  # add more file to @files_info(); player mode
   
   if ( not defined $files_info[0]{file} ){ @files_info = (); }      
   #print "--->  n = ",$#files_info + 1,"\n";
   my $music_number = $#files_info + 1;  # inicial size   
   
   my $j = 0;    
   for (my $i = 0; $i <= $#array_of_files; $i++){  # ($#array_of_files + 1) or @array is the size      	               	
			
      my %hash = determine_directory_and_filename_and_extension(filepath => $array_of_files[$i]);
      my $extension_input = $hash{extension_input};
      
      my $mesg = filename_from_unicode "\n<$array_of_files[$i]> : Not found a player to $extension_input files!\n";
      my $playable = $true;
      
      if    ($extension_input eq 'mp3'  and not ($mpg123_path or $mpg321_path or $madplay_path or $mplayer_path) ){ $playable = $false; }
      elsif ($extension_input eq 'mp4'  and not $mplayer_path                                                    ){ $playable = $false; }
      elsif ($extension_input eq 'mpc'  and not ($mpcdec_path or $mplayer_path)                                  ){ $playable = $false; }
      elsif ($extension_input eq 'ogg'  and not ($ogg123_path or $mplayer_path)                                  ){ $playable = $false; }
      elsif ($extension_input eq 'ape'  and not ( ($ape_path and ($play_path or $aplay_path)) or $mplayer_path ) ){ $playable = $false; }
      elsif ($extension_input eq 'flac' and not ($flac123_path or $mplayer_path)                                 ){ $playable = $false; }
      elsif ($extension_input eq 'wav'  and not ($aplay_path or $mplayer_path)                                   ){ $playable = $false; }       
      
      if ($playable) { $j += 1; }
      else { print $mesg; next; }
      
      # making array with anonymous hashes - see <man perlref> 
      push @files_info, { 
                          rip       => $true,
	                  file      => $j + $music_number,
			  
	                  filepath         => $array_of_files[$i],			  
			  #filepath        => eval_to_unicode($array_of_files[$i]),
                          #filepath_local   => $array_of_files[$i],
			  
			  directory_remain => remove_directory_base($directory_base,$array_of_files[$i]),
			  filename         => $hash{filename},
			  directory        => $hash{directory},			  
			  extension_input  => $extension_input,
			  			  			  			  			  
			  editable  => $true,
			  show      => $true,
			  remove    => $false, #remove from playlist
			  playing   => $false,
			  played    => 0,
                        };
   }

   for (my $row = $music_number; $row <= $#files_info ; $row++){    
			
      # use the new Gtk2::FileChooser 
      my $total_files = $#files_info + 1 - $music_number;
      my $cont = $row + 1 - $music_number;  
      my $percentage  = number_value( sprintf("%.2f", ( $cont/$total_files ) ) );
      my $percentage2 = number_value( sprintf("%.2f", ( $cont/$total_files * 100) ) );
      my $filename = $files_info[$row]{filename};
	 
      $label_pct->set_label("$cont/$total_files (${percentage2}%)");                      
	  
      $progbar_files_info->set_text( reduce_length_size($filename, 100) );  # Gtk2::ProgressBar to show file info
      $progbar_files_info->set_fraction ($percentage);                      # $fraction (double)
      
      #printf "Percentage = $percentage ; filename = $filename\n";      
      #print "\ncreate_model_files_to_be_played --> \$music_number = $music_number;new files = $total_files;\$cont = $cont\n";
      
      get_info_from_file( row => $row,
                          filepath => $files_info[$row]{filepath},
                          extension_input => $files_info[$row]{extension_input},
			  show_tag => $false,
                        );
      
      while (Gtk2->events_pending) {Gtk2->main_iteration};            						 
   
   # get the 8 tags   
   #$files_info[$row]{title}  = $Title;
   #$files_info[$row]{artist}  = $Artist;  
   #$files_info[$row]{album}  = $Album; 
   #$files_info[$row]{track}  = $Track_Number; 
   #$files_info[$row]{total_track}  = $Total_Track; 
   #$files_info[$row]{comment}  = $Comment;
   #$files_info[$row]{year}  = $Year;  
   #$files_info[$row]{genre}  = $Genre; 
   # get all technical informations:
   #$files_info[$row]{technical_info}  = $Technical_Info;
   #$files_info[$row]{bitrate}  = $bitrate_original;
   #$files_info[$row]{bitrate_average}  = $bitrate_average; 
   #$files_info[$row]{frequency}  = $Frequency;  
   #$files_info[$row]{mode}  = $mode_channel; 
   #$files_info[$row]{length}  = $Time_Min_Sec;   
   #$files_info[$row]{fileSize}  = $fileSize;     
   }
   
   # get all artists/albums one times only   
   #for (my $i = 0; $i <= $#files_info; $i++){
   
      # $hash{'artist_names'} = [artist_1,artist_2, ..., artist_n]; # anonymous array 
      # To append a new value: push @{ $hash{'artist_names'} }, $row;
      #my @artists = return_artist_name($files_info[$i]); # $files_info[$i] is a hash
      #foreach my $art (@artists) { push @{ $files_info[$i]{artist_names} }, $art; }
	     	  
      #$files_info[$i]{album_names} = return_album_name($files_info[$i]);
   #}   
          
   #my $model = create_standard_model(@files_info);
   my $model = create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@files_info );
   
   return $model;	
}

my %treeview_play_rows;   # used to find $iter and $path without need to search inside all treeview using loop.
my %treeview_artist_rows;
my %treeview_album_rows;
#create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@files_info );

sub create_standard_model {  # 12Jun2008
   my %args = (  treeview            => 'treeview_play', # default value
                 array_with_hash_ref => undef,
                 @_,                 # argument pair list goes here
   );
   my $model = Gtk2::ListStore->new ('Glib::Boolean', # => G_TYPE_BOOLEAN	                             
                                     'Glib::Uint',    # => G_TYPE_UINT
				     'Glib::String',
				     'Glib::String',  # => G_TYPE_STRING
                                     'Glib::String',  # => G_TYPE_STRING
                                     'Glib::String',  # you get the idea				     
				     'Glib::String', 'Glib::Uint',   # length, bitrate
				     'Glib::String', 'Glib::Uint',   # year, freq , Glib::Double
				     'Glib::String', 'Glib::String', # filepath, extension_input
				     'Glib::String',                 # filename
				     'Glib::Uint',                   # count play times
				     'Gtk2::Gdk::Color',             # to select one color
				    );

   my $rrow = 0; # relative row that is showed on treeview

   if    ( $args{treeview} eq 'treeview_play'   ) { %treeview_play_rows   = ();  }
   elsif ( $args{treeview} eq 'treeview_artist' ) { %treeview_artist_rows = () ; }
   elsif ( $args{treeview} eq 'treeview_album'  ) { %treeview_album_rows  = () ; }
		    
   # append more data to the list store            
   foreach my $hash ( @{$args{array_with_hash_ref}} ) {  # print "\$hash->{file} = $hash->{file} ; \$hash->{rip} = $hash->{rip}\n"; 
      next if ($hash->{remove});

      my $iter = $model->append;
      $model->set ($iter,
		     COLUMN_RIP,       $hash->{rip},  # rip or play
		     COLUMN_FILE,      $hash->{file}, # file number. The total row number is: row = $hash->{file} - 1
                     COLUMN_TRACK,     $hash->{track},
		     COLUMN_ARTIST,    $hash->{artist},
	             COLUMN_TITLE,     $hash->{title},
		     COLUMN_ALBUM,     $hash->{album},
	             COLUMN_LENGTH,    $hash->{length},		   	
		     COLUMN_BITRATE,   $hash->{bitrate},		   
		     COLUMN_YEAR,      $hash->{year},		   	
		     COLUMN_FREQUENCY, $hash->{frequency},		     	   	
                     COLUMN_FILEPATH,  $hash->{filepath},		     
		    #COLUMN_FILEPATH,  $hash->{directory_remain},
		     COLUMN_EXTENSION, $hash->{extension_input},		     
		     COLUMN_FILENAME,  $hash->{filename},
		     COLUMN_PLAY_COUNT,$hash->{played}, # played n times
		     COLUMN_COLOR,     $hash->{playing} ? $color_row_playing : 
		                       $hash->{played}  ? $color_row_already_played : undef, # undef: without color; this column is hidden
                  );      
      
      if    ( $args{treeview} eq 'treeview_play'   ) { $treeview_play_rows  { $hash->{file} - 1     } = $rrow; } # row = track - 1
      elsif ( $args{treeview} eq 'treeview_artist' ) { $treeview_artist_rows{ uc( $hash->{artist} ) } = $rrow; }
      elsif ( $args{treeview} eq 'treeview_album'  ) { $treeview_album_rows { uc( $hash->{album} )  } = $rrow; }
      
      #if    ( $args{treeview} eq 'treeview_artist' ) { print "\$treeview_artist_rows{ $hash->{artist} } = $treeview_artist_rows{ uc( $hash->{artist} ) } \n"; }
      #elsif ( $args{treeview} eq 'treeview_album'  ) { print "\$treeview_album_rows{ $hash->{album} } = $treeview_album_rows{ uc( $hash->{album} ) } \n";     }
      
      $rrow += 1;
      #print "\$hash->{artist} = $hash->{artist} ; \$hash->{played} = $hash->{played}\n";
   }
   return $model;	
}


my $treeview_artist; 
my $renderer_artist_playlist; my $column_artist_playlist;  my $renderer_artist_play_count;
my $renderer_album_playlist;  my $column_album_playlist;   my $renderer_album_play_count;

###-------------- scrolled_window_album ------------###
###---------------------- start --------------------###

my $scrolled_window_album = Gtk2::ScrolledWindow->new (undef, undef);
$scrolled_window_album->set_shadow_type ('etched-in');
$scrolled_window_album->set_policy('automatic', 'always');
$scrolled_window_album->set_size_request( 80, 60 ); # width, height : minimun size
# $vbox->pack_start( $child, $expand, $fill, $padding ); 
$vbox_right_play_list->pack_start( $scrolled_window_album, $true, $true, 0 );  
$scrolled_window_album->show;

# create tree view
my $treeview_album = Gtk2::TreeView->new( create_standard_model() ); # start with an empty array
$treeview_album->set ( 'rules-hint'  => $true,  # draw rows in alternating colors
                       'reorderable' => $false, 
		     );
#$treeview_album->set_search_column (COLUMN_ALBUM);
$treeview_album->get_selection->set_mode ('multiple'); # single,multiple
$treeview_album->get_selection->signal_connect (changed => \&selection_album);
$treeview_album->show;	 
# add tree view to the ScrolledWindow
$scrolled_window_album->add ($treeview_album);

# album column
   $renderer_album_playlist = Gtk2::CellRendererText->new;
   $renderer_album_playlist->set_data (column => COLUMN_ALBUM);
   $renderer_album_playlist->set ('font' => $window_font_name, style => 'italic', scale => '0.9');
     
   $column_album_playlist = Gtk2::TreeViewColumn->new_with_attributes ($langs{name053}, $renderer_album_playlist, text => COLUMN_ALBUM,
                                                                       'cell-background-gdk' => COLUMN_COLOR);
   $column_album_playlist->set_resizable ($true);
   $column_album_playlist->set (alignment => 0.0); # Alignment of the column header text
   $column_album_playlist->set_expand ($true);     # this column expand to max width
   $column_album_playlist->set_sort_column_id (COLUMN_ALBUM);
   $treeview_album->insert_column ($column_album_playlist, COLUMN_ALBUM);

#add_columns_album_artist( column_show_play_count => $column_show_play_count);

#-----------------------------------------------------#

#my %albums_already_played;             # hash whose key is only the played album name
#$albums_already_played{uc($album)}++;  # Set True to the album already played
#if ( $albums_already_played{uc($album)} ){ }

#-----------------------------------------------------#
# See "The Schwartzian Transform" -- "Learning Perl Objects, References, and Modules", Chap.7.4, First Edition
# See "Perl CookBook, Chap 4.16 and 'A Fresh Look at Efficient Perl Sorting' by Uri Guttman and Larry Rosler.
# Perl's simple sort function is O(N) efficiency order.
# Perl's advanced sort function, like sort { uc($a) cmp uc($b) },  is O(N*logN) efficiency order.
# The 'packed-default sort' technique is quasi-O(N) behavior.

# To obtain an array without repeated values: my %unique = map {$_ => 1}, @numbers;
# search for all differents albums "efficiently". Eficincia: uso racional do recursos, cpu, processamento.

sub all_albums2 {  # Using the 'Schwartzian Transform sort' technique. - Not used
   my @array_of_hash = @_;  # @files_info
   if ( not defined $array_of_hash[0]{album} ){ return; }
   
   my %seen = ();  # hash ; save all differents albums indicating the total songs inside each album 
	      
   my @temp = map  { album => $_->[0] , played => $albums_already_played{uc($_->[0])} }, # set 'played' to False if $albums_already_played{uc($_)} is undef
              sort { $a->[1] cmp $b->[1] }     # sort the uc(album name); all elements are already differents
              map  [ $_, uc($_) ],             # Sort the references to anonymous arrays that contain the original data $_ and the uc($_).
	      #keys %{{ map {return_album_name($_) => 1} @array_of_hash }}; 
              grep { not $seen{uc($_)} ++ }    # Eliminate duplicate values from a list; Perl CookBook , Chap 4.7	      
	      map  return_album_name($_),      # $_ is an element of @array_of_hash
	      @array_of_hash; 	      
	      
   #foreach my $k (sort keys %seen){ print "$k => $seen{$k} songs\n"; }
      
   my @all_albums = ( { album => 'All' , played => 0 } );  # 'All' is Always the first element
   push @all_albums, @temp;
   
   #foreach my $alb (@all_albums) { print "\$alb->{album} = $alb->{album}\n";  }         
   return @all_albums;
}

sub all_albums3 {  # Using the 'packed-default sort' technique. - Not used
   my @array_of_hash = @_;  # @files_info
   if ( not defined $array_of_hash[0]{album} ){ return; }
   
   my %seen = ();  # hash ; save all differents albums indicating the total songs inside each album 
	      
   my @temp = map  { album => $_->[0] , played => $albums_already_played{uc($_->[0])} }, # set 'played' to False if $albums_already_played{uc($_)} is undef	      
	      sort { $a->[1] cmp $b->[1] }
              map  [ $_, pack( 'C4' => /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ) . uc($_) ],	       
              keys %{{ map {return_album_name($_) => 1} @array_of_hash }};      
  
  # The 'packed-default sort' is a little-known optimization that improves on the Schwartzian Transform (ST) by eliminating the sortsub itself, 
  # relying on the default lexicographic sort, which is very efficient. This is the method used in the new Sort::Maker module.
  # The packed-default sort is about twice as fast as the ST, which is the fastest familiar Perl sorting algorithm.
      
   my @all_albums = ( { album => 'All' , played => 0 } );  # 'All' is Always the first element
   push @all_albums, @temp;
   
   #foreach my $alb (@all_albums) { print "\$alb->{album} = $alb->{album}\n";  }         
   return @all_albums;
}

sub all_albums {  # Using 'My Best' technique.
   my @array_of_hash = @_;  # @files_info
   if ( not defined $array_of_hash[0]{album} ){ return; }   
   
   #my %unique  = map { uc(return_album_name($_)) => return_album_name($_) } @array_of_hash;  # use the 'sub return_album_name' 2*N times 
   my %unique1 = map { return_album_name($_) => 1  } @array_of_hash; # Eliminate duplicate values from a list.
   my %unique2 = map { NFKD(uc($_))          => $_ } keys %unique1;  # Sort the keys and get the values from hash.
      
   my @all_albums = ( { album => 'All' , played => 0 } );   # 'All' is Always the first element      
   foreach (sort keys %unique2){                            # sort compared lexicographically improves the performance of all sorting techniques
      push @all_albums, { album => $unique2{$_} , played => $albums_already_played{uc($unique2{$_})} };
      #print "$_ => $unique{$_} \n";       # set 'played' = 0 if album not played.
   }        
   return @all_albums;
}

sub return_album_name { 
   my $hash = shift;
   my $album = $hash->{album};
   if ($album eq ""){                                                      # if the album name is empty
      ($album = $hash->{filepath}) =~ s/.*\/(.*)\/.*$/\(directory\)$1/go;  # get the last directory name 
   }
   return $album;
}

# get treeview_album selection and return the tracks inside the selected album
sub selection_album {
   my $model = $treeview_album->get_model;
   my $tree_selection = $treeview_album->get_selection;
   my @paths = $tree_selection->get_selected_rows; # sel = Gtk2::TreePath
   return unless @paths;
   
   my %albums_selected;  # hash whose key is the album name
   foreach my $path (@paths){
      my $iter = $model->get_iter($path);
      next unless $iter;
      my $album = $model->get_value($iter,COLUMN_ALBUM);
      $albums_selected{uc($album)}++;  # Set True to the album name;  See 'Programming Perl', 24.2, 3a. Ed, "Efficiency"
   }
   #foreach my $alb (keys %albums_selected) { print "albums = $alb\n"; }  
   my @tracks_in_the_album;
   
   LOOP:for (my $i = 0; $i <= $#files_info; $i++){      
      next if $files_info[$i]->{remove};                       # create_standard_model will filter this.
      my $album_guess = return_album_name($files_info[$i]);    # if no album name, create a guess name from filepath

      if ( $albums_selected{uc($album_guess)} or $albums_selected{uc('All')} ){  # Search for all tracks inside this album	 
         push @tracks_in_the_album, $files_info[$i];
	 next LOOP; 	          
      }
   }     
   return if (@tracks_in_the_album <= 0);  
   
   # add new files to tree model
   #$model = create_standard_model(@tracks_in_the_album);
   $model = create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@tracks_in_the_album );
    
   $treeview_play->set_model($model);   # add the new model
   #$treeview_play->columns_autosize;   # lost the performance
   
   count_artists_and_album_already_played(update_model_artist => $false, update_model_album => $true);

   #foreach (@tracks_in_the_album){print " --> array = \"$_->{artist}\"\n";}    
   make_artist_and_album_treeview_column( make_artist_column => $true, make_album_column => $false, array_with_tracks => \@tracks_in_the_album ); 
   
   return unless $playing_music;
   color_the_selected_tracks_and_scroll( select_color => 'playing', color_album => $false ); 
}

sub make_artist_and_album_treeview_column {   # make artist and album treeview column with an array
   my %args = ( make_artist_column => $true,
                make_album_column  => $true,
		array_with_tracks  => undef,  # reference to array with hash
                @_,     # argument pair list goes here
	      );        
   my @selected_info = @{$args{array_with_tracks}};         # get array from reference_to_array
   return unless defined $selected_info[0]{file};   	      	      
   my ( $new_title, $model );
    
   if ( $args{make_artist_column} ){   
      my @all_dif_artist = all_artists( @selected_info );    # search for all differents artists     
      $model = create_standard_model ( treeview => 'treeview_artist', array_with_hash_ref => \@all_dif_artist );
      
      $treeview_artist->set_model($model);                  # add the new model
      $new_title = @all_dif_artist > 0 ? $langs{name046} ." ($#all_dif_artist)" : $langs{name046} ;
      $column_artist_playlist->set_title( $new_title );     # artist (number)
   }
   if ( $args{make_album_column} ){    
      my @all_dif_album = all_albums( @selected_info );     # search for all differents albums
      $model = create_standard_model ( treeview => 'treeview_album', array_with_hash_ref => \@all_dif_album );
      
      $treeview_album->set_model($model);                   # add the new model
      $new_title = @all_dif_album > 0 ? $langs{name053} ." ($#all_dif_album)" : $langs{name053} ;
      $column_album_playlist->set_title( $new_title );      # album (number)
   }
}

sub count_artists_and_album_already_played { # 09Jun2008
   my %args = ( update_model_artist  => $false,
		update_model_album   => $false,
                @_,  # argument pair list goes here
	      );
   my $model;      
   my @rows_checked   = ();
   my @rows_unchecked = ();
   
   for (my $row = 0; $row <= $#files_info; $row++){
      if ($files_info[$row]{rip} eq $true){ push @rows_checked,   $row; }  # Get array_with_files_checked
      else                                { push @rows_unchecked, $row; }  # To fill with the unchecked rows;
   }
   
   %artists_already_played = ();  # played artists count
   %albums_already_played  = ();  # played albums count
   my $debug = $false;            # to print messages
   
   print "\n\n --> count_artists_and_album_already_played:\n" if $debug;      
   
   # refresh Play Count artist
   
   foreach my $row (@rows_checked){
      my @artists = return_artist_name($files_info[$row]); 	  
      foreach my $art (@artists) { $artists_already_played{ uc($art) }  = 0; }  # Set = 0 if artist not played
   }   
   foreach my $row (@rows_unchecked){
      my @artists = return_artist_name($files_info[$row]);
      foreach my $art (@artists) { $artists_already_played{ uc($art) } += 1; }  # Add +1
   }
      
   #($iter, $path) = get_iter_path_given_track_art_alb ( artist => $artist, treeview => 'treeview_artist' );	 
   #$model->set ( $iter, COLUMN_COLOR, $color ) if $iter;  # to color the selected artist line 
      
   if ( $args{update_model_artist} ){
      $model = $treeview_artist->get_model;
      $model->foreach( sub{  # model is a $ListStore
         my($ListStore,$path,$iter) = @_;
         my $artist = $model->get ( $iter, COLUMN_ARTIST) if $iter; 
         $model->set ( $iter, COLUMN_PLAY_COUNT, $artists_already_played{ uc($artist) } ) if $iter;  # to color the selected artist line 
         print "artists = $artist ; \$artists_play_count{$artist} = $artists_already_played{uc($artist)}\n" if $debug;
         return $false; # to don't abandon the loop	      
      } );
   }   

   # refresh Play Count album
   
   foreach my $row (@rows_checked){     
      my $album = return_album_name($files_info[$row]); # if no album name, create a guess name from filepath  
      $albums_already_played{ uc($album) }  = 0;        # Set = 0 if album not played
   }   
   foreach my $row (@rows_unchecked){
      my $album = return_album_name($files_info[$row]); # if no album name, create a guess name from filepath  	     	  
      $albums_already_played{ uc($album) } += 1;        # Add +1
   }
      
   if ( $args{update_model_album} ){
      $model = $treeview_album->get_model;
      $model->foreach( sub{  # model is a $ListStore
         my($ListStore,$path,$iter) = @_;
         my $album = $model->get ( $iter, COLUMN_ALBUM) if $iter; 
         $model->set ( $iter, COLUMN_PLAY_COUNT, $albums_already_played{ uc($album) } ) if $iter;   # to color the selected artist line 
         print "album = $album ; \$albums_already_played{$album} = $albums_already_played{uc($album)}\n" if $debug;
         return $false; # to don't abandon the loop	      
      } );
   }     
}

###---------------------- final --------------------###
###-------------- scrolled_window_album ------------###

###-------------- scrolled_window_artist ------------###
###---------------------- start --------------------###

my $scrolled_window_artist = Gtk2::ScrolledWindow->new (undef, undef);
$scrolled_window_artist->set_shadow_type ('etched-in');
$scrolled_window_artist->set_policy ('automatic', 'always');
$scrolled_window_artist->set_size_request( 80, 20 ); # width, height : minimun size
# $vbox->pack_start( $child, $expand, $fill, $padding ); 
$vbox_left_play_list->pack_start( $scrolled_window_artist, $true, $true, 0 );  
$scrolled_window_artist->show;

# create tree view
$treeview_artist = Gtk2::TreeView->new( create_standard_model() ); # start with an empty array
$treeview_artist->set ( 'rules-hint'  => $true,  # draw rows in alternating colors
                        'reorderable' => $false, 
		      );
#$treeview_artist->set_search_column (COLUMN_ARTIST);
$treeview_artist->get_selection->set_mode ('multiple'); # single,multiple
$treeview_artist->get_selection->signal_connect (changed => \&selection_artist);
$treeview_artist->show;	 
# add tree view to the ScrolledWindow
$scrolled_window_artist->add ($treeview_artist);

   # artist column
   $renderer_artist_playlist = Gtk2::CellRendererText->new;
   $renderer_artist_playlist->set_data (column => COLUMN_ARTIST);
   $renderer_artist_playlist->set ('font' => $window_font_name, style => 'italic', scale => '0.9');
     
   $column_artist_playlist = Gtk2::TreeViewColumn->new_with_attributes ($langs{name046}, $renderer_artist_playlist, text => COLUMN_ARTIST,
                                                                        'cell-background-gdk' => COLUMN_COLOR);
   $column_artist_playlist->set_resizable ($true);
   $column_artist_playlist->set (alignment => 0.0); # Alignment of the column header text
   $column_artist_playlist->set_expand ($true);     # this column expand to max width
   $column_artist_playlist->set_sort_column_id (COLUMN_ARTIST);
   $treeview_artist->insert_column ($column_artist_playlist, COLUMN_ARTIST);

add_columns_album_artist( column_show_play_count => $column_show_play_count); 

#-----------------------------------------------------#

#my %artists_already_played;              # hash whose key is only the played artist name
#$artists_already_played{uc($artist)}++;  # Set True to the artist already played

#-----------------------------------------------------#

sub all_artists {
   my @array_of_hash = @_;
   if ( not defined $array_of_hash[0]{artist} ){ return; }
   
   my @all_art = map return_artist_name($_), @array_of_hash;
   my %unique  = map { NFKD(uc($_)) => $_ }  @all_art;        # Eliminate duplicate values from a list;
   
   my @all_artists = ( { artist => 'All' , played => 0 } );   # 'All' is Always the first element      
   foreach (sort keys %unique){                               # sort compared lexicographically improves the performance of all sorting techniques      
      push @all_artists, { artist => $unique{$_} , played => $artists_already_played{ uc($unique{$_}) } };      
      #print "$_ => $unique{$_} \n";
   }        
   return @all_artists;
}


sub return_artist_name {
   my $hash = shift;
   return undef if not $hash->{artist};          # 'if not' == 'unless'
   return split (/\s*&\s*/, $hash->{artist});    # split 'artist1 & artist2 & ...' to 'artist1,artist2,...'
}

# get treeview_artist selection and return the track selected
sub selection_artist {
   my $model = $treeview_artist->get_model;
   my $tree_selection = $treeview_artist->get_selection;
   my @paths = $tree_selection->get_selected_rows; # sel = Gtk2::TreePath
   return unless @paths;
   
   my %artists_selected;
   foreach my $path (@paths){
      my $iter = $model->get_iter($path);
      next unless $iter;
      my $artist = $model->get_value($iter,COLUMN_ARTIST);
      $artists_selected{uc($artist)}++;  # See 'Programming Perl', 24.2, 3a. Ed, "Efficiency"
   }  
   my @tracks_with_artist; 
   
   LOOP:for (my $i = 0; $i <= $#files_info; $i++){
      next if $files_info[$i]->{remove};
      my @artist_cmp = return_artist_name($files_info[$i]); # 'art1 & art2' return (art1,art2)
      
      foreach my $art (@artist_cmp){
	 if ( $artists_selected{uc($art)} or $artists_selected{uc('All')} ){
	    push @tracks_with_artist, $files_info[$i];
	    next LOOP; # to not select the same files_info, not duplicate
         }
      }
   }     
   return if (@tracks_with_artist <= 0);        
   
   # add new files to tree model
   #$model = create_standard_model(@tracks_with_artist);	
   $model = create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@tracks_with_artist );
   
   $treeview_play->set_model($model); # add the new model
   #$treeview_play->columns_autosize;
   
   count_artists_and_album_already_played(update_model_artist => $true, update_model_album => $false);
      
   #my $row = $tracks_with_artist[0]{file} - 1; # [0] is the fisrt track
   make_artist_and_album_treeview_column( make_artist_column => $false, make_album_column => $true, array_with_tracks => \@tracks_with_artist );
   
   return unless $playing_music;
   color_the_selected_tracks_and_scroll( select_color => 'playing', color_artist => $false );
}

#-----------------------------------------------------#
my @paths_button; # to save the selected rows

sub button_press_event_treeview { # see /usr/share/doc/perl-Gtk2-1.083/examples/multisel.pl 
   my ($widget, $event, $data) = @_;    # $widget = Gtk2::TreeView
   @paths_button = ();
   return unless ($event->button >= 3); # Press mouse button 3 ; see <man Glib>
  
   my $selection = $widget->get_selection;     
   @paths_button = $selection->get_selected_rows; # sel = Gtk2::TreePath
   #my @sel_rows = map $_->to_string, @paths_button;
   #print "\n button3 ---> \@sel_rows = @sel_rows";
   return unless @paths_button;
   
   # [[$treeview_play->get_selection]] is an Gtk2::TreeSelection  
   #$treeview_play->get_selection->unselect_all;
                  
   my $menu = Gtk2::Menu->new;     
   my $item = Gtk2::ImageMenuItem->new("$langs{msg092}");   # "remove this music from list"
   $item->set_image( Gtk2::Image->new_from_stock ('gtk-delete','menu') );
   $item->signal_connect( "activate", \&remove_item_from_playlist, $treeview_play );
   $menu->append($item);       
   # $menu->popup ($parent_menu_shell, $parent_menu_item, $menu_pos_func, $data, $button, $activate_time)
   $menu->popup(undef, undef, undef,undef,$event->button,$event->time);
   $menu->show_all;         			      
}

# $button->signal_connect (clicked => \&remove_item, $treeview);
sub remove_item_from_playlist {  # See /usr/share/doc/perl-Gtk2-1.083/gtk-demo/editable_cells.pl
  my ($widget, $treeview) = @_;
  my $model = $treeview->get_model;
  $treeview->set_reorderable ($true);
  
  #while (@paths_button > 0) {
  #   my $path = splice(@paths_button, -1);  # remove the last element of @array  
  
  foreach my $path (reverse @paths_button){  # descending order
     my $iter = $model->get_iter($path);
     if ($iter) {
        my $row_abs = $model->get_value($iter,COLUMN_FILE) - 1; # absolute position into @files_info
        #print "row_abs = $row_abs ; remove filepath = $files_info[$row_abs]->{filepath} ; files_info_number = ",$#files_info+1,"\n";
      
        #splice (@files_info, $row_abs, 1);  # remove one element
        $files_info[$row_abs]->{remove}=$true;
	$model->remove($iter);        
     }
  }    
}

###---------------------- final --------------------###
###------------- scrolled_window_artist ------------###

###--------------------- frame5 --------------------###
###--------------------- incio --------------------###
# we put frame5a + frame5b inside vbox5 and then inside notebook5
my $frame5a = new Gtk2::Frame( $langs{name058} );
$frame5a->set_label_align( 1.0, 0.0 );
$frame5a->set_shadow_type( 'etched_out' );
$vbox5->pack_start( $frame5a, $true, $true, 0 );
$frame5a->show();

#adicionamos uma tabela dentro do frame
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
my $table5a = new Gtk2::Table (3, 4, 0); 
$table5a->set_border_width (4);
$table5a->set_row_spacings(4);
$table5a->set_col_spacings(10);
$frame5a->add( $table5a );
$table5a->show;

my $frame5b = new Gtk2::Frame( $langs{name059} );
$frame5b->set_label_align( 1.0, 0.0 );
$frame5b->set_shadow_type( 'etched_out' );
$vbox5->pack_start( $frame5b, $true, $true, 0 );
$frame5b->show();

#adicionamos uma tabela dentro do frame
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
my $table5b = new Gtk2::Table (3, 4, 0); 
$table5b->set_border_width (4);
$table5b->set_row_spacings(4);
$table5b->set_col_spacings(10);
$frame5b->add( $table5b );
$table5b->show;

#-----------------------table5a-----------------------#
$ComboBox_Names = Gtk2::ComboBox->new_text;
foreach (sort keys %langs) { $ComboBox_Names->append_text ($_); }
$ComboBox_Names->set_active($Names_Active_Num); #init value
$ComboBox_Names->set_size_request( 92, -1 );
$ComboBox_Names->signal_connect("changed", \&show_textview_language, $ComboBox_Names);
$tooltips->set_tip($ComboBox_Names, $langs{tip501}) if $show_all_tooltips;
$table5a->attach ($ComboBox_Names, 0, 1, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_Names->set_add_tearoffs($true);  # Whether dropdowns should have a tearoff menu item		       
$ComboBox_Names->show;

$label = new Gtk2::Label( $langs{name016} . ":" );
$label->set_alignment( 1.0, 0.5 );   
$table5a->attach ($label, 1, 2, 0, 1, 'fill', 'shrink', 0, 0);
$label->show;

$ComboBox_Lang_5a = Gtk2::ComboBox->new_text;
foreach (sort keys %all_language) { $ComboBox_Lang_5a->append_text ($_); }
#foreach (sort { uc($a) cmp uc($b) } keys %all_language) { $ComboBox_Lang_5a->append_text ($_); }

my $pos = 0;
foreach my $key (sort keys %all_language) { if ($key eq $language) {$ComboBox_Lang_5a->set_active($pos); last;} $pos++; }

$ComboBox_Lang_5a->set_size_request( 92, -1 );
$ComboBox_Lang_5a->signal_connect("changed", \&lang_choice5a);
$tooltips->set_tip($ComboBox_Lang_5a, $langs{tip502});
$table5a->attach ($ComboBox_Lang_5a, 3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_Lang_5a->show;
   
#-----------------------table5b-----------------------#
my $ComboBox_NewLang = Gtk2::ComboBox->new_text;
foreach ( $langs{name060} , $langs{name061} ) { $ComboBox_NewLang->append_text ($_); }
$ComboBox_NewLang->set_active(0);
$ComboBox_NewLang->set_size_request( 92, -1 );
$ComboBox_NewLang->signal_connect("changed", \&add_new_lang, $ComboBox_NewLang);
$table5b->attach ($ComboBox_NewLang, 0, 1, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_NewLang->show;

# Create the Entry to add new language
my $entry_lang = new Gtk2::Entry();
$entry_lang->set_text( "" );
$entry_lang->signal_connect("changed",\&ative_save_lang);
$tooltips->set_tip( $entry_lang, $langs{name062} ) if $show_all_tooltips;
$table5b->attach ($entry_lang, 1, 2, 0, 1, 'fill', 'shrink', 0, 0);
#$entry_lang->set_sensitive($false);
$entry_lang->hide;

my $button_save_lang = Gtk2::Button->new;
$button_save_lang->add( DrawIcons('gtk-save','button') );
$button_save_lang->signal_connect( "clicked", \&save_lang_button );
$button_save_lang->set_sensitive($false);
$button_save_lang->set( 'focus-on-click' => $false, 'relief' => 'none' );
$tooltips->set_tip( $button_save_lang, $langs{tip504} ) if $show_all_tooltips;
$table5b->attach ($button_save_lang, 2, 3, 0, 1, 'shrink', 'shrink', 0, 0);	 
$button_save_lang->show;


my $ComboBox_Lang_5b = Gtk2::ComboBox->new_text;
foreach (sort keys %all_language) { $ComboBox_Lang_5b->append_text ($_); }

$pos = 0;
foreach my $key (sort keys %all_language) { if ($key eq $language) {$ComboBox_Lang_5b->set_active($pos); last;} $pos++; }

$ComboBox_Lang_5b->set_size_request( 92, -1 );
$ComboBox_Lang_5b->signal_connect("changed", \&lang_choice5b);
$tooltips->set_tip($ComboBox_Lang_5b, $langs{tip505} ) if $show_all_tooltips;
$table5b->attach ($ComboBox_Lang_5b, 3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_Lang_5b->show;

#-------------------textview_5a----------------------#
# Construct a textview to put Guidance Language
my $textview_5a = Gtk2::TextView->new;
$textview_5a->set (         'editable' => $false, 
                      'cursor_visible' => $false, 
		         'left_margin' => 0, 
			'right_margin' => 0,
                           'wrap-mode' => 'word');

$textview_5a->set_border_width (4);			   
my $color_5a_base = Gtk2::Gdk::Color->parse ("#E6EDBD");  
$textview_5a->modify_base ('normal', $color_5a_base);
my $color_5a_bg = Gtk2::Gdk::Color->parse ("#A0B8A3");
$textview_5a->modify_bg ('normal', $color_5a_bg);
$tooltips->set_tip($textview_5a, $langs{tip503} ) if $show_all_tooltips;
$table5a->attach ($textview_5a, 0, 4, 1, 2, ['expand','fill'], ['expand','fill'], 0, 0);
$textview_5a->show;

# $buffer = Gtk2::TextBuffer->new; # see <man Gtk2::TextBuffer>
my $buffer_5a = $textview_5a->get_buffer;
$buffer_5a->create_tag ("italic_about",      'foreground' => "black",   # see <man Gtk2::TextTag> for more options
                                            #'background' => "yellow",
                                            justification => 'left', 
                                                     font => "Sans",
				            'size-points' => "14");

#-------------------textview_5b----------------------#
# Construct a textview to put Guidance Language
my $textview_5b = Gtk2::TextView->new;
$textview_5b->set (         'editable' => $true, 
                      'cursor_visible' => $true, 
		         'left_margin' => 0, 
			'right_margin' => 0,
                           'wrap-mode' => 'word');

$textview_5b->set_border_width (4);			   
my $color_5b_base = Gtk2::Gdk::Color->parse ("#E6EDBD");  
$textview_5b->modify_base ('normal', $color_5b_base);
my $color_5b_bg = Gtk2::Gdk::Color->parse ("#A0B8A3");
$textview_5b->modify_bg ('normal', $color_5b_bg);
$table5b->attach ($textview_5b, 0, 4, 1, 2, ['expand','fill'], ['expand','fill'], 0, 0);
$textview_5b->show;

# $buffer = Gtk2::TextBuffer->new; # see <man Gtk2::TextBuffer>
my $buffer_5b = $textview_5b->get_buffer;
$buffer_5b->signal_connect( 'changed', \&ative_save_lang );
$buffer_5b->create_tag ("version",           'foreground' => "blue",   
                                            justification => 'left',
					             font => "Sans",
					    'size-points' => "14");
					    
#----------------------------------------------------#

sub show_textview_language{   
   lang_choice5a();
   lang_choice5b();
}

sub lang_choice5a {
    my $entry=$ComboBox_Lang_5a->get_active_text;
    $language = $entry if defined $entry;  #print "111a-->\$language = $language \n";
    set_language();
    $tooltips->set_tip($ComboBox_Lang_5a, $langs{tip502});
    #$ComboBox_NewLang->set_popdown_strings ( $langs{name060} , $langs{name061} );
    show_textview_language_5a($ComboBox_Names);  #print "222a-->\$language = $language \n";
}

sub lang_choice5b {
    my $entry=$ComboBox_Lang_5b->get_active_text;
    $language = $entry if defined $entry;  #print "111b-->\$language = $language \n";
    set_language();
    $tooltips->set_tip($ComboBox_Lang_5b, $langs{tip505}) if $show_all_tooltips;
    show_textview_language_5b($ComboBox_Names);  #print "222b-->\$language = $language \n";
}

sub show_textview_language_5a {
    my ($combo_copy) = @_; 
    my $key=$combo_copy->get_active_text;
    
    $textview_5a->get_buffer->delete($textview_5a->get_buffer->get_bounds); #clear
    my $iter_5a = $buffer_5a->get_iter_at_offset (0); # get start of buffer 
    $buffer_5a->insert_with_tags_by_name ($iter_5a, $langs{$key}, "italic_about");
}
show_textview_language_5a($ComboBox_Names);

sub show_textview_language_5b {
    my ($combo_copy) = @_; 
    my $key=$combo_copy->get_active_text;    
    
    $textview_5b->get_buffer->delete($textview_5b->get_buffer->get_bounds); #clear
    my $iter_5b = $buffer_5b->get_iter_at_offset (0); # get start of buffer 
    $buffer_5b->insert_with_tags_by_name ($iter_5b, $langs{$key}, "version");
}
show_textview_language_5b($ComboBox_Names);

sub add_new_lang {
    $entry_lang->hide if ( $ComboBox_NewLang->get_active == 0 );
    $entry_lang->show if ( $ComboBox_NewLang->get_active == 1 );
    #print "------> \$ComboBox_NewLang->get_active = ",$ComboBox_NewLang->get_active," \n";
}

sub ative_save_lang {
   $button_save_lang->set_sensitive($true); # if ($textview_5b->get_buffer->get_modified);
}

sub save_lang_button {
   my $key_names = $ComboBox_Names->get_active_text;
   
   if ( $ComboBox_NewLang->get_active == 1 and $entry_lang->get_text eq "" ){ 
      $status_bar->push($context_id, $langs{msg095} ); 
      return $false; 
   }
   $language = $ComboBox_Lang_5b->get_active_text; # print "--> Old \$language = $language \n";
   my $new_lang = $language;   
   
   if ( $ComboBox_NewLang->get_active == 1 and $entry_lang->get_text ne "" ){
      $new_lang = $entry_lang->get_text;  # print "\$new_lang = $new_lang\n";
       
      $ComboBox_Lang_5a->append_text ($new_lang) if not $all_language{"$new_lang"};
      $ComboBox_Lang_5b->append_text ($new_lang) if not $all_language{"$new_lang"};
      $all_language{"$new_lang"} = $true;       
   }         
   set_language();
   
   # Usage: Gtk2::TextBuffer::get_text(buffer, start, end, include_hidden_chars)
   $langs{$key_names} = $textview_5b->get_buffer->get_text($textview_5b->get_buffer->get_bounds,$true);    
   
   my $lang_file = "$lang_dir/${new_lang}.txt";
   open( OUTPUT, '>:utf8', filename_from_unicode $lang_file ) or die "Couldn't open <$lang_file> for writing: $!\n";
   
      #foreach my $key ( sort keys %langs ) { ( my $value  = $langs{$key}) =~ s/\"/\\\"/g; print OUTPUT '$langs{',$key,'} = "',$value,"\";\n"; }
      foreach my $key ( sort keys %langs ) { print OUTPUT $key, '<===>', $langs{$key}, "\n"; }
      
   close( OUTPUT );
   
   print $key_names, ' = ', $langs{$key_names}, "\n";
   print "--> \"$lang_file\" \n";
   $status_bar->push($context_id, "--> \"$lang_file\"");   
   $button_save_lang->set_sensitive($false);
}


###---------------------- final --------------------###
###--------------------- frame5 --------------------###

###--------------------- frame6 --------------------###
###--------------------- in�cio --------------------###
# Adicionamos este frame6 em vbox6 (vbox6 est� dentro do notebook)
my $frame6 = new Gtk2::Frame();
# Set the frame's label
# Align the label at the right of the frame
$frame6->set_label_align( 1.0, 0.0 );
# Set the style of the frame
$frame6->set_shadow_type( 'etched_out' );
# $vbox->pack_start( $child, $expand, $fill, $padding ); 
$vbox6->pack_start( $frame6, $true, $true, 0 );  
#$vbox6->add($frame6);
$frame6->show();

###-------------------------------------------------###

###------------------frame_normalize----------------###

# we put this $frame_normalize inside the vbox_up
# Adicionamos este $frame_normalize em vbox_up ;; Este frame cont�m o bot�o normalize
my $frame_normalize = new Gtk2::Frame();  
$frame_normalize->set_label_align( 1.0, 0.0 );
$frame_normalize->set_shadow_type( 'etched_out' );
#$box->pack_start ($child, $expand, $fill, $padding)
$vbox_up->pack_start( $frame_normalize, $false, $true, 0 );
#$vbox_up->add( $frame_normalize );
$frame_normalize->show();

# adicionamos um hbox dentro do $frame_normalize
# Gtk2::HBox->new ($homogeneous=0, $spacing=5)
my $hbox_normalize = new Gtk2::HBox ( $false, 2 );
$hbox_normalize->set_border_width(2);
$frame_normalize->add($hbox_normalize);
$hbox_normalize->show;

###----------------frame_prog_bar--------------------###
# we put this frame_prog_bar inside the vbox_up ;; This frame contain the Progress Bar
# Adicionamos este frame em vbox_up ;; Este frame cont�m os 'progress bar'
$frame_prog_bar = new Gtk2::Frame();
# Set the style of the frame
$frame_prog_bar->set_shadow_type( 'etched_out' );
#$box->pack_start ($child, $expand, $fill, $padding)
$vbox_up->pack_start( $frame_prog_bar, $false, $true, 0 );
$frame_prog_bar->show ;

#adicionamos uma tabela dentro do frame_prog_bar
#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
$table_down = new Gtk2::Table (3, 4, $false); 
$table_down->set_border_width (4);
$table_down->set_row_spacings(4);
$table_down->set_col_spacings(2);
#$table_down->set_size_request( 510, 90 ); # width, height
$frame_prog_bar->add( $table_down );
$table_down->show;

###------------------frame_debug----------------------###
# we put this frame_debug inside the vbox_down
# Adicionamos este frame em vbox_down
# Este frame cont�m os comandos utilizados , debug
$frame_debug = new Gtk2::Frame();
$frame_debug->set_label_align( 1.0, 0.0 );
$frame_debug->set_shadow_type( 'etched_out' );
#$box->pack_start ($child, $expand, $fill, $padding)
$vbox_down->pack_start( $frame_debug, $true, $true, 0 );
#$frame_debug->show;

## --------------------- Statusbar ------------------- ##
$status_bar = Gtk2::Statusbar->new; 
$vbox_main->pack_start( $status_bar, $false, $true, 0 );
$status_bar->set_has_resize_grip ($true);
#$status_bar->signal_connect ( button_press_event => \&event_bar_button );
$status_bar->show;

sub event_bar_button{  # not used, only for test
   my $widget = shift;	  # Gtk2::Statusbar  
   my $event = shift;	  # GdkEventButton *event  : see Gtk2::Gdk::Event

   #print "fora \n";
   if ($event->button == 1) {
      #print "button 1\n";
      $table3->set_size_request( ($window->allocation->width) * 0.70    ,-1 ); # width (70%), height;
      my $height_fd = $frame_debug->allocation->height;
      print "height_fd = $height_fd  \n";
   }
}

###----------------------------------------------------###
####################----------------######################
##------------------------------------------------------##

#--------------------- I c o n s ----------------------#

my @items = ( { stock_id => "gtk-apply", label => "_unselect" },
              { stock_id => "gtk-go-down", label => ""    },
	      { stock_id => "gtk-open", label => ""       },
	      { stock_id => "gtk-add",   label => ""      },
	      { stock_id => "gtk-go-up", label => ""      },
	      { stock_id => "gtk-cdrom", label => ""      },
	      { stock_id => "gtk-close", label => ""      },
	      { stock_id => "gtk-cancel", label => ""     },
	      { stock_id => "gtk-refresh", label => ""    },
	      { stock_id => "gtk-go-back", label => ""    },
	      { stock_id => "gtk-go-forward", label => "" },
	      { stock_id => "gtk-goto-first", label => "" },
	      { stock_id => "gtk-goto-last", label => ""  },	      
	      { stock_id => "gtk-goto-bottom", label => "_Show"    },
	      { stock_id => "gtk-goto-top", label => "_Hide"       },	      
              { stock_id => "gtk-yes", label => "_normalize", },
	    );
Gtk2::Stock->add (@items);           # Register our stock items
#print Gtk2::Stock->list_ids;

###--------------------------------------------------###

#####------------------T a b l e 1 ------------------#####
# Now, we put the widgets in table1

# criar um label (etiqueta - r�tulo) ao lado do menu
$label = new Gtk2::Label( $langs{name001} . ":");
$label->set_alignment( 1.0, 0.5 );  # right   
$table1->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0);
$label->show();

#####------------ start of ComboBox ----------#####
my @normalize_type = ( 'Track', 'Album', 'None' );

my $ComboBox_Norm_Type = Gtk2::ComboBox->new_text;
foreach my $type (@normalize_type) { $ComboBox_Norm_Type->append_text ($type); }

$pos = 0;
#$ComboBox_Norm_Type->set_active($pos); # set default value: $norm_type = 'Track';
foreach my $type (@normalize_type) { if ($type eq $norm_type) {$ComboBox_Norm_Type->set_active($pos); last;} $pos++; }

#$ComboBox_Norm_Type->set_size_request( 92, -1 );
$ComboBox_Norm_Type->signal_connect("changed", \&change_norm_type);
$tooltips->set_tip( $ComboBox_Norm_Type, $langs{tip101} ) if $show_all_tooltips;
$table1->attach ($ComboBox_Norm_Type,  1, 2, 0, 1, 'fill', 'shrink', 0, 0);
$ComboBox_Norm_Type->show;

sub change_norm_type {
   my ($ComboBox_copy) = @_;
   $norm_type = $ComboBox_copy->get_active_text;
    
   if ($norm_type eq "Track" ) {$spinner->set_sensitive($true );}
   if ($norm_type eq "Album" ) {$spinner->set_sensitive($false);}
   if ($norm_type eq "None"  ) {$spinner->set_sensitive($false);}
   return $norm_type;
}

#####------------ final of ComboBox ----------#####

# Create a centering alignment object;
$align = Gtk2::Alignment->new(0.0, 0.5, 0, 0);
$table1->attach_defaults ($align,  2, 3, 0, 1);
$align->show;

# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
my $adj = new Gtk2::Adjustment( $gain, -12.00, 12.00, 0.01, 0, 0 );
#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits );
$spinner = new Gtk2::SpinButton( $adj, 5, 2 );
$spinner->set_wrap( $true );
$spinner->set_editable($true);
$spinner->set_numeric ($true);
$spinner->set_update_policy( 'if_valid' );
$tooltips->set_tip( $spinner, $langs{tip102} ) if $show_all_tooltips;
$align->add($spinner);
$spinner->show;

#-------------------------------------#

change_norm_type($ComboBox_Norm_Type);

#-------------------------------------#

$label = new Gtk2::Label( $langs{name002} . ":" );
$label->set_alignment( 1.0, 0.5 );  # right   
$table1->attach ($label, 3, 4, 0, 1, 'fill', 'shrink', 0, 0);
$label->show();

$align = Gtk2::Alignment->new(0.0, 0.5, 0, 0);
$table1->attach ($align,  4, 5, 0, 1, 'fill', 'shrink', 0, 0);
$align->show;

# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
$insensibility = number_value($insensibility);
$adj = new Gtk2::Adjustment( $insensibility, 0.2, 5.0, 0.1, 0, 0 );
#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits );
$spinner_sensi = new Gtk2::SpinButton( $adj, 0.2, 1 );
$spinner_sensi->set_wrap( $false );
$spinner_sensi->set_editable($false);
$spinner_sensi->set_update_policy( 'if_valid' );
$tooltips->set_tip( $spinner_sensi, $langs{tip103} ) if $show_all_tooltips;
$align->add($spinner_sensi);
$spinner_sensi->show();

$label = new Gtk2::Label( "dB" );
$label->set_alignment( 0.0, 0.5 );  # right   
$table1->attach ($label, 5, 6, 0, 1, 'fill', 'shrink', 0, 0);
$label->show();

# criar um label (etiqueta - rtulo) ao lado do menu
$label = new Gtk2::Label( $langs{name003} . ":" );
$label->set_alignment( 1.0, 0.5 );  # right 
$table1->attach ($label, 0, 1, 1, 2, 'fill', 'fill', 0, 0);
$label->show();

# Create the Entry to put the file to normalize
$entry_f = new Gtk2::Entry( ); 
#$entry_f->set_max_length (100);
$entry_f->set_text( " " );
$tooltips->set_tip( $entry_f, $langs{msg063} ) if $show_all_tooltips;
$entry_f->select_region( 0, length( $entry_f->get_text() ) );
$table1->attach_defaults ($entry_f, 1, 6, 1, 2 );
$entry_f->set_sensitive($false);
$entry_f->set('editable' => $false );
$entry_f->show();

#--------------- Input Directory -----------------#

$label = new Gtk2::Label( $langs{name004} . ":" );
$label->set_alignment( 1.0, 0.5 );  # right   
$table1->attach ($label, 0, 1, 2, 3, 'fill', 'fill', 0, 0);
$label->show();

# Create the Entry to put the directory path
$entry_dir_input = new Gtk2::Entry( );
#$entry_dir_input->set_max_length (100);

$directory = $ENV{'PWD'};                               # start value
eval { $directory = filename_to_unicode $directory; };  # convert filename to unicode
$directory =~ s/\/{1,}$//;                              # remove the '/' character from final if it exists.
$directory_base = $directory;                           # used to find 'directory_ramain' with remove_directory_base()
   
$entry_dir_input->set_text( $directory );
$tooltips->set_tip( $entry_dir_input, "$directory") if $show_all_tooltips;
$entry_dir_input->select_region( 0, length( $entry_dir_input->get_text() ) );
$table1->attach_defaults ($entry_dir_input, 1, 5, 2, 3 );
$entry_dir_input->set_sensitive($false);
$entry_dir_input->set('editable' => $false );
$entry_dir_input->show;

# Create Dir_Selection button
#$button = Gtk2::Button->new_from_stock ('gtk-open');
$button = Gtk2::Button->new;
$button->add( DrawIcons('gtk-open','button') );  # 'button' is the size

$tooltips->set_tip( $button, $langs{tip104} ) if $show_all_tooltips;
$button->signal_connect( "clicked", \&dir_selection );
$table1->attach ($button,  5, 6, 2, 3, 'shrink', 'shrink', 0, 0);
$button->show_all;
# This makes it so the button is the default.
$button->can_default($true);
# This grabs this button to be the default button. Simply hitting the "Enter"
# key will cause this button to activate.
$button->grab_default;
$button->set( 'focus-on-click' => $false, 'relief' => 'none' );

#--------------- Output Directory -----------------#

$label = new Gtk2::Label( $langs{name052} . ":" );
$label->set_alignment( 1.0, 0.5 );  # right   
$table1->attach ($label, 0, 1, 3, 4, 'fill', 'fill', 0, 0);
$label->show();

my $entry_dir_output = new Gtk2::Entry();
if ( ! -e filename_from_unicode $directory_output ){ $directory_output = $home;}
$entry_dir_output->set_text( $directory_output );
$tooltips->set_tip( $entry_dir_output, $directory_output ) if $show_all_tooltips;
$entry_dir_output->set('editable' => $false );
$table1->attach_defaults ($entry_dir_output, 1, 5, 3, 4 );
$entry_dir_output->show;

$button = Gtk2::Button->new;
$button->add( DrawIcons('gtk-go-down','button') );
$tooltips->set_tip( $button, $langs{tip105} ) if $show_all_tooltips;
$button->signal_connect( "clicked", \&dir_selection_output);
$button->set( 'focus-on-click' => $false, 'relief' => 'none' );
$table1->attach ($button,  5, 6, 3, 4, 'shrink', 'shrink', 0, 0);
$button->show;

#----------- Scrolling Label Viewport -------------#
#my $viewport_directory_input = scrolling_label_viewport( $directory, 60, 2);
#$table1->attach ( $viewport_directory_input, 1, 5, 2, 3, ['expand','fill'], 'shrink', 0, 0);

#$table1->remove( $viewport_directory_output );
#$viewport_directory_output = scrolling_label_viewport( $directory_output, 60, 2);
#$table1->attach( $viewport_directory_output, 1, 5, 3, 4, ['expand','fill'], 'shrink', 0, 0);

my $timer_label; my $hadj;
sub scrolling_label_viewport { # not used
   my ($text, $interval, $incremental) = @_;
   
   # $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
   $hadj = new Gtk2::Adjustment( 5, 1.0, 30.0, 1.0, 1.0, 50.0 ); 
   
   my $label = Gtk2::Label->new( $text );
   $label->set_alignment(0.0, 0.5);
   $label->show;
         
   # See <man Gtk2::Viewport> and Gtk2::Adjustment
   #widget = Gtk2::Viewport->new ($hadjustment=undef, $vadjustment=undef)
   my $viewport = Gtk2::Viewport->new($hadj, undef);
   $viewport->set_shadow_type('out');
   $viewport->add ($label);
   $viewport->set_size_request(20,-1);    
   $viewport->signal_connect ( 'enter-notify-event' => sub {
      if ( defined($timer_label) ){ Glib::Source->remove($timer_label);}  # to not duplicate the MainLoop
      $timer_label = Glib::Timeout->add ($interval, \&scroll_label, $incremental);      # see <man Glib::MainLoop>  
   });
   $viewport->signal_connect ( 'leave_notify_event' => sub { if ( defined $timer_label ){ Glib::Source->remove($timer_label); } } );
   $viewport->set_events ([ @{ $viewport->get_events }, 'exposure-mask', 'enter-notify-mask', 'leave-notify-mask'] );
   $viewport->show;  	 	   
   return $viewport; #widget
}

my $sign = 1; my $i=1; 
sub scroll_label {
   my $incremental = shift;
   my $upper = $hadj->upper;
   my $page_size = $hadj->page_size;
   my $offset = $upper - $page_size;
   if ( $offset <= 0 ){ return; }     
   my $x=$hadj->get_value;
     
   if ( $x <= 0 or $x >= $offset ) { $sign = - $sign; }     
   $i = $i + $sign * $incremental; 
     
   $hadj->set_value($i);     
   #print "x = $x ; sign = $sign ; offset = $offset ; upper = $upper ; page_size = $page_size\n";	     
   return $timer_label;  
}

# Output : Lossy Compression
# Output : Lossless Compression
# Output : Uncompressed


################-----Output--------################## Output : Lossy Compression
#######---------Lossy Compression-----------#########

# veja:   man perlnumber  ou perlop ou man overload

my $button_output_mp3 = new Gtk2::RadioButton(  undef , "mp3");
$tooltips->set_tip( $button_output_mp3, $langs{tip108} . "\n\n" . $langs{tip115} ) if $show_all_tooltips;
$table11->attach_defaults($button_output_mp3, 0, 1, 0, 1);
$button_output_mp3->signal_connect( "toggled", \&set_extension_output );
$button_output_mp3->show;   

my $button_output_mp4 = new Gtk2::RadioButton( $button_output_mp3, "mp4");
$tooltips->set_tip( $button_output_mp4, $langs{tip109} . "\n\n" . $langs{tip115} ) if $show_all_tooltips;
$table11->attach_defaults($button_output_mp4, 1, 2, 0, 1);
$button_output_mp4->signal_connect( "toggled", \&set_extension_output );
$button_output_mp4->show;

my $button_output_mpc = new Gtk2::RadioButton( $button_output_mp4, "mpc");
$tooltips->set_tip( $button_output_mpc, $langs{tip110} . "\n\n" . $langs{tip115} ) if $show_all_tooltips;
$table11->attach_defaults($button_output_mpc, 0, 1, 1, 2);
$button_output_mpc->signal_connect( "toggled", \&set_extension_output );
$button_output_mpc->show;

my $button_output_ogg = new Gtk2::RadioButton( $button_output_mpc, "ogg");
$tooltips->set_tip( $button_output_ogg, $langs{tip111} . "\n\n" . $langs{tip115} ) if $show_all_tooltips;
$table11->attach_defaults($button_output_ogg, 1, 2, 1, 2);
$button_output_ogg->signal_connect( "toggled", \&set_extension_output );
$button_output_ogg->show;

################-----Output--------################## Output : Lossless Compression
#######-------Lossless Compression----------#########

# see /usr/share/doc/perl-Gtk2-doc/examples/assistant.pl for RadioButton   

my $button_output_ape = new Gtk2::RadioButton( $button_output_ogg, "ape");
$tooltips->set_tip( $button_output_ape, $langs{tip112} . "\n\n" . $langs{tip116} ) if $show_all_tooltips;
$table12->attach_defaults($button_output_ape, 0, 1, 0, 1);
$button_output_ape->signal_connect( "toggled", \&set_extension_output );
$button_output_ape->show;  

my $button_output_flac = new Gtk2::RadioButton( $button_output_ape, "flac");
$tooltips->set_tip( $button_output_flac, $langs{tip113} . "\n\n" . $langs{tip116} ) if $show_all_tooltips;
$table12->attach_defaults($button_output_flac, 1, 2, 0, 1);
$button_output_flac->signal_connect( "toggled", \&set_extension_output );
$button_output_flac->show; 

################-----Output--------################## Output : Uncompressed
#######------------Uncompressed-------------#########

my $button_output_wav = new Gtk2::RadioButton( $button_output_flac, "wav");
$tooltips->set_tip( $button_output_wav, $langs{tip114} ) if $show_all_tooltips;
$table13->attach_defaults($button_output_wav, 0, 1, 0, 1);
$button_output_wav->signal_connect( "toggled", \&set_extension_output );
$button_output_wav->show; 

##----------------------------------------------------##
#####----------------T a b l e 2 ------------------#####

$check_button_del_wav = Gtk2::CheckButton->new ( $langs{name009} );
$check_button_del_wav->set_active($delete_wave);
$tooltips->set_tip( $check_button_del_wav, $langs{tip201} ) if $show_all_tooltips;
#$check_button_del_wav->set_alignment (6,0);
$table2->attach($check_button_del_wav,  0, 1, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$check_button_del_wav->show;

$check_button_tooltips = Gtk2::CheckButton->new ($langs{name057});
$check_button_tooltips->set_active($show_all_tooltips);
$tooltips->set_tip( $check_button_tooltips, $langs{tip204} ."\n". $langs{tip502} );
$table2->attach($check_button_tooltips,  1, 2, 0, 1, 'fill', 'shrink', 0, 0);
$check_button_tooltips->show;


$label = new Gtk2::Label( $langs{name012} . ":" );
$label->set_alignment( 1.0, 0.5 ); 
$table2->attach ($label, 2, 3, 0, 1, ['fill','expand'], 'shrink', 0, 0);
$label->show();

$adj = new Gtk2::Adjustment( $priority, 0, 19, 1, 0, 0 );
$spinner_pri = new Gtk2::SpinButton( $adj, 0.1, 0 );
$spinner_pri->set_editable($false);
$spinner_pri->set_size_request( 72, -1 );
$spinner_pri->set_update_policy( 'if_valid' );
$spinner_pri->set_wrap( $true );
$tooltips->set_tip( $spinner_pri, $langs{tip206} ) if $show_all_tooltips;
$table2->attach($spinner_pri,  3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$spinner_pri->show();

$check_change_properties = Gtk2::CheckButton->new ($langs{name010});
$check_change_properties->set_active($change_properties);
$check_change_properties->signal_connect( "clicked", \&encode_choice_sensitive );
$tooltips->set_tip( $check_change_properties, $langs{tip202} ) if $show_all_tooltips;
$table2->attach($check_change_properties,  0, 1, 1, 2, 'fill', 'fill', 0, 0);
$check_change_properties->show;

$check_button_animation = Gtk2::CheckButton->new ( $langs{name055} );
$check_button_animation->set_active($show_tux_animation);
$check_button_animation->signal_connect( "clicked", \&tux_animation_textview );
$tooltips->set_tip( $check_button_animation, $langs{tip205} ) if $show_all_tooltips;
$table2->attach($check_button_animation, 1, 2, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$check_button_animation->show;

#####---------------------------------------------#####

$check_button_overwrite = Gtk2::CheckButton->new ($langs{name011});
$check_button_overwrite->set_active($overwrite);
$tooltips->set_tip( $check_button_overwrite, $langs{tip203} ) if $show_all_tooltips;
$table2->attach($check_button_overwrite,  0, 1, 2, 3, 'fill', 'fill', 0, 0);
$check_button_overwrite->show;

#####---------------------------------------------#####

$label = new Gtk2::Label( $langs{name014} . ":" );
$label->set_alignment( 1.0, 0.5 ); 
$table2->attach ($label, 2, 3, 1, 2, ['fill','expand'], 'shrink', 0, 0);
$label->show;

$entry_format_cda = new Gtk2::Entry( );
$entry_format_cda->set_text( $file_format_cda_rip );
$tooltips->set_tip( $entry_format_cda, $langs{tip207} ) if $show_all_tooltips;
$table2->attach($entry_format_cda,  3, 4, 1, 2, ['fill','expand'], 'shrink', 0, 0);
$entry_format_cda->show;

#####---------------------------------------------#####

$label = new Gtk2::Label( "Comment Tag" . ":" );
$label->set_alignment( 1.0, 0.5 ); 
$table2->attach ($label, 2, 3, 2, 3, ['fill','expand'], 'shrink', 0, 0);
$label->show;

$entry_def_comment = new Gtk2::Entry; # see 'sub normalize'
$entry_def_comment->set_text( $comment_tag );
$tooltips->set_tip( $entry_def_comment, $langs{tip250} ) if $show_all_tooltips;
$table2->attach($entry_def_comment,  3, 4, 2, 3, ['fill','expand'], 'shrink', 0, 0);
$entry_def_comment->show;

##----------------------------------------------------##
#####---------------T a b l e 202 -----------------#####

#####--------------------Combo---------------------#####

# criar um label (etiqueta - rtulo) ao lado do menu
$label = new Gtk2::Label( $langs{name015} . ":" );
$label->set_alignment( 1.0, 0.5 ); 
$table202->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0);
$label->show();

my @all_encodings = Encode->encodings(":all"); # see <man Encode>
#print ("Encode list = @all_encodings\n");

$ComboBox_char = Gtk2::ComboBox->new_text;
#foreach (@all_encodings) { $ComboBox_char->append_text ($_); }
#$pos = 0; foreach my $key (@all_encodings) { if ($key eq $id3tag_character) {$ComboBox_char->set_active($pos); last;} $pos++; }
ComboBox_fill_with_array(\$ComboBox_char,\@all_encodings);
ComboBox_select_this_text(\$ComboBox_char,\@all_encodings,\$id3tag_character);  
$ComboBox_char->set_size_request( 90, -1 );
$ComboBox_char->signal_connect("changed", \&ComboBox_choice,\$id3tag_character);
$table202->attach ($ComboBox_char, 1, 2, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$tooltips->set_tip( $ComboBox_char, $langs{tip229} ) if $show_all_tooltips;  # "Used to encode ID3v2.3.0 Tag for MP3 files."
$ComboBox_char->show;

sub ComboBox_choice {   # see 'sub player_choice'
   my ($ComboBox_copy, $scalar_ref) = @_;
   my $char = $ComboBox_copy->get_active_text;
   	   
   $$scalar_ref = $char;
   #print "\nComboBox_copy = $ComboBox_copy ;; \n\$scalar_ref = $scalar_ref ;; scalar_ref value = $$scalar_ref \n";
}

sub ComboBox_fill_with_array {
   my ($ref_ComboBox, $ref_array) = @_;      
   $$ref_ComboBox->remove_text(0) while ( $$ref_ComboBox->get_active >= 0 ); # remove all old values
   $$ref_ComboBox->append_text($_) foreach (@$ref_array);
}

sub ComboBox_select_this_text {
   my ($ref_ComboBox, $ref_array, $ref_val) = @_;            # the selected text is $ref_val
   return if ( not defined $$ref_val or @$ref_array <= 0 );  # print "ref_val = $$ref_val \n";
   
   my $index = 0;
   foreach my $key (@$ref_array) { if ($key eq $$ref_val) {$$ref_ComboBox->set_active($index); last;} $index++; }
   
   # if no one selection, then select the first array element  
   if ($$ref_ComboBox->get_active < 0 and @$ref_array > 0){
      $$ref_ComboBox->set_active(0);                  # print "antes  ref_val = $$ref_val \n";
      $$ref_val = $$ref_ComboBox->get_active_text;    # print "depois ref_val = $$ref_val \n";
   }
}

#####-------------------final of Combo-------------#####

#####--------------------Combo---------------------#####

$label = new Gtk2::Label( $langs{name029} . ":" );
$label->set_alignment( 1.0, 0.5 );  
$table202->attach ($label, 0, 1, 1, 2, 'fill', 'shrink', 0, 0);
$label->show;

my @rippers = ( "cdparanoia", "cdda2wav" );

$ComboBox_rip = Gtk2::ComboBox->new_text;
ComboBox_fill_with_array(\$ComboBox_rip,\@rippers);
#ComboBox_set_popdown_strings($ComboBox_rip,@rippers);
ComboBox_select_this_text(\$ComboBox_rip,\@rippers,\$ripper);
$ComboBox_rip->set_size_request( 90, -1 );
$ComboBox_rip->signal_connect("changed", \&ripperChanged);
$table202->attach ($ComboBox_rip, 1, 2, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_rip->show;

sub ripperChanged {
   my ($ComboBox_copy) = @_;
   $ripper = $ComboBox_copy->get_active_text;
   
   if ($ripper eq "cdparanoia"){ 
      $notebook2->remove_page (3);
      $notebook2->append_page_menu ( $frame204, $label_ripper, undef  );
      change_font_for_all_child($window_font_name,$frame204); 
   }
   if ($ripper eq "cdda2wav"){ 
      $notebook2->remove_page (3);
      $notebook2->append_page_menu ( $frame205, $label_ripper, undef  );
      change_font_for_all_child($window_font_name,$frame205); 
   }   
}

#####-------------------final of Combo-------------#####

#####--------------------Combo---------------------#####

$label = new Gtk2::Label( $langs{name064} . ":" );
$label->set_alignment( 1.0, 0.5 );  
$table202->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0);
$label->show;

my @all_cdplayer;

sub Make_ComboBox_cdplayer {   # See the cdplayer_available() subroutine to search the cdplayer
   my $ComboBox_cdplayer = Gtk2::ComboBox->new_text;   
   ComboBox_fill_with_array(\$ComboBox_cdplayer,\@all_cdplayer);
   ComboBox_select_this_text(\$ComboBox_cdplayer,\@all_cdplayer,\$cdplayer);    
   $ComboBox_cdplayer->signal_connect("changed", \&cdplayerChanged);
   $table202->attach ($ComboBox_cdplayer, 1, 2, 2, 3, ['expand','fill'], 'shrink', 0, 0);
   $ComboBox_cdplayer->show;
}

sub cdplayerChanged {  ## choose cdplayer
   my ($ComboBox_copy) = @_;
   $cdplayer = $ComboBox_copy->get_active_text; # $cdplayer = "gnormalize::cdplay", "Audio::CD", "cdcd"
   # print "cdplayer = $cdplayer\n";

   if ( $cdplayer eq "Audio::CD" and $use_audiocd ){ # see <man Audio::CD>
       $audiocd = Audio::CD->init("$audiodevice_path");
       $have_current_track = audio_cd_have_current_track($audiodevice_path);
   }   
}

#####-------------------final of Combo-------------#####

#------------------------- Font -----------------------#
# criar um label (etiqueta - r�tulo) ao lado do menu
$label = new Gtk2::Label( $langs{name017} . ":" );
$label->set_alignment( 1.0, 0.5 );  
$table202->attach ($label, 2, 3, 0, 1, 'fill', 'shrink', 0, 0);
$label->show;

# Build the font-button
$button_font = Gtk2::Button->new($window_font_name);
$button_font->signal_connect( 'clicked', \&window_select_font );
#$button_font->signal_connect( 'clicked', \&gnome_font);
$table202->attach ($button_font, 3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$tooltips->set_tip( $button_font, $langs{tip208} ) if $show_all_tooltips;
$button_font->set_sensitive($true);
$button_font->show;

#------------------------------------------------------#

# my $widget = Glib::Object->new(  veja histogram 
my $window_bg_color = color_bg($window);
#print "window_bg_color = $window_bg_color \n"; #E6E7E6

# return the background color of widget in hexdecimal format
sub color_bg {  # not used
   my ( $widget ) = @_;
   my $color;
   my $red;
   my $green;
   my $blue;
 
   # see man Gtk2::Style
   $red = $widget->get_style->bg('normal')->red;
   $green = $widget->get_style->bg('normal')->green;
   $blue = $widget->get_style->bg('normal')->blue;

   # Convert to HTML format.  There are better ways to do this.   
   # uc: Returns an uppercased version of EXPR.
   # %x   an unsigned integer, in hexadecimal ; l: long
   $red   = uc( sprintf( "%02lx", $red/256 ) );  #print "red = $red\n";
   $green = uc( sprintf( "%02lx", $green/256 ) );
   $blue  = uc( sprintf( "%02lx", $blue/256 ) );
   
   $color = "#$red$green$blue"; #   print "color = $color\n";  # like #E6E7E6
   return $color;
} 

sub window_select_font {
	my $widget = $label;
	
	# repair the standard cancel label
        my @items = ( { stock_id => "gtk-cancel", label => "_Cancel"     } );
        Gtk2::Stock->add (@items);  # Register our stock items

	my $fsd = Gtk2::FontSelectionDialog->new ('Font Selection Dialog');
	$fsd->set_position('mouse');
	$fsd->set_preview_text('abcdefghijk ABCDEFGHIJK 1234567890');
        
	my $original_font_name = $widget->get_style->font_desc->to_string;
	$fsd->set_font_name ($original_font_name);
        #print "original_font_name = $original_font_name\n";

	$fsd->signal_connect ('response' => sub {
		my (undef, $response) = @_;
		if ($response eq 'ok') {
		   my $font_name = $fsd->get_font_name;
		   return unless $font_name;
		   $button_font->set_label($font_name);
		   change_font_for_all_child($font_name, $window);
		   $window_font_name = $font_name;
	           #print "aquui  -> window_font_name = $window_font_name\n";	   
		}
		$fsd->destroy;
	});

	$fsd->show;	
}

sub change_font_for_all_child {
  my $font_name = shift || 'Sans 10';
  my $container = shift || $window;
 
  my $font_desc = Gtk2::Pango::FontDescription->from_string($font_name);
    
  # notebook: notebook labels
  $label_data->modify_font($font_desc); $label_config->modify_font($font_desc);
  $label_info->modify_font($font_desc); $label_rip->modify_font($font_desc); 
  $label_about->modify_font($font_desc);
  
  # notebook2: notebook labels
  $label_option1->modify_font($font_desc); $label_option2->modify_font($font_desc);
  $label_cddb->modify_font($font_desc);    $label_ripper->modify_font($font_desc);
    
  # TreeViewColumn : treeview_play
  my @cols = $treeview_play->get_columns; # Retuns an array of columns.
  foreach my $col (@cols){ 
     # list = $tree_column->get_cell_renderers ; see <man Gtk2::TreeViewColumn>
     my $renderer = $col->get_cell_renderers;
     next if ($renderer =~ /Toggle/);
     $renderer->set ('font' => $font_name);
  }
  $renderer_track->set  ('font' => $font_name, 'xalign' => 0.5) if $renderer_track;
  $renderer_artist->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_artist;
  $renderer_title->set  ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_title;  
  $renderer_album->set  ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_album;
  
  # TreeViewColumn : treeview_album
  $renderer_album_playlist->set ('font' => $font_name, style => 'italic', scale => '0.9')   if $renderer_album_playlist;
  $renderer_album_play_count->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_album_play_count;
  # TreeViewColumn : treeview_artist
  $renderer_artist_playlist->set ('font' => $font_name, style => 'italic', scale => '0.9')   if $renderer_artist_playlist;
  $renderer_artist_play_count->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_artist_play_count;

  foreach my $child0 ($container->get_children) {
     if (not child_has_child ($font_desc, $child0) ) { next; }    
     foreach my $child1 ($child0->get_children) {
        if (not child_has_child ($font_desc, $child1) ) { next; } 
        foreach my $child2 ($child1->get_children) {
	   if (not child_has_child ($font_desc, $child2) ) { next; } 
           foreach my $child3 ($child2->get_children) {	   
	      if (not child_has_child ($font_desc, $child3) ) { next; } 
              foreach my $child4 ($child3->get_children) {
	         if (not child_has_child ($font_desc, $child4) ) { next; } 
                 foreach my $child5 ($child4->get_children) {
		    if (not child_has_child ($font_desc, $child5) ) { next; } 
                    foreach my $child6 ($child5->get_children) {
		       if (not child_has_child ($font_desc, $child6) ) { next; } 
                       foreach my $child7 ($child6->get_children) {
		          if (not child_has_child ($font_desc, $child7) ) { next; } 
                          foreach my $child8 ($child7->get_children) {
			     if (not child_has_child ($font_desc, $child8) ) { next; }
			     foreach my $child9 ($child8->get_children) {
			        if (not child_has_child ($font_desc, $child9) ) { next; }
                                $child9->modify_font($font_desc);
			     }
			  }
		       }
		    }
		 }
	      } 
	   }
	}      
     }
  } 
  
}

sub child_has_child {
   my $font_desc = shift;
   my $child = shift;
   # Don't change the font of this widget child, so don't search for its child
   if ( $child =~ /(Gtk2::Label|Gtk2::SpinButton|Gtk2::Entry|Gtk2::HSeparator|Gtk2::AccelLabel|Gtk2::TextView)/i  or
        $child =~ /(Gtk2::HSeparator|Gtk2::ProgressBar|Gtk2::DrawingArea|Gtk2::Image|Gtk2::Arrow|Gtk2::ComboBox)/i ){ 
              $child->modify_font($font_desc); 
              return $false; 
   }
   return $true;
}

sub gnome_font { # not more used
   exec_cmd_system2("gnome-font-properties");
   $change_fonte = $true;
   $change_fonte_norm = $true;
   $change_font_layout = $true;
   $change_font_rand = $true;   
}

# change_font_for_all_child($window_font_name); # change the font at the end

##-------------------------------------------------------##
#####----------------- T a b l e 203 -----------------#####

$check_button_cddb = Gtk2::CheckButton->new ( $langs{name018} );
$check_button_cddb->set_active($discDB);
$check_button_cddb->signal_connect( "clicked", \&cddb_sensitive );
$tooltips->set_tip( $check_button_cddb, $langs{tip209} ) if $show_all_tooltips;
$table203->attach($check_button_cddb,  0, 1, 0, 1, 'fill', 'shrink', 0, 0);
$check_button_cddb->show;

$check_button_overwrite_cddb = Gtk2::CheckButton->new ( $langs{name019} );
$check_button_overwrite_cddb->set_active($overwrite_cddb);
$tooltips->set_tip( $check_button_overwrite_cddb, $langs{tip210} ) if $show_all_tooltips;
$table203->attach($check_button_overwrite_cddb,  1, 2, 0, 1, 'fill', 'shrink', 0, 0);
$check_button_overwrite_cddb->show;

$label = new Gtk2::Label( $langs{name020} . ":" );
$label->set_alignment( 1.0, 0.5 ); 
$table203->attach ($label, 0, 1, 1, 2, 'fill', 'shrink', 0, 0);
$label->show();

$entry_CDDB_server = new Gtk2::Entry( ); 
$entry_CDDB_server->set_text( $CDDB_server );
$tooltips->set_tip( $entry_CDDB_server, $langs{tip211} ) if $show_all_tooltips;
$table203->attach($entry_CDDB_server,  1, 2, 1, 2, ['fill','expand'], 'fill', 0, 0);
$entry_CDDB_server->show;

$label = new Gtk2::Label( $langs{name021} . ":" );
$label->set_alignment( 1.0, 0.5 ); 
$table203->attach ($label, 2, 3, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$label->show();

$adj = new Gtk2::Adjustment( $cddb_port, 0, 9999, 1, 0, 0 );
$spinner_cddb_port = new Gtk2::SpinButton( $adj, 0.9, 0 );
$spinner_cddb_port->set_editable($true);
$spinner_cddb_port->set_size_request( 72, -1 );
$spinner_cddb_port->set_update_policy( 'if_valid' );
$spinner_cddb_port->set_wrap( $false );
$tooltips->set_tip( $spinner_cddb_port, $langs{tip212} ) if $show_all_tooltips;
$table203->attach($spinner_cddb_port,  3, 4, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$spinner_cddb_port->show();

$label = new Gtk2::Label( $langs{name022} . ":" );
$label->set_alignment( 1.0, 0.5 ); 
$table203->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0);
$label->show();

#####--------------------Combo---------------------#####

my @transport = ( "cddb", "http" );

my $ComboBox_cddb_transport = Gtk2::ComboBox->new_text;
foreach (@transport) { $ComboBox_cddb_transport->append_text ($_); }   
$pos = 0;
foreach my $key (@transport) { if ($key eq $cddb_transport) {$ComboBox_cddb_transport->set_active($pos); last;} $pos++; }   
$ComboBox_cddb_transport->signal_connect("changed", \&ComboBox_choice, \$cddb_transport);
$table203->attach ($ComboBox_cddb_transport, 1, 2, 2, 3, 'fill', 'shrink', 0, 0);
$ComboBox_cddb_transport->show;

#####-------------------final of Combo-------------#####

sub cddb_sensitive{
   if ($check_button_cddb->get_active ){
      $check_button_overwrite_cddb->set_sensitive ($true);
      $entry_CDDB_server->set_sensitive ($true);
      $spinner_cddb_port->set_sensitive ($true);
      $ComboBox_cddb_transport->set_sensitive ($true); 
   }
   else{
      $check_button_overwrite_cddb->set_sensitive ($false);
      $entry_CDDB_server->set_sensitive ($false);
      $spinner_cddb_port->set_sensitive ($false);
      $ComboBox_cddb_transport->set_sensitive ($false); 
   }
}
cddb_sensitive();

##-------------------------------------------------------##
#####----------------- T a b l e 204 -----------------#####

$button_noia1 = Gtk2::CheckButton->new ( $langs{name023} );
$button_noia1->set_active($disable_paranoia);
$tooltips->set_tip( $button_noia1, $langs{tip213} ) if $show_all_tooltips;
$table204->attach($button_noia1,  0, 1, 0, 1, ['fill','expand'], 'shrink', 0, 0);
$button_noia1->show;

$button_noia2 = Gtk2::CheckButton->new ( $langs{name026} );
$button_noia2->set_active($never_skip_repair);
$tooltips->set_tip( $button_noia2, $langs{tip214} ) if $show_all_tooltips;
$table204->attach($button_noia2,  1, 2, 0, 1, ['fill','expand'], 'shrink', 0, 0);
$button_noia2->show;

$button_noia3 = Gtk2::CheckButton->new ( $langs{name024} );
$button_noia3->set_active($disable_extra_paranoia);
$tooltips->set_tip( $button_noia3, $langs{tip215} ) if $show_all_tooltips;
$table204->attach($button_noia3,  0, 1, 1, 2, ['fill','expand'], 'shrink', 0, 0);
$button_noia3->show;

$button_noia4 = Gtk2::CheckButton->new ( $langs{name025} );
$button_noia4->set_active($abort_on_skip);
$tooltips->set_tip( $button_noia4, $langs{tip216} ) if $show_all_tooltips;
$table204->attach($button_noia4,  0, 1, 2, 3, ['fill','expand'], 'shrink', 0, 0);
$button_noia4->show;

##-------------------------------------------------------##
#####----------------- T a b l e 205 -----------------#####

$button_cdda1 = Gtk2::CheckButton->new ("paranoia");
$button_cdda1->set_active($paranoia);
$tooltips->set_tip( $button_cdda1, $langs{tip217} ) if $show_all_tooltips;
$table205->attach($button_cdda1,  0, 1, 0, 1, ['fill','expand'], 'shrink', 0, 0);
$button_cdda1->show;

$button_cdda2 = Gtk2::CheckButton->new ( $langs{name028} );
$button_cdda2->set_active($paranoia_disable);
$tooltips->set_tip( $button_cdda2, $langs{tip218} ) if $show_all_tooltips;
$table205->attach($button_cdda2,  1, 2, 0, 1, ['fill','expand'], 'shrink', 0, 0);
$button_cdda2->show;

$button_cdda3 = Gtk2::CheckButton->new ( $langs{name027} );
$button_cdda3->set_active($paranoia_no_verify);
$tooltips->set_tip( $button_cdda3, $langs{tip219} ) if $show_all_tooltips;
$table205->attach($button_cdda3,  0, 1, 1, 2, ['fill','expand'], 'shrink', 0, 0);
$button_cdda3->show;


###-----------------------------------------------------###
#####----------------T a b l e 21 --------------------#####

# criar um label (etiqueta - r�tulo) ao lado do menu
$label = new Gtk2::Label( $langs{name030} . ":" );
$label->set_alignment( 1.0, 0.5 );   
$table21->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0);
$label->show();

#####--------------------Combo---------------------#####

my @encode_type_mp3 = ( "average", "constant", "variable" );
my @encode_type_mp4 = ( "average", "variable" );
my @encode_type_ogg = ( "average", "variable" );
my @encode_type_mpc = ( "variable" );
# The hash %encode_type save the last encode type

my $model_encode = Gtk2::ListStore->new ('Glib::String');
foreach (@encode_type_mp3) { $model_encode->set ($model_encode->append, 0, $_); } # fill model


$ComboBox_encode_type = Gtk2::ComboBox->new ($model_encode);

my $renderer = Gtk2::CellRendererPixbuf->new;
$ComboBox_encode_type->pack_start ($renderer, $false);
$ComboBox_encode_type->add_attribute ($renderer, stock_id => 0);
$renderer = Gtk2::CellRendererText->new;
$ComboBox_encode_type->pack_start ($renderer, $true);
$ComboBox_encode_type->add_attribute ($renderer, text => 0);

#ComboBox_fill_with_array(\$ComboBox_encode_type,\@encode_type_mp3);
ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_mp3);
ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_mp3,\$encode_type{'mp3'});

$table21->attach($ComboBox_encode_type,  1, 2, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_encode_type->signal_connect("changed", \&encode_choice,$ComboBox_encode_type);
$ComboBox_encode_type->set_sensitive($change_properties);
$ComboBox_encode_type->show;

sub ComboBox_set_popdown_strings {
   my ($ComboBox_copy, @array) = @_;  
   return if ($ComboBox_copy->get_active < 0); # return if empty
   
   $ComboBox_copy->get_model->clear;                                        # $model->clear ;; remove all old values
   foreach (@array) { $model_encode->set ($model_encode->append, 0, $_); }  # fill the model with new values
}

## encode type: constant, average or variable bitrate ;; show or hide some widgets
sub encode_choice {
   my ($self, $ComboBox_copy) = @_;
   return if ($ComboBox_copy->get_active < 0); # return if empty
   $encode = $ComboBox_copy->get_active_text;
   #print "\n---> \$encode = $encode\n";
   
   encode_choice_sensitive();                                        
   $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate." );
   
   # set the last encode type
   if ($button_output_mp3->get_active ){$encode_type{'mp3'} = $encode;}
   if ($button_output_mp4->get_active ){$encode_type{'mp4'} = $encode;}
   if ($button_output_ogg->get_active ){$encode_type{'ogg'} = $encode;}
   if ($button_output_mpc->get_active ){$encode_type{'mpc'} = $encode;}
   
   #foreach my $k (sort keys %encode_type){ print "$k => $encode_type{$k}\n"; }
}

# Set widget sensitive according to encoder choice
sub encode_choice_sensitive {
   #$encode = $ComboBox_encode_type->get_active_text;   # refresh $encode value
   
   $vb_Max = $ComboBox_Max->get_active_text;; #refresh value
   $vb_Min = $ComboBox_Min->get_active_text;
      
   if ($button_output_mp3->get_active ){
       if ( $check_change_properties->get_active){
           if ( $encode eq "constant" ){ encode_sensitive(1,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1);}
	   if ( $encode eq "average"  ){ encode_sensitive(1,0,1,0,0,0,0,1,1,0,0,0,0,1,1,1,1,2,1,1);}
	   if ( $encode eq "variable" ){ encode_sensitive(1,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,0,1,1);}
       }	 
       else{ 
           if ( $encode eq "constant" ){ encode_sensitive(0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,1,1);} 
	   if ( $encode eq "average"  ){ encode_sensitive(0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,2,1,1);}	   
	   if ( $encode eq "variable" ){ encode_sensitive(0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,0,1,1);}
       }    
   }   
   if ($button_output_mp4->get_active ){
       if ( $check_change_properties->get_active){
           if ( $encode eq "average" ) { encode_sensitive(1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,2,3,1,2);}
	   if ( $encode eq "variable" ){ encode_sensitive(1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,2,3,1,2);}
       }	 
       else{ encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,1,2); }    
   }   
   if ($button_output_ogg->get_active ){
       if ( $check_change_properties->get_active){
           if ( $encode eq "average" ) { encode_sensitive(1,0,1,0,1,0,0,1,0,0,0,0,0,1,0,1,3,4,1,4);}
	   if ( $encode eq "variable" ){ encode_sensitive(1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,3,4,1,4);}
       }	 
       else{ encode_sensitive(0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,3,4,1,4); }    
   }	      
   if ($button_output_mpc->get_active ){
       if ( $check_change_properties->get_active){
             encode_sensitive(1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0,3); }	 
       else{ encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,3); }    
   }
   if ($button_output_ape->get_active ){
       if ( $check_change_properties->get_active){
             encode_sensitive(0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,5,2,5); }	 
       else{ encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,2,5); }    
   }
   if ($button_output_flac->get_active ){
       if ( $check_change_properties->get_active){
             encode_sensitive(0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,6,2,6); }	 
       else{ encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,2,6); }    
   }
   if ($button_output_wav->get_active ){
       encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,1,7);
   }        
   
   if ($button_output_mp3->get_active){  
      if ( not $check_change_properties->get_active){
         if ( $bitrate_average ){ $status_bar->push($context_id, $langs{msg065}."$extension_output with average bitrate.");}
         else { $status_bar->push($context_id, $langs{msg065}."$extension_output with constant bitrate.");}
      }
      else { $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate.");}	 
   } 
   if ($button_output_mp4->get_active){  
      if ( not $check_change_properties->get_active){
         { $status_bar->push($context_id, $langs{msg065}."$extension_output with average bitrate.");}
      }
      else { $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate.");}	 
   } 
   if ($button_output_ogg->get_active){  
      if ( not $check_change_properties->get_active){
         { $status_bar->push($context_id, $langs{msg065}."$extension_output with average bitrate.");}
      }
      else { $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate.");}	 
   }  
   if ($button_output_mpc->get_active){  
      $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate."); 
   }
   if ($button_output_ape->get_active){ 
         my $comp_ape = $spinner_compress->get_value_as_int();
         $status_bar->push($context_id, $langs{msg065}."$extension_output with compression level = $comp_ape.");
   }
   if ($button_output_flac->get_active){ 
         my $comp_flac = $spinner_compress_flac->get_value();
         $status_bar->push($context_id, $langs{msg065}."$extension_output with compression level = $comp_flac.");
   }
   if ($button_output_wav->get_active){ 
         $status_bar->push($context_id, $langs{msg065}."$extension_output without compression.");
   }     
  
}

sub encode_sensitive { # there are 20 widget - the order is important
   my $opt1 = shift; my $opt2 = shift; my $opt3 = shift; my $opt4 = shift;  
   my $opt5 = shift; my $opt6 = shift; my $opt7 = shift; my $opt8 = shift; 
   my $opt9 = shift; my $opt10 = shift; my $opt11 = shift; my $opt12 = shift;
   my $opt13 = shift; my $opt14 = shift; my $opt15 = shift; my $opt16 = shift;
   my $opt17 = shift; my $opt18 = shift; my $opt19 = shift; my $opt20 = shift;
   $ComboBox_encode_type->set_sensitive($opt1);
   $ComboBox_const_bitrate->set_sensitive($opt2);
   $spinner_bitrate_mp3->set_sensitive($opt3); 
   $spinner_bitrate_mp4->set_sensitive($opt4);
   $spinner_bitrate_ogg->set_sensitive($opt5); 
   $spinner_compress->set_sensitive($opt6);
   $spinner_compress_flac->set_sensitive($opt7);
   $ComboBox_Min->set_sensitive($opt8);
   $ComboBox_mode->set_sensitive($opt9);
   $spinner_V->set_sensitive($opt10);
   $spinner_Vmp4->set_sensitive($opt11);
   $spinner_Vogg->set_sensitive($opt12);
   $spinner_Vmpc->set_sensitive($opt13);
   $ComboBox_Max->set_sensitive($opt14);
   $spinner_q->set_sensitive($opt15);
   $ComboBox_freq->set_sensitive($opt16);
   if ($opt17 == 1){
      $spinner_V->show;
      $spinner_Vmp4->hide;
      $spinner_Vogg->hide;
      $spinner_Vmpc->hide;
   }
   if ($opt17 == 2){
      $spinner_V->hide;
      $spinner_Vmp4->show;
      $spinner_Vogg->hide;
      $spinner_Vmpc->hide;
   }
   if ($opt17 == 3){
      $spinner_V->hide;
      $spinner_Vmp4->hide;
      $spinner_Vogg->show;
      $spinner_Vmpc->hide;
   }
   if ($opt17 == 4){
      $spinner_V->hide;
      $spinner_Vmp4->hide;
      $spinner_Vogg->hide;
      $spinner_Vmpc->show;
   }
   if ($opt18 == 1){
      $ComboBox_const_bitrate->show;
      $spinner_bitrate_mp3->hide;
      $spinner_bitrate_mp4->hide;
      $spinner_bitrate_ogg->hide;
      $spinner_compress->hide;
      $spinner_compress_flac->hide;
   }
   if ($opt18 == 2){
      $ComboBox_const_bitrate->hide;
      $spinner_bitrate_mp3->show;
      $spinner_bitrate_mp4->hide;
      $spinner_bitrate_ogg->hide;
      $spinner_compress->hide;
      $spinner_compress_flac->hide;
   }
   if ($opt18 == 3){  # mp4
      $ComboBox_const_bitrate->hide;
      $spinner_bitrate_mp3->hide;
      $spinner_bitrate_mp4->show;
      $spinner_bitrate_ogg->hide;
      $spinner_compress->hide;
      $spinner_compress_flac->hide;
   }
   if ($opt18 == 4){  # ogg 
      $ComboBox_const_bitrate->hide;
      $spinner_bitrate_mp3->hide;
      $spinner_bitrate_mp4->hide;
      $spinner_bitrate_ogg->show;
      $spinner_compress->hide;
      $spinner_compress_flac->hide;
   }
   if ($opt18 == 5){
      $ComboBox_const_bitrate->hide;
      $spinner_bitrate_mp3->hide;
      $spinner_bitrate_mp4->hide;
      $spinner_bitrate_ogg->hide;
      $spinner_compress->show;
      $spinner_compress_flac->hide;
   } 
   if ($opt18 == 6){
      $ComboBox_const_bitrate->hide;
      $spinner_bitrate_mp3->hide;
      $spinner_bitrate_mp4->hide;
      $spinner_bitrate_ogg->hide;
      $spinner_compress->hide;
      $spinner_compress_flac->show;
   } 
   if ($opt19 == 1){
      $label_mp3b->show;
      $label_comp->hide;
   }
   if ($opt19 == 2){
      $label_mp3b->hide;
      $label_comp->show;
   }     
   if ($opt20 == 1){
      $entry_command_mp3->show;
      $entry_command_mp4->hide;
      $entry_command_mpc->hide;
      $entry_command_ogg->hide;
      $entry_command_ape->hide;
      $entry_command_flac->hide;
   }
   if ($opt20 == 2){ # mp4
      $entry_command_mp3->hide;
      $entry_command_mp4->show;
      $entry_command_mpc->hide;
      $entry_command_ogg->hide;
      $entry_command_ape->hide;
      $entry_command_flac->hide;
   }
   if ($opt20 == 3){ # mpc
      $entry_command_mp3->hide;
      $entry_command_mp4->hide;
      $entry_command_mpc->show;
      $entry_command_ogg->hide;
      $entry_command_ape->hide;
      $entry_command_flac->hide;
   }
   if ($opt20 == 4){  # ogg 
      $entry_command_mp3->hide;
      $entry_command_mp4->hide;
      $entry_command_mpc->hide;
      $entry_command_ogg->show;
      $entry_command_ape->hide;
      $entry_command_flac->hide;
   }
   if ($opt20 == 5){
      $entry_command_mp3->hide;
      $entry_command_mp4->hide;
      $entry_command_mpc->hide;
      $entry_command_ogg->hide;
      $entry_command_ape->show;
      $entry_command_flac->hide;
   } 
   if ($opt20 == 6){ #flac
      $entry_command_mp3->hide;
      $entry_command_mp4->hide;
      $entry_command_mpc->hide;
      $entry_command_ogg->hide;
      $entry_command_ape->hide;
      $entry_command_flac->show;
   }
   if ($opt20 == 7){ #wav
      $entry_command_mp3->hide;
      $entry_command_mp4->hide;
      $entry_command_mpc->hide;
      $entry_command_ogg->hide;
      $entry_command_ape->hide;
      $entry_command_flac->hide;
   }     
}

#####-------------------final of Combo-------------#####

# criar um label (etiqueta - r�tulo) ao lado do menu
$label_mp3b = new Gtk2::Label( "Bitrate:" );
$label_mp3b->set_alignment( 1, 0.5 ); 
$table21->attach ($label_mp3b, 4, 5, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$label_mp3b->show();

$label_comp = new Gtk2::Label( "Comp:" );
$label_comp->set_alignment( 1, 0.5 ); 
$table21->attach ($label_comp, 4, 5, 0, 1, ['expand','fill'], 'shrink', 0, 0);
#$label_comp->show();

#####--------------------ComboBox------------------#####
my @all_const_bitrate = ( "32", "40", "48", "56", "64", "80", "96", "112", "128", "160",  "192", "224", "256", "320" );

$ComboBox_const_bitrate = Gtk2::ComboBox->new_text;
ComboBox_fill_with_array(\$ComboBox_const_bitrate,\@all_const_bitrate);
ComboBox_select_this_text(\$ComboBox_const_bitrate,\@all_const_bitrate,\$bitrate_constant);  #standard value
$ComboBox_const_bitrate->set_size_request( 72, -1 );
$ComboBox_const_bitrate->signal_connect("changed", \&BitrateChanged);
$table21->attach ($ComboBox_const_bitrate, 5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0);
#$ComboBox_const_bitrate->show;

## audio mp3 bitrate is changed
sub BitrateChanged {
   $bitrate_constant = $ComboBox_const_bitrate->get_active_text; # copy the value of bitrate changed
   $status_bar->push($context_id, " constant $extension_output bitrate set to $bitrate_constant Kb/s");
   #print "\$bitrate_constant = $bitrate_constant \n";
}

#####----------------final of ComboBox-------------#####

###--------------------SpinButton--------------------###

# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
$adj = new Gtk2::Adjustment( $bitrate_avr_mp3, 8, 320, 1, 5, 0 );
#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits );
$spinner_bitrate_mp3 = new Gtk2::SpinButton( $adj, 0.5, 0 );
$spinner_bitrate_mp3->set_wrap( $true );
$spinner_bitrate_mp3->set_size_request( 72, -1 );
$spinner_bitrate_mp3->set_editable($false);
$spinner_bitrate_mp3->set_update_policy( 'if_valid' );
$tooltips->set_tip( $spinner_bitrate_mp3, $langs{tip220} ) if $show_all_tooltips;
$table21->attach($spinner_bitrate_mp3,  5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$spinner_bitrate_mp3->signal_connect("value-changed", sub{ $bitrate_avr_mp3 = $spinner_bitrate_mp3->get_value_as_int(); } );
#$spinner_bitrate_mp3->set_sensitive($false);
$spinner_bitrate_mp3->show();

$adj = new Gtk2::Adjustment( $bitrate_avr_ogg, 8, 320, 1, 5, 0 );
$spinner_bitrate_ogg = new Gtk2::SpinButton( $adj, 0.5, 0 );
$spinner_bitrate_ogg->set_wrap( $true );
$spinner_bitrate_ogg->set_size_request( 72, -1 );
$spinner_bitrate_ogg->set_editable($false);
$spinner_bitrate_ogg->set_update_policy( 'if_valid' );
$tooltips->set_tip( $spinner_bitrate_ogg, $langs{tip220} ) if $show_all_tooltips;
$table21->attach($spinner_bitrate_ogg,  5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$spinner_bitrate_ogg->signal_connect("value-changed", sub{ $bitrate_avr_ogg = $spinner_bitrate_ogg->get_value_as_int(); } );
#$spinner_bitrate_mp3->set_sensitive($false);
#$spinner_bitrate_mp3->show();

$adj = new Gtk2::Adjustment( $bitrate_avr_mp4, 8, 320, 1, 5, 0 );
$spinner_bitrate_mp4 = new Gtk2::SpinButton( $adj, 0.5, 0 );
$spinner_bitrate_mp4->set_wrap( $true );
$spinner_bitrate_mp4->set_size_request( 72, -1 );
$spinner_bitrate_mp4->set_editable($false);
$spinner_bitrate_mp4->set_update_policy( 'if_valid' );
$tooltips->set_tip( $spinner_bitrate_mp4, $langs{tip220} ) if $show_all_tooltips;
$table21->attach($spinner_bitrate_mp4,  5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$spinner_bitrate_mp4->signal_connect("value-changed", sub{ $bitrate_avr_mp4 = $spinner_bitrate_mp4->get_value_as_int(); } );
#$spinner_bitrate_mp3->set_sensitive($false);
#$spinner_bitrate_mp3->show();

# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
$adj = new Gtk2::Adjustment( $comp_ape, 1000, 5000, 1000, 0, 0 );
#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits );
$spinner_compress = new Gtk2::SpinButton( $adj, 0.1, 0 );
$spinner_compress->set_wrap( $true );
$spinner_compress->set_size_request( 72, -1 );
$spinner_compress->set_editable($false);
$spinner_compress->set_update_policy( 'if_valid' );
$spinner_compress->signal_connect("value-changed", 
sub{ 
   my $comp_ape = $spinner_compress->get_value_as_int();
   $status_bar->push($context_id, $langs{msg065}."$extension_output with compression level = $comp_ape.");
} );
$tooltips->set_tip( $spinner_compress, $langs{tip226} ) if $show_all_tooltips;
$table21->attach($spinner_compress,  5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0);
#$spinner_compress->show();
# $comp = $spinner_compress->get_value_as_int();

# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
$adj = new Gtk2::Adjustment( $comp_flac, 0, 8, 1, 0, 0 );
#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits );
$spinner_compress_flac = new Gtk2::SpinButton( $adj, 0.1, 0 );
$spinner_compress_flac->set_wrap( $true );
$spinner_compress_flac->set_size_request( 72, -1 );
$spinner_compress_flac->set_editable($false);
$spinner_compress_flac->set_update_policy( 'if_valid' );
$spinner_compress_flac->signal_connect("value-changed", 
sub{ 
   my $comp_flac = $spinner_compress_flac->get_value_as_int();
   $status_bar->push($context_id, $langs{msg065}."$extension_output with compression level = $comp_flac.");
} );
$tooltips->set_tip( $spinner_compress_flac, $langs{tip227} ) if $show_all_tooltips;
$table21->attach($spinner_compress_flac,  5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0);
#$spinner_compress->show();
# $comp = $spinner_compress->get_value_as_int();

###-------------final-of--SpinButton-----------------###

# criar um label (etiqueta - r�tulo) ao lado do menu
$label = new Gtk2::Label( "Kb/s" );
$label->set_alignment( 0.0, 0.5 );   
$table21->attach ($label, 6, 7, 0, 1, 'fill', 'shrink', 0, 0);
$label->show();

#####--------------------Combo---------------------#####
# Min BitRate Quality

# criar um label (etiqueta - r�tulo) ao lado do menu
$label = new Gtk2::Label( "Min:" ); 
$label->set_alignment( 1, 0.5 );
$table21->attach ($label, 7, 8, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$label->show;

$ComboBox_Min = Gtk2::ComboBox->new_text;
ComboBox_fill_with_array(\$ComboBox_Min,\@all_const_bitrate);
ComboBox_select_this_text(\$ComboBox_Min,\@all_const_bitrate,\$vb_Min);  #standard value
$ComboBox_Min->set_size_request( 72, -1 );
$ComboBox_Min->signal_connect("changed", \&bit_Min);
$table21->attach ($ComboBox_Min, 8, 9, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_Min->set_sensitive($true);
$ComboBox_Min->show;

## Minimum Bitrate with variable encode
sub bit_Min {   
   $vb_Min = $ComboBox_Min->get_active_text;
   
   if ( $vb_Min > $vb_Max ) { # always assert this condition
      $vb_Min = $vb_Max;
      ComboBox_select_this_text(\$ComboBox_Min,\@all_const_bitrate,\$vb_Min);
   }
}
#####-------------------final of Combo-------------#####


#####--------------------Combo---------------------#####
# Mode for mp3 files

# criar um label (etiqueta - r�tulo) ao lado do menu
my $label_combo_mode = new Gtk2::Label( $langs{name031} . ":" );  
$label_combo_mode->set_alignment( 1, 0.5 );
$table21->attach ($label_combo_mode, 0, 1, 1, 2, 'fill', 'shrink', 0, 0);
$label_combo_mode->show();

my @all_mode = ( 'joint stereo', 'stereo', 'forced joint stereo', 'dual channels', 'mono' );

$ComboBox_mode = Gtk2::ComboBox->new_text;
ComboBox_fill_with_array(\$ComboBox_mode,\@all_mode);
ComboBox_select_this_text(\$ComboBox_mode,\@all_mode,\$mode);  #standard value
$ComboBox_mode->set_size_request( 104, -1 );
$table21->attach ($ComboBox_mode, 1, 2, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_mode->show;

#####-------------------final of Combo-------------#####
#####--------------------Combo---------------------#####
# Variable  BitRate Quality

# criar um label (etiqueta - r�tulo) ao lado do menu
$label_VB = new Gtk2::Label( $langs{name033} . ":" );  
$label_VB->set_alignment( 1, 0.5 );
$table21->attach ($label_VB, 4, 5, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$label_VB->show();

###--------------------SpinButton--------------------###

$adj = new Gtk2::Adjustment( $V, 0, 9, 1, 0, 0 );
$spinner_V = new Gtk2::SpinButton( $adj, 0.1, 0 );
$spinner_V->set_editable($false);
$spinner_V->set_size_request( 72, -1 );
$spinner_V->set_update_policy( 'if_valid' );
$spinner_V->set_wrap( $false );
$tooltips->set_tip( $spinner_V, $langs{tip221} ) if $show_all_tooltips;
$table21->attach($spinner_V,  5, 6, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$spinner_V->set_sensitive($false);
$spinner_V->show();

# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
$adj = new Gtk2::Adjustment( $Vogg, -1.0, 10.0, 0.1, 0, 0 );
$spinner_Vogg = new Gtk2::SpinButton($adj, 0.4, 1);
$spinner_Vogg->set_editable($false);
$spinner_Vogg->set_size_request( 72, -1 );
$spinner_Vogg->set_update_policy( 'if_valid' );
$spinner_Vogg->set_wrap( $false );
$tooltips->set_tip( $spinner_Vogg, $langs{tip222} ) if $show_all_tooltips;
$table21->attach($spinner_Vogg,  5, 6, 1, 2, ['expand','fill'], 'shrink', 0, 0);
#$spinner_Vogg->set_sensitive($false);
#$spinner_Vogg->show();

# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
$adj = new Gtk2::Adjustment( $Vmpc, 2, 8, 1, 0, 0 );
$spinner_Vmpc = new Gtk2::SpinButton($adj, 0.4, 0);
$spinner_Vmpc->set_editable($false);
$spinner_Vmpc->set_size_request( 72, -1 );
$spinner_Vmpc->set_update_policy( 'if_valid' );
$spinner_Vmpc->set_wrap( $false );
$tooltips->set_tip( $spinner_Vmpc, $langs{tip225} ) if $show_all_tooltips;
$table21->attach($spinner_Vmpc,  5, 6, 1, 2, ['expand','fill'], 'shrink', 0, 0);
#$spinner_Vogg->set_sensitive($false);
#$spinner_Vogg->show();      

# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
$adj = new Gtk2::Adjustment( $Vmp4, 10, 500, 1, 0, 0 );
$spinner_Vmp4 = new Gtk2::SpinButton($adj, 0.8, 0);
$spinner_Vmp4->set_editable($false);
$spinner_Vmp4->set_size_request( 72, -1 );
$spinner_Vmp4->set_update_policy( 'if_valid' );
$spinner_Vmp4->set_wrap( $false );
$tooltips->set_tip( $spinner_Vmp4, $langs{tip224} ) if $show_all_tooltips;
$table21->attach($spinner_Vmp4,  5, 6, 1, 2, ['expand','fill'], 'shrink', 0, 0);
#$spinner_Vogg->set_sensitive($false);
#$spinner_Vogg->show();     

###-------------final-of--SpinButton-----------------###
#####--------------------Combo---------------------#####
# Max BitRate Quality

# criar um label (etiqueta - r�tulo) ao lado do menu
$label = new Gtk2::Label( "Max:" );   
$label->set_alignment( 1, 0.5 );
$table21->attach ($label, 7, 8, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$label->show;

$ComboBox_Max = Gtk2::ComboBox->new_text;
ComboBox_fill_with_array(\$ComboBox_Max,\@all_const_bitrate);
ComboBox_select_this_text(\$ComboBox_Max,\@all_const_bitrate,\$vb_Max);  #standard value
$ComboBox_Max->set_size_request( 72, -1 );
$ComboBox_Max->signal_connect("changed", \&bit_Max);
$table21->attach ($ComboBox_Max, 8, 9, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_Max->set_sensitive($true);
$ComboBox_Max->show;

sub bit_Max {   
   $vb_Max = $ComboBox_Max->get_active_text;
   
   if ( $vb_Max < $vb_Min ) { # always assert this condition
      $vb_Max = $vb_Min;
      ComboBox_select_this_text(\$ComboBox_Max,\@all_const_bitrate,\$vb_Max);
   }
}

#####-------------------final of Combo-------------#####

#####-------------------final of Combo-------------#####

# criar um label (etiqueta - r�tulo) ao lado do menu
$label = new Gtk2::Label( $langs{name032} . ":" );
$label->set_alignment( 1.0, 0.5 );
$table21->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0);
$label->show();

###--------------------SpinButton--------------------###

# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size );
$adj = new Gtk2::Adjustment( $quality, 0, 9, 1, 5, 0 );
#$spin = new Gtk2::SpinButton( $adjustment, $climb_rate, $digits );
$spinner_q = new Gtk2::SpinButton( $adj, 0, 0 );
$spinner_q->set_wrap( $true );
$spinner_q->set_editable($false);
$spinner_q->set_size_request( 72, -1 );
$spinner_q->set_update_policy( 'if_valid' );
$tooltips->set_tip( $spinner_q, $langs{tip223} ) if $show_all_tooltips;
$table21->attach($spinner_q,  1, 2, 2, 3, ['expand','fill'], 'shrink', 0, 0);
$spinner_q->signal_connect("value-changed", sub{ $quality = $spinner_q->get_value; } );
$spinner_q->show();

###-------------final-of--SpinButton-----------------###

#####--------------------Combo---------------------#####
# Frequency

# criar um label (etiqueta - r�tulo) ao lado do menu
$label = new Gtk2::Label( $langs{name041} . ":" );   
$label->set_alignment( 1, 0.5 );
$table21->attach ($label, 4, 5, 2, 3, ['expand','fill'], 'shrink', 0, 0);
$label->show();

my @all_freq = ( "8000", "11025", "12000", "16000", "22050", "24000", "32000", "44100", "48000" );

$ComboBox_freq = Gtk2::ComboBox->new_text;
ComboBox_fill_with_array(\$ComboBox_freq,\@all_freq);
ComboBox_select_this_text(\$ComboBox_freq,\@all_freq,\$freq);  #standard value
$ComboBox_freq->set_size_request( 72, -1 );
#$ComboBox_freq->signal_connect("changed", \&BitrateChanged);
$table21->attach ($ComboBox_freq, 5, 6, 2, 3, ['expand','fill'], 'shrink', 0, 0);
$ComboBox_freq->set_sensitive($change_properties);
$ComboBox_freq->show;

$label = new Gtk2::Label( "Hz" );
$label->set_alignment( 0.0, 0.5 );  
$table21->attach ($label, 6, 7, 2, 3, 'fill', 'shrink', 0, 0);
$label->show();

#####-------------------final of Combo-------------#####

$label = new Gtk2::Label( $langs{name013} . ":" );
$label->set_alignment( 1.0, 0.5 ); 
$table21->attach ($label, 0, 1, 3, 4, 'fill', 'shrink', 0, 0);
$label->show();

# Create the Entry to put additional command line
$entry_command_mp3 = new Gtk2::Entry( ); 
$entry_command_mp3->set_text( $additional_command_mp3 );
$tooltips->set_tip( $entry_command_mp3, $langs{tip228} ) if $show_all_tooltips;
$table21->attach($entry_command_mp3,  1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0);

$entry_command_mp4 = new Gtk2::Entry( ); 
$entry_command_mp4->set_text( $additional_command_mp4 );
$tooltips->set_tip( $entry_command_mp4, $langs{tip228} ) if $show_all_tooltips;
$table21->attach($entry_command_mp4,  1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0);

$entry_command_mpc = new Gtk2::Entry( ); 
$entry_command_mpc->set_text( $additional_command_mpc );
$tooltips->set_tip( $entry_command_mpc, $langs{tip228} ) if $show_all_tooltips;
$table21->attach($entry_command_mpc,  1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0);

$entry_command_ogg = new Gtk2::Entry( ); 
$entry_command_ogg->set_text( $additional_command_ogg );
$tooltips->set_tip( $entry_command_ogg, $langs{tip228} ) if $show_all_tooltips;
$table21->attach($entry_command_ogg,  1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0);

$entry_command_ape = new Gtk2::Entry( ); 
$entry_command_ape->set_text( $additional_command_ape );
$tooltips->set_tip( $entry_command_ape, $langs{tip228} ) if $show_all_tooltips;
$table21->attach($entry_command_ape,  1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0);

$entry_command_flac = new Gtk2::Entry( ); 
$entry_command_flac->set_text( $additional_command_flac );
$tooltips->set_tip( $entry_command_flac, $langs{tip228} ) if $show_all_tooltips;
$table21->attach($entry_command_flac,  1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0);


###-----------------------------------------------------###
#####---------------- T a b l e 3 --------------------#####

###----------------id3 tag & mpeg info---------------###

$label = new Gtk2::Label( $langs{name034} . ":" ); # table 'info'
$label->set_alignment( 1.0, 0.5 );   
$table3->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0);
$label->show();

# Create the Entry to put the title of mp3 music
my $entry_title = new Gtk2::Entry();
$entry_title->set_text( "" );
$entry_title->signal_connect("changed",\&change_tag);
$table3->attach_defaults ($entry_title, 1, 6, 0, 1 );
$entry_title->show();

$label = new Gtk2::Label( $langs{name035} . ":" );
$label->set_alignment( 1.0, 0.5 );   
$table3->attach ($label, 0, 1, 1, 2, 'fill', 'shrink', 0, 0);
$label->show();

# Create the Entry to put the artist of mp3 music
my $entry_artist = new Gtk2::Entry();
$entry_artist->set_text( "" );
$entry_artist->signal_connect("changed",\&change_tag);
$tooltips->set_tip( $entry_artist, $langs{tip301}) if $show_all_tooltips;
$table3->attach_defaults ($entry_artist, 1, 6, 1, 2 );
$entry_artist->show();

$label = new Gtk2::Label( $langs{name036} . ":" );
$label->set_alignment( 1.0, 0.5 );   
$table3->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0);
$label->show();

# Create the Entry to put the album of mp3 music
my $entry_album = new Gtk2::Entry();
$entry_album->set_text( "" );
$entry_album->signal_connect("changed",\&change_tag);
$table3->attach_defaults ($entry_album, 1, 6, 2, 3 );
$entry_album->show();

$label = new Gtk2::Label( $langs{name037} . ":" );
$label->set_alignment( 1.0, 0.5 ); 
$table3->attach ($label, 0, 1, 3, 4, 'fill', 'shrink', 0, 0);
$label->show();

# Create the Entry to put the comment of mp3 music
my $entry_comment = new Gtk2::Entry();
$entry_comment->set_text( "" );
$entry_comment->signal_connect("changed",\&change_tag);
$table3->attach_defaults ($entry_comment, 1, 6, 3, 4 );
$entry_comment->show();

$label = new Gtk2::Label( $langs{name038} . ":" );
$label->set_alignment( 1.0, 0.5 );   
$table3->attach ($label, 0, 1, 4, 5, 'fill', 'shrink', 0, 0);
$label->show();

my $entry_year = new Gtk2::Entry();
$entry_year->set_text( "" );
$entry_year->set_size_request(50);
$entry_year->signal_connect("changed",\&change_tag);
$table3->attach_defaults ($entry_year, 1, 2, 4, 5 );
$entry_year->show();

$label = new Gtk2::Label( $langs{name039} . ":" );
$label->set_alignment( 1.0, 0.5 );   
$table3->attach ($label, 2, 3, 4, 5, 'fill', 'shrink', 0, 0);
$label->show();

# Create the Entry to put the track number of mp3 music
my $entry_tn = new Gtk2::Entry();
$entry_tn->set_text( "" );
$entry_tn->set_size_request(40);
$tooltips->set_tip( $entry_tn, $langs{tip302} ) if $show_all_tooltips;
$entry_tn->signal_connect("changed",\&change_tag);
$table3->attach_defaults ($entry_tn, 3, 4, 4, 5 );
$entry_tn->show();

$label = new Gtk2::Label( "/" );
$label->set_alignment( 1.0, 0.5 );   
$table3->attach ($label, 4, 5, 4, 5, 'fill', 'shrink', 0, 0);
$label->show();

my $entry_tt = new Gtk2::Entry();
$entry_tt->set_text( "" );
$entry_tt->set_size_request(40);
$tooltips->set_tip( $entry_tt, $langs{tip303} ) if $show_all_tooltips;
$entry_tt->signal_connect("changed",\&change_tag);
$table3->attach_defaults ($entry_tt, 5, 6, 4, 5 );
$entry_tt->show();

#####----------------Combo---mp3 info--------------#####
# Genre of mp3 info - see  mp3info  -G

# criar um label (etiqueta - r�tulo) ao lado do menu
$label = new Gtk2::Label( $langs{name040} . ":" );
$label->set_alignment( 1.0, 0.5 );  
$table3->attach ($label, 0, 1, 5, 6, 'fill', 'shrink', 0, 0);
$label->show();

# my $cmd = "mp3info -G";
# my $cmd = "lame --genre-list"; # see the command: < lame --genre-list >
# my $list_genre = exec_cmd_system($cmd); # list with all mp3 genre
# $list_genre =~ s/\s*(\d+)\s(.*)/ $1 => "$2", /g;  
# print "$list_genre";

# A hash represents a set of key/value pairs:  --- see perlintro, perlref, perlreftut
# 0 - 147 genre are default;; more than 148 is personal ;;  max number = 255
my %genre_hash = (  123 => "A Cappella",  34 => "Acid",  74 => "Acid Jazz",  73 => "Acid Punk",  99 => "Acoustic",  
20 => "Alternative",  40 => "Alt. Rock",  26 => "Ambient",  145 => "Anime",  90 => "Avantgarde",  116 => "Ballad",  
41 => "Bass",  135 => "Beat",  85 => "Bebob",  96 => "Big Band",  138 => "Black Metal",  89 => "Bluegrass",  0 => "Blues",  
107 => "Booty Bass",  132 => "BritPop",  65 => "Cabaret",  88 => "Celtic",  104 => "Chamber Music",  102 => "Chanson",  
97 => "Chorus",  136 => "Christian Gangsta Rap",  61 => "Christian Rap",  141 => "Christian Rock",  32 => "Classical",  
1 => "Classic Rock",  112 => "Club",  128 => "Club-House",  57 => "Comedy",  140 => "Contemporary Christian",  2 => "Country",  
139 => "Crossover",  58 => "Cult",  3 => "Dance",  125 => "Dance Hall",  50 => "Darkwave",  22 => "Death Metal",  4 => "Disco",  
55 => "Dream",  127 => "Drum & Bass",  122 => "Drum Solo",  120 => "Duet",  98 => "Easy Listening",  52 => "Electronic",  
48 => "Ethnic",  54 => "Eurodance",  124 => "Euro-House",  25 => "Euro-Techno",  84 => "Fast-Fusion",  80 => "Folk",  
115 => "Folklore",  81 => "Folk/Rock",  119 => "Freestyle",  5 => "Funk",  30 => "Fusion",  36 => "Game",  
59 => "Gangsta Rap",  126 => "Goa",  38 => "Gospel",  49 => "Gothic",  91 => "Gothic Rock",  6 => "Grunge",  
129 => "Hardcore",  79 => "Hard Rock",  137 => "Heavy Metal",  7 => "Hip-Hop",  35 => "House",  100 => "Humour",  
131 => "Indie",  19 => "Industrial",  33 => "Instrumental",  46 => "Instrumental Pop",  47 => "Instrumental Rock",  
8 => "Jazz",  29 => "Jazz+Funk",  146 => "JPop",  63 => "Jungle",  86 => "Latin",  71 => "Lo-Fi",  45 => "Meditative",  
142 => "Merengue",  9 => "Metal",  77 => "Musical",  82 => "National Folk",  64 => "Native American",  133 => "Negerpunk",  
10 => "New Age",  66 => "New Wave",  39 => "Noise",  11 => "Oldies",  103 => "Opera",  12 => "Other",  75 => "Polka",  
134 => "Polsk Punk",  13 => "Pop",  53 => "Pop-Folk",  62 => "Pop/Funk",  109 => "Porn Groove",  117 => "Power Ballad",  
23 => "Pranks",  108 => "Primus",  92 => "Progressive Rock",  67 => "Psychedelic",  93 => "Psychedelic Rock",  43 => "Punk",  
121 => "Punk Rock",  15 => "Rap",  68 => "Rave",  14 => "R&B",  16 => "Reggae",  76 => "Retro",  87 => "Revival",  
118 => "Rhythmic Soul",  17 => "Rock",  78 => "Rock & Roll",  143 => "Salsa",  114 => "Samba",  110 => "Satire",  
69 => "Showtunes",  21 => "Ska",  111 => "Slow Jam",  95 => "Slow Rock",  105 => "Sonata",  42 => "Soul",  37 => "Sound Clip",  
24 => "Soundtrack",  56 => "Southern Rock",  44 => "Space",  101 => "Speech",  83 => "Swing",  94 => "Symphonic Rock",  
106 => "Symphony",  147 => "Synthpop",  113 => "Tango",  18 => "Techno",  51 => "Techno-Industrial",  130 => "Terror",  
144 => "Thrash Metal",  60 => "Top 40",  70 => "Trailer",  31 => "Trance",  72 => "Tribal",  27 => "Trip-Hop",  28 => "Vocal",
# this is additional genre from Brazilian music
148 => "MPB", 149 => "Bossa Nova", 150 => "Capoeira", 151 => "Chorinho", 152 => "Forr", 153 => "Maracatu",
154 => "Timbalada", 155 => "Ax", 156 => "Sertanejo", 157 => "Pagode",
# this is additional genre
158 => "World Music"
);

# print "\nhash of genre --- element 32: ",$genre_hash{"32"}," \n";
my $count_pairs = keys %genre_hash; # Get the number of elements (key-value pairs) in the hash.
#print "count_pairs = $count_pairs\n";

my @array_genre = (); # array with only the names 
for my $key (0..158) {
   #print "$key => $genre_hash{$key}\n";
   push @array_genre,$genre_hash{$key};
}
@array_genre = sort @array_genre;

my $ComboBoxEntry_genre = Gtk2::ComboBoxEntry->new_text;
ComboBox_fill_with_array(\$ComboBoxEntry_genre,\@array_genre);
#ComboBox_select_this_text(\$ComboBoxEntry_genre,\@array_genre,"");  #standard value
$ComboBoxEntry_genre->child->set_text( "" );  #standard value
$ComboBoxEntry_genre->signal_connect("changed", \&change_tag);
$table3->attach ($ComboBoxEntry_genre, 1, 6, 5, 6, 'fill', 'fill', 0, 0);
$ComboBoxEntry_genre->show;


# when whatever tag is changed, the button_save_tag is set to set_sensitive($true)
my $abandon_change_tag = $false; # if '$abandon_change_tag eq $true' then force to abandon the 'sub change_tag'

sub change_tag {  # sub cell_edited {

   return if $abandon_change_tag;
   
   # get selected row  from 'sub get_selection_tree' that will be used by 'sub change_tag' and 'sub save_tag'
   my $row = $files_info[0]{get_selection_row}; 
   
   return unless defined $row;        
   
   my $filepath        = $files_info[$row]{filepath};
   #$filepath = filename_from_unicode $filepath if( ! -e $filepath );
   my $extension_input = $files_info[$row]{extension_input};   
   
   # get all current 8 entries:
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};       
   
   #print "\n sub change_tag --->1 \$row = $row \$filepath = $filepath ;; \$Title = $Title ;; \$Album = $Album ;; \$extension_input = $extension_input\n";
   
  
      my $title  = $entry_title->get_text;
      my $artist = $entry_artist->get_text;
      my $album  = $entry_album->get_text;
      my $comment= $entry_comment->get_text;
      my $genre  = $ComboBoxEntry_genre->child->get_text;                
      
      # some verifications/validations
      my $year = "invalid";
      if ( $entry_year->get_text =~ /^(\d{1,4})$/ ) { $year = $1; }
      if ( $entry_year->get_text eq "" ) { $year = ""; }                 
      my $tn = "invalid"; # track number
      if ( $entry_tn->get_text =~ /^(\d+)$/ ) { $tn = $1; } 
      if ( $entry_tn->get_text eq "" ) { $tn = ""; } 
      my $tt = "invalid"; # track total
      if ( $entry_tt->get_text =~ /^(\d+)$/ ) { $tt = $1; }
      if ( $entry_tt->get_text eq "" ) { $tt = ""; }          
      
      # verify any change in tag: Title, Artist, ...
      if ( ($extension_input =~ /(mp3|mpc|ogg|ape|flac|wav)/) and ($title ne $Title or $artist ne $Artist or $album ne $Album 
          or $comment ne $Comment or $year ne $Year or $tn ne $Track_Number or $tt ne $Total_Track or $genre ne $Genre) )
      {
          # Test if the $filepath is writable. '-w'  File is writable by effective uid/gid.
          if ( not file_is_writable($filepath) ) {
	      $button_save_tag->set_sensitive($false);
	      return $false;
	  }
          if ( $tn =~ /^(\d+)$/ and $tt =~ /^(\d+)$/ ) { 
	     if ( $tt < $tn ){ # only compare for numbers
	        $status_bar->push($context_id, $langs{msg080} );
	        $button_save_tag->set_sensitive($false);
	        return $false;
	     } 
	  }  
	  if ( ( $tn eq "" and $tt =~ /^(\d+)$/ ) or $tn eq "invalid" or $tt eq "invalid" or $year eq "invalid" ) {
	     $status_bar->push($context_id, $langs{msg080} );
	     $button_save_tag->set_sensitive($false);    
	     return $false; 
	  }          	  
          $tooltips->set_tip( $button_save_tag, $langs{tip304} ) if $show_all_tooltips;	  
      }
      elsif ( ($extension_input =~ /(cda)/) and ($title ne $Title or $artist ne $Artist or $album ne $Album 
          or $year ne $Year or $genre ne $Genre) )
      {
          if ( $year eq "invalid" ) {
	     $status_bar->push($context_id, $langs{msg080} );
	     $button_save_tag->set_sensitive($false);    
	     return $false; 
	  }
	  $tooltips->set_tip( $button_save_tag, $langs{tip305} ) if $show_all_tooltips;
      }	
      elsif ( $extension_input =~ /(mp4)/ ){ # for mp4 file
	  # get info to be saved on normalized file
          $status_bar->push($context_id, $langs{msg061} );
	  return $false;
      }		
      else { # $extension_input = other
          $status_bar->push($context_id, "" );
          $button_save_tag->set_sensitive($false);
	  return $false;
      }      
      
      update_tags($title,$artist,$album,$comment,$year,$tn,$tt,$genre);      
      
      $button_save_tag->set_sensitive($true);
      $status_bar->push($context_id, $langs{msg070} );
      
      #print "\n sub change_tag --->2 \$row = $row \$filepath = $filepath ;; title = $title ;; album = $album\n";
      
      return $true;      
}

my %temp_tags; # the hash %temp_tags is a temporaty variables only used on sub change_tag

sub update_tags {  # used by save_tag
   my ($title,$artist,$album,$comment,$year,$tn,$tt,$genre) = @_;

   %temp_tags = ();

   # the hash %temp_tags is a temporaty variables only used on 'sub change_tag'.
   $temp_tags{title}   = remove_change_10_chars($title);
   $temp_tags{artist}  = remove_change_10_chars($artist);   
   $temp_tags{album}   = remove_change_10_chars($album);
   $temp_tags{comment} = remove_change_10_chars($comment);
   $temp_tags{genre}   = remove_change_10_chars($genre);
   $temp_tags{year}    = remove_change_10_chars($year);
   $temp_tags{track}   = remove_change_10_chars($tn);     # $Track_Number
   $temp_tags{total_track}  = remove_change_10_chars($tt);   
   
   #print "\n sub update_tags ---> Title = $temp_tags{title} ;; Artist = $temp_tags{artist} ;; Album = $temp_tags{album}\n";
}

sub file_is_writable {
   # Test if the $filepath is writable.
   # '-w' file is writable by effective uid/gid.
   my $filepath = shift;
   if ( not -w filename_from_unicode $filepath ) {
      $status_bar->push($context_id, " $filepath ".$langs{msg012} );
      return $false;
   }
   return $true;
}

#####-------------final of Combo---mp3 info--------#####


###----------------------table 31 -------------------###

my $label_mpeg = new Gtk2::Label( "MPEG" );
#$label_mpeg->set_justify( 'left' );   
$label_mpeg->set_alignment( 0, 0.5 );
$table31->attach ($label_mpeg, 0, 1, 1, 2, 'fill', ['expand','fill'], 0, 0 );
$label_mpeg->show();
#$label_mpeg->set_label ($str);

my $label_kbps = new Gtk2::Label( "Bitrate:" );  
$label_kbps->set_alignment( 0, 0.5 );
$table31->attach ($label_kbps, 0, 1, 2, 3, 'fill', ['expand','fill'], 0, 0 );
$label_kbps->show();

my $label_freq = new Gtk2::Label( $langs{name041} . ":" );  
$label_freq->set_alignment( 0, 0.5 );
$table31->attach ($label_freq, 0, 1, 3, 4, 'fill', ['expand','fill'], 0, 0);
$label_freq->show();

my $label_mode = new Gtk2::Label( $langs{name031} . ":" ); 
$label_mode->set_alignment( 0, 0.5 );   
$table31->attach ($label_mode, 0, 1, 4, 5, 'fill', ['expand','fill'], 0, 0);
$label_mode->show();

my $label_time = new Gtk2::Label( $langs{name042} . ":" );  
$label_time->set_alignment( 0, 0.5 ); 
$table31->attach ($label_time, 0, 1, 5, 6, 'fill', ['expand','fill'], 0, 0);
$label_time->show();

my $label_size = new Gtk2::Label( $langs{name048} . ":" );  
$label_size->set_alignment( 0, 0.5 ); 
$table31->attach ($label_size, 0, 1, 6, 7, 'fill', ['expand','fill'], 0, 0);
$label_size->show();

$separator = Gtk2::HSeparator->new;
$table31->attach ( $separator, 0, 1, 7, 8, ['expand','fill'],['expand','fill'], 0, 0 );
$separator->show;


$button_save_tag = Gtk2::Button->new;
$button_save_tag->add( DrawIcons('gtk-save','button') );
#$tooltips->set_tip( $button_save_tag, "Save changes of tag to $extension_input file.");
$button_save_tag->signal_connect( "clicked", \&save_tag );
$table31->attach ($button_save_tag,  0, 1, 8, 9 , 'shrink', 'shrink', 0, 0);
$button_save_tag->set_sensitive($false);
$button_save_tag->set( 'focus-on-click' => $false, 'relief' => 'none' );	 
$button_save_tag->show();


###----------------id3 tag & mpeg info---------------###
######--------------------------------------------######

###----------------------table 4 --------------------###
#--------------------------Rip-------------------------#

# some buttons
my $hbox4 = Gtk2::HBox->new ($false, 2);
#$box->pack_start ($child, $expand, $fill, $padding)
$vbox4->pack_start ($hbox4, $false, $false, 0);
$hbox4->show;

$label = new Gtk2::Label( " cdrom:" );
$label->set_alignment( 1.0, 0.5 );  
$hbox4->pack_start ($label, $false, $false, 0);
$label->show();

# Create the Entry to put the cdrom drive path
$entry_cda = new Gtk2::Entry();
$entry_cda->set_text($audiodevice_path);
$tooltips->set_tip( $entry_cda, $langs{tip401} ) if $show_all_tooltips;
$entry_cda->set_size_request(120);
$entry_cda->signal_connect("changed", \&entry_cda_change );
$hbox4->pack_start ($entry_cda, $false, $false, 0);
$entry_cda->show();

$button = Gtk2::Button->new;
$button->add( DrawIcons('gtk-refresh','button') );
$button->set( 'focus-on-click' => $false, 'relief' => 'none' );
$tooltips->set_tip( $button, $langs{tip402} ) if $show_all_tooltips;
$button->signal_connect (clicked => \&refresh_cda);
$hbox4->pack_start ($button, $false, $false, 0);
$button->show;

# my $button_selec = Gtk2::Button->new ("unselect all");
my $button_selec = Gtk2::Button->new;
$button_selec->add( DrawIcons('gtk-close','button') );
$button_selec->set( 'focus-on-click' => $false, 'relief' => 'none' );
$tooltips->set_tip( $button_selec, $langs{tip404} ) if $show_all_tooltips;
$button_selec->signal_connect (clicked => \&unselect_cda);
#$button_selec->set_sensitive($false);
$button_selec->show;

my $button_unselec = Gtk2::Button->new;
$button_unselec->add( DrawIcons('gtk-cancel','button') );
$button_unselec->set( 'focus-on-click' => $false, 'relief' => 'none' );
$tooltips->set_tip( $button_unselec, $langs{tip403} ) if $show_all_tooltips;
$button_unselec->signal_connect (clicked => \&unselect_cda);
$button_unselec->set_sensitive($false);
$button_unselec->show;

# this align is a container that hold two buttons alternately
my $align_selec = Gtk2::Alignment->new(0.5, 0.5 , 0, 0);
$align_selec->add ($button_unselec);
$hbox4->pack_start ($align_selec, $false, $false, 0);
$align_selec->show;

# to fill the empty space
$label = new Gtk2::Label( " " );
$label->set_alignment( 0.5, 0.5 );   
$hbox4->pack_start ($label, $true, $true, 0);
$label->show;


###---------------------- Display --------------------###
#------------------------- start -----------------------#

# convert sound.png -resize 32x32 -enhance -colors 16 sound.xpm  or use gimp > Image > Mode > Indexed
# convert sound.xpm -resample 12x40 -colors 16 -enhance  sound2.xpm
# cat sound.xpm | sed "s/\\\$/S/g" | sed "s/\@/x/g"|sed "/pixels/d" >sound3.xpm
my @sound = (
# /* columns rows colors chars-per-pixel */
"160 186 41 1",
" 	c None",
".	c #2C2827",
"+	c #39312E",
"x	c #453331",
"#	c #413739",
"S	c #413A35",
"%	c #453935",
"&	c #483C38",
"*	c #46403A",
"=	c #4A4041",
"-	c #524641",
";	c #514647",
">	c #5C4750",
",	c #594A51",
"'	c #5A4D49",
")	c #594E4E",
"!	c #62535A",
"~	c #605555",
"{	c #645752",
"]	c #695A61",
"^	c #675C5D",
"/	c #716169",
"(	c #6F635E",
"_	c #6E6364",
":	c #766964",
"<	c #75696B",
"[	c #796E6E",
"}	c #7D7272",
"|	c #827676",
"1	c #867A7B",
"2	c #8B7F7F",
"3	c #8F8384",
"4	c #92837F",
"5	c #968A8A",
"6	c #9C9090",
"7	c #A29697",
"8	c #A99D9E",
"9	c #B0A3A4",
"0	c #B6AAAA",
"a	c #BCB0B0",
"b	c #DBD5D3",
"                                                                                                                                                                ",
"                                                                                                                                                                ",
"                                                                                 888888888888888888                                                             ",
"                                                                             88888888888888888888888888                                                         ",
"                                                                         888888888888888888888888888888888                                                      ",
"                                                                       88888888888888888888888888888888888888                                                   ",
"                                                                    8888888888888888888888888888888888888888888                                                 ",
"                                                                  88888888888888888876553333556788888888888888888                                               ",
"                                                                88888888888888863|[<<::::__(____<[13688888888888888                                             ",
"                                                              888888888888865|[<<<<<_({{{''''{{{^__((<158888888888888                                           ",
"                                                             8888888888885|<<<:_{'-&&&&&&&&&&&&&&&-''{((:1688888888888                                          ",
"                                                           8888888888861[<<:({-&&&&&&&&&&&&&&&&&&&&&&&&-{((<588888888888                                        ",
"                                                          88888888886|<<<_{-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-{^<38888888888                                       ",
"                                                        888888888861[<<('&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-'^<5888888888                                      ",
"                                                       88888888872[[<{-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'(|788888888                                     ",
"                                                      8888888885[[[(-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-{_5888888888                                   ",
"                                                     888888886|[[:'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-{|888888888                                  ",
"                                                   8888888885[[<{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'<688888888                                 ",
"                                                  8888888882[[_-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-{588888888                                ",
"                                                 888888886|[[{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{288888888                               ",
"                                                888888885}[<'&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&'|88888888                              ",
"                                               888888883[[(*&&&&&&&&&&&&&&&&&&&&---------*SSSSSSSSS%&&&&&&&&&&&&&&&&&&&&&'|8888888                              ",
"                                              888888882[[{&&&&&&&&&&&&&&&&&'{{^________<<<<_~'*SSSSSSSS%&&&&&&&&&&&&&&&&&&-}8888888                             ",
"                                             888888881[['&&&&&&&&&&&&&&-{__^^^_________<<<<<<[[_{*SSSSSSSS%&&&&&&&&&&&&&&&&-|8888888                            ",
"                                            888888881[['&&&&&&&&&&&&&{<<^^^^^^^_________<<<<<[[[[[_'SSSSSSSSS&&&&&&&&&&&&&&&-18888888                           ",
"                                           888888881[<-&&&&&&&&&&&-(<_^^^^^^^^^^________<<<<<<[[[[[[<{*SSSSSSSS&&&&&&&&&&&&&&-38888888                          ",
"                                           88888881}[-&&&&&&&&&&-_[^^^^^^^^^^^^^^________<<<<<[[[[[[[[<'SSSSSSSS%&&&&&&&&&&&&&'5888888                          ",
"                                          88888882}[-&&&&&&&&&&^[^^^^^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[_-SSSSSSSS%&&&&&&&&&&&&{6888888                         ",
"                                         88888883}[-&&&&&&&&&{[^^^^^^^^^^^^^^^^^^^________<<<<<[[[[[[[[[[[{SSSSSSSSS&&&&&&&&&&&&_8888888                        ",
"                                        88888885}['&&&&&&&&-<_~~~~~^^^^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[_*SSSSSSSSS&&&&&&&&&&&}888888                        ",
"                                       88888886}['&&&&&&&&'<^~~~~~~~~~^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[[<'SSSSSSSSS&&&&&&&&&&*5888888                       ",
"                                       8888886|}{&&&&&&&&(_~~~~~~~~~~~~~^^^^^^^^^^^^______<<<<<[[[[[[[[[[[[[[[{SSSSSSSSS&&&&&&&&&&'7888888                      ",
"                                      8888887|}{&&&&&&&-<^~~~~~~~~~~~~~~~^^^^^^^^^^^_______<<<<[[[[[[[[[[[[[[[[{SSSSSSSSS&&&&&&&&&&<888888                      ",
"                                     88888882}_&&&&&&&-_~~~~~~~~~~~~~~~~~~^^^^^^^^^^^______<<<<<[[[[[[[[[[[[[[[[{SSSSSSSSS&&&&&&&&&&3888888                     ",
"                                     8888885}<-&&&&&&'_~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^______<<<<<[[[[[[[[[[[[[[[[[^SSSSSSSSS&&&&&&&&&'888888                     ",
"                                    8888886|}'&&&&&&'^~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^______<<<<<[[[[[[[[[[[[[[[[[[~SSSSSSSSS&&&&&&&&&[888888                    ",
"                                   88888881}{&&&&&&'^~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^_____<<<<<[[[[[[[[[[[[[[[[[[[{SSSSSSSSS&&&&&&&&*6888888                   ",
"                                   8888883}(&&&&&&'~~~~~~~~~~~~~~)~~~~~~~~~~~^^^^^^^^^______<<<<[[[[[[[[[[[[[[[[[[[['SSSSSSSSS&&&&&&&&(888888                   ",
"                                  8888886}[-&&&&&'~~~~)~))))))))))~)~~~~~~~~~~^^^^^^^^______<<<<[[[[[[[[[[[[[[[[[[[[<*SSSSSSSSS&&&&&&&&5888888                  ",
"                                 8888888|}'&&&&&-~~~))))))))))))))))~~~~~~~~~~^^^^^^^^______<<<<[[[[[[[[[[[[[[[[[[[[[_*SSSSSSSSS&&&&&&&{888888                  ",
"                                 8888883}^&&&&&-~~~))))))))))))))))))~~~~~~~~~~^^^^^^^______<<<<[[[[[[[[[[[[[[[[[[[[[[{SSSSSSSSS%&&&&&&&5888888                 ",
"                                8888886|[&&&&&&~~~)))))))))'''))))))))~~~~~~~~~^^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[-SSSSSSSSS&&&&&&&{888888                 ",
"                                8888882}'&&&&&)~~)))))))))''')))'))))))~~~~~~~~^^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[<*SSSSSSSSS&&&&&&&588888                 ",
"                               8888885|_&&&&&)))))))))'''''''')'')'))))))~~~~~~~^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[[^SSSSSSSSSS&&&&&&(888888                ",
"                               888888|}-&&&&-~))))))''''''''''''''))))))~~~~~~~~^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[[[-SSSSSSSSS&&&&&&&688888                ",
"                              8888885|{&&&&*)))))''''''))))))))'''))')))))~~~~~~^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[[[_SSSSSSSSSS&&&&&&<888888               ",
"                              888887|[-&&&%))))))''''))))))))))))''))))))~~~~~~~^^^^^^^____<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[['SSSSSSSSS%&&&&&-788888               ",
"                             8888883|{&&&%-)))'''')))))------))))))''))))))~~~~~^^^^^^^____<<<<[[[[[}}}}}}}}}}}}}[[[[[[[[[<SSSSSSSSSS&&&&&&288888               ",
"                             888888|[&&&&*)))''''))))-;;;;;;;;-))))'''')))~~~~~~~^^^^^^____<<<<[[[}}}}}}}}}}}}}}}}}[[[[[[[['SSSSSSSSSS&&&&&{888888              ",
"                          +%5888883|{&&&%)))''')'));;;;;;;;;;;;;-))''')))))~~~~~~^^^^^^____<<<<[[}}}}}}}}}}}}}}}}}}}}[[[[[[<*SSSSSSSSS&&&&&&688888              ",
"                       +++%{888887|[&&&%-)))'')))-;;;;;;;;;;;;;;;-)''''')))~~~~~~^^^^^^___<<<<[[}}}}}}}}}}}}}}}}}}}}}}}[[[[['SSSSSSSSSS&&&&&}88888              ",
"                      ++-:47888885|{&&&%))''')));;;;;;;;;;;;;;;;;;)))'')))))~~~~~^^^^^^___<<<<[[}}}}}}}|||||||}}}}}}}}}}[[[[_SSSSSSSSSS&&&&&'888888             ",
"                    ++'|444888888|[&&&%;)'''))-;;;;;;;;;;;;;;;;;;;;)))'')))~~~~~~^^^^^___<<<<[[[}}}||||||||||||||}}}}}}}}}[[[-SSSSSSSSS%&&&&&688888             ",
"                   +%:44447888885|{&&S&)'''))-;;;;;;;--;;;-;;;;;;;;-))''')))~~~~~^^^^^___<<<<[[}}|||||||||||||||||||}}}}}}}[[{%SSSSSSSSS&&&&&[88888             ",
"                  +-|444448888882}&&&&)'''))-;;;;;;-;--;;--;;;;;;;;;)''''))~~~~~~^^^^^___<<<[[}}|||||||||||||||||||||}}}}}}}[[*%SSSSSSSS%&&&&'888888            ",
"                 +'4444446888886|^&&%=)''))-;;;;;-;;;------;-;;;;;;;-)''))))~~~~~^^^^^__<<<<[[}}|||||||||||||||||||||||}}}}}}['%%SSSSSSSS&&&&&688888            ",
"                +'44444448888883|-&&%)''))-;;;;;;--;-=====---;=-===;;))'')))~~~~{^^^^___<<<[[}}||||||1111111111|||||||||}}}}}}_S%SSSSSSSS&&&&&188888            ",
"               +-44444445888887|(&&%=)'')-;;;;;;;--========S+........+S-))))~~~~~^^^____<<[[[}||||111111111111111||||||||}}}}}[*S%SSSSSSSS&&&&(888888           ",
"              +&444444446888885|'&%%'''));;;;---;=======#+...............S))~~~~~^^^___<<<[[}}||1111112222222211111|||||||}}}}}{%%%SSSSSSS&&&&-888888           ",
"             +%|444444448888881[&&S=''));;;;---=======#....................=)~~{^^^^___<<[[}}|||111222222222222221111||||||}}}}_SS%SSSSSSS&&&&&588888           ",
"            ++:44444446b888887|{&S%)')';;;;---=====-*+......................+)~^^^^^__<<<[[}|||11222222444442222221111||||||}}}[-%S%SSSSSSS&&&&|88888           ",
"            +'44444444ba888885}-&S&'')-;;;---====-&+..........................){^^^___<<[[}}||1122222343333333242222111|||||}}}}'SS%SSSSSSS&&&&(888888          ",
"           +%44444444ba7888881<&&%;'');;;;-;====**+............................)^^^___<<[}}||112222333333333333322222111|||||}}}^S%%%SSSSSS&&&&'888888          ",
"           +(4444444ab/888886|{&S%'));;;;;-===-**..............................+)^___<<[[}|||1222333333333333333342222111||||}}}<*SS%SSSSSS%&&&&688888          ",
"          +-44444448b<<888883|-&%=')-;;;;-===-&*...............................++~__<<<[}}||12233333555555555533333222211|||||}}[-SS%SSSSSSS&&&&588888          ",
"          +:4444444b7>5888881:&%%'));;;-;-==-&*...............................+++S^_<<[[}||1122333555555555555553333232211||||}}}'*S%%SSSSSS&&&&|88888          ",
"         +-4444444ab>>888887|{&%&');;;;-;==-&*................................++++;<<<[}}||12233355555555555555555333222111||||}}{*SS%SSSSSS&&&&_88888          ",
"         +:4444445b|>/888885|-%+-'-;;;;-===&&+...............................+++++#^<[[}||123335555555565555555555533322211||||}}_*SS%SSSSSSS&&&'888888         ",
"        +%4444444aa>>1888882<&%%));;;-;===*&+...............................+++++++=<[}||11223555556666666666655555533322211||||}[&*SS%SSSSS%&&&-888888         ",
"        +{4444446b/>>688887|{&%='-;;;-;==*&S.................+##====#++.....+++++#SS^[}||12333555566666666666666555553322211||||}}-*SS%SSSSSS&&&&788888         ",
"        +|444444aa>>!888886|-%+;);;;--==-*&................#;,,,,,,,,,,=#..++++++#SS;[||1223355566666666666666666555433342211|||}}'&SS%SSSSSS&&&&588888         ",
"       +-4444444b|>>/888885[&%%)-;;;--==&&+..............#,,,,,,,,,,,,,,,,#+++++#SS==_||1223555666666677777766666655553332211||||}{&*%%SSSSSS&&&&188888         ",
"       +(4444449b>>>1888882(&+&);;;;-==*&S.............#,,,,,,,,,,,,,,,,,,,,+++#SSS==~|12333556666677777777777666665555332211||||}{&*S%%SSSSS&&&&[88888         ",
"       +|444444b7>>>588888|{%+=-;;;--==&=.............=,,,,,,,,,,,,,,,,,,,,,,#++SS===;|123355666667777777777777666665553322211|||}(**S%%SSSSSS&&&_88888         ",
"      +%4444444b/>>>788886|-%+;;;;;-==*=S..........++;!!!!!!,,,,,,,,,,,,,,,,!!=SSS==;;<223555666677777888887777766665555332211|||}:&&SS%SSSSS%&&&{888888        ",
"      +'4444440b>>>]888885}&SS-;;;;===*&.........++#;]]]]]]!!!,,,,,,,,,,,,,!!!!=S===;;^233556667777888888888877776666555332211||||[&*SS%SSSSSS&&&'888888        ",
"      +(444444b8>>><888883_S+&;;;;-==**S........++S;////////]]!!,,,,,,,,,,,!!!!!===;;)~2355566777788888888888887776665553322211|||[-&*%%SSSSSS&&&-888888        ",
"      +|444444b1>>>3888881{%+=;;;--==*=+.......++#;/<|11111<//]]!,,,,,,,,,!!!!!]!==;;))1355667778888888998888888777666555332211|||}-&&%SSSSSS%&&&*888888        ",
"     +%4444446b!>>>6888871'%+;;;-;==*&#.......++S=]<133553331<//]!!,,,,,,,!!!!!]]);;))~|556667788888999999998888777666555332211|||}'**S%SSSSSS&&&&788888        ",
"     +-4444440b>>>>888886|-%S;;;;;==&&+.......++=)<13577777531|//]!!,,,,,,!!!!]]]];;))~[556677888899999999999888877766655332211|||}'**SSSSSSSS&&&&688888        ",
"     +'444444a0>>>!888885[&+%;;;;==-&=........+#=/|3578999977531//]!!,,,,!!!!!]]]/~))~~<566777888999999999999988877766655332211|||}'&&SSSSSSSS&&&&588888        ",
"     +{444444b6>>>/888883_S+&;;;-==*&#........+#;/13679000098751|/]!!,,,,!!!!!]]///))~^<566778889999999999999998887766655533221||||'*&SSSSSSSS&&&&588888        ",
"     +(444444b1>>>|888882{%+-;;-;==*=+........+S!/136790aaa098731</]!!,,,!!!!]]]///~~~^<6677888999999900009999998887766555332211|||{*&SS%SSSSS&&&&588888        ",
"     +:444444b/>>>1888881'S+;;;;==-&&+........+#]/|357900aa009753|/]!!,,!!!!!]]]///^~~^<667788999999000000099999888776655533221||||{&*SS%SSSSS&&&&388888        ",
"     +}444446b!>>>5888871-%%;;--==*&&.........+#]/<1367900a009753|/]!!,,!!!!!]]/////~^^<6678889999000000000099999887766655332211|||{&*SS%SSSSS&&&&388888        ",
"     +|444446b!>>>688887|&+%;;;;==&=#..........=!]/<1367990099753|/]!!!!!!!!]]]////<^^^<6778899990000000000009999887766655332211|||{&*SS%SSSSS&&&&388888        ",
"     +|444447b>>>>788886[*+%;;--==&&+..........=!!]/|136779887631</]!!!!!!!!]]]////<^^_<6788899900000000000000999888776655332211|||{&*SS%SSSSS&&&&388888        ",
"     +|444448b>>>!888885<%+=;;;==-&=+..........,,!]//<1335676531|//]!!!!!!!!]]////<<_^_[6788999900000aaaa00000999988776655532211|||{**SS%SSSSS&&&&388888        ",
"     +|444448b>>>]888885(S+=;--==*&=+..........;,,!!]//|1133311|//]!!!,!!!!!]]////<<<^_}788899900000aaaaaa0000099988776655532211|||'**SS%SSSSS&&&&588888        ",
"     +|444448b>>>/888883{S+=;;-==&&&...........;,,,!!]///<|||<///]!!!,,!!!!]]]////<|<_<|78899900000aaaaaaaa000099988776655532211|||'&*SS%SSSSS&&&&588888        ",
"     +:444448b>>>/888882{%+;;;;==&&%...........,,,,,!!!]]/////]]!!!!,,,!!!!]]]////<|<_<17889990000aaaaaaaaa000099988776655532211|||'&*SS%SSSS%&&&&588888        ",
"     +:444447b>>><888882'%+;;--==*=#...........,,,,,,,,!!!!!!!!!!!,,,,,!!!!]]]///<<|<_<3788999000aaaaaaaaaaa00099988776655532211||}-&*SS%SSSSS&&&&688888        ",
"     +(444446b!>>1888881'%%;;;==-*=#...........=,,,,,,,,,,,!!,,,,,,,,,!!!!!]]////<<|<_<5889990000aaaaaaaaaaa00099988776655532211||}-&*SS%SSSS%&&&&688888        ",
"     +'444444b/>>1888881-+%;-;==-&=#...........#,,,,,,,,,,,,,,,,,,,,,,!!!!!]]////<|1<_<688999000aaaaaaaaaaaaa0099988776655532211||}-*&SSSSSSS%&&&&788888        ",
"     +-444444b|>>388888|-+%;-;==-&=#...........#,,,,,,,,,,,,,,,,,,,,,,!!!!]]]////<||_<[788999000aaaaaaaaaaaa0009998877665533421|||[&*&SSSSSSS&&&&-888888        ",
"     +%444444b3>>388888}&+%;;-==-&=#...........+,,,,,,,,,,,,,,,,,,,,,,!!!!]]]////<||_<|788999000aaaaaaaaaaaa00099988776655332211||:&&*SSSSSSS&&&&-888888        ",
"      +|44444b9>>388887}&+%;;-==-*&%............;,,,,,,,,,,,,,,,,,,,,,!!!!]]]////<|<_<3788999000aaaaaaaaaaaaa009998877665433221|||(&**S%SSSSS&&&&'888888        ",
"      +(44444ab>>588887[&+%;;-==-*&#............#,,,,,,,,,,,,,,,,,,,,,!!!!]]]///<<|__<688999000aaaaaaaaaaaaa0009998877665533221|||{&**SSSSSSS&&&&{888888        ",
"      +-444447b>>588887[%+%;;-==-&&&............+,,,,,,,,,,,,,,,,,,,,,!!!!]]]///<<<^_[788999000aaaaaaaaaaaaa0009998876665533221|||{&&&%%SSSS%&&&&(88888         ",
"      +%444444b<>588887[S+%;;-===&*&.............=,,,,,,,,,,,,,,,,,,,,!!!!]]]///<<_^_17889990000aaaaaaaaaaaa0009998776655533211|||'*&*S%SSSS%&&&&[88888         ",
"       +(44444b8>588887<%+%;;-===*&=+............+,,,,,,,,,,,,,,,,,,,,!!!!]]]///<<^^_57889999000aaaaaaaaaaa00009998876655532211|||-&*SS%SSSSS&&&&188888         ",
"       +&444440b>588887<%+%;-;===**&+.............=,,,,,,,,,,,,,,,,,,,!!!!]]]///<^^^[67889999000aaaaaaaaaaa00099988776655334211||[**&SS%SSSS&&&&&588888         ",
"        +:44444b/588887<%+%;-;-==-&&S..............;,,,,,,,,,,,,,,,,,,!!!!]]]///_~^^2778889990000aaaaaaaaa00009998877665533221|||:&&*S%%SSSS&&&&&688888         ",
"        +-44444b8588887<%+%;--;===***..............+,,,,,,,,,,,,,,,,,,!!!!]]]///~~^_6677889990000aaaaaaaaa00099998876665533221|||{&**%SSSSSS&&&&*888888         ",
"         +(44449b788887<&+%;;--===-*&...............#,,,,,,,,,,,,,,,,,!!!!]]]//~)~^|66778899900000aaaaaaa000099988776655533211|||'*&*%%SSSS%&&&&'888888         ",
"         +x|4444b088887<&+%;;;-====-*+...............#,,,,,,,,,,,,,,,,!!!!]]]])))~^5667788999900000aaaa00000999988776655332211||}-&*SS%SSSS&&&&&(888888         ",
"          +-4444aa88888[&%%;;;;;====-S................#;,,,,,,,,,,,,,,!!!!]]]);))~}6667788999900000000000000999887766655332211||[**&SS%SSSS&&&&&[88888          ",
"           +-4444088888[&%%;;---=====&.................+;,,,,,,,,,,,,,!!!!])=;;))^5666778889999000000000000999988776655533221|||(&&*S%SSSS%&&&&&288888          ",
"            +-444788888}&S%;;;;;;=====+..................#,,,,,,,,,,,,!!!,===;;))15566777889999900000000009999887776655332211|||{&&*%%SSSS%&&&&&688888          ",
"             +&:4788888|&S+;;;----=====....................#=,,,,,,,,,,;=S#==;;)_55566677888999990000000099999887766655332211||}-&*SS%SSSS&&&&&-788888          ",
"              ++-3888881*S+;;;;;;-;====+......................+##===##++#SS===;~25556667788899999900000999999887766655533221|||[-&&SS%SSSS&&&&&{888888          ",
"               ++{888882-%+=;;;;;;--;--=............................++++#SS===;|35556667778889999999999999998887766655332211|||(&**S%SSSS%&&&&&<88888           ",
"                 _888883-%+=;;;;;;-;;---S...........................+++++SSS==<233555666778889999999999999988877666555332211|||'&&S%%SSSS&&&&&&388888           ",
"                  888885'&+&;;;;;;-;;---;+..........................++++++SS=^223355566677788899999999999988877766555332211|||}-&&SS%SSSS&&&&&&688888           ",
"                  888886{&%%;;;;;;;;;--;;=..........................++++++SS~1223355556667788888999999998888777666555332211|||(&**S%SSSS%&&&&&'888888           ",
"                  888886{&SS;;;;;;;;;;;;;;=..........................++++#S~|122333556666777888888999988888777666655332221||||{&*S%%SSSS&&&&&&(888888           ",
"                  888888(&S+-;;;;;;;;;;;;;;S.........................++++#~||122233555666677788888888888887776666555332211|||}-&&SS%SSSS&&&&&&288888            ",
"                  888888<&%+--;;;;;;;;;;;;;;S........................++++^}||11223355556666777788888888887776666555332221||||(*&*S%SSSSS&&&&&&688888            ",
"                  888888}&&+-)-;;;;;;;;;;;-))=.......................++=_}}||11223334556666677777888887777766665543332211|||}'**SS%SSSS&&&&&&'888888            ",
"                   888882&&S&)))--;;;;;;-))))';+.....................+)<[}}||1122233555566666777777777777766666555332221||||[***SS%SSS%&&&&&&[88888             ",
"                   888885-&S%''))))))))))))'''''=..................+;_<[[}||||112233355556666677777777776666665553322211|||}{**S%%SSSS&&&&&&&588888             ",
"                   888886'&%+)))'))))))')'''')')))=+.............+;^<<<[[}||||11222335555566666677777766666665553332211||||}-&*SS%SSS%&&&&&&-888888             ",
"                   888887{&&%-''')))))'''')''))))~~~)=+......+S;~__<<<<[[}|||||1122333555556666666666666666555533322211|||}:&*S%%SSSS&&&&&&&_888888             ",
"                   888888<&&S&)'''''''''''))))))~~~~~~~~~~~~^^^____<<<<[[}}||||112223335555566666666666666555553322211||||}'**SS%SSS%&&&&&&&388888              ",
"                    888881&&%%'''')''''))')))))~~~~~~~~^^^^^^^^____<<<[[}}}|||||1122233355555666666666665555553322211||||}:&*S%%SSSS&&&&&&&-788888              ",
"                    888885&&&%-'))))))')))))))~~~~~~~~^^^^^^^^_____<<<[[}}}}||||1122233335555555656555555545333222111||||}{**SS%SSS%&&&&&&&<888888              ",
"                    888886'&&%&)))))))))))))~~~~~~~~~^^^^^^^^_____<<<<[[}}}}|||||11224333355555555555555555333232211||||}<&*S%%SSSS&&&&&&&&588888               ",
"                    888888{&&%%)))))))))))~)~~~~~~~~^^^^^^^^______<<<[[[}}}}}||||1112223333555555555554553333222211||||}}{&*SS%SSS%&&&&&&&'888888               ",
"                    888888[&&&%'))))))))~~~~~~~~~~~^^^^^^^^______<<<<[[[[}}}}|||||11122433333555555555533333222211|||||}<-&SS%SSSS&&&&&&&&}888888               ",
"                     888883&&&%=)))))~~)~~~~~~~~~~^^^^^^^^^_____<<<<[[[[[}}}}}|||||112222333333335533333333222211|||||}}{*SSS%SSS&&&&&&&&&688888                ",
"                     888886-&&&%)~~))~~~~~~~~~~~~^^^^^^^^^_____<<<<[[[[[[[}}}}|||||11122222333333333333332222111|||||}}:**SS%SSSS&&&&&&&&(888888                ",
"                     888888^&&&%-~~~~~~~~~~~~~~^^^^^^^^^^______<<<<[[[[[[[}}}}}||||||11122222333333333422222111|||||}}}'&S%%%SSS&&&&&&&&&3888888                ",
"                     888888|&&&&*~~~~~~~~~~~~~^^^^^^^^^^______<<<<[[[[[[[[[}}}}}||||||111222222422242222222111||||||}}_*SSS%SSS&&&&&&&&&'888888                 ",
"                      888885*&&&S)~~~~~~~~~~~^^^^^^^^^^______<<<<<[[[[[[[[[}}}}}}||||||111122222222222222111|||||||}}[-SSS%SSS%&&&&&&&&&1888888                 ",
"                      888888{&&&&-~~~~~~~~~^^^^^^^^^^^______<<<<<[[[[[[[[[[[}}}}}}||||||1111112222222211111|||||||}}}{*SS%SSSS&&&&&&&&&-888888                  ",
"                      888888[&&&&S~~~~~~~^^^^^^^^^^^^______<<<<<[[[[[[[[[[[[[}}}}}}|||||||111111111111111|||||||}}}}<*SS%%SSS&&&&&&&&&&[888888                  ",
"                       888885&&&&&-~~~~^^^^^^^^^^^^^_______<<<<[[[[[[[[[[[[[[[}}}}}}|||||||||1111111111||||||||}}}}[-SSS%SSSS&&&&&&&&&-788888                   ",
"                       888888{&&&&&~~^^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[[[[[}}}}}}|||||||||||||||||||||||||}}}}}{SSS%SSSS&&&&&&&&&&[888888                   ",
"                       888888|&&&&&-^^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[[[[[[[}}}}}}||||||||||||||||||||||}}}}}}<&%S%SSSS&&&&&&&&&&-788888                    ",
"                        888887&&&&&&~^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[[[[[[[[[}}}}}}}||||||||||||||||||}}}}}}}[-SS%SSSS&&&&&&&&&&&[888888                    ",
"                        888888(&&&&&-^^^^^^^^^^________<<<<<[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}||||||||||||||}}}}}}}}['SS%SSSS&&&&&&&&&&&-7888888                    ",
"                         888883&&&&&&~^^^^^^^^________<<<<<[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}||||||||}}}}}}}}}}[^%S%SSSS&&&&&&&&&&&&|888888                     ",
"                         888888'&&&&&-_^^^^^^________<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}}}}}}}}}}}}}}}}}[_&S%SSSS&&&&&&&&&&&&'788888                      ",
"                         888888|&&&&&&{_^^^_________<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}}}}}}}}}}}}}[[<&%%SSSS&&&&&&&&&&&&&2888888                      ",
"                          888887-&&&&&&(___________<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}}}}}}}}}[[[[-%%SSSS&&&&&&&&&&&&&{888888                       ",
"                          888888[&&&&&&*[________<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}}}[[[[[[-%SSSSSS&&&&&&&&&&&&&6888888                       ",
"                           888887-&&&&&&'}______<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[['%SSSSSS&&&&&&&&&&&&&[888888                        ",
"                           888888[&&&&&&&{|____<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[['SSSSSSS&&&&&&&&&&&&&'7888888                        ",
"                            888887-&&&&&&&_|__<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[['SSSSSS&&&&&&&&&&&&&&&3888888                         ",
"                            888888}&&&&&&&&[|<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<'SSSSSS&&&&&&&&&&&&&&&[888888                          ",
"                             888887'&&&&&&&&[1<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<-SSSSSS&&&&&&&&&&&&&&&'8888888                          ",
"                             8888882&&&&&&&&&}2<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<*SSSSS%&&&&&&&&&&&&&&&&5888888                           ",
"                              888888{&&&&&&&&&[3[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[^*SSSSS&&&&&&&&&&&&&&&&&18888888                           ",
"                              8888886&&&&&&&&&&<3|[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{SSSSS%&&&&&&&&&&&&&&&&&(8888888                            ",
"                               888888}&&&&&&&&&&{32[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<-SSSS%&&&&&&&&&&&&&&&&&&'8888888                             ",
"                               8888888{&&&&&&&&&&'23|[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{*SSSS%&&&&&&&&&&&&&&&&&&-6888888                              ",
"                                8888886-&&&&&&&&&&&[52}[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[_-SSSS%&&&&&&&&&&&&&&&&&&&&58888888                              ",
"                                 8888882&&&&&&&&&&&&{252}[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<{SSSS%&&&&&&&&&&&&&&&&&&&&&18888888                               ",
"                                 8888888<&&&&&&&&&&&&&_352}[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<{*SSS%&&&&&&&&&&&&&&&&&&&&&&}8888888                                ",
"                                  8888888{&&&&&&&&&&&&&-_353|[[[[[[[[[[[[[[[[[[[[[[[[[[[[<{*SSS&&&&&&&&&&&&&&&&&&&&&&&&<8888888                                 ",
"                                   8888886'&&&&&&&&&&&&&&-(1552|[[[[[[[[[[[[[[[[[[[[[[<_'SSS&&&&&&&&&&&&&&&&&&&&&&&&&&(88888888                                 ",
"                                   88888885-&&&&&&&&&&&&&&&&'<15531|}[[[[[[[[[[[[[[<_'*S%&&&&&&&&&&&&&&&&&&&&&&&&&&&&_88888888                                  ",
"                                    88888883&&&&&&&&&&&&&&&&&&&-{[135332211||||}<{'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(88888888                                   ",
"                                     88888882&&&&&&&&&&&&&&&&&&&&&&&-'{{{{{{'-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&:88888888                                    ",
"                                      88888881&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&[88888888                                     ",
"                                      788888881&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-188888888                                      ",
"                                       788888882&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-588888888                                       ",
"                                        888888885-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{688888888                                        ",
"                                         888888886'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&[888888888                                         ",
"                                          888888887(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-3888888888                                          ",
"                                           8888888881*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&_7888888888                                           ",
"                                            7888888886{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'3888888888                                             ",
"                                             78888888881-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-}7888888888                                              ",
"                                              78888888886<&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&<68888888888                                               ",
"                                                88888888886(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-:68888888888                                                 ",
"                                                 788888888886<-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'|788888888888                                                  ",
"                                                  78888888888882{*&&&&&&&&&&&&&&&&&&&&&&&&&&&-<5888888888888                                                    ",
"                                                    788888888888872(-&&&&&&&&&&&&&&&&&&&&&{[588888888888888                                                     ",
"                                                     788888888888888861:{'-&&&&&&&&&-'(}37888888888888888                                                       ",
"                                                       788888888888888888886655555678888888888888888888                                                         ",
"                                                         78888888888888888888888888888888888888888888                                                           ",
"                                                           7788888888888888888888888888888888888888                                                             ",
"                                                             77888888888888888888888888888888888                                                                ",
"                                                                77888888888888888888888888887                                                                   ",
"                                                                     77888888888888888887                                                                       ",
"                                                                                                                                                                ");

my $pixbuf_sound = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@sound);
# $pixbuf_sound->scale_simple ($dest_width, $dest_height, $interp_type)
my $sound_size_w = 14; # (36 46) scale the pixbuf_sound button
my $sound_size_h = 16; 
$pixbuf_sound = $pixbuf_sound->scale_simple ( $sound_size_w, $sound_size_h, 'bilinear'); # hyper, bilinear


my @random = (
# /* columns rows colors chars-per-pixel */
"200 200 3 1",
" 	c None",
".	c $color_cdplayer_arrows",
"+	c $color_cdplayer_shadow",
"                                                                                                                                                                                                        ",
"                                                                                                                                                                                                        ",
"                                                                                                                                                                                                        ",
"                                                                                                                                                                                                        ",
"                                                                                                                                                                                                        ",
"                                                                                      ............................                                                                                      ",
"                                                                                 ......................................                                                                                 ",
"                                                                             ..............................................                                                                             ",
"                                                                         ......................................................                                                                         ",
"                                                                      ............................................................                                                                      ",
"                                                                   ..................................................................                                                                   ",
"                                                                ........................................................................                                                                ",
"                                                              ............................................................................                                                              ",
"                                                            ................................................................................                                                            ",
"                                                         ..............................++++++++++++++++++++++++++..............................                                                         ",
"                                                        ..........................++++++++++++++++++++++++++++++++++++..........................                                                        ",
"                                                      ........................++++++++++++++++++++++++++++++++++++++++++++........................                                                      ",
"                                                    ......................++++++++++++++++++++++++++++++++++++++++++++++++++++......................                                                    ",
"                                                  .....................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.....................                                                  ",
"                                                 ....................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................                                                 ",
"                                               ...................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................                                               ",
"                                              ..................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................                                              ",
"                                            ..................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................                                            ",
"                                           .................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................                                           ",
"                                          ................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................                                          ",
"                                         ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                         ",
"                                       ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                       ",
"                                      ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                      ",
"                                     ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                     ",
"                                    ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                   ",
"                                   ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............                                   ",
"                                  .............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............                                  ",
"                                ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............                                ",
"                                .............++++++++++++++++++++++++++++++++++++++++++++......................++++++++++++++++++++++++++++++++++++++++++++.............                                ",
"                               .............++++++++++++++++++++++++++++++++++++++++.................................+++++++++++++++++++++++++++++++++++++++.............                               ",
"                              ............++++++++++++++++++++++++++++++++++++++.........................................+++++++++++++++++++++++++++++++++++++.............                             ",
"                             ............++++++++++++++++++++++++++++++++++++...............................................+++++++++++++++++++++++++++++++++++............                             ",
"                            .............++++++++++++++++++++++++++++++++++...................................................+++++++++++++++++++++++++++++++++.............                            ",
"                           ............++++++++++++++++++++++++++++++++++........................................................++++++++++++++++++++++++++++++++............                           ",
"                          ............+++++++++++++++++++++++++++++++++............................................................+++++++++++++++++++++++++++++++............                          ",
"                          ............++++++++++++++++++++++++++++++++..............................................................++++++++++++++++++++++++++++++............                          ",
"                         ...........++++++++++++++++++++++++++++++++..................................................................++++++++++++++++++++++++++++++...........                         ",
"                        ...........+++++++++++++++++++++++++++++++.....................................................................++++++++++++++++++++++++++++++...........                        ",
"                       ............++++++++++++++++++++++++++++++........................................................................++++++++++++++++++++++++++++............                       ",
"                      ............++++++++++++++++++++++++++++++..........................................................................++++++++++++++++++++++++++++............                      ",
"                      ...........++++++++++++++++++++++++++++++............................................................................++++++++++++++++++++++++++++...........                      ",
"                     ...........++++++++++++++++++++++++++++++..............................................................................++++++++++++++++++++++++++++...........                     ",
"                    ...........++++++++++++++++++++++++++++++................................................................................++++++++++++++++++++++++++++...........                    ",
"                    ...........+++++++++++++++++++++++++++++..................................................................................+++++++++++++++++++++++++++...........                    ",
"                   ...........+++++++++++++++++++++++++++++....................................................................................+++++++++++++++++++++++++++...........                   ",
"                  ...........+++++++++++++++++++++++++++++......................................................................................+++++++++++++++++++++++++++...........                  ",
"                  ...........++++++++++++++++++++++++++++.......................................................................................+++++++++++++++++++++++++++...........                  ",
"                 ...........+++++++++++++++++++++++++++++........................................................................................+++++++++++++++++++++++++++...........                 ",
"                 ..........+++++++++++++++++++++++++++++.........................................................................................++++++++++++++++++++++++++++..........                 ",
"                ..........+++++++++++++++++++++++++++++...........................................................................................++++++++++++++++++++++++++++..........                ",
"                ..........+++++++++++++++++++++++++++++........................................+++++++++++........................................++++++++++++++++++++++++++++..........                ",
"               ..........+++++++++++++++++++++++++++++.....................................++++++++++++++++++++....................................++++++++++++++++++++++++++++..........               ",
"              ...........++++++++++++++++++++++++++++....................................++++++++++++++++++++++++..................................++++++++++++++++++++++++++++...........              ",
"              ..........+++++++++++++++++++++++++++++..................................+++++++++++++++++++++++++++.................................+++++++++++++++++++++++++++++..........              ",
"              ..........+++++++++++++++++++++++++++++................................+++++++++++++++++++++++++++++++................................++++++++++++++++++++++++++++..........              ",
"             ..........+++++++++++++++++++++++++++++................................+++++++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++..........             ",
"             ..........+++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++..............................+++++++++++++++++++++++++++++..........             ",
"            ..........+++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++++..............................+++++++++++++++++++++++++++++..........            ",
"            ..........+++++++++++++++++++++++++++++..............................+++++++++++++++++++++++++++++++++++++++.............................+++++++++++++++++++++++++++++..........            ",
"           ..........++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++..........           ",
"           ..........+++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++..........           ",
"           .........++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++.........           ",
"          ..........++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++..........          ",
"          ..........++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++..........          ",
"          .........++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++.........          ",
"         ..........++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++..........         ",
"         .........+++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++.........         ",
"         .........+++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++..........        ",
"        ..........++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++...........................+++++++++++++++++++++++++++++++++..........        ",
"        .........+++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++...........................++++++++++++++++++++++++++++++++++.........        ",
"        .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++.........        ",
"        .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++.........        ",
"       ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++..........       ",
"       .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................+++++++++++++++++++++++++++++++++++.........       ",
"       .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++.........       ",
"       .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++.........       ",
"      ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................+++++++++++++++++++++++++++++++++++++..........      ",
"      .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++.........      ",
"      .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............................++++++++++++++++++++++++++++++++++++++.........      ",
"      .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............................+++++++++++++++++++++++++++++++++++++++.........      ",
"      .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++++++.........      ",
"     ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................................++++++++++++++++++++++++++++++++++++++++..........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................................++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................................++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................................+++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................................++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................................+++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................+++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................+++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................+++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.....................................++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................+++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........     ",
"     ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........     ",
"      .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........      ",
"      .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........      ",
"      .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........      ",
"      .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........      ",
"      ..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........      ",
"       .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........       ",
"       .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........       ",
"       .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........       ",
"       ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........       ",
"        .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........        ",
"        .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........        ",
"        .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........        ",
"        ..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........        ",
"         .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........        ",
"         .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........         ",
"         ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........         ",
"          .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........          ",
"          ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........          ",
"          ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........          ",
"           .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.........           ",
"           ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........           ",
"           ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........           ",
"            ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........            ",
"            ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........            ",
"             ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........             ",
"             ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........             ",
"              ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........              ",
"              ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........              ",
"              ...........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........              ",
"               ..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........               ",
"                ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........                ",
"                ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........                ",
"                 ..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........                 ",
"                 ...........++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........                 ",
"                  ...........+++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........                  ",
"                  ...........+++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........                  ",
"                   ...........++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........                   ",
"                    ...........+++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........                    ",
"                    ...........+++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........                    ",
"                     ...........++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........                     ",
"                      ...........+++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........                      ",
"                      ............++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++............                      ",
"                       ............+++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++............                       ",
"                        ...........+++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++...........                        ",
"                         ...........++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++............                        ",
"                          ............++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++............                          ",
"                          ............++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++............                          ",
"                           ............+++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++............                           ",
"                            .............+++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++.............                            ",
"                             ............+++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++............                             ",
"                             .............++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++.............                             ",
"                               .............++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++.............                               ",
"                                .............+++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++.............                                ",
"                                ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............                                ",
"                                  .............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............                                  ",
"                                   ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............                                   ",
"                                   ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                   ",
"                                     ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                     ",
"                                      ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                      ",
"                                       ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                       ",
"                                         ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............                                         ",
"                                          ................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................                                         ",
"                                           .................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................                                           ",
"                                            ..................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................                                            ",
"                                              ..................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................                                              ",
"                                               ...................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................                                               ",
"                                                 ....................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................                                                 ",
"                                                  .....................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.....................                                                  ",
"                                                    ......................++++++++++++++++++++++++++++++++++++++++++++++++++++......................                                                    ",
"                                                      ........................++++++++++++++++++++++++++++++++++++++++++++........................                                                      ",
"                                                        ..........................++++++++++++++++++++++++++++++++++++..........................                                                        ",
"                                                         ..............................++++++++++++++++++++++++++..............................                                                         ",
"                                                            ................................................................................                                                            ",
"                                                              ............................................................................                                                              ",
"                                                                ........................................................................                                                                ",
"                                                                   ..................................................................                                                                   ",
"                                                                      ............................................................                                                                      ",
"                                                                        ........................................................                                                                        ",
"                                                                             ..............................................                                                                             ",
"                                                                                 ......................................                                                                                 ",
"                                                                                      ............................                                                                                      ",
"                                                                                                                                                                                                        ",
"                                                                                                                                                                                                        ",
"                                                                                                                                                                                                        ",
"                                                                                                                                                                                                        ",
"                                                                                                                                                                                                        ");


my $pixbuf_random = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@random);
# $pixbuf_sound->scale_simple ($dest_width, $dest_height, $interp_type)
my $random_w = 14; # (38 64) scale
my $random_h = 14; 
$pixbuf_random = $pixbuf_random->scale_simple ( $random_w, $random_h, 'bilinear'); # hyper, bilinear

my @random2 = @random; # To change the color of the random button, then make copy
$random2[3] = ".	c #BFBFBF"; # #BFBFBF
my $pixbuf_random2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@random2);
$pixbuf_random2 = $pixbuf_random2->scale_simple ( $random_w, $random_h, 'bilinear');


my @loop = (
# /* columns rows colors chars-per-pixel */
"100 98 3 1",
" 	c None",
".	c $color_cdplayer_shadow",
"+	c $color_cdplayer_arrows",
"                                            ........................................                ",
"                                           ...........................................              ",
"                                           ............................................             ",
"                                    .      ...++++++++++++++++++++++++++++++++++++++...             ",
"                                .......    ...+++++++++++++++++++++++++++++++++++++....             ",
"                            ...........    ...++++++++++++++++++++++++++++++++++++....              ",
"                         .........++...    ...+++++++++++++++++++++++++++++++++++....               ",
"                       .......++++.....    ...++++++++++++++++++++++++++++++++++....                ",
"                     ......++++++.....     ...+++++++++++++++++++++++++++++++++....                 ",
"                   ......++++++.....       ...++++++++++++++++++++++++++++++++....                  ",
"                  .....+++++++....         ...+++++++++++++++++++++++++++++++....                   ",
"                .....++++++++....          ...++++++++++++++++++++++++++++++....                    ",
"               ....++++++++++...           ...++++++++++++++++++++++++++++.....                     ",
"              ....++++++++++...            ...+++++++++++++++++++++++++++.....                      ",
"             ....++++++++++...             ...++++++++++++++++++++++++++.....                       ",
"            ...+++++++++++....             ...+++++++++++++++++++++++++++.....                      ",
"           ...++++++++++++...              ...+++++++++++++++++++++++++++++.....                    ",
"          ...++++++++++++...               ...++++++++++++++++++++++++++++++.....                   ",
"         ....+++++++++++....               ...++++++++++++++++++++++++++++++++....                  ",
"         ...++++++++++++...                ...+++++++++++++++++++++++++++++++++....                 ",
"        ...++++++++++++...                 ...++++++++++++++++++++++++++++++++++....                ",
"       ...+++++++++++++...                 ...+++++++++++++++++++++++++++++++++++....               ",
"       ...++++++++++++...                  ...++++++++++++++++++++++++++++++++++++....              ",
"      ...+++++++++++++...                  ...+++++++++++++++++++++++++++++++++++++....             ",
"      ...+++++++++++++...                  ...++++++++++++++++++++++++++++++++++++++...             ",
"     ...+++++++++++++...                   ...+++++++++++++++++++++++++++++++++++++++...            ",
"     ...+++++++++++++...                   ...+++++++++++++++++++++++++++++++++++++++....           ",
"    ...++++++++++++++..                    ...++++++++++++++++++++++++++++++++++++++++....          ",
"    ...+++++++++++++...                    ...+++++++++++++++++++++++++++++++++++++++++...          ",
"    ..++++++++++++++...                    ...+++++++++++.+++++++++++++++++++++++++++++....         ",
"   ...++++++++++++++...                    ...++++++++++...+++++++++++++++++++++++++++++...         ",
"   ...++++++++++++++..                     ...++++++++++.....++++++++++++++++++++++++++++...        ",
"   ..+++++++++++++++..                     ...+++++++++.......+++++++++++++++++++++++++++...        ",
"  ...++++++++++++++...                     ...++++++++.... .....++++++++++++++++++++++++++...       ",
"  ...++++++++++++++...                     ...+++++++....   .....+++++++++++++++++++++++++...       ",
"  ..+++++++++++++++...                     ...++++++....      ....+++++++++++++++++++++++++...      ",
"  ..+++++++++++++++...                     ...+++++....        ....++++++++++++++++++++++++...      ",
" ...+++++++++++++++...                     ...+++++...          ....+++++++++++++++++++++++...      ",
" ...++++++++++++++++..                     ...++++...            ....+++++++++++++++++++++++...     ",
" ...++++++++++++++++..                     ...+++....             ....++++++++++++++++++++++...     ",
" ..+++++++++++++++++..                     ...++....               ....+++++++++++++++++++++...     ",
" ..+++++++++++++++++...                    ...+....                 ...++++++++++++++++++++++...    ",
" ..+++++++++++++++++...                    .......                   ...+++++++++++++++++++++...    ",
" ..+++++++++++++++++...                    ......                    ....++++++++++++++++++++...    ",
" ..++++++++++++++++++..                     ....                      ...++++++++++++++++++++...    ",
"...++++++++++++++++++...                     ..                        ...+++++++++++++++++++...    ",
"...++++++++++++++++++...                                               ...+++++++++++++++++++...    ",
"...++++++++++++++++++...                                                ...+++++++++++++++++++..    ",
" ..+++++++++++++++++++...                                               ...+++++++++++++++++++...   ",
" ..+++++++++++++++++++...                                               ...+++++++++++++++++++...   ",
" ..++++++++++++++++++++...                                               ...++++++++++++++++++...   ",
" ..++++++++++++++++++++...                        ..                     ...++++++++++++++++++...   ",
" ...++++++++++++++++++++...                     .....                    ...++++++++++++++++++...   ",
" ...++++++++++++++++++++...                     .....                     ...+++++++++++++++++..    ",
" ...+++++++++++++++++++++...                   ...+..                     ...++++++++++++++++...    ",
"  ..+++++++++++++++++++++....                 ...++..                     ...++++++++++++++++...    ",
"  ...+++++++++++++++++++++....               ...+++..                     ...++++++++++++++++...    ",
"  ...++++++++++++++++++++++...              ....+++..                     ...++++++++++++++++...    ",
"  ...+++++++++++++++++++++++...            ....++++..                     ...++++++++++++++++...    ",
"   ...+++++++++++++++++++++++...          ....+++++..                     ...++++++++++++++++...    ",
"   ...++++++++++++++++++++++++...        ....++++++..                      ..+++++++++++++++...     ",
"    ..+++++++++++++++++++++++++....     ....+++++++..                      ..+++++++++++++++...     ",
"    ...+++++++++++++++++++++++++....    ...++++++++..                     ...+++++++++++++++...     ",
"    ...++++++++++++++++++++++++++..... ...+++++++++...                    ...+++++++++++++++...     ",
"     ...++++++++++++++++++++++++++.......++++++++++...                    ...++++++++++++++...      ",
"     ...++++++++++++++++++++++++++++....+++++++++++...                    ...++++++++++++++...      ",
"      ...+++++++++++++++++++++++++++++..+++++++++++...                    ...++++++++++++++...      ",
"       ...+++++++++++++++++++++++++++++++++++++++++...                    ..++++++++++++++...       ",
"       ...+++++++++++++++++++++++++++++++++++++++++...                   ...++++++++++++++...       ",
"        ...++++++++++++++++++++++++++++++++++++++++...                   ...++++++++++++++...       ",
"         ...+++++++++++++++++++++++++++++++++++++++...                   ...+++++++++++++...        ",
"         ....++++++++++++++++++++++++++++++++++++++...                  ...++++++++++++++...        ",
"          ....+++++++++++++++++++++++++++++++++++++...                  ...+++++++++++++...         ",
"           ....++++++++++++++++++++++++++++++++++++...                 ...++++++++++++++...         ",
"            ....+++++++++++++++++++++++++++++++++++...                 ...+++++++++++++...          ",
"             ....++++++++++++++++++++++++++++++++++...                ...+++++++++++++....          ",
"              ....+++++++++++++++++++++++++++++++++...                ...+++++++++++++...           ",
"               ....++++++++++++++++++++++++++++++++...               ...+++++++++++++...            ",
"                .....++++++++++++++++++++++++++++++...               ...++++++++++++....            ",
"                 .....+++++++++++++++++++++++++++++...              ...++++++++++++....             ",
"                   .....+++++++++++++++++++++++++++...             ....+++++++++++....              ",
"                    .....++++++++++++++++++++++++++...            ....+++++++++++....               ",
"                    ....+++++++++++++++++++++++++++...           ....+++++++++++....                ",
"                   ....++++++++++++++++++++++++++++...           ...+++++++++++....                 ",
"                  ....+++++++++++++++++++++++++++++...         ....++++++++++.....                  ",
"                 ....++++++++++++++++++++++++++++++...        ....++++++++++.....                   ",
"                ....+++++++++++++++++++++++++++++++...       ....+++++++++.....                     ",
"               ....++++++++++++++++++++++++++++++++...     .....++++++++......                      ",
"              ....+++++++++++++++++++++++++++++++++...    .....++++++.......                        ",
"             ....++++++++++++++++++++++++++++++++++...   .....+++.........                          ",
"            ....+++++++++++++++++++++++++++++++++++...   ...............                            ",
"           ....++++++++++++++++++++++++++++++++++++...   ...........                                ",
"          ....+++++++++++++++++++++++++++++++++++++...    ......                                    ",
"          ...++++++++++++++++++++++++++++++++++++++...                                              ",
"          ............................................                                              ",
"           ..........................................                                               ",
"             ......                                                                                 ",
"                                                                                                    ");

my $pixbuf_loop = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@loop);
# $pixbuf_sound->scale_simple ($dest_width, $dest_height, $interp_type)
my ( $loop_w , $loop_h ) = ( 15, 15 ); # Scale (60, 50)
$pixbuf_loop = $pixbuf_loop->scale_simple ( $loop_w, $loop_h, 'bilinear'); # hyper, bilinear

my @loop2 = @loop; # To change the color of the loop button, then make copy
$loop2[3] = ".	c #BFBFBF"; # #A7B1BE
my $pixbuf_loop2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@loop2);
$pixbuf_loop2 = $pixbuf_loop2->scale_simple ( $loop_w, $loop_h, 'bilinear');


my @buttons = (  # 8 buttons ; (x,y) = (256,128) = (4,2)*64 ; the dimension of each button is 64x64
# /* columns rows colors chars-per-pixel */
"256 128 3 1",
#" 	c #000000",
" 	c None",
".	c $color_cdplayer_arrows", # RGB = (  0,  0,  0) = black
#".	c #FFFFFF", # RGB = (255,255,255) = white 
#"&	c #6e95ef", # azul mdio
"&	c $color_cdplayer_shadow",
"                                                                                                                                                                                                                                                                ",
"                                                                                                                                                                                                                                                                ",
"                        &&&&&&&&&&&&&&&&                                                    &&&&&&&&                                                    &&&&&&&&&&&&&&&&                                                    &&&&&&&&                            ",
"                     &&&&&&&&&&&&&&&&&&&&&&                                            &&&&&&&&&&&&&&&&&&                                            &&&&&&&&&&&&&&&&&&&&&&                                            &&&&&&&&&&&&&&&&&&                       ",
"                   &&&&&&&&&&&&&&&&&&&&&&&&&&                                        &&&&&&&&&&&&&&&&&&&&&&                                        &&&&&&&&&&&&&&&&&&&&&&&&&&                                        &&&&&&&&&&&&&&&&&&&&&&                     ",
"                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&                                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&                  ",
"               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 ",
"              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               ",
"             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              ",
"           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&            ",
"          &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&           ",
"         &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&          ",
"         &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         ",
"        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         ",
"       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&        ",
"      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       ",
"      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&............&&&&&&&&............&&&&&&&&&             &&&&&&&&&&&&..&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       ",
"     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&           &&&&&&&&&&............&&&&&&&&............&&&&&&&&&&           &&&&&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&           &&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&      ",
"     &&&&&&&&&&&&&............................&&&&&&&&&&&&&          &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&          &&&&&&&&&&&&&.....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&....&&&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&     ",
"    &&&&&&&&&&&&&&............................&&&&&&&&&&&&&&         &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&         &&&&&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         &&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&     ",
"    &&&&&&&&&&&&&&............................&&&&&&&&&&&&&&         &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&         &&&&&&&&&&&&&&.........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&     ",
"   &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&       &&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&       &&&&&&&&&&&&&&&............&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       &&&&&&&&&&&&.........&&&&&&&&&&&&&&&&.......&&&&&&&&&&&&    ",
"   &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&       &&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&       &&&&&&&&&&&&&&&..............&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       &&&&&&&&&&&&..........&&&&&&&&&&&&&&&.......&&&&&&&&&&&&    ",
"   &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&      &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&      &&&&&&&&&&&&&&&................&&&&&&&&&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&............&&&&&&&&&&&&&.......&&&&&&&&&&&&&   ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&     &&&&&&&&&&&&&&&&..................&&&&&&&&&&&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&.............&&&&&&&&&&&&.......&&&&&&&&&&&&&   ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&     &&&&&&&&&&&&&&&&....................&&&&&&&&&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&...............&&&&&&&&&&.......&&&&&&&&&&&&&   ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&     &&&&&&&&&&&&&&&&......................&&&&&&&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&................&&&&&&&&&.......&&&&&&&&&&&&&   ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&     &&&&&&&&&&&&&&&&........................&&&&&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&..................&&&&&&&.......&&&&&&&&&&&&&   ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&&    &&&&&&&&&&&&&&&&..........................&&&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&...................&&&&&&.......&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&&    &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.....................&&&&.......&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&&    &&&&&&&&&&&&&&&&..............................&&&&&&&&&&&&&&    &&&&&&&&&&&&&&......................&&&.......&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&&    &&&&&&&&&&&&&&&&................................&&&&&&&&&&&&    &&&&&&&&&&&&&&........................&.......&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&&    &&&&&&&&&&&&&&&&................................&&&&&&&&&&&&    &&&&&&&&&&&&&&........................&.......&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&&    &&&&&&&&&&&&&&&&..............................&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.......................&&.......&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&&    &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.....................&&&&.......&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&&    &&&&&&&&&&&&&&&&..........................&&&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&....................&&&&&.......&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&     &&&&&&&&&&&&&&&&........................&&&&&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&..................&&&&&&&.......&&&&&&&&&&&&&   ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&     &&&&&&&&&&&&&&&&......................&&&&&&&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&.................&&&&&&&&.......&&&&&&&&&&&&&   ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&     &&&&&&&&&&&&&&&&....................&&&&&&&&&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&...............&&&&&&&&&&.......&&&&&&&&&&&&&   ",
"  &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&     &&&&&&&&&&&&&&&&..................&&&&&&&&&&&&&&&&&&&&&&&&&&     &&&&&&&&&&&&&..............&&&&&&&&&&&.......&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&      &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&      &&&&&&&&&&&&&&&................&&&&&&&&&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&............&&&&&&&&&&&&&.......&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&       &&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&       &&&&&&&&&&&&&&&..............&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       &&&&&&&&&&&&...........&&&&&&&&&&&&&&.......&&&&&&&&&&&&    ",
"   &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&       &&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&       &&&&&&&&&&&&&&&............&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       &&&&&&&&&&&&.........&&&&&&&&&&&&&&&&.......&&&&&&&&&&&&    ",
"    &&&&&&&&&&&&&&............................&&&&&&&&&&&&&&         &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&         &&&&&&&&&&&&&&..........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&     ",
"    &&&&&&&&&&&&&&............................&&&&&&&&&&&&&&         &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&         &&&&&&&&&&&&&&........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         &&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&     ",
"     &&&&&&&&&&&&&............................&&&&&&&&&&&&&          &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&          &&&&&&&&&&&&&.....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&....&&&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&     ",
"     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&           &&&&&&&&&&............&&&&&&&&............&&&&&&&&&&           &&&&&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&           &&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&      ",
"      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&............&&&&&&&&............&&&&&&&&&             &&&&&&&&&&&&..&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       ",
"      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       ",
"       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&        ",
"        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         ",
"         &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         ",
"         &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&          ",
"          &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&           ",
"           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&            ",
"             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              ",
"              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                             &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               ",
"               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 ",
"                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&                                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                   &&&&&&&&&&&&&&&&&&&&&&&&&&&&                  ",
"                   &&&&&&&&&&&&&&&&&&&&&&&&&&                                        &&&&&&&&&&&&&&&&&&&&&&                                        &&&&&&&&&&&&&&&&&&&&&&&&&&                                        &&&&&&&&&&&&&&&&&&&&&&                     ",
"                     &&&&&&&&&&&&&&&&&&&&&&                                            &&&&&&&&&&&&&&&&&&                                            &&&&&&&&&&&&&&&&&&&&&&                                            &&&&&&&&&&&&&&&&&&                       ",
"                        &&&&&&&&&&&&&&&&                                                    &&&&&&&&                                                    &&&&&&&&&&&&&&&&                                                    &&&&&&&&                            ",
"                                                                                                                                                                                                                                                                ",
"                                                                                                                                                                                                                                                                ",
"                                                                                                                                                                                                                                                                ",
"                                                                                                                                                                                                                                                                ",
"                            &&&&&&&&                                                        &&&&&&&&                                                        &&&&&&&&                                                        &&&&&&&&                            ",
"                       &&&&&&&&&&&&&&&&&&                                              &&&&&&&&&&&&&&&&&&                                              &&&&&&&&&&&&&&&&&&                                              &&&&&&&&&&&&&&&&&&                       ",
"                     &&&&&&&&&&&&&&&&&&&&&&                                          &&&&&&&&&&&&&&&&&&&&&&                                          &&&&&&&&&&&&&&&&&&&&&&                                          &&&&&&&&&&&&&&&&&&&&&&                     ",
"                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&                                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&                                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&                                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&                  ",
"                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 ",
"               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               ",
"              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                            &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                            &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                            &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              ",
"            &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&            ",
"           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&           ",
"          &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&          ",
"         &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         ",
"         &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         ",
"        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                &&&&&&&&&&&&&&&&&&&&&&&..&&&&&&&&&&&&&&&&&&&&&&&                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&        ",
"       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&&&&&&&&&&&&&&&....&&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       ",
"       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.&&&&&&&&&       ",
"      &&&&&&&&.&&&&&&&&&&&&&&&&&&.&&&&&&&&&&&&&&&&&&&&&&&&            &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&            &&&&&&&&&&&&&&&&&&&&&&........&&&&&&&&&&&&&&&&&&&&&&            &&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&&...&&&&&&&&&&      ",
"     &&&&&&&&&...&&&&&&&&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&&&&&&&&&&&&&&&.&&&&&&&&&&&&&&&&&&.&&&&&&&&&          &&&&&&&&&&&&&&&&&&&&&&..........&&&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&....&&&&&&&&&&&     ",
"     &&&&&&&&&....&&&&&&&&&&&&&&&.....&&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&&&&&&&&&&&&&...&&&&&&&&&&&&&&&&...&&&&&&&&&          &&&&&&&&&&&&&&&&&&&&&............&&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&&     ",
"     &&&&&&&&&......&&&&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&&&&&&&&&&&.....&&&&&&&&&&&&&&&....&&&&&&&&&          &&&&&&&&&&&&&&&&&&&&..............&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&     ",
"    &&&&&&&&&&.......&&&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&        &&&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&&&&......&&&&&&&&&&        &&&&&&&&&&&&&&&&&&&&................&&&&&&&&&&&&&&&&&&&&        &&&&&&&&&&&&.......&&&&&&&&&&&&&&&&.........&&&&&&&&&&&&    ",
"    &&&&&&&&&&.........&&&&&&&&&&.........&&&&&&&&&&&&&&&&&&        &&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&&.......&&&&&&&&&&        &&&&&&&&&&&&&&&&&&&&................&&&&&&&&&&&&&&&&&&&&        &&&&&&&&&&&&.......&&&&&&&&&&&&&&&..........&&&&&&&&&&&&    ",
"   &&&&&&&&&&&...........&&&&&&&&...........&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&&.........&&&&&&&&&&.........&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&&&..................&&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&&&&&&&............&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&............&&&&&&&............&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&&&&&...........&&&&&&&&...........&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&&....................&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&&&&&&.............&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&..............&&&&&..............&&&&&&&&&&&&&&      &&&&&&&&&&&&&&&&............&&&&&&&............&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&......................&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&&&&...............&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&...............&&&&...............&&&&&&&&&&&&&      &&&&&&&&&&&&&&..............&&&&&..............&&&&&&&&&&&      &&&&&&&&&&&&&&&&&........................&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&&&................&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&.................&&.................&&&&&&&&&&&      &&&&&&&&&&&&&...............&&&&...............&&&&&&&&&&&      &&&&&&&&&&&&&&&&&........................&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&..................&&&&&&&&&&&&&   ",
"  &&&&&&&&&&&&..................&...................&&&&&&&&&&    &&&&&&&&&&&&.................&&.................&&&&&&&&&&&&    &&&&&&&&&&&&&&&&&..........................&&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.......&&&&&&...................&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&.......................................&&&&&&&&&    &&&&&&&&&&...................&..................&&&&&&&&&&&&    &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.......&&&&.....................&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&........................................&&&&&&&&    &&&&&&&&&.......................................&&&&&&&&&&&&    &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.......&&&......................&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&.........................................&&&&&&&    &&&&&&&&........................................&&&&&&&&&&&&    &&&&&&&&&&&&&&&..............................&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.......&........................&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&.........................................&&&&&&&    &&&&&&&.........................................&&&&&&&&&&&&    &&&&&&&&&&&&&&................................&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.......&........................&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&........................................&&&&&&&&    &&&&&&&.........................................&&&&&&&&&&&&    &&&&&&&&&&&&&&................................&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.......&&.......................&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&.......................................&&&&&&&&&    &&&&&&&&........................................&&&&&&&&&&&&    &&&&&&&&&&&&&..................................&&&&&&&&&&&&&    &&&&&&&&&&&&&&.......&&&&.....................&&&&&&&&&&&&&&  ",
"  &&&&&&&&&&&&..................&..................&&&&&&&&&&&    &&&&&&&&&.......................................&&&&&&&&&&&&    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&    &&&&&&&&&&&&&&.......&&&&&....................&&&&&&&&&&&&&&  ",
"   &&&&&&&&&&&................&&&................&&&&&&&&&&&&      &&&&&&&&&&..................&..................&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&..................&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&...............&&&&...............&&&&&&&&&&&&&      &&&&&&&&&&&&................&&&................&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&&.................&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&.............&&&&&&.............&&&&&&&&&&&&&&&      &&&&&&&&&&&&&...............&&&&...............&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&&&&...............&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&..........&&&&&&&&&..........&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&&&.............&&&&&&.............&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&&&&&..............&&&&&&&&&&&&&   ",
"   &&&&&&&&&&&.........&&&&&&&&&&.........&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&..........&&&&&&&&&..........&&&&&&&&&&&      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&      &&&&&&&&&&&&&.......&&&&&&&&&&&&&............&&&&&&&&&&&&&   ",
"    &&&&&&&&&&.......&&&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&        &&&&&&&&&&&&&&&&&&.........&&&&&&&&&&.........&&&&&&&&&&        &&&&&&&&&&&&...............................&&&&&&&&&&&&&        &&&&&&&&&&&&.......&&&&&&&&&&&&&&...........&&&&&&&&&&&&    ",
"    &&&&&&&&&&.....&&&&&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&&&        &&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&&.......&&&&&&&&&&        &&&&&&&&&&&&...............................&&&&&&&&&&&&&        &&&&&&&&&&&&.......&&&&&&&&&&&&&&&&.........&&&&&&&&&&&&    ",
"     &&&&&&&&&....&&&&&&&&&&&&&&&....&&&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&&&&&.....&&&&&&&&&          &&&&&&&&&&&...............................&&&&&&&&&&&&          &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&     ",
"     &&&&&&&&&...&&&&&&&&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&&&&&&&&&&&&....&&&&&&&&&&&&&&&....&&&&&&&&&          &&&&&&&&&&&...............................&&&&&&&&&&&&          &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&&     ",
"     &&&&&&&&&.&&&&&&&&&&&&&&&&&&.&&&&&&&&&&&&&&&&&&&&&&&&&          &&&&&&&&&&&&&&&&&&&&&&&...&&&&&&&&&&&&&&&&...&&&&&&&&&          &&&&&&&&&&&...............................&&&&&&&&&&&&          &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&....&&&&&&&&&&&     ",
"      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&            &&&&&&&&&&&&&&&&&&&&&&&&.&&&&&&&&&&&&&&&&&&.&&&&&&&&            &&&&&&&&&&...............................&&&&&&&&&&&            &&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&&...&&&&&&&&&&      ",
"       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&...............................&&&&&&&&&&              &&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&&&&.&&&&&&&&&       ",
"       &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              &&&&&&&&&...............................&&&&&&&&&&              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&       ",
"        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                &&&&&&&&...............................&&&&&&&&&                &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&        ",
"         &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         ",
"         &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&         ",
"          &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&          ",
"           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                      &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&           ",
"            &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                        &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&            ",
"              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                            &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                            &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                            &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              ",
"               &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                              &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&               ",
"                 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                 ",
"                  &&&&&&&&&&&&&&&&&&&&&&&&&&&&                                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&                                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&                                    &&&&&&&&&&&&&&&&&&&&&&&&&&&&                  ",
"                     &&&&&&&&&&&&&&&&&&&&&&                                          &&&&&&&&&&&&&&&&&&&&&&                                          &&&&&&&&&&&&&&&&&&&&&&                                          &&&&&&&&&&&&&&&&&&&&&&                     ",
"                       &&&&&&&&&&&&&&&&&&                                              &&&&&&&&&&&&&&&&&&                                              &&&&&&&&&&&&&&&&&&                                              &&&&&&&&&&&&&&&&&&                       ",
"                            &&&&&&&&                                                        &&&&&&&&                                                        &&&&&&&&                                                        &&&&&&&&                            ",
"                                                                                                                                                                                                                                                                ",
"                                                                                                                                                                                                                                                                ");



my $pixbuf_buttons = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons);
my ( $buttons_w, $buttons_h ) = ( 15 , 15 );
my ( $buttons_ws, $buttons_hs ) = ( 4*$buttons_w , 2*$buttons_h ); # (256,128) = (4,2)*64
$pixbuf_buttons = $pixbuf_buttons->scale_simple ( $buttons_ws, $buttons_hs, 'bilinear'); # hyper, bilinear

# To change the color of buttons (shadow) - Motion
my @buttons2 = @buttons; # make copy
$buttons2[2] = ".	c $color_cdplayer_arrows_motion";
$buttons2[3] = "&	c $color_cdplayer_shadow_motion";
#"&	c #FFFFFF"; # white color
my $pixbuf_buttons2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons2);
$pixbuf_buttons2 = $pixbuf_buttons2->scale_simple ( $buttons_ws, $buttons_hs, 'bilinear'); # hyper, bilinear

# To change the color of buttons (arrows), - Pressed
my @buttons3 = @buttons; # make copy
$buttons3[2] = ".	c #000000";
#"&	c #FFFFFF"; # white color
my $pixbuf_buttons3 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons3);
$pixbuf_buttons3 = $pixbuf_buttons3->scale_simple ( $buttons_ws, $buttons_hs, 'bilinear'); # hyper, bilinear

my @posbar = ( # position bar of cd player
# /* columns rows colors chars-per-pixel */
"30 10 16 1",
" 	c None",
".	c #2451BA",
"+	c #2C61C2",
"x	c #2E6BC5",
"#	c #487AD0",
"S	c #4081D3",
"%	c #4C8FDE",
"&	c #598ECF",
"*	c #589DEB",
"=	c #64A1E4",
"-	c #72ADEC",
";	c #6AB0F8",
">	c #83B1E5",
",	c #7BC3FF",
"'	c #89CFFF",
")	c #95D9FF",
"   .....++++++++++++++.....   ",
"  +++x#######SSSS#####xxx++.  ",
" ..S=>>>>>>>>>>>>>>>>>>>-&#.. ",
"..x%=>>>>>>>>>>>>>>>>>>>-=%+.+",
"+x#%**=****===--====*****%Sx++",
"x#S%********=;---;;=****%%S#xx",
"xS**;;;;;;;;;,,,,,;;;;;;***%S#",
" S*;;,,,,,,,'')))'',,,,,;;=&S ",
"  &-,,'''''')))))))))'',,-=&  ",
"   x##########SS#########xx   ");

my $pixbuf_posbar = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@posbar);
my ( $posbar_w, $posbar_h ) = ( 12 , 5 ); # (30,10) = (3,1)*10 
$pixbuf_posbar = $pixbuf_posbar->scale_simple ( $posbar_w, $posbar_h, 'bilinear'); # hyper, bilinear


my @numbers2 = ( # min:sec of cd player
# /* columns rows colors chars-per-pixel */
"420 40 3 1",
" 	c None",
".	c $color_cdplayer_digit",
"+	c None",    # none, background color
#"+	c #ADD8E6",
"     ....................          ++++++++++++++++++++          ....................          ....................          ++++++++++++++++++++          ....................          ....................          ....................          ....................          ....................                             ...                                                                    ++++++++++++++++++++     ",
"     ....................          ++++++++++++++++++++          ....................          ....................          ++++++++++++++++++++          ....................          ....................          ....................          ....................          ....................                            ....                                                                    ++++++++++++++++++++     ",
"   ..  ................  ..      ++  ++++++++++++++++  ..      ++  ................  ..      ++  ................  ..      ..  ++++++++++++++++  ..      ..  ................  ++      ..  ................  ++      ++  ................  ..      ..  ................  ..      ..  ................  ..                         .....                                                                  ++  ++++++++++++++++  ++   ",
"   ..  ................  ..      ++  ++++++++++++++++  ..      ++  ................  ..      ++  ................  ..      ..  ++++++++++++++++  ..      ..  ................  ++      ..  ................  ++      ++  ................  ..      ..  ................  ..      ..  ................  ..                         ....                                                                   ++  ++++++++++++++++  ++   ",
"   .... .............. ....      ++++                ....      ++++ .............. ....      ++++ .............. ....      ....                ....      .... .............. ++++      .... .............. ++++      ++++ .............. ....      .... .............. ....      .... .............. ....                        ....                                                                    ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                        ...                                                                     ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                       ....                                                                     ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                      ....                    ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                      ....                    ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                     ....                     ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                     ....                     ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                    ....                      ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                    ....                      ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                   ....                                                                         ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                   ....                                                                         ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                  ....                                                                          ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                  ....                                                                          ++++                ++++   ",
"   .....              .....      ++++               .....      ++++               .....      ++++               .....      .....              .....      .....               ++++      .....               ++++      ++++               .....      .....              .....      .....              .....                 ....                                                                           ++++                ++++   ",
"   ..  ++++++++++++++++  ..      ++  ++++++++++++++++  ..      ++  ................  ..      ++  ................  ..      ..  ................  ..      ..  ................  ++      ..  ................  ++      ++  ++++++++++++++++  ..      ..  ................  ..      ..  ................  ..                 ....                                                ..................         ++  ++++++++++++++++  ++   ",
"   ..  ++++++++++++++++  ..      ++  ++++++++++++++++  ..      ++  ................  ..      ++  ................  ..      ..  ................  ..      ..  ................  ++      ..  ................  ++      ++  ++++++++++++++++  ..      ..  ................  ..      ..  ................  ..                ....                                                 ..................         ++  ++++++++++++++++  ++   ",
"   ..  ++++++++++++++++  ..      ++  ++++++++++++++++  ..      ..  ................  ++      ++  ................  ..      ++  ................  ..      ++  ................  ..      ..  ................  ..      ++  ++++++++++++++++  ..      ..  ................  ..      ++  ................  ..                ....                                                 ..................         ++  ++++++++++++++++  ++   ",
"   ..  ++++++++++++++++  ..      ++  ++++++++++++++++  ..      ..  ................  ++      ++  ................  ..      ++  ................  ..      ++  ................  ..      ..  ................  ..      ++  ++++++++++++++++  ..      ..  ................  ..      ++  ................  ..               ....                                                  ..................         ++  ++++++++++++++++  ++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....               ....                                                  ..................         ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....              ....                                                                              ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....              ....                                                                              ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....             ....                             ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....             ....                             ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....            ....                              ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....            ....                              ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....           ....                               ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....           ....                               ......                                            ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....          ....                                                                                  ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....          ....                                                                                  ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....         ....                                                                                   ++++                ++++   ",
"   .....              .....      ++++               .....      .....               ++++      ++++               .....      ++++               .....      ++++               .....      .....              .....      ++++               .....      .....              .....      ++++               .....         ....                                                                                   ++++                ++++   ",
"   .... .............. ....      ++++                ....      .... .............. ++++      ++++ .............. ....      ++++                ....      ++++ .............. ....      .... .............. ....      ++++                ....      .... .............. ....      ++++ .............. ....        ....                                                                                    ++++                ++++   ",
"   ..  ................  ..      ++  ++++++++++++++++  ..      ..  ................  ++      ++  ................  ..      ++  ++++++++++++++++  ..      ++  ................  ..      ..  ................  ..      ++  ++++++++++++++++  ..      ..  ................  ..      ++  ................  ..        ....                                                                                    ++  ++++++++++++++++  ++   ",
"   ..  ................  ..      ++  ++++++++++++++++  ..      ..  ................  ++      ++  ................  ..      ++  ++++++++++++++++  ..      ++  ................  ..      ..  ................  ..      ++  ++++++++++++++++  ..      ..  ................  ..      ++  ................  ..       ....                                                                                     ++  ++++++++++++++++  ++   ",
"     ....................          ++++++++++++++++++++          ....................          ....................          ++++++++++++++++++++          ....................          ....................          ++++++++++++++++++++          ....................          ....................         ....                                                                                       ++++++++++++++++++++     ",
"     ....................          ++++++++++++++++++++          ....................          ....................          ++++++++++++++++++++          ....................          ....................          ++++++++++++++++++++          ....................          ....................        ....                                                                                        ++++++++++++++++++++     ");


my $pixbuf_numbers = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@numbers2);
my ( $numbers_w, $numbers_h ) = ( 9 , 12 ); # (30,40) = 10 * (3,4) = (width,height) of the the 14 digits
my ( $numbers_ws, $numbers_hs ) = ( 14*$numbers_w , 1*$numbers_h ); # (420,40) = (14*30,1*40)
$pixbuf_numbers = $pixbuf_numbers->scale_simple ( $numbers_ws, $numbers_hs, 'bilinear'); # hyper, bilinear

# To change the color of numbers on the display - lapsed time color
my @numbers3 = @numbers2; # make copy and change only the color information
$numbers3[2] = ".	c $color_cdplayer_digit_remaining"; #red , color information

my $pixbuf_numbers2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@numbers3);
$pixbuf_numbers2 = $pixbuf_numbers2->scale_simple ( $numbers_ws, $numbers_hs, 'bilinear'); # hyper, bilinear


my @skin_xTunes = ( # cd player skin_xTunes
# /* columns rows colors chars-per-pixel */
"225 90 80 1",
".	c none",
" 	c #484342",
"+	c #595553",
"Q	c #636562",
"#	c #666B6D",
"P	c #6A6B69",
"%	c #6E6D65",
"S	c #747672",
"*	c #7D7E78",
"=	c #828677",
"-	c #848683",
";	c #8C8D8A",
">	c #8F9283",
",	c #939491",
"R	c #989B8C",
")	c #989B97",
"!	c #A0A29F",
"~	c #A1A495",
"{	c #A6A1A0",
"]	c #9FA4A6",
"^	c #A4A2A6",
"/	c #A0A69C",
"(	c #A3A5A2",
"_	c #A7AA94",
":	c #A6A8A5",
"<	c #ACA7A6",
"[	c #A9ABA2",
"}	c #A6ABAE",
"|	c #ABA9AD",
"1	c #A9ABA8",
"2	c #ABADAA",
"3	c #B1ABAA",
"4	c #ACB0A0",
"5	c #AFB1AE",
"6	c #B2B1A9",
"7	c #ADB3B5",
"8	c #B6B0AF",
"9	c #B3B1B5",
"0	c #B2B4B1",
"a	c #B6B8B5",
"b	c #BDB8B6",
"c	c #B9BCAC",
"d	c #BBB8BD",
"e	c #B8C0A8",
"f	c #BABCB9",
"g	c #B7BDBF",
"h	c #BBC0C3",
"i	c #BEC0BD",
"j	c #BEC2B8",
"k	c #BDC5AE",
"l	c #C0C4B4",
"m	c #C3C0C5",
"n	c #C6C0BF",
"o	c #BEC3C6",
"p	c #C2C4C1",
"q	c #C6C9B9",
"r	c #C4CBB4",
"s	c #CBC5C4",
"t	c #C8C6CA",
"u	c #C6C8C5",
"v	c #C7C9C6",
"w	c #C8CCBB",
"x	c #C9CBC8",
"y	c #CEC9C9",
"z	c #CACCC9",
"A	c #CBD1B7",
"B	c #CCCECB",
"C	c #CED0CC",
"D	c #CFD1CE",
"E	c #D0D2CF",
"F	c #D1D9C1",
"G	c #D4DABC",
"H	c #DADCD8",
"I	c #DFDAD8",
"J	c #DBE1C2",
"K	c #DFE1DE",
"L	c #E4E3DA",
"M	c #E5E4DB",
"N	c #E6E9E5",
"O	c #EDF0EC",
".....NNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOON.....",
"...HHHCuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvpBHHH...",
"..CEu35780aaffniiptttyzBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBxytttpiindfaa0812apCB..",
".ipa|<11|3500abfbfimptuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzvvtumpinfbaaa089223|aif.",
".aa:<:1125500aafffmipptvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBxtuppmifffaaa0052211:aa.",
":2!{(]:||225508aaffiiopuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuupoiifffab00522||:]:{!:(",
"!::1322500aaafffipppuvxzBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBxvuuppiifffaa05552131::(",
",(^::11129500ddfffiipsutyvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBytvspopiifddaa09522111^:;",
"((]::1127500aadffihnptuvvvvvvvBBBBzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvvvvvvvvvutpnhiffdaa0057211::]((,",
"11312550aaafffiippuvxztCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCtzxvuppiifffaaa05521311)",
"(((::11|5509adfffinoputtvvvvvvBBBBBBBBzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvvvvvvvvttuponifffda9055|11::(((,",
"::|}33508aaaffiipptuvxzDBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBDzxvutppiiffaaa80533}|::)",
"(]:|1122900abdffifa!;SSSPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPSSS;!afiffdba0092211|:](,",
"((:}1225580aaaa:;SQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQS;:aaaa0855221}:((,",
"!^]<:11238800:;SQ%*=>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>=*%QS;:00883211:<]^!,",
"(]::11225550,SP%=R_ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkke_R=%PS,05552211::](,",
":^|3}225002;PP=_erGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFGGGre_=PP;200522}3|^:)",
":112255501-PSReAGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGAeRSP-105552211:)",
"(({::118:-P*_kGGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGGk_*P-:811::{((,",
":1112252;S*_AGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGA_*S;2522111:)",
":::}11a,S*_rGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGr_*S,a11}:::)",
"!](<:a:-*~rFJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJFr~*-:a:<(]!,",
"!!(^5a)*RkGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGkR*)a5^(!!,",
"((:(f1;-eFJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJFe-;1f(:((,",
"::12a!-_rGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGr_-!a21::)",
"!!]b0)-eGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGe-)0b]!!,",
"({!f1,RrJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJrR,1f!{(,",
"::1f1,_GJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJG_,1f1::)",
"!)5f1,cGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGc,1f5)!,",
":!ff1ReGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGeR1ff!:)",
":)fa1/kJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJk/1af):)",
":!ii5/rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr/5ii!:)",
":)ff5~rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr~5ff):)",
":!ipf[rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr[fpi!:)",
"!!aif[kJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJk[fia!!,",
"(!5pi[cJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJc[ip5!(,",
"1(<pu0cGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGc0up<(1)",
"(({fpf4GJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJG4fpf{((,",
"(()fpv6rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr6vpf)((,",
"!]!3uBpcGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGcpBu3!]!,",
"!!(:ivB6rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr6Bvi:(!!,",
"!^(!2vCvcGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGcvCv2!(^!,",
":111{fvCjkGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGkjCvf{111:)",
"!((:{1pCCjrGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGrjCCp1{:((!,",
"!^((:(8xHElrJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJrlEHx8(:((^!,",
"::1221:0BHEjrGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGrjEHB0:1221::)",
"!!((::11aCHKjkGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGkjKHCa11::((!!,",
"1112955518zHKClrGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGrlCKHz8155592111)",
":11}3250925vHNKCqrAGGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGGArqCKNHv5290523}11:)",
"(({::1125558bEKNKHwwqeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeqwwHKNKEb8555211::{((,",
"!!]]^:|3225508avHNNKKKLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMLLLLLLLLLLKKKNNHva8055223|:^]]!!,",
"111225509aaffff0afpEKNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNKEpfa0ffffaa905522111)",
"::122550aaafffnipppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppnnnpnppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppinfffaaa055221::)",
"!^(::}|235500aabffioopuyvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvyupooiffbaa005532|}::(^!,",
"::11322507aaagbhionsuvxDBBBBBBzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBDxvusnoihbgaaa70522311::)",
":::1129509aaafnihmpuvvxBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBxvvupmhinfaaa9059211:::)",
",((]}1122588adbbfiippoutxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBtvtsppiinbdab805521}}::)",
",((:|1233580aadffiiopuuvxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBzvvuopiifdfaa808322|:::)",
"):|1}2559aa,PPPPP##PPPPPPPPPPPPPPPPPP#PP#PPPPPPP##PP#PPP##PPPPPPPPPPPPPPPPPP#PP#PPPPPPP##PP#PPP#PP##PPPPPPPPPPPPPPPPPP#PP#PPPPPPP##PP#PPP#PP##PPPPPPPPPPPPPPPPPP#PP#PPPPPPP##PP#PPP#PP##PPPPPPPPPP#PP#PPPPPPP##PP#P#P,a00552}1|:)",
",!!^^::1112(({!{!(!!{{{!{{{({{!{!{{{!{{{{{{!{{{!!(!{!{!!(!!{{{!{{{({{!{!{{{!{{{{{{!{{{!!(!{!{!{!{!(!!{{{!{{{({{!{!{{{!{{{{{{!{{{!!(!{!{!{!{!(!!{{{!{{{({{!{!{{{!{{{{{{!{{{!!(!{!{!{!{!(!!{{{!{{{{!{{{{{{!{{{!!(!{!{!((2211::^^!!,",
"):11|}5508bpHIHIHHIHHIHHHHHHIHIIIHHHHHHHHHHHHIHHIHHIHHHHHIHHIHHHHHHIHIIIHHHHHHHHHHHHIHHIHHIHHHHHIHHIHHIHHHHHHIHIIIHHHHHHHHHHHHIHHIHHIHHHHHIHHIHHIHHHHHHIHIIIHHHHHHHHHHHHIHHIHHIHHHHHIHHIHHIHHHHHHHHHHHHHHHIHHIHHIHIHHpb8055}|11:)",
",!((^:113552500aaffiippppppppppppppppiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiippppppppppppppppuuuuuuuupppppuuuuuppppppppppppppppppppppppiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiipppppppppppppiffaa0052053221|:((,",
",!!{(:|11|57908aadgiipppvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvpppiigdaa80975|11|:({!!,",
"):11325509abdffiippstvxBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBxvtsppiiffdba90552311:)",
"):::122253500abfbfimptuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvvvvvvvvttupnnmgffaa0085211::(((,",
",!!^{<:115500aafffmipptvvvvvvvvvvvvvvvvvvvvvvvvvvvvvppppppppppppppppppppppppppppppppppppppppppppppppnnnpnpppppppppppppppppppppppppppppppuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuspmpinffaa78952}11:<{^!!,",
",!((:|112225508aaffiiopuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuppnihdfaaa9559211|:((!,",
")::1132250aaafffipppuvxzBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBDxvusnoihbgaaa70522311::)",
"):::112959500ddfffiipsutyvvvvvvvvvvvvvvvvvvvvvvvvvvvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBxvvupmhinfaaa9059211:::)",
",!!{(]:11500aadffihnptuvvvvvvvBBBBzzzzzzzzzzzzzzzzzzvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvpppiigdaa80975|11|:({!!,",
":|2255009500ddfffiipsutyvvvvvvvvvvvvvvvvvvvvvvvvvvvppppppppppppppppppppppppppppppppppppppppppppppppnnnpnppppppppppppppppppppppppppppppppppppppnnnpnppppppppppppppppppppppppnnnpnpppppppppppppppvvvvvvvvvvpppiigdaa80975|11|:({!!,",
"<1125590500aadffihnptuvvvvvvvBBBBzzzzzzzzzzzzzzzzzzvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvCCCCCCCCCBBxvtsppiiffdba90552311:)",
"!^::}12270aadgfiimppuvyxxxxxxvvvvvvvvvvvvvvvvvvvvvvzzzzzzzzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzzxxxxxxvvvvvvvvttupnnmgffaa0085211::(((,",
"^:}322553500abfbfimptuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBuuuuuuuuuspmpinffaa78952}11:<{^!!,",
"!(]:<1135500aafffmipptvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvuppnihdfaaa9559211|:((!,",
"(:::1129225508aaffiiopuuuuuuuuuuuuuuuuuuuuuuuuuuuuuzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzCCBBBBBBBDxvusnoihbgaaa70522311::)",
"112}550a0aaafffipppuvxzBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCvvvvvvvvvvpppiigdaa80975|11|:({!!,",
"(^:111|59500ddfffiipsutyvvvvvvvvvvvvvvvvvvvvvvvvvvvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBxvtsppiiffdba90552311:)",
"]{(::1}}500aadffihnptuvvvvvvvBBBBzzzzzzzzzzzzzzzzzzvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxvvvvvvvvttupnnmgffaa0085211::(((,",
"1}12250070aadgfiimppuvyxxxxxxvvvvvvvvvvvvvvvvvvvvvvzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxzzzzzzzzzzzzzzzxxxxxuuuuuuuuuspmpinffaa78952}11:<{^!!,",
"]112227500aafffioppuvtzzzzzzzvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvuppnihdfaaa9559211|:((!,",
":}}12550550adagffinpputvvvvvvvvvvvvvvvvvvvvvvvvvvvvzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzCCBBBBBBBDxvusnoihbgaaa70522311::)",
"-!!](::1aafbhhppsuvvzBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCuuuuuuuspppiiffaba7552|11::(]!!-",
"-,((^:1|32550ababpuuvxyBBBBBBBBBBBBBBBBBBBBBBBBzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvtuppiiffbaba05523|1:^((,-",
"*;:|13125580adfffinppttuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzztvvupniifffda08552131|:;*",
".S;1235500aadffhituvvyBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDBzyyupmihffdaa0055321;S.",
".QP;22557aaaffmhipsvvzBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCyxvystpihmffaaa75522;PQ.",
"..++*,!(700aadffimipppuvvvvvvvvvvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBBxvupppmiffdaa007(!,*++..",
"...  +P-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------P+  ...",
".....                                                                                                                                                                                                                       .....");


my ($scroll_w, $scroll_h);

sub scale_buttons {
   my ( $width, $height, $corner, $delta ) =  @_ ; # ( $widht , $heigth );
   
   my $dist_dig = 1; #distance between numbers digits
   
   $buttons_h = int ( $height/2 - 4 ) - 1;                               # min:(15,15)   max:(22,22)
   $buttons_w = int ( ($width/2 - 4*$delta - $corner) * 2 / 9 - 1.2 );
   
   if ( $buttons_w >= 22 ){ $buttons_w = 22; }  # Set the max w values.  
   if ( $buttons_h >= 22 ){ $buttons_h = 22; }  # Set the max h values   
   
   $numbers_w = int( ( 2*$width/3 - 10*$dist_dig - $corner )/11 - 1);         # min:(9,12)   max:(13,18)
   $numbers_h = int ( $height/2 - $corner - 4 );  
   if ( $numbers_w >= 13 ){ $numbers_w = 13; }  # Set the max w values.  
   if ( $numbers_h >= 18 ){ $numbers_h = 18; }  # Set the max h values   
   
   ( $sound_size_w , $sound_size_h ) = ( $buttons_w - 5, $buttons_h - 3 ); 
   ( $loop_w , $loop_h ) = ( $buttons_w - 1, $buttons_h - 4 ); # min:(15,15) - (1,4) = (14,11)   max:(18,16)
   #print "loop_w = $loop_w ; loop_h = $loop_h\n";
   if ( $loop_w >= 18 ){ $loop_w = 18; }
   if ( $loop_h >= 16 ){ $loop_h = 16; }
   
   ( $random_w , $random_h ) = ( $buttons_w - 3, $buttons_h - 3 );  # min:(12,12)   max:(17,17)
   if ( $random_w >= 17 ){ $random_w = 17; }
   if ( $random_h >= 17 ){ $random_h = 17; }
   
   ( $posbar_w, $posbar_h ) = ( int( (2*$width/3) / 8 - 2 ) , int( $height/10 + 1 ) ); # min:(12,5)   max:(20,8)  
   if ( $posbar_w >= 20 ){ $posbar_w = 20; }
   if ( $posbar_h >= 8 ){ $posbar_h = 8; }
   #print "buttons_h = $buttons_h ; buttons_w = $buttons_w ; numbers_w = $numbers_w ; numbers_h = $numbers_h\n";
   #print "posbar_w = $posbar_w ; posbar_h = $posbar_h\n";
   
   $scroll_h = $buttons_h - 2;
   $scroll_h = 16 if $scroll_h >= 16;
   
   if ( $buttons_w <= 5 or $buttons_h <= 3 ){ return; }
   scale_pixbuf();
}

sub scale_pixbuf {
   $pixbuf_buttons  = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons);
   $pixbuf_buttons  = $pixbuf_buttons->scale_simple ( 4*$buttons_w , 2*$buttons_h, 'bilinear');   
   $pixbuf_buttons2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons2);
   $pixbuf_buttons2 = $pixbuf_buttons2->scale_simple ( 4*$buttons_w , 2*$buttons_h, 'bilinear');
   $pixbuf_buttons3 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons3);
   $pixbuf_buttons3 = $pixbuf_buttons3->scale_simple ( 4*$buttons_w , 2*$buttons_h, 'bilinear');
   
   $pixbuf_sound = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@sound);
   $pixbuf_sound = $pixbuf_sound->scale_simple ( $sound_size_w, $sound_size_h, 'bilinear');
   
   $pixbuf_numbers  = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@numbers2);   
   $pixbuf_numbers  = $pixbuf_numbers->scale_simple ( 14*$numbers_w , 1*$numbers_h, 'bilinear');
   $pixbuf_numbers2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@numbers3);
   $pixbuf_numbers2 = $pixbuf_numbers2->scale_simple ( 14*$numbers_w , 1*$numbers_h, 'bilinear');
   
   $pixbuf_posbar = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@posbar);
   $pixbuf_posbar = $pixbuf_posbar->scale_simple ( $posbar_w, $posbar_h, 'bilinear');
   
   $pixbuf_loop  = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@loop);
   $pixbuf_loop  = $pixbuf_loop->scale_simple ( $loop_w, $loop_h, 'bilinear'); # hyper, bilinear
   $pixbuf_loop2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@loop2);
   $pixbuf_loop2 = $pixbuf_loop2->scale_simple ( $loop_w, $loop_h, 'bilinear');
    
   $pixbuf_random = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@random);
   $pixbuf_random = $pixbuf_random->scale_simple ( $random_w, $random_h, 'bilinear'); # hyper, bilinear
   $pixbuf_random2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@random2);
   $pixbuf_random2 = $pixbuf_random2->scale_simple ( $random_w, $random_h, 'bilinear');
}

# see /usr/share/doc/perl-Gtk2-1.080/gtk-demo/drawingarea.pl and examples/scribble.pl
# GtkDrawingArea is a blank area where you can draw custom displays
# of various kinds.   See man Gtk2::Gdk::Drawable, Gtk2::Curve

$da = Gtk2::DrawingArea->new;
$da->set_size_request (170, 40); # set a minimum size: (width,height) = (170, 40)
$hbox4->pack_start ($da, $false, $false, 0);
$da->signal_connect ( 'expose_event'         => \&expose_event_cdplayer);
$da->signal_connect ( 'configure_event'      => \&configure_event_cdplayer);
$da->signal_connect ( 'button_press_event'   => \&button_press_event_cdplayer);
$da->signal_connect ( 'button_release_event' => \&button_release_event_cdplayer);
$da->signal_connect ( 'motion_notify_event'  => \&motion_notify_event_cdplayer);
$da->set_events ([ @{ $da->get_events },
                      'exposure-mask',
                      'leave-notify-mask',
                      'button-press-mask',
		      'button-release-mask',
		      'pointer-motion-mask',
		      #'pointer-motion-hint-mask',
		      #'all-events-mask'
		 ]);		 			 
$da->set_sensitive($false);	 
$da->show;

#  ---  Colors   ---  # See <man Gtk2::Gdk::Color>

my $gc_bg; my $gc_blue; my $gc_green; 
my $gc_skin; my $gc_skin2; my $color_skin2;

# #E6EDBD = (230,237,189) : yellow   #FFFFFF=(255,255,255):white   #000000=(0,0,0):black
my $color_bg    = Gtk2::Gdk::Color->parse ($color_bg_cdplay);         # #E6EDBD , background color default
my $color_blue  = Gtk2::Gdk::Color->new (85*256, 90*256, 190*256);    #  RGB = 85 90 190 ; my color blue
my $color_green = Gtk2::Gdk::Color->new (167*256, 177*256, 190*256);  # '#A7B1BE' ; my green color 

my $delta    = 2;  # distance inter buttons
my $dista    = 7;  # distance (shift) from center
my $corner   = 4;
my $dist_dig = 1;  # distance between numbers digits

# text scrolling position on the $da
my ($xdest, $ydest); # inicial position on the $drawing_area    

#numbers position on the $da
my $xdest_numbers; my $ydest_numbers;

# progress bar of elapsed time; position on the $da
my $xdest_posbar; my $ydest_posbar; my $posbar_length;

# loop button; position on the $da
my $xdest_loop; my $ydest_loop;

# random button; position on the $da
my $xdest_random; my $ydest_random;

# sound button; position on the $da
my $xdest_sound; my $ydest_sound;

# buttons (Stop button); position on the $da
my $xdest_buttons; my $ydest_buttons;

# Pixmap for cd player
my ($pixmap, $pixmap_mask) = (undef, undef);
 
sub expose_event_cdplayer {
   my ($widget, $event ) = @_;    # $widget = $da = Gtk2::DrawingArea
                                  # $drawable = $widget->state;  Gtk2::Gdk::Drawable					  					      
				      
   $widget->window->draw_drawable ($widget->style->fg_gc($widget->state), # (Gtk2::Gdk::GC)
                                  $pixmap,
                                  # Only copy the area that was exposed.
                                  $event->area->x, $event->area->y,       # $xsrc,  $ysrc,
                                  $event->area->x, $event->area->y,       # $xdest, $ydest
                                  $event->area->width, $event->area->height);     
   return $false;
}

# Redraw the screen from the pixmap
sub configure_event_cdplayer {
   my ($widget, $event, @color) = @_;     # $widget = $da = Gtk2::DrawingArea
                                          # $drawable = $widget->state;  Gtk2::Gdk::Drawable
					  # color = Gtk2::Gdk::Color
					  					     
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width  = $widget->allocation->width;
   
   # background color definition
   $gc_bg = Gtk2::Gdk::GC->new ($widget->window); #  ($da->window) = Gtk2::Gdk::Drawable   
   $color_bg_cdplay = $color[0] if defined($color[0]);
   $color_bg = Gtk2::Gdk::Color->parse ($color_bg_cdplay);  
   $gc_bg->set_rgb_fg_color ($color_bg);
   
   # background skin color definition
   $gc_skin = Gtk2::Gdk::GC->new ($widget->window); #  ($da->window) = Gtk2::Gdk::Drawable     
   $gc_skin->set_rgb_fg_color ( Gtk2::Gdk::Color->parse ('#C8C8C8') );
   
   # background display skin color definition
   $gc_skin2 = Gtk2::Gdk::GC->new ($widget->window); #  ($da->window) = Gtk2::Gdk::Drawable
   $color_skin2 = Gtk2::Gdk::Color->parse ('#DBE1C2');
   $gc_skin2->set_rgb_fg_color ($color_skin2);
      
   # my blue color definition
   $gc_blue = Gtk2::Gdk::GC->new ($widget->window); #  ($widget->window) = Gtk2::Gdk::Drawable   
   $gc_blue->set_rgb_fg_color ($color_blue);
   
   # my green color definition ; limite lines
   $gc_green = Gtk2::Gdk::GC->new ($widget->window);  
   $gc_green->set_rgb_fg_color ($color_green);
   
   # button color (shadow) - Static
   $buttons[3] = "&	c $color[1]"  if defined($color[1]);
   $color_cdplayer_shadow = $color[1] if defined($color[1]);
   
   # button color (arrows) - Static
   $buttons[2]  = ".	c $color[2]"  if defined($color[2]);
   $color_cdplayer_arrows = $color[2] if defined($color[2]);
   
   # button color - random ? - when active
   $random[2] = ".	c $color[2]" if defined($color[2]);
   $random[3] = "+	c $color[1]" if defined($color[1]);
   
   # button color - loop - when active
   $loop[2] = ".	c $color[1]" if defined($color[1]);
   $loop[3] = "+	c $color[2]" if defined($color[2]);
   
   # button color (shadow) - Motion
   $buttons2[3] = "&	c $color[3]" if defined($color[3]);
   $color_cdplayer_shadow_motion = $color[3] if defined($color[3]);
   
   # button color (arrows) - Motion
   $buttons2[2] = ".	c $color[4]" if defined($color[4]);
   $color_cdplayer_arrows_motion = $color[4] if defined($color[4]);
   
   # button color (shadow) - Pressed
   $buttons3[3] = "&	c $color_cdplayer_shadow_motion";   
   
   # button color (digit)
   $numbers2[2] = ".	c $color[5]" if defined($color[5]);
   $color_cdplayer_digit = $color[5] if defined($color[5]);
   
   # button color (digit_remaining)
   $numbers3[2] = ".	c $color[6]" if defined($color[6]);
   $color_cdplayer_digit_remaining = $color[6] if defined($color[6]);
   
   $pixmap = undef if $pixmap; # get rid of the old one
   $pixmap_mask = undef if $pixmap_mask;   
   
   if ($show_cdplayer_skin and defined $window_cd_player){ # with skin_xTunes
      $widget->set_size_request (225, 90); # set a minimum size: (width,height) ; skin_xTunes
      
      #(pixmap, mask) = Gtk2::Gdk::Pixmap->create_from_xpm ($drawable, $transparent_color, $filename)
      #($pixmap, $pixmap_mask) = Gtk2::Gdk::Pixmap->create_from_xpm ($widget->window, undef, '/tmp/skin_xTunes.xpm');
      ($pixmap, $pixmap_mask) = Gtk2::Gdk::Pixmap->create_from_xpm_d($widget->window, undef, @skin_xTunes);
								    								               
      #my $pixmap_widget = Gtk2::Image->new_from_pixmap ($gdkpixmap, $mask);   
      $window_cd_player->shape_combine_mask( $pixmap_mask, 0, 0 ) if not $window_cd_player->get_decorated;
      
      ($xdest, $ydest) = (74, 22);         # inicial position on the $drawing_area    
      ($scroll_w, $scroll_h) = (138, 14);  # width and height of scrolling text
        
      #numbers position on the $da
      $xdest_numbers = 16; $ydest_numbers = 22;
      $numbers_w = 9; $numbers_h = 13;
      
      # progress bar of elapsed time; position on the $da
      $xdest_posbar = 10; 
      $ydest_posbar = 55;
      $posbar_length = 204;
      $posbar_w = 18; $posbar_h = 6;            
      
      # buttons; position on the $da
      $xdest_buttons = 80;  # x_destination of Stop button on the $da
      $ydest_buttons = 63;
      ($buttons_w, $buttons_h) = (20,20);  
      
      # loop button; position on the $da
      $xdest_loop = 170;
      $ydest_loop = 36;
      
      # random button; position on the $da
      $xdest_random = 152;
      $ydest_random = 36;
      
      # sound button; position on the $da
      $xdest_sound = 186;     
      $ydest_sound = 63;
      ($sound_size_w, $sound_size_h) = (18,20);              
           
      scale_pixbuf(); 
   }
   if (not defined $pixmap){ # without skin_xTunes
      $gc_skin  = $gc_bg;
      $gc_skin2 = $gc_bg;
      $color_skin2 = $color_bg;
      
      $widget->set_size_request (170, 40); 
      # pixmap = Gtk2::Gdk::Pixmap->new ($drawable, $width, $height, $depth) ; $depth (number of colors)
      $pixmap = Gtk2::Gdk::Pixmap->new ($widget->window, $width, $height, -1);     
   
      $pixmap->draw_rectangle ( $window->style->bg_gc($window->state), # fill with window bg color
                                $true, 0, 0, $width, $height);

      my ($xc,$yc,$r,$n) = (6,6,6,10);  # ( x, y ) = ( xc, yc ) + r * ( cos(theta), sin(theta) )
      
      my @coord_up_left    = coordinates_rounded_corner(         $xc,          $yc,$r,180,270,$n);  
      my @coord_up_right   = coordinates_rounded_corner($width - $xc,          $yc,$r,270,360,$n);
      my @coord_down_left  = coordinates_rounded_corner($width - $xc,$height - $yc,$r,  0, 90,$n);  
      my @coord_down_right = coordinates_rounded_corner(         $xc,$height - $yc,$r, 90,180,$n);
      		     
      $pixmap->draw_polygon ($gc_bg, $true, # fill whith color $gc_bg
                                     @coord_up_left,   @coord_up_right,
				     @coord_down_left, @coord_down_right );
				     
      @coord_up_left    = coordinates_rounded_corner(         $xc - 0.1,          $yc - 0.1,$r,180,270,$n);  
      @coord_up_right   = coordinates_rounded_corner($width - $xc - 0.1,          $yc - 0.1,$r,270,360,$n);
      @coord_down_left  = coordinates_rounded_corner($width - $xc - 0.1,$height - $yc - 0.1,$r,  0, 90,$n);  
      @coord_down_right = coordinates_rounded_corner(         $xc - 0.1,$height - $yc - 0.1,$r, 90,180,$n);			     
				     			      				            				      
      # draw the limite lines
      # $drawable->draw_polygon ($gc, $filled, $x1, $y1, ...)
      $pixmap->draw_polygon ($gc_green, $false, # $widget->style->black_gc,
                                        @coord_up_left,   @coord_up_right,
				        @coord_down_left, @coord_down_right );
				     
      # refresh the sizes and scale      
      scale_buttons($width, $height, $corner, $delta);
      
      ($xdest, $ydest) = (int($corner + 5*($numbers_w + $dist_dig) + $numbers_w/2), int($corner/2) ); # inicial position on the $drawing_area    
      ($scroll_w, $scroll_h) = (int($width - $xdest - $corner), $scroll_h);           # width and height of scrolling text
      
      #numbers position on the $da
      $xdest_numbers = $corner; $ydest_numbers = $corner;
   
      # progress bar of elapsed time; position on the $da
      $xdest_posbar  = int($corner + 5*($numbers_w + $dist_dig) + $numbers_w/2);      
      
      $ydest_posbar  = int($scroll_h + $corner);      
      $posbar_length = int($width - $xdest_posbar - $corner);
      
      # loop button; position on the $da
      $xdest_loop = $corner;
      $ydest_loop = $height - $corner - $loop_h;
      
      # random button; position on the $da
      $xdest_random = $corner + $loop_w + 2;
      $ydest_random = $height - $corner - $random_h;
      
      # sound button; position on the $da
      $xdest_sound = $width/2 - $sound_size_w - 5*$buttons_w/2 - 4*$delta + $dista;     
      $ydest_sound = $height - $corner - $sound_size_h;
      
      # buttons; position on the $da
      $xdest_buttons = $width/2 + $dista;  # Stop button x_destination drawing on the $da
      $ydest_buttons = $height - $buttons_h - 2;              		     			     			      			     
   }			      				      
   draw_buttons( All => $true );
   
   # show current time   
   my ($hour,$min,$sec) = sec_to_time($count); 
   draw_play_time($da, undef, ($min,$sec,$hour) );
   
   # sound button
   draw_sound_button($da,undef);
   
   # random button ?
   draw_random($da,undef);
   
   # loop button
   draw_loop($da,undef); 					       	        
				             
   # draw lapsed time, progress bar
   my $pct = 0;
   if ($total_time>0){$pct = number_value( sprintf("%.2f", $count/$total_time) );}
   draw_lapsed_time($da, undef, $pct);      
   
   # draw scrolling text
   show_scrolling_text();
   
   # return TRUE because we've handled this event, so no further processing is required. 
   return $true;
}

sub coordinates_rounded_corner {    # arc of circle  - (10Jul2008)
   my ($xc,$yc,$r,$t1,$t2,$n) = @_; # ( x, y ) = ( xc, yc ) + r * ( cos(theta), sin(theta) ) :polar coordinate
   my @coordinates = ();
   my $pi = 3.141592654;
   
   foreach my $i ( 0 .. $n ) {  # arc is divided by n equal segments
      my $theta_i = ( $t1 + ($i/$n)*($t2 - $t1) )*($pi/180);
      my $x_i = number_value( sprintf("%.4f", $xc + $r * cos($theta_i)) );  # sin(), cos(): see man perlfunc
      my $y_i = number_value( sprintf("%.4f", $yc + $r * sin($theta_i)) );
      push @coordinates, ( $x_i, $y_i );
   }
   #foreach my $i ( 0 .. 2*$n+1 ) { print "\$coordinates($i) = $coordinates[$i] \n"; }
   return @coordinates;
}

my $button_press_stop    = $false; my $button_press_play  = $false; my $button_press_pause  = $false; 
my $button_press_forward = $false; my $button_press_eject = $false; my $button_press_rewind = $false;
my $button_press_next    = $false; my $button_press_back  = $false;

sub button_release_event_cdplayer {
   # Set the default color to all buttons that is released.
   if    ($button_press_stop   ){ draw_buttons(Draw_Stop => $true   ); $button_press_stop = $false;   }
   elsif ($button_press_play   ){ draw_buttons(Draw_Play => $true   ); $button_press_play = $false;   }
   elsif ($button_press_pause  ){ draw_buttons(Draw_Pause => $true  ); $button_press_pause = $false;  }
   elsif ($button_press_forward){ draw_buttons(Draw_Forward => $true); $button_press_forward = $false;}
   elsif ($button_press_eject  ){ draw_buttons(Draw_Eject => $true  ); $button_press_eject = $false;  }
   elsif ($button_press_rewind ){ draw_buttons(Draw_Rewind => $true ); $button_press_rewind = $false; }
   elsif ($button_press_next   ){ draw_buttons(Draw_Next => $true   ); $button_press_next = $false;   }
   elsif ($button_press_back   ){ draw_buttons(Draw_Back => $true   ); $button_press_back = $false;   }
   return $true;
}

sub draw_buttons { # Get the 8 buttons from @buttons. Redraw only the button that is pressed.
   my %args = ( 
        Press_Stop => $false,   Draw_Stop => $false,    Shadow_Stop => $false, # If 'Press_Stop = $true' then change the button color
        Press_Play => $false,   Draw_Play => $false,    Shadow_Play => $false, # default value,             
	Press_Pause => $false,  Draw_Pause => $false,   Shadow_Pause => $false,
	Press_Forward => $false,Draw_Forward => $false,	Shadow_Forward => $false,	
	Press_Eject => $false,  Draw_Eject => $false,   Shadow_Eject => $false,
	Press_Rewind => $false, Draw_Rewind => $false,  Shadow_Rewind => $false,
	Press_Next => $false,   Draw_Next => $false,    Shadow_Next => $false,
	Press_Back => $false,	Draw_Back => $false,    Shadow_Back => $false,
	All => $false,	 # draw all buttons
        @_,              # argument pair list goes here
	      );
   my $widget = $da;	          
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width  = $widget->allocation->width ;
   my $pixbuf_copy = $pixbuf_buttons;
   # $buttons_h is the height of buttons and $buttons_w is the width of buttons

   my @update_rect;
   $update_rect[0] = $xdest_buttons;
   $update_rect[1] = $ydest_buttons;
   $update_rect[2] = $buttons_w;
   $update_rect[3] = $buttons_h;  
   #$widget->queue_draw_area (@update_rect); 
   return if not defined $pixmap;
        	
   # -------------------- 8 buttons ---------------------- #
   if ( $args{Draw_Stop} or $args{All} ){  # Draw independently the 8 buttons
      
      $update_rect[0] = $xdest_buttons - 1*$buttons_w/2 + 0*$delta;
      $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first
      if    ($args{Shadow_Stop}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button
      elsif ($args{Press_Stop} ){ $pixbuf_copy = $pixbuf_buttons3; }
      # stop button , on the center of display 
      # $drawable->draw_pixbuf ($gc, $pixbuf, $src_x, $src_y, $dest_x, $dest_y, $width, $height, $dither, $x_dither, $y_dither)
      $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 0*$buttons_w, 0*$buttons_h, @update_rect, 'normal', 0, 0);
      $widget->queue_draw_area (@update_rect); 			       
   }
   if ( $args{Draw_Play} or $args{All} ){
   
      $update_rect[0] = $xdest_buttons + 1*$buttons_w/2 + 1*$delta;
      $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first
      if    ($args{Shadow_Play}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button
      elsif ($args{Press_Play} ){ $pixbuf_copy = $pixbuf_buttons3; }	        				       				       	   
      # play or pause button
      my $button_y = 2*$buttons_w;
      unless ( $pause eq $true or $playing_music eq $false ){ $button_y = 1*$buttons_w; } 
      $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, $button_y, 0*$buttons_h, @update_rect, 'normal', 0, 0);	
      $widget->queue_draw_area (@update_rect); 				       
   }
   if ( $args{Draw_Forward}  or $args{All} ){					       		       			          
      $update_rect[0] = $xdest_buttons + 3*$buttons_w/2 + 2*$delta;
      $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first
      if    ($args{Shadow_Forward}){ $pixbuf_copy = $pixbuf_buttons2; }
      elsif ($args{Press_Forward} ){ $pixbuf_copy = $pixbuf_buttons3; }	   
      # fastforward button 
      $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 0*$buttons_w, 1*$buttons_h, @update_rect, 'normal', 0, 0);
      $widget->queue_draw_area (@update_rect); 				       
   }
   if ( $args{Draw_Next} or $args{All} ){
      $update_rect[0] = $xdest_buttons + 5*$buttons_w/2 + 3*$delta;
      $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first
      if    ($args{Shadow_Next}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button
      elsif ($args{Press_Next} ){ $pixbuf_copy = $pixbuf_buttons3; }	   				       
      # next button
      $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 3*$buttons_w, 0*$buttons_h, @update_rect, 'normal', 0, 0);				       
      $widget->queue_draw_area (@update_rect); 	
   }
   if ( $args{Draw_Eject} or $args{All} ){
      $update_rect[0] = $xdest_buttons + 7*$buttons_w/2 + 4*$delta;
      $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first
      if    ($args{Shadow_Eject}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button
      elsif ($args{Press_Eject} ){ $pixbuf_copy = $pixbuf_buttons3; }	   
      # eject button  
      $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 2*$buttons_w, 1*$buttons_h, @update_rect, 'normal', 0, 0);
      $widget->queue_draw_area (@update_rect); 				       				       					             
   }
   if ( $args{Draw_Rewind} or $args{All} ){
      $update_rect[0] = $xdest_buttons - 3*$buttons_w/2 - 1*$delta;
      $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first
      if    ($args{Shadow_Rewind}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button
      elsif ($args{Press_Rewind} ){ $pixbuf_copy = $pixbuf_buttons3; }	   
      # rewind button  
      $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 1*$buttons_w, 1*$buttons_h, @update_rect, 'normal', 0, 0);
      $widget->queue_draw_area (@update_rect); 					       
   }
   if ( $args{Draw_Back} or $args{All} ){
      $update_rect[0] = $xdest_buttons - 5*$buttons_w/2 - 2*$delta;
      $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first
      if    ($args{Shadow_Back}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button
      elsif ($args{Press_Back} ){ $pixbuf_copy = $pixbuf_buttons3; }	   
      # back button  
      $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 3*$buttons_w, 1*$buttons_h, @update_rect, 'normal', 0, 0);
      $widget->queue_draw_area (@update_rect); 		 			       
   }
   #while (Gtk2->events_pending()) {Gtk2->main_iteration()};  NEVER use this here			       				       				       				        	
}

sub draw_play_time {
   my ($widget, $event, @data) = @_;   # $widget = $da = Gtk2::DrawingArea
   
   return if not defined $pixmap;
   #draw_play_time($da, undef, ($min,$sec,$hour) );
   my ($min, $sec, $hour) = @data; # the format "00:00" have 5 digits 
   
   my ($digit1,$digit2) = (13*$numbers_w,13*$numbers_w); #start value with background color
   my ($digit3,$digit4) = (13*$numbers_w,13*$numbers_w);
   my ($digit5,$digit6) = (13*$numbers_w,13*$numbers_w);
   my $two_points = 11*$numbers_w; # " : "
   my $division   = 10*$numbers_w; # " / "
      
   if ( $min != -2 ){  #  not blink - n�o piscar
      $digit1 = ( int($min/10) )*$numbers_w;
      $digit2 = ( $min % 10    )*$numbers_w;
      $digit3 = ( int($sec/10) )*$numbers_w;  # 35 : int($sec/10) $sec%10
      $digit4 = ( $sec % 10    )*$numbers_w;
      $digit5 = ( int($hour/10) )*$numbers_w if defined($hour);
      $digit6 = ( $hour % 10    )*$numbers_w if defined($hour);
   }
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width  = $widget->allocation->width ;   
   my $pixbuf_copy = $show_time_remaining ? $pixbuf_numbers2 : $pixbuf_numbers; # to change the colors.   

   my @update_rect;
   $update_rect[0] = $xdest_numbers; #$corner
   $update_rect[1] = $ydest_numbers;
   $update_rect[2] = $numbers_w;
   $update_rect[3] = $numbers_h;
   
   #print "\$update_rect[1] = $update_rect[1]\n";
   #$widget->queue_draw_area (@update_rect);
   
   # "00:00"; there are 5 digits; Each button have (width,height) = ($numbers_w, $numbers_h)
   
   # erase all ; rectangle : $drawable->draw_rectangle ($gc, $filled, $x, $y, $width, $height); See <man Gtk2::Gdk::Drawable>
   $pixmap->draw_rectangle ($gc_skin2, $true, $xdest_numbers, $ydest_numbers, 5*($numbers_w + $dist_dig), $numbers_h); # erase all
          
      # -------------------- 5 digits ---------------------- #
      # 1o. digit : $drawable->draw_pixbuf ($gc, $pixbuf, $src_x, $src_y, $dest_x, $dest_y, $width, $height, $dither, $x_dither, $y_dither) 
      $update_rect[0] = $xdest_numbers + 0*($numbers_w + $dist_dig);
      $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $digit1, 0*$numbers_h, @update_rect, 'normal', 0, 0);
      		       
      # 2o. digit 
      $update_rect[0] = $xdest_numbers + 1*($numbers_w + $dist_dig);
      $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $digit2, 0*$numbers_h, @update_rect, 'normal', 0, 0);
      			        	
      # : Two points 
      $update_rect[0] = $xdest_numbers + 2*($numbers_w + $dist_dig);
      $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $two_points, 0*$numbers_h, @update_rect, 'normal', 0, 0); 
				       	 
      # 3o. digit
      $update_rect[0] = $xdest_numbers + 3*($numbers_w + $dist_dig);
      $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $digit3, 0*$numbers_h, @update_rect, 'normal', 0, 0);
       
      # 4o. digit
      $update_rect[0] = $xdest_numbers + 4*($numbers_w + $dist_dig);
      $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $digit4, 0*$numbers_h, @update_rect, 'normal', 0, 0);
   
   # See man Gtk2::Widget            
   $widget->queue_draw_area ($xdest_numbers, $ydest_numbers, 5*($numbers_w + $dist_dig), $numbers_h);		            			        
}


sub draw_lapsed_time { # progress bar of elapsed time
   my ($widget, $event, $pct) = @_;   # $widget = $da = Gtk2::DrawingArea
         
   return if not defined $pixmap;
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width = $widget->allocation->width;    
       
   # pct vary from 0.000 to 1.000 
   my $max_length  = $posbar_length - $posbar_w; #posbar_w is the button width
   my $lapsed_time = $pct * $max_length;
   
   my $rail_h = 2;
   my $y = $ydest_posbar;
   my $y_rail = int ( ( 2*$y + $posbar_h - $rail_h )/2 );   
   #print "y = $y ; y_rail = $y_rail, posbar_h = $posbar_h\n";	
    
   # rectangle  $drawable->draw_rectangle ($gc, $filled, $x, $y, $width, $height); See <man Gtk2::Gdk::Drawable>
   $pixmap->draw_rectangle ($gc_skin,  $true,  $xdest_posbar - 1, $y,       $posbar_length + 2, $posbar_h );  # erase all first
   $pixmap->draw_rectangle ($gc_green, $false, $xdest_posbar,     $y_rail , $posbar_length,     $rail_h   );  # path, rail
   # posbar button
   # $drawable->draw_pixbuf ($gc, $pixbuf, $src_x, $src_y, $dest_x, $dest_y, $width, $height, $dither, $x_dither, $y_dither)
   $pixmap->draw_pixbuf ($gc_bg, $pixbuf_posbar, 0, 0,
                                 $xdest_posbar + $lapsed_time, $y, 
				 $posbar_w, $posbar_h, 'normal', 0, 0);
   my @update_rect;
   $update_rect[0] = $xdest_posbar - 1;
   $update_rect[1] = $y;
   $update_rect[2] = $posbar_length + 2;
   $update_rect[3] = $posbar_h;  
   $widget->queue_draw_area (@update_rect);			       
}

sub draw_sound_button {
   my ($widget, $event, @data) = @_;   # $widget = $da = Gtk2::DrawingArea
                                       # @data is an array
   return if not defined $pixmap;
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width  = $widget->allocation->width;
   
   my @update_rect;
   $update_rect[0] = $xdest_sound;         
   $update_rect[1] = $ydest_sound;
   $update_rect[2] = $sound_size_w;  
   $update_rect[3] = $sound_size_h; 
   
   $pixmap->draw_rectangle ($gc_skin, $true, @update_rect); # erase first
   $pixmap->draw_pixbuf ($gc_skin, $pixbuf_sound, 0, 0, @update_rect, 'normal', 0, 0);  # sound button
   $widget->queue_draw_area (@update_rect); #update the $da = Gtk2::DrawingArea
}

sub draw_random {
   my ($widget, $event, @data) = @_;   # $widget = $da = Gtk2::DrawingArea
                                       # @data is an array
   return if not defined $pixmap;
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width  = $widget->allocation->width;
   
   my $pixbuf_copy = $pixbuf_random;
   $pixbuf_copy = $play_random ? $pixbuf_random : $pixbuf_random2;
   
   my @update_rect;
   $update_rect[0] = $xdest_random;  $update_rect[1] = $ydest_random;
   $update_rect[2] = $random_w;      $update_rect[3] = $random_h; 
   
   $pixmap->draw_rectangle ($gc_skin2, $true, @update_rect); # erase first
   $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, 0, 0, @update_rect, 'normal', 0, 0);
   $widget->queue_draw_area (@update_rect); #update the $da = Gtk2::DrawingArea
}

sub draw_loop {
   my ($widget, $event, @data) = @_;   # $widget = $da = Gtk2::DrawingArea
                                       # @data is an array
   return if not defined $pixmap;
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width  = $widget->allocation->width;    
       
   my $pixbuf_copy = $pixbuf_loop;
   $pixbuf_copy = $loop_tracks ? $pixbuf_loop : $pixbuf_loop2;
   
   my @update_rect;
   $update_rect[0] = $xdest_loop;  $update_rect[1] = $ydest_loop;
   $update_rect[2] = $loop_w;      $update_rect[3] = $loop_h; 
   
   $pixmap->draw_rectangle ($gc_skin2, $true, @update_rect); # erase first
   $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, 0, 0, @update_rect, 'normal', 0, 0);
   $widget->queue_draw_area (@update_rect); #update the $da = Gtk2::DrawingArea
   
   #if ($loop_tracks){print "Loop ON\n";}
   #else{print "Loop OFF\n";}
}

#------------------ Scrolling Text -------------------#
#--------------------- Start -------------------------#

my $timer_scroll; my $timer_wait;
my $pixmap_layout = undef;
my ($width_layout, $height_layout);
my $xsrc = 0; my $ysrc = 0;
my $sinal = 1; # sign: +1 or -1
my @array_text_layout; my @array_width_layout; my @array_height_layout;
my $scroll_count = 0; my $scroll_count_h3 = 0; my $ind1 = 0; # matrix indice
my $scrolling_type_temp;

sub show_scrolling_text { # choose the scrolling direction
   return unless defined $scrolling_type;
   
   @array_text_layout = (); @array_width_layout = (); @array_height_layout = (); # clear
   
   my @all_scrolling = ( 'horinzontal1', 'horinzontal2', 'horinzontal3', 'vertical' ); # all scrolling types
   my $rand = int( rand($#all_scrolling + 1) );  # pick one random element: 0  <=  rand() <  $#all_scrolling + 1
       
   $scrolling_type_temp = $scrolling_type eq 'random' ? $all_scrolling[$rand] : $scrolling_type;   
   #print "scrolling_type = $scrolling_type ;;  scrolling_type_temp = $scrolling_type_temp\n";
   
   #print "sub show_scrolling_text --> \$scrolling_type = $scrolling_type ; \$rand = $rand ; \$scrolling_type_temp = $scrolling_type_temp\n";
   
   if    ( $scrolling_type_temp eq 'horinzontal1' or $scrolling_type_temp eq 'vertical'     ){ show_scrolling_text_special(); }
   elsif ( $scrolling_type_temp eq 'horinzontal2' or $scrolling_type_temp eq 'horinzontal3' ){ show_scrolling_text_normal();  }
   return $false;  # to stop the loop of $timer_wait for "loop on", "random on", ...
}

sub show_scrolling_text_normal { # horizontal2 and horizontal3
   my ($pixmap_layout, $width_layout, $height_layout);
   my $row = $selected_row;
   my $scrol_text;
   
   if ( defined $files_info[$row]{artist} ){      
      $scrol_text = " *** $files_info[$row]{file}. ";
      $scrol_text .= "$files_info[$row]{artist} - "  if $files_info[$row]{artist};
      $scrol_text .= "$files_info[$row]{title} - "   if $files_info[$row]{title};
      $scrol_text .= "$files_info[$row]{album} - "   if $files_info[$row]{album};
      
      if ($files_info[$row]{artist} eq "" and $files_info[$row]{title} eq "" and $files_info[$row]{album} eq ""){
	 (my $file = $files_info[$row]{filename}) =~ s/\.(...|flac)$//i; # remove extension_input
         $scrol_text .= "$file - "
      }          
      $scrol_text .= "track $files_info[$row]{track} " if $files_info[$row]{track};      
      $scrol_text .= "($files_info[$row]{length}) - $files_info[$row]{bitrate} kb/s ";
   }
   
   ($pixmap_layout, $width_layout, $height_layout) = defined $scrol_text ? draw_layout( text => "$scrol_text" ) : draw_layout( );      
   push @array_text_layout,  $pixmap_layout;
   push @array_width_layout, $width_layout;
   push @array_height_layout, $height_layout;
   
   my $ind = ($ind1)%($#array_text_layout+1); # cyclic indices ;; always $ind = 0 ;; $ind is local
   draw_text_scrolling(layout => $array_text_layout[$ind], center => int(($scroll_w - $array_width_layout[$ind])/2) ); 
}

sub show_scrolling_text_special { # horizontal1 or vertical
   my ($pixmap_layout, $width_layout, $height_layout);
   my $row = $selected_row;
   
   if ( defined $files_info[$row]{artist} ){
      
      my @all_artist = return_artist_name($files_info[$row]); # 'art1 & art2' return (art1,art2)
      
      foreach my $artist ( @all_artist ) {
         next unless $artist;
	 ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "$artist" );      
         push @array_text_layout,  $pixmap_layout;
         push @array_width_layout, $width_layout;
	 push @array_height_layout, $height_layout;      
      }      
      foreach my $item ( 'title', 'album' ) {
         next unless $files_info[$row]{$item};
	 ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "$files_info[$row]{$item}" );      
         push @array_text_layout,  $pixmap_layout;
         push @array_width_layout, $width_layout;
	 push @array_height_layout, $height_layout;      
      }     
      if (@array_text_layout <= 0){
	 (my $file = $files_info[$row]{filename}) =~ s/\.(...|flac)$//i; # remove extension_input
	 ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "$file" );
	 push @array_text_layout,  $pixmap_layout;
         push @array_width_layout, $width_layout;
	 push @array_height_layout, $height_layout;
      }
      if ($files_info[$row]{track}){
         ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "track $files_info[$row]{track} ($files_info[$row]{length})" );
         push @array_text_layout,  $pixmap_layout;
         push @array_width_layout, $width_layout;
	 push @array_height_layout, $height_layout;
      }
      if ($files_info[$row]{frequency}){
         ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "$files_info[$row]{frequency} Hz ($files_info[$row]{bitrate} kb/s)" );
         push @array_text_layout,  $pixmap_layout;
         push @array_width_layout, $width_layout;
	 push @array_height_layout, $height_layout;
      }
   }
   else{
      ($pixmap_layout, $width_layout, $height_layout) = draw_layout();      
      push @array_text_layout,  $pixmap_layout;
      push @array_width_layout, $width_layout;
      push @array_height_layout, $height_layout;
   }
   
   $ind1 = ($ind1)%($#array_text_layout+1); # cyclic indices ;; $ind1 is global
   draw_text_scrolling(layout => $array_text_layout[$ind1], center => int(($scroll_w - $array_width_layout[$ind1])/2) );
}	

sub draw_text_scrolling {
   my %args = ( 
	        widget     => $da,    # $widget = $da = Gtk2::DrawingArea
		event      => undef,
		scrolling  => $true,
		center     => int(($scroll_w - $width_layout)/2), # put the text on the center 
                @_,                   # argument pair list goes here
	      );      
   my $widget = $args{widget};
   my $text   = $args{text};
   $pixmap_layout = $args{layout};
   return if not defined $pixmap_layout;
   
   # init values
   if ($scrolling_type_temp eq 'horinzontal2' or $scrolling_type_temp eq 'horinzontal3'){ $xsrc = 0; $scroll_count_h3 = 170; }
   $scroll_count = 0 if ( $scroll_count >= 3 ); # for 'horinzontal1' and 'vertical'
   $sinal = +1;
   
   my @update_rect;
   $update_rect[0] = $xdest;
   $update_rect[1] = $ydest;
   $update_rect[2] = $scroll_w;
   $update_rect[3] = $scroll_h;
   
   $pixmap->draw_rectangle ($gc_skin2, $true, @update_rect); # erase all first  
   #$drawable->draw_drawable ($gc, $src, $xsrc, $ysrc, $xdest, $ydest, $width, $height)
   $pixmap->draw_drawable ($gc_skin2, $pixmap_layout, -$args{center}, 0, $xdest, $ydest, $scroll_w, $scroll_h); # draw the layout
   $widget->queue_draw_area (@update_rect);  # refresh
   
   begin_scroll_loop(scrolling => $args{scrolling});
}   

sub begin_scroll_loop {
   my %args = ( 
		scrolling  => $true,
                @_,        # argument pair list goes here
	      );

   if ( defined($timer_scroll) ){ Glib::Source->remove($timer_scroll);}  # to not duplicate the MainLoop
   if ( defined($timer_wait)   ){ Glib::Source->remove($timer_scroll);}  # to not duplicate "loop on", "random on", ...
   if ($args{scrolling}){   # 250 milliseconds = 0.250 second 
      # integer = Glib::Timeout->add ($interval, $callback, $data=undef, $priority=G_PRIORITY_DEFAULT); see <man Glib::MainLoop>      
      $timer_scroll = Glib::Timeout->add ($scrolling_text_speed, \&scroll_text_v, undef, 0)  if ($scrolling_type_temp eq 'vertical'); 
      $timer_scroll = Glib::Timeout->add ($scrolling_text_speed, \&scroll_text_h1, undef, 0) if ($scrolling_type_temp eq 'horinzontal1'); 
      $timer_scroll = Glib::Timeout->add ($scrolling_text_speed, \&scroll_text_h2, undef, 0) if ($scrolling_type_temp eq 'horinzontal2');
      $timer_scroll = Glib::Timeout->add ($scrolling_text_speed, \&scroll_text_h3, undef, 0) if ($scrolling_type_temp eq 'horinzontal3');
   } 
}

sub draw_layout { # return the $pixmap_layout->draw_layout_with_colors with text
   my %args = ( 
	        widget     => $da,    # $widget = $da = Gtk2::DrawingArea
		text       => " ***   artist - title - album - track (length) ",
                @_,                   # argument pair list goes here
	      );
   my $widget = $args{widget};
   my $text   = $args{text};            
   return if not defined $pixmap;
   
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width = $widget->allocation->width;
				          
   #my $purple = Gtk2::Gdk::Color->parse ('purple');
   my $purple = Gtk2::Gdk::Color->parse ('#6419b8');
   
   #my $desc = Gtk2::Pango::FontDescription->new();
   #my $context = Gtk2::Pango::Context->new();
   #my $layout = Gtk2::Pango::Layout->new ($context);
   my $layout = $widget->create_pango_layout ("");
   my $context = $layout->get_context;
   my $fontdesc = $context->get_font_description;
   # Choose the Fonts: "Sans", "Fixed", "Utopia", "Courier", "LucidaTypewriter", "Luxi Mono" etc
   $fontdesc->set_family ("Sans");
   $fontdesc->set_style ("normal");  
   
   # find the nice height size and change the font
   my $max_height = $scroll_h;
   $height_layout = $max_height - 1;  # start value
   my $max_font_size = 2;             # start height size
   while ( $height_layout <= $max_height ){  # to determine the maximum height size
       $fontdesc->set_size ( $max_font_size * PANGO_SCALE );
       $layout->set_text ("0�g�X_"); # only to get its width and height
       ($width_layout, $height_layout) = $layout->get_pixel_size; 
       #print "height_layout = $height_layout ; max_height = $max_height ; max_font_size = $max_font_size\n";    
       $max_font_size += 1 if ($height_layout <= $max_height) ;  
   }
   $max_font_size -= 1 if ($height_layout > $max_height);   
 
   $fontdesc->set_size ( $max_font_size * PANGO_SCALE );
   $layout->set_text ($text); 
   ($width_layout, $height_layout) = $layout->get_pixel_size;    # get its width and height ; global variable
   #print "-> height_layout = $height_layout <= max_height = $scroll_h ; max_font_size = $max_font_size\n";            
   
   $layout->set_text ($text." ");  # Put adicional pixels to fix border problem. 

   #pixmap = Gtk2::Gdk::Pixmap->new ($drawable, $width, $height, $depth)
   $pixmap_layout = Gtk2::Gdk::Pixmap->new ($widget->window, $width_layout, $height_layout, -1);
   #$drawable->draw_layout_with_colors ($gc, $x, $y, $layout, $foreground, $background); see <man Gtk2::Gdk::Drawable>
   $pixmap_layout->draw_layout_with_colors ($gc_bg, 0, 0, $layout, $purple, $color_skin2);
      
   return ($pixmap_layout, $width_layout, $height_layout);
}

sub scroll_text_h1 {
     my $incremental = $scrolling_text_incremental || 1; #  1 is default (1 pixel).                              
     my $sep = 16; # separation
     
     $ind1 = ($ind1)%($#array_text_layout+1); # cyclic indices
     my $ind2 = $scrolling_text_orientation > 0 ? ($ind1 + 1)%($#array_text_layout+1) :                  # next crescent   : 0 1 2 3 0 1 2
                                                  ($ind1 + $#array_text_layout)%($#array_text_layout+1); # next decrescent : 0 3 2 1 0 3 2
  
     $xsrc = $xsrc + $scrolling_text_orientation * abs($incremental); # $scrolling_text_orientation : + (up) ; - (down)   
     $ysrc = 0;
     
     if ( abs($xsrc) > int(($array_width_layout[$ind1] + $array_width_layout[$ind2])/2) + $sep ){ 
        $xsrc = 0;
     	$scroll_count += 1;
     }    
     if ( $scroll_count < 4 ){ return $true; }
     if ( $scroll_count > 4 ){ $scroll_count = 0; $ind1 = $ind2; return $true; }                   
     
     my @update_rect;
     $update_rect[0] = $xdest;     $update_rect[1] = $ydest;
     $update_rect[2] = $scroll_w;  $update_rect[3] = $scroll_h;
     $pixmap->draw_rectangle($gc_skin2, $true, @update_rect); # erase all first
     
     my $center1h = int(($scroll_w - $array_width_layout[$ind1])/2);     
     
     my $i = $ind1;                             # the center indice
     my $ini = $center1h - $xsrc;
     my $remain = $scroll_w - $ini;     
     while ( $remain > 0 ){                     # the right side from the center layout 
        my $ind = ($i)%($#array_text_layout+1); # cyclic indices
	my $wid = $array_width_layout[$ind] + $sep;
	my $x0 = $ini > 0 ? 0 : abs($ini);
        $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind],                # $src (Gtk2::Gdk::Drawable)
                                        $x0, $ysrc,                              # $xsrc,  $ysrc,
				        $xdest + maximum($ini,0), $ydest,        # $xdest, $ydest
				        minimum($remain,$scroll_w), $scroll_h);  # $width, $height	
	$remain -= $wid;
	$ini += $wid;
	$i += 1;
     } 
           
     $i = $ind1 + $#array_text_layout;          # the next decrescent array element : 0 3 2 1 0 3 2 1
     $remain = $center1h - $xsrc;
     while ( $remain > 0 ){                     # the left side from the center layout 
        my $ind = ($i)%($#array_text_layout+1); # cyclic indices
	my $wid = $array_width_layout[$ind] + $sep; 
        $remain -= $wid;  
	my $x0 = $remain >= 0 ? 0 : abs($remain);
        $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind],                  # $src (Gtk2::Gdk::Drawable)
                                        $x0, $ysrc,                                # $xsrc,  $ysrc,
				        $xdest + maximum($remain,0), $ydest,       # $xdest, $ydest
				        minimum($wid - $x0,$scroll_w), $scroll_h); # $width, $height
	$i -= 1;
     }
     
     $da->queue_draw_area (@update_rect); # refresh the area
     return $true;
}

sub scroll_text_h2 {
     my $incremental = $scrolling_text_incremental || 1; #  1 is default (1 pixel).
     my $ind = ($ind1)%($#array_text_layout+1);          # $ind = 0, because the @array_width_layout has only one element
     my $center1h = int(($scroll_w - $array_width_layout[$ind])/2);   
     my $wid = $array_width_layout[$ind];
                              
     $xsrc = $xsrc + $sinal * $scrolling_text_orientation * abs($incremental);
     $ysrc = 0;
     
     my @update_rect;
     $update_rect[0] = $xdest;     $update_rect[1] = $ydest;
     $update_rect[2] = $scroll_w;  $update_rect[3] = $scroll_h;
     $pixmap->draw_rectangle($gc_skin2, $true, @update_rect);  # erase all first 
     
     if ( $center1h <= 0 ) {   # closed loop
        my $ini = $center1h - $xsrc;
        my $remain = $scroll_w - $ini;     
        while ( $remain > 0 ){             # the right side from the center layout
	   my $x0 = $ini > 0 ? 0 : abs($ini);
           $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind],                # $src (Gtk2::Gdk::Drawable)
                                           $x0, $ysrc,                              # $xsrc,  $ysrc,
				           $xdest + maximum($ini,0), $ydest,        # $xdest, $ydest
				           minimum($remain,$scroll_w), $scroll_h);  # $width, $height	
	   $remain -= $wid;
	   $ini += $wid;
        }
			
        $remain = $center1h - $xsrc;
        while ( $remain > 0 ){             # the left side from the center layout
           $remain -= $wid;  
	   my $x0 = $remain >= 0 ? 0 : abs($remain);
           $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind],                  # $src (Gtk2::Gdk::Drawable)
                                           $x0, $ysrc,                                # $xsrc,  $ysrc,
				           $xdest + maximum($remain,0), $ydest,       # $xdest, $ydest
				           minimum($wid - $x0,$scroll_w), $scroll_h); # $width, $height
        }   
     }
     elsif ( $center1h > 0 ) {   # zig-zag, movimento de vai e vem.
        if ( abs($xsrc) > abs($center1h) ) { # when the layout touches one extreme, change the $sinal.
           $scroll_count_h3 = 0; 
	   $sinal = -$sinal;
        }                         
		
        $pixmap->draw_drawable ($gc_bg, $pixmap_layout,           # $src (Gtk2::Gdk::Drawable)
                                        $xsrc - $center1h, $ysrc, # $xsrc, $ysrc,
				        $xdest, $ydest,           # $xdest, $ydest
				        $scroll_w, $scroll_h);    # $width, $height
     }
     
     $da->queue_draw_area (@update_rect); # refresh the area  
     return $true;
}

sub scroll_text_h3 { 
     my $incremental = $scrolling_text_incremental || 1; #  1 is default (1 pixel).
     my $center1h = int( ($scroll_w - $width_layout)/2 );
     $ysrc = 0;
     
     $scroll_count_h3 += 1;     
     if ( $scroll_count_h3 < 200 or $center1h >= 0 ) { return $true; }    
                              
     $xsrc = $xsrc + $sinal * $scrolling_text_orientation * abs($incremental);
     $xsrc = 0 if ( abs($xsrc) > abs($center1h) + abs($incremental) );
          
     if ( abs($xsrc) > abs($center1h) ) { # when the layout touches one extreme, the $sinal is changed.
        $scroll_count_h3 = 0; 
	$sinal = -$sinal;
     }
          
     my @update_rect;
     $update_rect[0] = $xdest;     $update_rect[1] = $ydest;
     $update_rect[2] = $scroll_w;  $update_rect[3] = $scroll_h;
     $pixmap->draw_rectangle($gc_skin2, $true, @update_rect);  # erase all first           
		
     $pixmap->draw_drawable ($gc_bg, $pixmap_layout,           # $src (Gtk2::Gdk::Drawable)
                                     $xsrc - $center1h, $ysrc, # $xsrc, $ysrc,
				     $xdest, $ydest,           # $xdest, $ydest
				     $scroll_w, $scroll_h);    # $width, $height
				     			           		     	     
     $da->queue_draw_area (@update_rect); # refresh the area            
     return $true;
}

sub scroll_text_v {
     my $incremental = $scrolling_text_incremental || 1; #  1 is default (1 pixel).                              
     my $sep = 2; # separation
						  
     $ind1 = ($ind1)%($#array_text_layout+1); # cyclic indices
     my $ind2 = $scrolling_text_orientation > 0 ? ($ind1 + 1)%($#array_text_layout+1) :                  # next crescent   : 0 1 2 3 0 1 2
                                                  ($ind1 + $#array_text_layout)%($#array_text_layout+1); # next decrescent : 0 3 2 1 0 3 2
          
     $xsrc = 0; 
     $ysrc = $ysrc - $scrolling_text_orientation * abs($incremental); # $scrolling_text_orientation : + (down) ; - (up)   
     
     if ( abs($ysrc) > $array_height_layout[$ind1] + $sep ){ 
        $ysrc = 0;
     	$scroll_count += 1;
     }  
     if ( $scroll_count < 14 ){ return $true; }
     if ( $scroll_count > 14 ){ $scroll_count = 0; $ind1 = $ind2; return $true;}
            
     my $center1 = int(($scroll_w - $array_width_layout[$ind1])/2); $center1 = 0 if $center1 < 0;
     my $center2 = int(($scroll_w - $array_width_layout[$ind2])/2); $center2 = 0 if $center2 < 0;
     
     my @update_rect;
     $update_rect[0] = $xdest;     $update_rect[1] = $ydest;
     $update_rect[2] = $scroll_w;  $update_rect[3] = $scroll_h;
     $pixmap->draw_rectangle($gc_skin2, $true, @update_rect);      # erase all first 
     
     $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind1],    # $src (Gtk2::Gdk::Drawable)
                                     $xsrc, $ysrc,                 # $xsrc,  $ysrc,
				     $xdest + $center1, $ydest,    # $xdest, $ydest
				     $scroll_w, $scroll_h);        # $width, $height     
     if ( $ysrc > $sep ) {      # up     			     
        $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind2], # $src (Gtk2::Gdk::Drawable)
                                        $xsrc, 0,                  # $xsrc, $ysrc,
				        $xdest + $center2, $ydest + $scroll_h - ( $ysrc - $sep ),   # $xdest, $ydest
				        $scroll_w, $ysrc - $sep);  # $width, $height
     }
     if ( $ysrc + $sep < 0 ) {  # down     
        $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind2],        # $src (Gtk2::Gdk::Drawable)
                                        $xsrc, $array_height_layout[$ind2] + $ysrc + $sep,  # $xsrc, $ysrc,
				        $xdest + $center2, $ydest,        # $xdest, $ydest
				        $scroll_w, abs($ysrc + $sep));    # $width, $height   
     } 
     $da->queue_draw_area (@update_rect); # refresh the area
     return $true;
}

#--------------------- Final -------------------------#
#------------------ Scrolling Text -------------------#

#----------- CD player Color Selection ---------------#
#--------------------- Start -------------------------#
 
# see /usr/share/doc/perl-Gtk2-1.054/gtk-demo/colorsel.pl

my $window_cdplayer_color; my $notebook_cdplayer; my $button_cdplayer_color;
my $darea1; my $darea2; my $darea3; my $darea4; 
my $darea5; my $darea6; my $darea7;

sub make_window_cdplayer_color {

   $window_cdplayer_color = Gtk2::Window->new('toplevel'); # 'toplevel' or 'popup'
   $window_cdplayer_color->set_title ("gnormalize player");
   $window_cdplayer_color->set_border_width (4);
   $window_cdplayer_color->signal_connect (destroy => \&Quit_window_cdplayer_color);
   $window_cdplayer_color->set_position ('none'); # none, center-always, center-on-parent , mouse 
   $window_cdplayer_color->set( 'resizable' => $true, 'allow-shrink' => $false, 'allow-grow' => $true);
   $window_cdplayer_color->realize;

   my $vbox_cdplayer_color = Gtk2::VBox->new ($false, 8);
   $vbox_cdplayer_color->set_border_width (2);
   $window_cdplayer_color->add ($vbox_cdplayer_color);
      
   my $frame_cdplayer_color = Gtk2::Frame->new;
   $frame_cdplayer_color->set_shadow_type ('in');
   
   my $frame_cdplayer_players = Gtk2::Frame->new;
   $frame_cdplayer_players->set_shadow_type ('in');
   
   my $frame_cdplayer_columns = Gtk2::Frame->new;
   $frame_cdplayer_columns->set_shadow_type ('in');
   
   my $frame_cdplayer_skins = Gtk2::Frame->new;
   $frame_cdplayer_skins->set_shadow_type ('in');
   
   #----Notebook----#
   $notebook_cdplayer = Gtk2::Notebook->new;
   $notebook_cdplayer->set( 'homogeneous' => $true, 'scrollable' => $true );
   $notebook_cdplayer->append_page( $frame_cdplayer_color,   $langs{all_tab11} );   # Colors
   $notebook_cdplayer->append_page( $frame_cdplayer_players, $langs{all_tab12} );   # Players 
   $notebook_cdplayer->append_page( $frame_cdplayer_columns, $langs{all_tab13} );   # Columns
   $notebook_cdplayer->append_page( $frame_cdplayer_skins,   $langs{all_tab14} );   # Skins   
   $vbox_cdplayer_color->pack_start( $notebook_cdplayer, $true, $true, 0 );
   
   #$notebook_cd_player_num = $notebook->get_current_page;
   #$notebook->set_current_page ($notebook_cd_player_num); # see this command on the final    

   #$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous );
   my $table_cdplayer_color = new Gtk2::Table (6, 3, 0); 
   $table_cdplayer_color->set_border_width (4);
   $table_cdplayer_color->set_row_spacings(4);
   $table_cdplayer_color->set_col_spacings(2);
   $frame_cdplayer_color->add( $table_cdplayer_color );

   my $label_cdplayer_color1 = Gtk2::Label->new("Background color: ");
   $label_cdplayer_color1->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_color->attach ($label_cdplayer_color1, 0, 1, 0, 1, 'fill', 'fill', 0, 0);
   
   my @def_size = (90,24); # color button size
      
   $darea1 = Gtk2::DrawingArea->new;   
   #my $color_bg    = Gtk2::Gdk::Color->parse ($color_bg_cdplay);
   $darea1->modify_bg ('normal', $color_bg ); # set the color

   #my $button_cdplayer_color = Gtk2::Button->new;
   $button_cdplayer_color = Gtk2::Button->new;
   $button_cdplayer_color->add ($darea1);  # ->set_image ($darea1);
   $button_cdplayer_color->set_size_request (@def_size); # set a minimum size 
   $button_cdplayer_color->signal_connect (clicked => \&change_color_cdplayer_bg, "display" );
   $table_cdplayer_color->attach ($button_cdplayer_color, 1, 2, 0, 1, 'shrink', 'fill', 0, 0);
   
   #-------- Static --------#
   
   my $hsep = Gtk2::HSeparator->new;
   $table_cdplayer_color->attach ($hsep, 0, 2, 1, 2, ['fill','expand'], 'fill', 0, 0);   
   my $label_stat = Gtk2::Label->new("Static Appearance");
   $table_cdplayer_color->attach ($label_stat, 0, 2, 2, 3, 'fill', 'fill', 0, 0);   
     
   my $label_cdplayer_color2 = Gtk2::Label->new("Buttons (shadow): ");
   $label_cdplayer_color2->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_color->attach ($label_cdplayer_color2, 0, 1, 3, 4, 'fill', 'fill', 0, 0);
      
   $darea2 = Gtk2::DrawingArea->new;    
   $darea2->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_shadow) ); # set the color

   my $button_cdplayer_color2 = Gtk2::Button->new;
   $button_cdplayer_color2->add ($darea2);
   $button_cdplayer_color2->set_size_request (@def_size); # set a minimum size 
   $button_cdplayer_color2->signal_connect (clicked => \&change_color_cdplayer_bg, "shadow" );
   $table_cdplayer_color->attach ($button_cdplayer_color2, 1, 2, 3, 4, 'shrink', 'fill', 0, 0); 
   
   my $label_cdplayer_color3 = Gtk2::Label->new("Buttons (arrows): ");
   $label_cdplayer_color3->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_color->attach ($label_cdplayer_color3, 0, 1, 4, 5, 'fill', 'fill', 0, 0);
      
   $darea3 = Gtk2::DrawingArea->new;     
   $darea3->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_arrows) ); # set the color

   my $button_cdplayer_color3 = Gtk2::Button->new;
   $button_cdplayer_color3->add ($darea3);
   $button_cdplayer_color3->set_size_request (@def_size); # set a minimum size 
   $button_cdplayer_color3->signal_connect (clicked => \&change_color_cdplayer_bg, "arrows" );
   $table_cdplayer_color->attach ($button_cdplayer_color3, 1, 2, 4, 5, 'shrink', 'fill', 0, 0);     
   
   #-------- Motion --------#
   
   my $hsep2 = Gtk2::HSeparator->new;
   $table_cdplayer_color->attach ($hsep2, 0, 2, 5, 6, ['fill','expand'], 'fill', 0, 0);   
   my $label_mov = Gtk2::Label->new("Motion Appearance");
   $table_cdplayer_color->attach ($label_mov, 0, 2, 6, 7, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_color4 = Gtk2::Label->new("Buttons (shadow): ");
   $label_cdplayer_color4->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_color->attach ($label_cdplayer_color4, 0, 1, 7, 8, 'fill', 'fill', 0, 0);
      
   $darea4 = Gtk2::DrawingArea->new;    
   $darea4->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_shadow_motion) ); # set the color

   my $button_cdplayer_color4 = Gtk2::Button->new;
   $button_cdplayer_color4->add ($darea4);
   $button_cdplayer_color4->set_size_request (@def_size); # set a minimum size 
   $button_cdplayer_color4->signal_connect (clicked => \&change_color_cdplayer_bg, "shadow_motion" );
   $table_cdplayer_color->attach ($button_cdplayer_color4, 1, 2, 7, 8, 'shrink', 'fill', 0, 0);   
   
   
   my $label_cdplayer_color5 = Gtk2::Label->new("Buttons (arrows): ");
   $label_cdplayer_color5->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_color->attach ($label_cdplayer_color5, 0, 1, 8, 9, 'fill', 'fill', 0, 0);
      
   $darea5 = Gtk2::DrawingArea->new;   
   $darea5->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_arrows_motion) ); # set the color

   my $button_cdplayer_color5 = Gtk2::Button->new;
   $button_cdplayer_color5->add ($darea5); 
   $button_cdplayer_color5->set_size_request (@def_size); # set a minimum size 
   $button_cdplayer_color5->signal_connect (clicked => \&change_color_cdplayer_bg, "arrows_motion" );
   $table_cdplayer_color->attach ($button_cdplayer_color5, 1, 2, 8, 9, 'shrink', 'fill', 0, 0);  
   
   
   #-------- Digits --------#
   
   my $hsep3 = Gtk2::HSeparator->new;
   $table_cdplayer_color->attach ($hsep3, 0, 2, 9, 10, ['fill','expand'], 'fill', 0, 0);   
   my $label_dig = Gtk2::Label->new("Digits");
   $table_cdplayer_color->attach ($label_dig, 0, 2, 10, 11, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_color6 = Gtk2::Label->new("Current time: ");
   $label_cdplayer_color6->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_color->attach ($label_cdplayer_color6, 0, 1, 11, 12, 'fill', 'fill', 0, 0);
      
   $darea6 = Gtk2::DrawingArea->new;      
   $darea6->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_digit) ); # set the color

   my $button_cdplayer_color6 = Gtk2::Button->new;
   $button_cdplayer_color6->add ($darea6);
   $button_cdplayer_color6->set_size_request (@def_size); # set a minimum size 
   $button_cdplayer_color6->signal_connect (clicked => \&change_color_cdplayer_bg, "digit" );
   $table_cdplayer_color->attach ($button_cdplayer_color6, 1, 2, 11, 12, 'shrink', 'fill', 0, 0);  
    
   
   my $label_cdplayer_color7 = Gtk2::Label->new("Remaining time: ");
   $label_cdplayer_color7->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_color->attach ($label_cdplayer_color7, 0, 1, 12, 13, 'fill', 'fill', 0, 0);
      
   $darea7 = Gtk2::DrawingArea->new;  
   $darea7->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_digit_remaining) ); # set the color

   my $button_cdplayer_color7 = Gtk2::Button->new;
   $button_cdplayer_color7->add ($darea7);
   $button_cdplayer_color7->set_size_request (@def_size); # set a minimum size 
   $button_cdplayer_color7->signal_connect (clicked => \&change_color_cdplayer_bg, "digit_remaining" );
   $table_cdplayer_color->attach ($button_cdplayer_color7, 1, 2, 12, 13, 'shrink', 'fill', 0, 0);   
   
   
   #------- Players -------#
   my $table_cdplayer_players = new Gtk2::Table (6, 3, 0); 
   $table_cdplayer_players->set_border_width (4);
   $table_cdplayer_players->set_row_spacings(4);
   $table_cdplayer_players->set_col_spacings(2);
   $frame_cdplayer_players->add( $table_cdplayer_players );
   
   my $label_cdplayer_players0 = Gtk2::Label->new("player");
   $label_cdplayer_players0->set_alignment( 0.5, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players0, 1, 2, 0, 1, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_players01 = Gtk2::Label->new("device type");
   $label_cdplayer_players01->set_alignment( 0.5, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players01, 3, 4, 0, 1, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_players02 = Gtk2::Label->new("device path");
   $label_cdplayer_players02->set_alignment( 0.5, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players02, 3, 4, 2, 3, 'fill', 'fill', 0, 0);

   my $label_cdplayer_players1 = Gtk2::Label->new("mp3: ");
   $label_cdplayer_players1->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players1, 0, 1, 1, 2, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_players2 = Gtk2::Label->new("mp4: ");
   $label_cdplayer_players2->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players2, 0, 1, 2, 3, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_players3 = Gtk2::Label->new("mpc: ");
   $label_cdplayer_players3->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players3, 0, 1, 3, 4, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_players4 = Gtk2::Label->new("ogg: ");
   $label_cdplayer_players4->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players4, 0, 1, 4, 5, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_players5 = Gtk2::Label->new("ape: ");
   $label_cdplayer_players5->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players5, 0, 1, 5, 6, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_players6 = Gtk2::Label->new("flac: ");
   $label_cdplayer_players6->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players6, 0, 1, 6, 7, 'fill', 'fill', 0, 0);
   
   my $label_cdplayer_players7 = Gtk2::Label->new("wav: ");
   $label_cdplayer_players7->set_alignment( 1.0, 0.5 ); 
   $table_cdplayer_players->attach ($label_cdplayer_players7, 0, 1, 7, 8, 'fill', 'fill', 0, 0);
   
   
   #---mp3---#   
      
   my $ComboBox_mp3_player = Gtk2::ComboBox->new_text;  # "mpg321", "mpg123", "madplay", "mplayer"
   foreach (sort keys %all_mp3_player) { $ComboBox_mp3_player->append_text ($_); }   
   my $pos = 0;
   foreach my $key (sort keys %all_mp3_player) { if ($key eq $player_mp3) {$ComboBox_mp3_player->set_active($pos); last;} $pos++; }   
   $ComboBox_mp3_player->set_size_request( 90, -1 );
   $ComboBox_mp3_player->signal_connect("changed", \&player_choice, \$player_mp3);
   $table_cdplayer_players->attach ($ComboBox_mp3_player, 1, 2, 1, 2, ['fill','expand'], 'fill', 0, 0);
   $ComboBox_mp3_player->show;

   sub player_choice {   
      my ($ComboBox_copy, $ref_player) = @_;
      my $entry = $ComboBox_copy->get_active_text;
      
      #  See 'man perlref', 'man perlop' and 'man perlobj'.
      #  "\" operator for taking a reference;  "$" operator for taking a dereference to scalar variable.
      # "$player" is a scalar variable that references to a variable.
      # "\$player" typically creates another reference to a variable, because there's already a reference to the variable in the symbol table.
      # "$$player" is the value that the reference "\$player" points to.      
	   
      $$ref_player = $entry;
      #print "\nComboBox_copy = $ComboBox_copy ;; \nref_player = $ref_player ;; ref_palyer value = $$ref_player  \n";
   }   
   
   #---------#   
   my @device_type_array = ( "arts", "oss", "alsa", "esd", "jack", "nas", "sun" );
   
   my $ComboBoxEntry_device_type = Gtk2::ComboBoxEntry->new_text;
   ComboBox_fill_with_array(\$ComboBoxEntry_device_type,\@device_type_array);
   $ComboBoxEntry_device_type->child->set_text( $device_type ); #standard value 
   $ComboBoxEntry_device_type->set_size_request( 90, -1 );
   $ComboBoxEntry_device_type->child->set_editable ($true);
   $ComboBoxEntry_device_type->signal_connect("changed", \&device_choice, \$device_type);
   $table_cdplayer_players->attach ($ComboBoxEntry_device_type, 3, 4, 1, 2, ['fill','expand'], 'fill', 0, 0);
   #$ComboBoxEntry_device_type->show;      
   
   sub device_choice {
      my ($combo_copy, $ref_device) = @_; 
      my $entry=$combo_copy->child->get_text;		
      if ( $entry eq "" ){ return; } # return if empty
      $$ref_device = $entry;		
   }
     
   my @device_path_array = ( "/dev/audio", "/dev/sound/adsp", "/dev/dsp" );
   
   my $ComboBoxEntry_device_path = Gtk2::ComboBoxEntry->new_text;
   ComboBox_fill_with_array(\$ComboBoxEntry_device_path,\@device_path_array);
   $ComboBoxEntry_device_path->child->set_text( $device_path ); #standard value 
   $ComboBoxEntry_device_path->set_size_request( 140, -1 );
   $ComboBoxEntry_device_path->child->set_editable ($true);
   $ComboBoxEntry_device_path->signal_connect("changed", \&device_choice, \$device_path);
   $table_cdplayer_players->attach ($ComboBoxEntry_device_path, 3, 4, 3, 4, ['fill','expand'], 'fill', 0, 0);     
   
   #---mp4---#  
   my $ComboBox_mp4_player = Gtk2::ComboBox->new_text;  # "mplayer"
   foreach (sort keys %all_mp4_player) { $ComboBox_mp4_player->append_text ($_); }   
   $pos = 0;
   foreach my $key (sort keys %all_mp4_player) { if ($key eq $player_mp4) {$ComboBox_mp4_player->set_active($pos); last;} $pos++; }   
   $ComboBox_mp4_player->set_size_request( 90, -1 );
   $ComboBox_mp4_player->signal_connect("changed", \&player_choice, \$player_mp4);
   $table_cdplayer_players->attach ($ComboBox_mp4_player, 1, 2, 2, 3, ['fill','expand'], 'fill', 0, 0);
   $ComboBox_mp4_player->show; 
 
   #---mpc---#         
   my $ComboBox_mpc_player = Gtk2::ComboBox->new_text;  # "mpcdec", "mplayer"
   foreach (sort keys %all_mpc_player) { $ComboBox_mpc_player->append_text ($_); }   
   $pos = 0;
   foreach my $key (sort keys %all_mpc_player) { if ($key eq $player_mpc) {$ComboBox_mpc_player->set_active($pos); last;} $pos++; }   
   $ComboBox_mpc_player->set_size_request( 90, -1 );
   $ComboBox_mpc_player->signal_connect("changed", \&player_choice, \$player_mpc);
   $table_cdplayer_players->attach ($ComboBox_mpc_player, 1, 2, 3, 4, ['fill','expand'], 'fill', 0, 0);
   $ComboBox_mpc_player->show;  
   
   #---ogg---#
   my $ComboBox_ogg_player = Gtk2::ComboBox->new_text;  # "ogg123", "mplayer"
   foreach (sort keys %all_ogg_player) { $ComboBox_ogg_player->append_text ($_); }   
   $pos = 0;
   foreach my $key (sort keys %all_ogg_player) { if ($key eq $player_ogg) {$ComboBox_ogg_player->set_active($pos); last;} $pos++; }   
   $ComboBox_ogg_player->set_size_request( 90, -1 );
   $ComboBox_ogg_player->signal_connect("changed", \&player_choice, \$player_ogg);
   $table_cdplayer_players->attach ($ComboBox_ogg_player, 1, 2, 4, 5, ['fill','expand'], 'fill', 0, 0);
   $ComboBox_ogg_player->show;
         
   #---ape---#
   my $ComboBox_ape_player = Gtk2::ComboBox->new_text;  # "mac + play", "mplayer"
   foreach (sort keys %all_ape_player) { $ComboBox_ape_player->append_text ($_); }   
   $pos = 0;
   foreach my $key (sort keys %all_ape_player) { if ($key eq $player_ape) {$ComboBox_ape_player->set_active($pos); last;} $pos++; }   
   $ComboBox_ape_player->set_size_request( 90, -1 );
   $ComboBox_ape_player->signal_connect("changed", \&player_choice, \$player_ape);
   $table_cdplayer_players->attach ($ComboBox_ape_player, 1, 2, 5, 6, ['fill','expand'], 'fill', 0, 0);
   $ComboBox_ape_player->show; 
   
   #---flac---#  
   my $ComboBox_flac_player = Gtk2::ComboBox->new_text;  # "flac123", "mplayer"
   foreach (sort keys %all_flac_player) { $ComboBox_flac_player->append_text ($_); }   
   $pos = 0;
   foreach my $key (sort keys %all_flac_player) { if ($key eq $player_flac) {$ComboBox_flac_player->set_active($pos); last;} $pos++; }   
   $ComboBox_flac_player->set_size_request( 90, -1 );
   $ComboBox_flac_player->signal_connect("changed", \&player_choice, \$player_flac);
   $table_cdplayer_players->attach ($ComboBox_flac_player, 1, 2, 6, 7, ['fill','expand'], 'fill', 0, 0);
   $ComboBox_flac_player->show;
            
   #---wav---#   
   my $ComboBox_wav_player = Gtk2::ComboBox->new_text;  # "mplayer"
   foreach (sort keys %all_wav_player) { $ComboBox_wav_player->append_text ($_); }   
   $pos = 0;
   foreach my $key (sort keys %all_wav_player) { if ($key eq $player_wav) {$ComboBox_wav_player->set_active($pos); last;} $pos++; }   
   $ComboBox_wav_player->set_size_request( 90, -1 );
   $ComboBox_wav_player->signal_connect("changed", \&player_choice, \$player_wav);
   $table_cdplayer_players->attach ($ComboBox_wav_player, 1, 2, 7, 8, ['fill','expand'], 'fill', 0, 0);
   $ComboBox_wav_player->show;   
   
   #----------- play_with_filter -----------#    
   my @all_filter = ( $langs{name429} , # = 'Play Tracks Without Any Filters';
                      $langs{name430} , # = 'Play Tracks From Different Albums';
                      $langs{name431} , # = 'Play Tracks From Different Artists';
                      $langs{name432} , # = 'Play Tracks From Different Genres';
                      $langs{name433} , # = 'Play Tracks From Different Years';
		    );   	    	    
    
   $ComboBox_player_with_filter = Gtk2::ComboBox->new_text;  # filter can be albums, artists, ...
   foreach (@all_filter) { $ComboBox_player_with_filter->append_text ($_); }      
   $ComboBox_player_with_filter->set_active($use_filter);  # default value
   $ComboBox_player_with_filter->set_size_request( 90, -1 );
   $ComboBox_player_with_filter->signal_connect("changed", \&change_filter);   
   $table_cdplayer_players->attach ($ComboBox_player_with_filter, 0, 4, 8, 9, ['fill','expand'], 'fill', 0, 0);   
   $tooltips->set_tip( $ComboBox_player_with_filter, $langs{tip429} ) if $show_all_tooltips;  # "Play choosing only tracks that satisfies established filters...";
   $ComboBox_player_with_filter->show;

   sub change_filter {  # see 'sub choose_filter'
      $use_filter = $ComboBox_player_with_filter->get_active; # $use_filter is a number
      
      #@rows_already_played = (); # if change the filter, then reset playlist of rows_already_played.
   }     
   
   #---------------- Columns ---------------#
   my $table_cdplayer_columns = new Gtk2::Table (10, 3, 0); 
   $table_cdplayer_columns->set_border_width (4);
   $table_cdplayer_columns->set_row_spacings(4);
   $table_cdplayer_columns->set_col_spacings(2);
   $frame_cdplayer_columns->add( $table_cdplayer_columns );
   
   
   my $check_button_file = Gtk2::CheckButton->new ("Show File Number");
   $check_button_file->set_active($column_show_file);
   $check_button_file->signal_connect( "clicked", sub{
      $column_show_file = $check_button_file->get_active;      
      add_columns( show_play => $true);
      show_scrolling_text();     
   });
   $table_cdplayer_columns->attach ($check_button_file, 0, 1, 0, 1, 'fill', 'fill', 0, 0);
   
   
   my $check_button_artist = Gtk2::CheckButton->new ("Show Artist");
   $check_button_artist->set_active($column_show_artist);
   $check_button_artist->signal_connect( "clicked", sub{
      $column_show_artist = $check_button_artist->get_active;      
      add_columns( show_play => $true);
      show_scrolling_text();     
   });
   $table_cdplayer_columns->attach ($check_button_artist, 0, 1, 1, 2, 'fill', 'fill', 0, 0);
   
   my $check_button_album = Gtk2::CheckButton->new ("Show Album");
   $check_button_album->set_active($column_show_album);
   $check_button_album->signal_connect( "clicked", sub{
      $column_show_album = $check_button_album->get_active;      
      add_columns( show_play => $true);
      show_scrolling_text();      
   });
   $table_cdplayer_columns->attach ($check_button_album, 0, 1, 2, 3, 'fill', 'fill', 0, 0); 
   
   my $check_button_track = Gtk2::CheckButton->new ("Show Track");
   $check_button_track->set_active($column_show_track);
   $check_button_track->signal_connect( "clicked", sub{
      $column_show_track = $check_button_track->get_active;      
      add_columns( show_play => $true);
      show_scrolling_text();      
   });
   $table_cdplayer_columns->attach ($check_button_track, 0, 1, 3, 4, 'fill', 'fill', 0, 0); 
   
   my $check_button_bitrate = Gtk2::CheckButton->new ("Show Bitrate");
   $check_button_bitrate->set_active($column_show_bitrate);
   $check_button_bitrate->signal_connect( "clicked", sub{
      $column_show_bitrate = $check_button_bitrate->get_active;      
      add_columns( show_play => $true);
      show_scrolling_text();      
   });
   $table_cdplayer_columns->attach ($check_button_bitrate, 0, 1, 4, 5, 'fill', 'fill', 0, 0); 
   
   my $check_button_year = Gtk2::CheckButton->new ("Show Year");
   $check_button_year->set_active($column_show_year);
   $check_button_year->signal_connect( "clicked", sub{
      $column_show_year = $check_button_year->get_active;      
      add_columns( show_play => $true);      
   });
   $table_cdplayer_columns->attach ($check_button_year, 0, 1, 5, 6, 'fill', 'fill', 0, 0); 
   
   
   my $check_button_frequency = Gtk2::CheckButton->new ("Show Frequency");
   $check_button_frequency->set_active($column_show_frequency);
   $check_button_frequency->signal_connect( "clicked", sub{
      $column_show_frequency = $check_button_frequency->get_active;      
      add_columns( show_play => $true);      
   });
   $table_cdplayer_columns->attach ($check_button_frequency, 0, 1, 6, 7, 'fill', 'fill', 0, 0);       
   
   my $check_button_filepath = Gtk2::CheckButton->new ("Show Filepath");
   $check_button_filepath->set_active($column_show_filepath);
   $check_button_filepath->signal_connect( "clicked", sub{
      $column_show_filepath = $check_button_filepath->get_active;      
      add_columns( show_play => $true);     
   });
   $table_cdplayer_columns->attach ($check_button_filepath, 0, 1, 7, 8, 'fill', 'fill', 0, 0);  
   
   
   my $check_button_filename = Gtk2::CheckButton->new ("Show Filename");
   $check_button_filename->set_active($column_show_filename);
   $check_button_filename->signal_connect( "clicked", sub{
      $column_show_filename = $check_button_filename->get_active;      
      add_columns( show_play => $true);    
   });
   $table_cdplayer_columns->attach ($check_button_filename, 0, 1, 8, 9, 'fill', 'fill', 0, 0);         
  
   
   my $check_button_extension = Gtk2::CheckButton->new ("Show Extension");
   $check_button_extension->set_active($column_show_extension);
   $check_button_extension->signal_connect( "clicked", sub{
      $column_show_extension = $check_button_extension->get_active;      
      add_columns( show_play => $true);  
   });
   $table_cdplayer_columns->attach ($check_button_extension, 0, 1, 9, 10, 'fill', 'fill', 0, 0);
   
   my $check_button_play_count = Gtk2::CheckButton->new ("Show Play Count");
   $check_button_play_count->set_active($column_show_play_count);
   $check_button_play_count->signal_connect( "clicked", sub{
      $column_show_play_count = $check_button_play_count->get_active;      
      add_columns_album_artist( column_show_play_count => $column_show_play_count);  
   });
   $table_cdplayer_columns->attach ($check_button_play_count, 0, 1, 10, 11, 'fill', 'fill', 0, 0);
   
   #---------------- Skins ---------------#
   my $table_cdplayer_skins = new Gtk2::Table (6, 3, 0); 
   $table_cdplayer_skins->set_border_width (4);
   $table_cdplayer_skins->set_row_spacings(4);
   $table_cdplayer_skins->set_col_spacings(4);
   $frame_cdplayer_skins->add( $table_cdplayer_skins );
      
   my $label_st = Gtk2::Label->new("Scrolling Text");
   $table_cdplayer_skins->attach ($label_st, 0, 2, 0, 1, 'fill', 'fill', 0, 0);
   
   ###---###   
   my $label_scrolling_type = new Gtk2::Label( "Type:" );
   $label_scrolling_type->set_alignment( 1.0, 0.5 );  
   $table_cdplayer_skins->attach ($label_scrolling_type, 0, 1, 1, 2, 'fill', 'fill', 0, 0);    
   
   my @all_scrolling = ( "horinzontal1", "horinzontal2", "horinzontal3", "vertical", "random" );

   my $ComboBox_scrolling = Gtk2::ComboBox->new_text;
   ComboBox_fill_with_array(\$ComboBox_scrolling,\@all_scrolling);
   ComboBox_select_this_text(\$ComboBox_scrolling,\@all_scrolling,\$scrolling_type);  #standard value
   $ComboBox_scrolling->set_size_request( 120, -1 );
   $ComboBox_scrolling->signal_connect("changed", \&scrolling_choice, $ComboBox_scrolling);
   $table_cdplayer_skins->attach ($ComboBox_scrolling, 1, 2, 1, 2, ['fill','expand'], 'fill', 0, 0);
   #$ComboBox_scrolling->show;
      
   sub scrolling_choice {
        my ($self, $ComboBox_copy) = @_;
	$scrolling_type = $ComboBox_copy->get_active_text;
	show_scrolling_text();
   }  
   ###---### 
   
   my $label_sts = new Gtk2::Label( "Interval:" );
   $label_sts->set_alignment( 1.0, 0.5 );  
   $table_cdplayer_skins->attach ($label_sts, 0, 1, 2, 3, 'fill', 'fill', 0, 0);

   my $adj = new Gtk2::Adjustment( $scrolling_text_speed, 10, 2000, 5, 0, 0 );
   my $spinner_text = new Gtk2::SpinButton( $adj, 1.2, 0 );
   $spinner_text->set_editable($true);
   $spinner_text->set_size_request( 120, -1 );
   $spinner_text->set_update_policy( 'if_valid' );
   $spinner_text->set_wrap( $false );
   $tooltips->set_tip( $spinner_text, $langs{tip407} ) if $show_all_tooltips;
   $spinner_text->signal_connect( "value-changed", sub{ 
      $scrolling_text_speed = $spinner_text->get_value_as_int;
      begin_scroll_loop();
      #print "scrolling_text_speed = $scrolling_text_speed\n";
   });    
   $table_cdplayer_skins->attach ($spinner_text, 1, 2, 2, 3, ['fill','expand'], 'fill', 0, 0);
      
   
   my $label_step = new Gtk2::Label( "Step:" );
   $label_step->set_alignment( 1.0, 0.5 );  
   $table_cdplayer_skins->attach ($label_step, 0, 1, 3, 4, 'fill', 'fill', 0, 0);

   $adj = new Gtk2::Adjustment( $scrolling_text_incremental, 1, 20, 1, 0, 0 );
   my $spinner_step = new Gtk2::SpinButton( $adj, 0.2, 0 );
   $spinner_step->set_editable($true);
   $spinner_step->set_size_request( 120, -1 );
   $spinner_step->set_update_policy( 'if_valid' );
   $spinner_step->set_wrap( $false );
   $tooltips->set_tip( $spinner_step, $langs{tip408} ) if $show_all_tooltips;
   $spinner_step->signal_connect( "value-changed", sub{ 
      $scrolling_text_incremental = $spinner_step->get_value_as_int;
      #print "scrolling_text_incremental = $scrolling_text_incremental\n";
   });    
   $table_cdplayer_skins->attach ($spinner_step, 1, 2, 3, 4, 'fill', 'fill', 0, 0); 
     
        
   my $check_button_orientation = Gtk2::CheckButton->new ("Scrolling text orientation");        
   $tooltips->set_tip( $check_button_orientation, $langs{tip409} ) if $show_all_tooltips;
   $check_button_orientation->set_active( $scrolling_text_orientation == 1 ? $true : $false );
   $check_button_orientation->signal_connect( "clicked", sub{ 
      $scrolling_text_orientation = $check_button_orientation->get_active ? +1 : -1;
   });    
   $table_cdplayer_skins->attach ($check_button_orientation, 0, 2, 4, 5, 'fill', 'fill', 0, 0);
   
   my $hsepSkin = Gtk2::HSeparator->new;
   $table_cdplayer_skins->attach ($hsepSkin, 0, 2, 5, 6, ['fill','expand'], 'fill', 0, 0);   
   
   
   my $check_button_skin = Gtk2::CheckButton->new ("Show skin");
   $tooltips->set_tip( $check_button_skin, $langs{tip410} ) if $show_all_tooltips;
   $check_button_skin->set_active($show_cdplayer_skin);
   $check_button_skin->signal_connect( "clicked", sub{ 
      $show_cdplayer_skin = $check_button_skin->get_active;
      sensitive_bg_color();    
   });    
   $table_cdplayer_skins->attach ($check_button_skin, 0, 1, 6, 7, 'fill', 'fill', 0, 0);      
   
   my $check_button_border = Gtk2::CheckButton->new ("Show border");
   $check_button_border->set_active($show_cdplayer_border);
   $check_button_border->signal_connect( "clicked", sub{ 
      $show_cdplayer_border = $check_button_border->get_active;
   });
   $table_cdplayer_skins->attach ($check_button_border, 0, 1, 7, 8, 'fill', 'fill', 0, 0);
   
   my $check_button_keep_above = Gtk2::CheckButton->new ("Keep above");
   $tooltips->set_tip( $check_button_keep_above, $langs{tip411} ) if $show_all_tooltips;
   $check_button_keep_above->set_active($show_cdplayer_keep_above);
   $check_button_keep_above->signal_connect( "clicked", sub{ 
      $show_cdplayer_keep_above = $check_button_keep_above->get_active;   
   });    
   $table_cdplayer_skins->attach ($check_button_keep_above, 0, 1, 8, 9, 'fill', 'fill', 0, 0);
   
   #---------------- hbox ----------------#

   my $hbox2 = Gtk2::HBox->new ($false, 0);
   $hbox2->set_border_width (2);
   $vbox_cdplayer_color->pack_start ($hbox2, $false, $false, 0);    
   
   my $label_empty2 = Gtk2::Label->new(" ");
   $hbox2->pack_start ($label_empty2, $true, $false, 0);
   
   my $button = Gtk2::Button->new;
   $button->add( DrawIcons('gtk-close','button') );
   $tooltips->set_tip( $button, $langs{tip406} ) if $show_all_tooltips;
   $button->signal_connect( "clicked", \&Quit_window_cdplayer_color );
   $hbox2->pack_start ($button, $false, $false, 0);
   
   my $label_empty3 = Gtk2::Label->new(" ");
   $hbox2->pack_start ($label_empty3, $true, $false, 0);       
}

sub sensitive_bg_color{
   if ( defined $window_cdplayer_color ){
      $button_cdplayer_color->set_sensitive($true);
      if (defined $pixmap_mask){ # have skin_xTunes
         $button_cdplayer_color->set_sensitive($false);
      }
   }
}
     
sub cdplayer_color_selection {  

   if ( not defined($window_cdplayer_color) ) {
      make_window_cdplayer_color();
      $window_cdplayer_color->show_all;
      
      #---- $notebook->set_current_page  ----# 
   
      $notebook_cdplayer->set_current_page ($notebook_cd_player_num);   
      #$notebook_cd_player_num = $notebook->get_current_page;
      #$notebook->set_current_page ($notebook_cd_player_num); # see this command on the final 
      #print "\ncdplayer_color_selection -->1 \$notebook_cd_player_num = $notebook_cd_player_num\n";
   }
   else {       
      Quit_window_cdplayer_color(); 
  }
}

sub Quit_window_cdplayer_color {
      $notebook_cd_player_num = $notebook_cdplayer->get_current_page; 
      #print "\ncdplayer_color_selection -->2 \$notebook_cd_player_num = $notebook_cd_player_num\n";
            
      $window_cdplayer_color->destroy;
      $window_cdplayer_color = undef;
}

sub change_color_cdplayer_bg {
  my ( $self, $region ) = @_;
  my $color;
  
  # repair the standard cancel label
  my @items = ( { stock_id => "gtk-cancel", label => "_Cancel" } );
  Gtk2::Stock->add (@items);  # Register our stock items
  
  my $dialog = Gtk2::ColorSelectionDialog->new ("Change the color");    
  $dialog->set_transient_for ($window);  
  my $colorsel = $dialog->colorsel;

  my $previous_color;
  # $color_bg_cdplay = '#E6EDBD'; $color_cdplayer_shadow = '#6E95EF'; $color_cdplayer_arrows = '#000000';
  if    ($region eq 'display'){  $previous_color = Gtk2::Gdk::Color->parse ($color_bg_cdplay);        }
  elsif ($region eq 'shadow' ){  $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_shadow);  }
  elsif ($region eq 'arrows' ){  $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_arrows);  }
  elsif ($region eq 'shadow_motion' ){  $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_shadow_motion);  }
  elsif ($region eq 'arrows_motion' ){  $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_arrows_motion);  }
  elsif ($region eq 'digit'         ){  $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_digit);          }
  elsif ($region eq 'digit_remaining' ){  $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_digit_remaining);  }

  $colorsel->set_previous_color ($previous_color);
  $colorsel->set_current_color  ($previous_color);
  $colorsel->set_has_palette ($true);
  $colorsel->set_has_opacity_control ($false);
  
  my $response = $dialog->run;

  if ($response eq 'ok') {
      my $color_gdk = $colorsel->get_current_color; # $color = Gtk2::Gdk::Color      
      my ($red, $green, $blue) = ( $color_gdk->red, $color_gdk->green, $color_gdk->blue );
            
      # uc: Returns an uppercased version of EXPR.
      # %x   an unsigned integer, in hexadecimal ; l: long
      $red   = uc( sprintf( "%02lx", $red/256 ) );  #print "red = $red\n";
      $green = uc( sprintf( "%02lx", $green/256 ) );
      $blue  = uc( sprintf( "%02lx", $blue/256 ) );
   
      $color = "#${red}${green}${blue}"; # print "color = $color\n";  # like #E6E7E6 ; HTML-style hexadecimal
      
      if ($region eq 'display'){      
         configure_event_cdplayer( $da, undef, ($color, undef) ); # change display color
         $darea1->modify_bg ( 'normal', $color_gdk );
      }
      elsif ($region eq 'shadow'){      
         configure_event_cdplayer( $da, undef, (undef, $color) ); # change buttons color (shadow)
         $darea2->modify_bg ( 'normal', $color_gdk );
      }
      elsif ($region eq 'arrows'){      
         configure_event_cdplayer( $da, undef, (undef, undef, $color) ); # change buttons color (arrows)
         $darea3->modify_bg ( 'normal', $color_gdk );
      }
      elsif ($region eq 'shadow_motion'){      
         configure_event_cdplayer( $da, undef, (undef, undef, undef, $color) ); # change buttons color (shadow_motion)
         $darea4->modify_bg ( 'normal', $color_gdk );
      }
      elsif ($region eq 'arrows_motion'){      
         configure_event_cdplayer( $da, undef, (undef, undef, undef, undef, $color) ); # change buttons color (arrows_motion)
         $darea5->modify_bg ( 'normal', $color_gdk );
      }
      elsif ($region eq 'digit'){      
         configure_event_cdplayer( $da, undef, (undef, undef, undef, undef, undef, $color) ); # change buttons color (digit)
         $darea6->modify_bg ( 'normal', $color_gdk );
      }
      elsif ($region eq 'digit_remaining'){      
         configure_event_cdplayer( $da, undef, (undef, undef, undef, undef, undef, undef, $color) ); # change buttons color (digit_remaining)
         $darea7->modify_bg ( 'normal', $color_gdk );
      }
      # refresh the whole area $da
      $da->queue_draw_area (0, 0, $da->allocation->width, $da->allocation->height); 
  }  
  $dialog->destroy;
  return $color;
}

#--------------------- Final -------------------------#
#----------- CD player Color Selection ---------------#
my ($click_x, $click_y) = (0,0);

sub button_press_event_cdplayer {
  my ($widget, $event, $data) = @_;    # $widget = $da = Gtk2::DrawingArea

  my (undef, $x, $y, $state) = $event->window->get_pointer; 
  if ( $cdplayer eq "Audio::CD" ){ $audiocd = Audio::CD->init("$audiodevice_path"); }
  
  ($click_x, $click_y) = ($x, $y);
  
  $go_back = $false;
  $go_forward = $false;
  
  my $width_r  = $buttons_w - 0;  # 14
  my $height_r = $buttons_h - 2;  # height of buttons 
  
  # Press mouse button 2 or 3 on cdplayer display to hide the main window
  if ($event->button >= 2) { 
     show_only_cd_display();
     sensitive_bg_color(); # cd_player bg color change   
  }
    
  if ($event->button == 1) {    
     my $height = $widget->allocation->height;
     my $width = $widget->allocation->width ;
     
     # stop button   
     my $xdest_but = $xdest_buttons - 1*$buttons_w/2 + 0*$delta;    
     if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
        draw_buttons(Press_Stop => $true, Draw_Stop => $true);
	$button_press_stop = $true;    
        #print "vc clicou em stop: x = $x, y = $y ;; height = $height ;; width = $width ;; dcentery = $dcentery\n";        
	stop_playing_music();
	show_time();
	$pause = $false;	
	return $true;
     }
     # (play || pause) buttons display
     $xdest_but = $xdest_buttons + 1*$buttons_w/2 + 1*$delta;    
     if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
        draw_buttons(Press_Play => $true, Draw_Play => $true); # change button color
	$button_press_play = $true;    	
	if ( $playing_music eq $false or $pause eq $true){           
           # Set volume level to play audio cd.
           change_volume_level( undef, $audio_cd_volume ); # 0 - 100	   
	
	   if ( $pause eq $false and $playing_music eq $false ){ play_selection();}
	   
	   if ( $pause eq $true){
	   
	      if ($files_info[$selected_row]{extension_input} ne 'cda'){
	         if(defined $pid_player){kill 18,$pid_player}; # to resume; See "Signals" in perlipc
	         $pause = $false;			
	         return $true;
              }	   
	   
	      if ( $cdplayer eq "cdcd" ){		 
		 my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'resume' );      
                 exec_cmd_system2(@cmd);   
              }
	      elsif ( $cdplayer eq "gnormalize::cdplay" ){
	         gnormalize::cdplay::resume_cdrom();
	      }
	      elsif ( $cdplayer eq "Audio::CD" ){
	         $audiocd->resume;
	      }
	   }
	   $pause = $false;
	}
	else{
           if ( $playing_music eq $false ){ return;}
	   
	   if ($files_info[$selected_row]{extension_input} ne 'cda'){
	      if(defined $pid_player){kill 19,$pid_player}; # see <kill -l>
	      $pause = $true;			
	      return $true;
           }
	   
           if ( $cdplayer eq "cdcd" ){	      
	      my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'pause' );	      
              exec_cmd_system2(@cmd);
           }
	   elsif ( $cdplayer eq "gnormalize::cdplay" ){ 
	      gnormalize::cdplay::pause_cdrom();
	   }
	   elsif ( $cdplayer eq "Audio::CD" ){ 
	      $audiocd->pause;
	   }
	   $pause = $true;		
	}	
	return $true;
     }            
     # fastforward button display
     $xdest_but = $xdest_buttons + 3*$buttons_w/2 + 2*$delta;    
     if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
        draw_buttons(Press_Forward => $true, Draw_Forward => $true);
	$button_press_forward = $true;    
        #print "vc clicou em ff: x = $x, y = $y ;; height = $height ;; width = $width ;; dcenterx = $dcenterx\n"; 
	if ( $playing_music eq $false ){ return;}
	
	if ($files_info[$selected_row]{extension_input} ne 'cda'){ 
	   $count = $count+15;
	   play_selection( skip => $count ); 
	   $pause = $false;	
	   return $true;    
        }
	
        if ( $cdplayer eq "cdcd" ){		   
	   my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'ff', '00:15' ); # advance 15 seconds  
           exec_cmd_system2(@cmd);   
        }
	elsif ( $cdplayer eq "gnormalize::cdplay" ){ 
	   gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1, Advance => 15);    # advance 15 seconds
	}
	elsif ( $cdplayer eq "Audio::CD" ){ 
	   $audiocd->advance(0, 15);  # advance 15 seconds
	}
	$count = $count+15;
	#show_time();
	$pause = $false;	
	return $true;
     }
     # next button display
     $xdest_but = $xdest_buttons + 5*$buttons_w/2 + 3*$delta;    
     if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
        draw_buttons(Press_Next => $true, Draw_Next => $true);
	$button_press_next = $true;    
        #print "vc clicou em next: x = $x, y = $y ;; height = $height ;; width = $width ;; dcenterx = $dcenterx\n"; 
        if ( $playing_music eq $true ){ go_forward(); }
	else { $go_forward = $false; }	
	return $true;
     }
     # eject button display
     $xdest_but = $xdest_buttons + 7*$buttons_w/2 + 4*$delta;    
     if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
        draw_buttons(Press_Eject => $true, Draw_Eject => $true);
	$button_press_eject = $true;    
        stop_playing_music();
	if ( $cdplayer eq "gnormalize::cdplay" ){ 
	   gnormalize::cdplay::eject_cdrom();
	}
        elsif ( $cdplayer eq "cdcd" ){	   
	   my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'eject' ); 
           exec_cmd_system2(@cmd);	   
	   # system("/usr/bin/eject /dev/hdc") || die " Error: $! \n";
	   # print " here, eject\n";	   
        }
	if ( $cdplayer eq "Audio::CD" ){ $audiocd->eject; }
	exec_cmd_system2( 'eject', $audiodevice_path );
	entry_cda_change();
	if ( not $window->is_active ) { show_only_cd_display(); } 
	return $true;
     }     
     # rewind button display
     $xdest_but = $xdest_buttons - 3*$buttons_w/2 - 1*$delta;    
     if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
        draw_buttons(Press_Rewind => $true, Draw_Rewind => $true);
	$button_press_rewind = $true;    
	if ( $playing_music eq $false ){ return;}
	
	if ($count >= 15){ $count = $count-15;}
	else { $count = 0; 
	       $go_back = $true;
	}
	
	if ($files_info[$selected_row]{extension_input} ne 'cda'){ 
	   play_selection( skip => $count ); 
	   $pause = $false;	
	   return $true;    
        }
	
        if ( $cdplayer eq "cdcd" ){	   
	   my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'rew', '00:15' ); # go back 15 seconds
           exec_cmd_system2(@cmd);	   
        }
	elsif ( $cdplayer eq "gnormalize::cdplay" ){ 
	   gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1, Advance => -15);  # go back 15 seconds
	}
	elsif ( $cdplayer eq "Audio::CD" ){ 
	   $audiocd->advance(0, -15);  # go back 15 seconds
	}		
	
	$pause = $false;	
	return $true;
     } 
     # back button display
     $xdest_but = $xdest_buttons - 5*$buttons_w/2 - 2*$delta;    
     if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
        draw_buttons(Press_Back => $true, Draw_Back => $true);	
	$button_press_back = $true;
	if ( $playing_music eq $true and @rows_already_played > 0 ) { go_back(); } 
        else { $go_back = $false; }
	return $true;
     }        
     # volume button display ; $pixbuf_sound
     if ( $x >= $xdest_sound and $x <= ($xdest_sound + $sound_size_w) and $y >= $ydest_sound and $y <= ($ydest_sound + $sound_size_h) ){            
	if ( $cdplayer eq "Audio::CD" or $cdplayer eq "cdcd" or $cdplayer eq "gnormalize::cdplay" ){ 
	   show_buttom_volume2();
	   $status_bar->push($context_id, "");
	}
	return $true;
     }                                  
     # rand layout ?    
     if ( $x >= $xdest_random and $x <= ($xdest_random + $random_w) and 
          $y >= $ydest_random and $y <= ($ydest_random + $random_h) ){
	$play_random ^= 1; 
	draw_random($da,undef);
	if($play_random){ draw_text_scrolling( layout => (draw_layout( text => "random on" ))[0], scrolling => $false ); }
	else{ draw_text_scrolling( layout => (draw_layout( text => "random off" ))[0], scrolling => $false ); }	
	
	if ( defined($timer_wait) ){ Glib::Source->remove($timer_scroll);}  # to not duplicate the MainLoop
        my $timer_wait = Glib::Timeout->add (700, \&show_scrolling_text);  
        return $true;
     }             
     # loop layout
     if ( $x >= $xdest_loop and $x <= ($xdest_loop + $loop_w) and 
          $y >= $ydest_loop and $y <= ($ydest_loop + $loop_h) ){   
	$loop_tracks ^= 1; 
	draw_loop($da,undef); 
	if($loop_tracks){ draw_text_scrolling( layout => (draw_layout( text => "loop on" ))[0], scrolling => $false ); }
	else{ draw_text_scrolling( layout => (draw_layout( text => "loop off" ))[0], scrolling => $false ); }	
	
	if ( defined($timer_wait) ){ Glib::Source->remove($timer_scroll); }  # to not duplicate the MainLoop
        my $timer_wait = Glib::Timeout->add (700, \&show_scrolling_text);
        return $true;
     }               
     # time min:sec display
     my $dist_dig = 1;      
     if ( $x >= $xdest_numbers and $x <= (5*($numbers_w + $dist_dig) + $xdest_numbers) and 
          $y >= $ydest_numbers and $y <= ($ydest_numbers + $numbers_h) ){
	$show_time_remaining ^= 1;
	if ( not $show_time_remaining){ $show_time_abs ^= 1; }
        show_time();
        return $true;
     }     
     # draw_text_scrolling  ; change background color
     if ( $x >= $xdest and $x <= ($xdest + $scroll_w) and $y >= $ydest and $y <= ($ydest + $scroll_h) ){		
	cdplayer_color_selection();
	sensitive_bg_color(); # cd_player bg color change   
        return $true;	
     }                                 
     # draw_lapsed_time ; progress bar of elapsed time;   
     if ( $x >= $xdest_posbar and $x <= ($xdest_posbar + $posbar_length) and 
          $y >= $ydest_posbar and $y <= ($ydest_posbar + $posbar_h) ){
        my $pct = number_value( sprintf ( "%.2f", ($x - $xdest_posbar + 1)/$posbar_length ) ); # 0.000 to 1.000
	if ($pct < 0){$pct = 0;}
	if ($pct > 1){$pct = 1;}
        #print "aqui ; x = $x ; y = $y ; pct = $pct\n";
	return if not $playing_music;			
     
        if ($files_info[$selected_row]{extension_input} ne 'cda'){ 	
	   my $total_sec = time_to_sec( $files_info[$selected_row]{length} );
	   $count = sprintf ('%.0f', $pct * $total_sec );
	   play_selection( skip => $count );
	   return $true;    
        }
	
	my $track = $selected_row + 1; 
        my $startframe = $start_sector[$track-1] + 150;  # for absolute frames, sum + 150 (gap)
	my $endframe   = $start_sector[$track] + 150;
	my $dif        = $endframe - $startframe;
        $startframe = int($startframe + $dif*$pct);
	$count      = int( $dif*$pct/75 ); # relative seconds
	my ($hour,$min,$sec) = sec_to_time( $count );	
	#print "startframe = $startframe ;  endframe = $endframe ; min:sec = $min:$sec\n";
		
	if ( $cdplayer eq "gnormalize::cdplay" ){ gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1, Position => $pct); }
	elsif ( $cdplayer eq "Audio::CD"       ){ $audiocd->play_frames($startframe, $endframe);                                  }
	elsif ( $cdplayer eq "cdcd" ){	 
	   # play [start track] [end track] [min:sec]  	   
	   my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'play', $track, $track, "$min:$sec" );
           exec_cmd_system2(@cmd);
        }		
		
        return $true;
     } 
        
  }
  # We've handled the event, stop processing
  return $true;
}

###--------------------------------------------------###
#####--------------- volume: begin ----------------#####

# see the $pixbuf_sound
my $window_volume;

sub show_buttom_volume2 {
   if ( not defined $window_volume ){ 
      show_buttom_volume();
   }
   else { 
      $window_volume->hide;      
      #$window_volume->destroy;
      $window_volume = undef;
   }
}

sub show_buttom_volume {
   $window_volume = Gtk2::Window->new('popup');
   $window_volume->set_decorated ($false);
   $window_volume->set_position ('mouse'); # none, center-always, center-on-parent , mouse   
      
   my ($position_x, $position_y) = $window_volume->get_position;
   #print "position_x = $position_x ;; position_y = $position_y\n";
   if ( $position_y > 130 ){ $window_volume->move ($position_x + 72, $position_y - 120 ); }
   else { $window_volume->move ($position_x + 72, $position_y + 130 ); }
   
   my $vbox_window_volume = Gtk2::VBox->new;
   my $frame_window_volume = Gtk2::Frame->new;
   my $vbox2_window_volume = Gtk2::VBox->new;
   my $label_window_volume = Gtk2::Label->new;
   my $hsep_window_volume = Gtk2::HSeparator->new;
   my $label2_window_volume = Gtk2::Label->new(" volume ");
	   
   # see <man Gtk2::Scale> and Gtk2::Range ;; Adjust the volume level
   # Gtk2::VScale->new_with_range ($min, $max, $step) 
   $button_volume = Gtk2::VScale->new_with_range (  0, 100, 1);
   $button_volume->set_digits(0);
   $button_volume->set_draw_value($false);
   $button_volume->set_inverted ($true);
   #$button_volume->set_value_pos ('left'); # left, right, top, bottom
   $button_volume->set_size_request( 40, 130 );
   $button_volume->signal_connect ('value-changed', \&change_label_volume, $label_window_volume );
   $button_volume->signal_connect ('value-changed', \&change_volume_level );
   $button_volume->signal_connect ( 'button_release_event' => \&show_buttom_volume2 );
   $button_volume->set_sensitive($true);
   # $button_volume->show;

   #$button_volume->set_value ( get_volume_level($audio_cd_volume) );
   # Get $audio_cd_volume value from config file $setting_file
   if ( $audio_cd_volume > 100 or $audio_cd_volume < 0 ){ $audio_cd_volume = 80; }
   $button_volume->set_value ( $audio_cd_volume );

   $window_volume->add($vbox_window_volume);
   $vbox_window_volume->add ($frame_window_volume);
   $frame_window_volume->add ($vbox2_window_volume);
   
   $vbox2_window_volume->add ($button_volume);
   $vbox2_window_volume->add ($hsep_window_volume);
   $vbox2_window_volume->add ($label_window_volume);
   $vbox2_window_volume->add ($label2_window_volume);
   
   #my ($width, $height) = $window_volume->get_size;
   #print "width = $width ;; height = $height \n";  
   
   $window_volume->show_all;
}

sub change_label_volume {
   my $widget = shift;  # $button_volume = Gtk2::VScale 
   my $label  = shift;  # Gtk2::Label
   
   my $volume = int( $button_volume->get_value );  # 0 - 100   
   $label->set_label( $volume."%" );               # 0 - 100%;
}

# Set volume level to play audio cd.
sub change_volume_level {
   my $widget  = shift;  # $button_volume = Gtk2::VScale   
   my $get_vol = defined $button_volume ? int($button_volume->get_value) : 80;
   
   my $volume = shift || $get_vol; # Valid volumes: 0 - 100
   if ( $volume > 100 or $volume < 0 ){ $volume = 80; }   
   $audio_cd_volume = $volume;                        # 0 - 100   
   $volume = sprintf ( "%.0f", $volume * (255/100) ); # 0 - 255
   
   return unless defined $files_info[$selected_row]{extension_input};
   
   if ($files_info[$selected_row]{extension_input} ne 'cda' and $amixer_path ne ""){ 
       # amixer set PCM 90% / amixer set Master 60% ; Mixer_device	
       my $cmd = "$amixer_path set Master $audio_cd_volume%";
       exec_cmd_system($cmd);
       $cmd = "$amixer_path set PCM $audio_cd_volume%";
       exec_cmd_system($cmd);
       #$cmd = "$amixer_path set Front $audio_cd_volume%";
       #exec_cmd_system($cmd);
       return $audio_cd_volume;  
   }

   # Valid volumes: 0 - 255 ;; volume: front or back
   if ( $cdplayer eq "Audio::CD" ){ 
       my $vol = $audiocd->get_volume; # Returns an Audio::CD::Volume object.
   
       # Change the volume channels
       $vol->front->left ( $volume );
       $vol->front->right( $volume );
       $vol->back->left  ( $volume );
       $vol->back->right ( $volume );
       # Save this changes
       $audiocd->set_volume ( $vol );
   }
   elsif ( $cdplayer eq "gnormalize::cdplay" ){
       gnormalize::cdplay::set_vol($volume);
   }
   elsif ( $cdplayer eq "cdcd" ){
       my $cmd = "$cdcd_path -d $audiodevice_path setvol $volume";
       exec_cmd_system($cmd);	   
   }
   return $audio_cd_volume;
}

sub get_volume_level { # not used, get the volume level from config file $setting_file
   my $volume;
   # Valid volumes: 0 - 255 ;; volume: front or back 
   if ( $cdplayer eq "Audio::CD" ){ 
      my $vol = $audiocd->get_volume; # Returns an Audio::CD::Volume object.   
      $volume = int ( ($vol->front->left + $vol->front->right)/2  );	
   }
   elsif ( $cdplayer eq "cdcd" ){
      my $cmd = "$cdcd_path -d $audiodevice_path getvol";
      my $output = exec_cmd_system($cmd);
      #         Left  Right
      #Front      54     54
      #Back        0      0
      while( $output =~ /Front\s+(\d+)\s+(\d+).*/g ){
         $volume = int ( ($1 + $2)/2  );	
      }	   
   } 
   $volume = sprintf ( "%.0f", $volume * (100/255) ); # 0 - 100
   return $volume;
}

#####--------------- volume: final ----------------#####
###--------------------------------------------------###

# to fill the empty space
my $label_fill = new Gtk2::Label( " " );
$label_fill->set_alignment( 0.5, 0.5 );   
$hbox4->pack_start($label_fill, $true, $true, 0);
$label_fill->show();

# Create Dir_Selection button
my $button_play_more = Gtk2::Button->new;
$button_play_more->add( DrawIcons('gtk-add','button') );
#$button_play_more->set_label("Dir / File");
$tooltips->set_tip( $button_play_more, $langs{tip405} ) if $show_all_tooltips;
$button_play_more->signal_connect( "clicked", \&dir_selection );
$button_play_more->set( 'focus-on-click' => $false, 'relief' => 'none' );
$hbox4->pack_start ($button_play_more, $false, $false, 0);
$button_play_more->show;


#####------------- Mode :: CD display -------------#####
###--------------------------------------------------###

sub show_only_cd_display {		
       
   if ($window->is_active) {    # Hide the main $window 

      $hbox4->remove($da);
      $hbox4->remove($label_fill);
      $hbox4->remove($button_play_more);
      $window->hide;
      
      $window_cd_player = Gtk2::Window->new('toplevel'); # 'toplevel' or 'popup'
      $window_cd_player->set_title( "" ); # no title
      $window_cd_player->set_position ('mouse'); # none, center-always, center-on-parent , mouse
      $window_cd_player->signal_connect( "delete_event", \&Quit );
      $window_cd_player->set( 'allow-shrink' => $false,
                              'resizable'    => (not $show_cdplayer_skin), 
                              'allow-grow'   => (not $show_cdplayer_skin) );
      $window_cd_player->resize($window_cd_player_width, $window_cd_player_height);
      $window_cd_player->set_title( "gnormalize" ) if ($window_cd_player_width > 100);       
      $show_cdplayer_keep_above ? $window_cd_player->set_keep_above($true) : $window_cd_player->set_keep_above($false);	         	 

      $window_cd_player->add($da);
      $window_cd_player->set_decorated ($show_cdplayer_border); # boolean = $window->get_decorated      
      $window_cd_player->realize;
      $window_cd_player->show_all;      
   }
   else {                       # Show the main $window
      # 'if not defined $pixmap_mask' is the same as 'without use skin'
      ($window_cd_player_width, $window_cd_player_height) = $window_cd_player->get_size if not defined $pixmap_mask;
      $window_cd_player->remove($da);
      $window_cd_player->destroy;
      $window_cd_player = undef;
      	
      $hbox4->pack_start($da, $false, $false, 0);
      $hbox4->pack_start($label_fill, $true, $true, 0);
      $hbox4->pack_start ($button_play_more, $false, $false, 0);
      $window->set_position ('mouse');
      $window->show;   
   }   
}

sub motion_notify_event_cdplayer {   # See /usr/share/doc/perl-Gtk2-1.080/examples/scribble.pl
  my ($widget, $event, @data) = @_;  # $widget = $da = Gtk2::DrawingArea ; GdkEventMotion *event
                                     # Gtk2::Gdk::Event::Motion
  
  my $height = $widget->allocation->height;
  my $width  = $widget->allocation->width;  				     
  
  #return if $window_cd_player is decorated;  $window->get_decorated  ; 				     
  my ($x, $y, $state);  

  if ($event->is_hint) { 
     (undef, $x, $y, $state) = $event->window->get_pointer; 
  } 
  else {
     $x = $event->x;
     $y = $event->y;
     $state = $event->state;
  }
  my ( $x_root , $y_root ) = ( $event->x_root , $event->y_root );
  my ($xoffset, $yoffset) = $event -> window() -> get_root_origin();
  #print "x = $x ; y = $y ; x_root = $x_root ; y_root = $y_root ; xoffset = $xoffset ; yoffset = $yoffset\n";

  if ( $state >= "button1-mask" and defined $window_cd_player ) {  
     if ( not $window_cd_player->get_decorated ) {
        # get (click_x, click_y) with button_press_event
        $window_cd_player->move( $x_root - $click_x , $y_root - $click_y); # move the $window_cd_player
     }   
  }
  
  if ( $y < $height/3  ){ return $true; } 
        
  my $xdest_but = $xdest_buttons - 1*$buttons_w/2 + 0*$delta;    
  # stop button display
  if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
     draw_buttons(Shadow_Stop => $true, Draw_Stop => $true); 
  }
  else { draw_buttons(Draw_Stop => $true); }  # default color
  # (play || pause) buttons display
  $xdest_but = $xdest_buttons + 1*$buttons_w/2 + 1*$delta;    
  if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
     draw_buttons(Shadow_Play => $true, Draw_Play => $true); 
  }
  else { draw_buttons(Draw_Play => $true); }  
  # fastforward button display
  $xdest_but = $xdest_buttons + 3*$buttons_w/2 + 2*$delta;    
  if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
     draw_buttons(Shadow_Forward => $true, Draw_Forward => $true);
  }
  else { draw_buttons(Draw_Forward => $true); }
  # next button display
  $xdest_but = $xdest_buttons + 5*$buttons_w/2 + 3*$delta;    
  if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
     draw_buttons(Shadow_Next => $true, Draw_Next => $true);
  }
  else { draw_buttons(Draw_Next => $true); }  
  # eject button display
  $xdest_but = $xdest_buttons + 7*$buttons_w/2 + 4*$delta;    
  if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 
     draw_buttons(Shadow_Eject => $true, Draw_Eject => $true);	
  }
  else { draw_buttons(Draw_Eject => $true); }   
  # rewind button display
  $xdest_but = $xdest_buttons - 3*$buttons_w/2 - 1*$delta;    
  if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
     draw_buttons(Shadow_Rewind => $true, Draw_Rewind => $true);
  }
  else { draw_buttons(Draw_Rewind => $true); } 
  # back button display
  $xdest_but = $xdest_buttons - 5*$buttons_w/2 - 2*$delta;    
  if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){
     draw_buttons(Shadow_Back => $true, Draw_Back => $true);	
  }
  else { draw_buttons(Draw_Back => $true); }
   
  #print "x = $x ; y = $y ; x_root = $x_root ; y_root = $y_root ; xoffset = $xoffset\n";   
  return $true; 
}


#------------------------- final -----------------------#
###---------------------- Display --------------------###

###---------------------- Frame6 ---------------------###
#--------------------------About------------------------#
# Construct a textview to put About
my $textview_about = Gtk2::TextView->new;
$textview_about->set (    'editable' => $false, 
                    'cursor_visible' => $false, 
		       'left_margin' => 10, 'right_margin' => 10,
                         'wrap-mode' => 'word');
my $color_about = Gtk2::Gdk::Color->parse ("#E6EDBD");  
$textview_about->modify_base ('normal', $color_about);
$textview_about->show;

$frame6->add($textview_about);
# my $container = $frame6->get_children;  # see <man Gtk2::Container>
$textview_about->set_border_width (4);
my $color_textview_about = Gtk2::Gdk::Color->parse ("#A0B8A3");
$textview_about->modify_bg ('normal', $color_textview_about);

# see <man Gtk2::TextBuffer>
# $buffer = Gtk2::TextBuffer->new;
my $buffer_about = $textview_about->get_buffer;
$buffer_about->create_tag ("italic_about",   'foreground' => "red",   # see <man Gtk2::TextTag> for more options
                                            #'background' => "yellow",
                                            justification => 'center', 
                                                     font => "Helvetica Italic",
				            'size-points' => "15");
$buffer_about->create_tag ("version",        'foreground' => "blue",   
                                            justification => 'center',
					             font => "Helvetica",
					    'size-points' => "12");
$buffer_about->create_tag ("descr",          'foreground' => "black",  
                                            justification => 'center',
					             font => "Sans",
					    'size-points' => "10");

my $count_textview = 1; my $count_same_gif = 1; my $next_string = 1;
my $timer_about;

sub tux_animation_textview {
   $textview_about->get_buffer->delete($textview_about->get_buffer->get_bounds); #clear
   my $iter_about = $buffer_about->get_iter_at_offset (0); # get start of buffer 
   $buffer_about->insert_with_tags_by_name ($iter_about, "gnormalize", "italic_about");
   $buffer_about->insert_with_tags_by_name ($iter_about, " - ", "descr");
   $buffer_about->insert_with_tags_by_name ($iter_about, "version $VERSION\n", "version");	        

   # ---------------------- animation --start-------------------# 
   # See /usr/share/doc/perl-Gtk2-1.080/gtk-demo/textview.pl
   my $animation = choose_random_animation(); # animation path filename
   my $widget_animation;
   eval { $widget_animation = Gtk2::Image->new_from_file ($animation); };
   if ($widget_animation and -e filename_from_unicode $animation and $check_button_animation->get_active) {
      
      $buffer_about->insert_with_tags_by_name ($iter_about, " ", "descr"); # to center line
      my $anchor = $buffer_about->create_child_anchor ($iter_about);
      $textview_about->add_child_at_anchor ($widget_animation, $anchor);
      $widget_animation->show;
      
      # textmark = $buffer->create_mark ($mark_name, $where, $left_gravity)
      $buffer_about->create_mark ('mark', $iter_about, $true);          
   
      # see <man Glib::MainLoop>  
      # integer = Glib::Timeout->add ($interval, $callback, $data=undef, $priority=G_PRIORITY_DEFAULT)
      if ( defined($timer_about) ){ Glib::Source->remove($timer_about);}  # to not duplicate the MainLoop      
      if ( $animation =~ /typing/i ){ $timer_about = Glib::Timeout->add (250, \&show_typing_char); }
      else { $timer_about = Glib::Timeout->add (20000, \&choose_textview_about); } # 15000 milliseconds = 15 seconds
   }
   # ---------------------- animation --final-------------------#
   else {
      if ( defined($timer_about) ){ Glib::Source->remove($timer_about);}  # remove the MainLoop
      $count_textview = 1; $count_same_gif = 1;
      $buffer_about->insert_with_tags_by_name ($iter_about, "\n$langs{msg040}", "descr");
      $buffer_about->insert_with_tags_by_name ($iter_about, "\n\n$langs{msg064}", "descr");
      $buffer_about->insert_with_tags_by_name ($iter_about, "\n\n$langs{msg093}", "descr");
      $buffer_about->insert_with_tags_by_name ($iter_about, "\n\n$langs{msg094}", "descr");
   }
}
 
sub choose_textview_about { 
   my $textmark = $buffer_about->get_mark ('mark');
   my $iter_mark = $buffer_about->get_iter_at_mark ($textmark);   
   #$iter_mark = $buffer_about->get_iter_at_line ( 3 );
   
   my $iter_end = $buffer_about->get_end_iter;
   $textview_about->get_buffer->delete($iter_mark , $iter_end ); #clear
   
   if ($count_textview == 1){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg084}", "descr"); }
   if ($count_textview == 2){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg085}", "descr"); }
   if ($count_textview == 3){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{tip429}", "descr"); } 
   if ($count_textview == 4){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg064}", "descr"); }   
   if ($count_textview == 5){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg093}", "descr"); }           
   if ($count_textview == 6){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg094}", "descr"); $count_textview = 0; $count_same_gif += 1;}
   if ($count_same_gif > 2 + int(rand(8)) and $count_textview == 1 ){ 
      $count_textview = 1; # start value
      $count_same_gif = 1;
      tux_animation_textview();
      return $false;
   }
   $count_textview += 1;
   return $true; # # if return is $false; then stop $timer_about loop
}

sub show_typing_char {
   my $string;
   if ($next_string == 1){$string = "\n$langs{msg084}";}
   if ($next_string == 2){$string = "\n$langs{msg085}";}
   if ($next_string == 3){$string = "\n$langs{tip429}";}
   if ($next_string == 4){$string = "\n$langs{msg064}";}
   if ($next_string == 5){$string = "\n$langs{msg093}";}   
   if ($next_string == 6){$string = "\n$langs{msg094}";}
   if ($next_string >= 7){
      $count_textview = 1; # start value
      $next_string = 1;
      tux_animation_textview();
      return $false;
   }   
   my $iter_mark = $buffer_about->get_iter_at_mark ( $buffer_about->get_mark ('mark') );      
   my $iter_end = $buffer_about->get_end_iter;
   $textview_about->get_buffer->delete($iter_mark , $iter_end ); #clear
   #                substr EXPR,OFFSET,LENGTH
   my $new_string = substr($string,  0, $count_textview);
   $buffer_about->insert_with_tags_by_name ($iter_mark, $new_string , "descr");
   
   if ( length($new_string) >= length($string) ) { $count_textview = 0; $next_string += 1; }
   $count_textview += 1;
   return $true; # # if return is $false; then stop $timer_about loop
}

sub choose_random_animation {
   my @array_animation = (  '/usr/share/gnormalize/animations/super_tux.gif', 
                            '/usr/share/gnormalize/animations/dancing_penguin.gif',
			    '/usr/share/gnormalize/animations/tux_lunapaint.gif',
			    '/usr/share/gnormalize/animations/penguin_computer.gif',
			    '/usr/share/gnormalize/animations/penguin_and_camel.gif',
			    '/usr/share/gnormalize/animations/penguin_typing.gif',
			    '/usr/share/gnormalize/animations/penguin_cold.gif',
			    '/usr/share/gnormalize/animations/penguin_ice.gif'
			 );
   my $count_gif = $#array_animation + 1; # Get the number of elements.	
   my $rand = int( rand( $count_gif ) );  # pick one random element: 0  <=  rand($count_gif)  <  $count_gif
   #print " rand[1---N] = $rand ; animation = $array_animation[$rand] ; count_gif = $count_gif\n";
   return $array_animation[$rand];
}
   
tux_animation_textview();

######--------------------------------------------######

#####------------- h b o x _normalize--------------#####
###--------------------- start ----------------------###

# New Button : Show Info
my $button_show_info = Gtk2::Button->new;
$button_show_info->add( DrawIcons('gtk-goto-bottom','button') );
#$button_show_info->set( 'focus-on-click' => $false, 'relief' => 'none' );
$button_show_info->signal_connect( clicked => \&button_with_4_phases, '1');
#$button_show_info->set( 'focus-on-click' => $false, 'relief' => 'none' );
$button_show_info->show;

# New Button : Hide Info
my $button_hide_info = Gtk2::Button->new;
$button_hide_info->add( DrawIcons('gtk-goto-top','button') );
$button_hide_info->signal_connect( clicked => \&button_with_4_phases, '1');
$button_hide_info->show;

# this align is a container that hold two buttons alternately
my $align_hold_2_buttons = Gtk2::Alignment->new(0.5, 0.5 , 0, 0);
$align_hold_2_buttons->add ($button_show_info);
$hbox_normalize->pack_start( $align_hold_2_buttons, $false, $false, 0 );
$align_hold_2_buttons->show;

#---------------------------------------#

my $normalize_button = Gtk2::ToggleButton->new("normalize");
$normalize_button->signal_connect( "toggled", \&toggle_button_normalize );
#my $color_green = Gtk2::Gdk::Color->parse ("#B1C3B2");
#$normalize_button->modify_bg ('normal', $color_green);
# a tabela ir� expandir de acordo com o tamando do hbox
$hbox_normalize->pack_start( $normalize_button, $true, $true, 0 );
$normalize_button->show();

# to be implemented: Thread. See <man Thread::Queue>, 
# <man threads::shared> and tutorial <man perlthrtut>

my $rip_sucess = $false; # get $true if rip is completed

##--------------------------------------------------------------##
#      this is the brain that control all normalize processes    #
##--------------------------------------------------------------##

sub toggle_button_normalize { 
    # To avoid exec the sub two times when the normalize button is pressed
    if ( not $normalize_button->get_active ){ return $false; }
        
    if ( $extension_input eq 'other' ){
        $normalize_button->set_active($false);
	$status_bar->push($context_id, $langs{msg003} );
	return $false;
    }
    elsif ( $extension_input eq 'error' ){
        $normalize_button->set_active($false);
	$status_bar->push($context_id, $langs{msg004} );
	return $false;
    }  
    
    # Test if the $directory is writable. -w : file is writable by effective uid/gid.
    if ( ! -w filename_from_unicode $directory_output ){ $status_bar->push($context_id, " $directory_output ".$langs{msg012} ); return $false;}
    
    # Not change the output extension frames while any encoding process
    $hbox1->set_sensitive($false);
    
    my @array; # fill with only the files that is toggled on treeview_play.
    if ($normalize_button->get_active){ 
       
       my %treeview_play_info = get_treeview_play_informations();
       @array = @{$treeview_play_info{array_checked}};  # get reference to array_checked that has files toggled.
                   
       if ( @array >= 1 ) { search_track_and_rip_dec(@array);  }
       else { $status_bar->push($context_id, $langs{msg013} ); }
    }
     
    # Show the final messages
    if ($extension_input eq 'cda' and @array >= 1){  
       if ($rip_sucess eq $true and $normalize_button->get_active){ $status_bar->push($context_id, $langs{msg014} ); }
       else { $status_bar->push($context_id, $langs{msg015} );}
    }
    if ($extension_input ne 'cda' and @array >= 1){
       if ($norm_type eq "None"){  $status_bar->push($context_id, $langs{msg016} );}
       elsif ($extension_input ne $extension_output){ $status_bar->push($context_id, $langs{msg017} );}
       else { $status_bar->push($context_id, $langs{msg018} );}
    }
    # Return the output extension frames to original state after processes
    $hbox1->set_sensitive($true);
    
    # After stop the process, label is changed.
    if ($extension_input eq 'cda'){ $normalize_button->set_label("rip + normalize + encode"); } 
    else { $normalize_button->set_label("normalize"); }
    change_font_for_all_child($window_font_name,$normalize_button);
    
    # before exit, set the normalize_button to false:
    $normalize_button->set_active($false); 
      
} # final of ''toggle_button_normalize''

sub search_track_and_rip_dec {
   my @files_that_is_toggled = @_;   
    	      
   for (my $file = 0; $file <= $#files_that_is_toggled ; $file++){
   
      my $row = $files_that_is_toggled[$file];
      next unless $files_info[$row]{rip};
      if ( $files_info[$row]{extension_input} eq 'cda' ) { $da->set_sensitive($false); stop_playing_music( change_color => $false ); }
      
      # for the case when the file is deleted or changed after pressed the normalize_button
      if ( not -e filename_from_unicode $files_info[$row]{filepath} and $files_info[$row]{extension_input} ne 'cda' ){
         print "\nsearch_track_and_rip_dec --> Can't find $files_info[$row]{filepath} file to normalize: $!\n";
         $status_bar->push($context_id, " Can't find $files_info[$row]{filepath} file to normalize!");
         next;
      }
      if ( $files_info[$row]{rip} and $normalize_button->get_active ){  # if the music/track is toggled, then normalize it
      	  
         $normalize_button->set_label( $files_info[$row]{extension_input} eq 'cda' ? $langs{msg019} : "stop decoding" );  # stop ripping/decoding
	 change_font_for_all_child($window_font_name,$normalize_button);
	     
	 my %hash = determine_directory_and_filename_and_extension(row => $row);
	 my $file_wav = $hash{file_wav};
	 #print "\nsearch_track_and_rip_dec ---> file_wav = \"$file_wav\" ;; \$row = $row\n";
	 # used by make_directory_final();
	 
	 $files_info[$row]{technical_info} ? set_tag_info($row) : get_info_from_file(%hash);   # get all mp3/mp4/mpc/... info if necessary
         set_output_and_refresh_progress_bar(%hash);
         refresh_input_output_arrows();
	     
	 insert_msg( "$langs{msg078}: " , "purple");	# "Selected file"
         insert_msg( "$hash{filename}\n" , "bg_yellow");
	     
	 color_the_selected_tracks_and_scroll( select_color => 'playing', scroll => $true, row => $row );

	 # ripping/decoding start here  ;;  $rip_sucess get $true if the rip is completed
	 insert_msg(" --- ripping ---\n" , "small-green") if ($files_info[$row]{extension_input} eq 'cda');
	 insert_msg(" --- decoding ---\n", "small-green") if ($files_info[$row]{extension_input} ne 'cda' and $files_info[$row]{extension_input} ne 'wav');
	     
	 my $track = sprintf("%02d", $row + 1 ); # 02d : leading zero
	 if    ($files_info[$row]{extension_input} eq 'cda' and $ripper eq "cdparanoia"){ $rip_sucess = rip_audio_cdparanoia($track,$file_wav);}
	 elsif ($files_info[$row]{extension_input} eq 'cda' and $ripper eq "cdda2wav"  ){ $rip_sucess = rip_audio_cdda2wav($track,$file_wav);  }
	     
	 if ( $normalize_button->get_active ){
	    # decode, normalize and encode the files
            dec_norm_enc(%hash);   # %hash have many information about the file.       		    		    
	 } 
	 color_the_selected_tracks_and_scroll( select_color => 'played', scroll => $false, row => $row);
	     
	 last unless $normalize_button->get_active;
      }  
   } # final of ''for (my $file = 0; $file <= $#files_that_is_toggled ; $file++){''
   
   if ( defined $cdcd_path or $use_audiocd eq $true or $os =~ /Linux/i ){ $da->set_sensitive($true); }
}

## decode, normalize and encode - for mp3/ogg/wav files
sub dec_norm_enc {
   my %args = ( @_,  # argument pair list goes here
	      );    

   my $file_mp3 = $args{file_mp3}; my $file_mp4 = $args{file_mp4};  my $file_mpc   = $args{file_mpc}; 
   my $file_ogg = $args{file_ogg}; my $file_ape = $args{file_ape};  my $file_flac  = $args{file_flac}; 
   my $file_cda = $args{file_cda}; my $file_wav = $args{file_wav};  
   my $filename = $args{filename}; my $dir      = $args{directory}; my $extension_input = $args{extension_input};
   my $filepath = $args{filepath};
   
   #print "\ndec_norm_enc --> (\$directory,\$file_wav) = (\"$dir\",\"$file_wav\") ;; \$extension_input = $extension_input ;; row = $args{row}\n\n";

   my $insensibility = $spinner_sensi->get_value;
   $priority = $spinner_pri->get_value; #priority              
       
   # decode, normalize and encode the files
   # decode:                     
   if    ( $extension_input eq 'mp3'  and $lame_path ne ""   ){ decode_mp3_to_wav(%args); }
   elsif ( $extension_input eq 'mp4'  and $faad_path ne ""   ){ decode_mp4_to_wav(%args); }
   elsif ( $extension_input eq 'mpc'  and $mpcdec_path ne "" ){ decode_mpc_to_wav(%args); }
   elsif ( $extension_input eq 'ogg'  and $oggdec_path ne "" ){ decode_ogg_to_wav(%args); }  
   elsif ( $extension_input eq 'ape'  and $ape_path ne ""    ){ decode_ape_to_wav(%args); }    
   elsif ( $extension_input eq 'flac' and $flac_path ne ""   ){ decode_flac_to_wav(%args);}
   elsif ( $extension_input eq 'wav'  and $directory_output ne $dir ){                           
      my @cmd = ( 'cp', '-f', $dir.'/'.$filename, $directory_output );
      insert_msg("." , "small-ini");
      insert_msg("@cmd" , "small"); #print on debug textview
      insert_msg("\n" , "small");
      exec_cmd_system2(@cmd);
   }
       
   # normalize:
   if ( $normalize_button->get_active ) { 
      $normalize_button->set_label("stop normalizing");	    
      change_font_for_all_child($window_font_name,$normalize_button);
      insert_msg(" --- normalizing ---\n" , "small-green");
      $pbar->set_fraction(1) if ($extension_input ne 'wav');
      normalize_wav(%args);
   }
   # [[$treeview_play->get_selection]] is an Gtk2::TreeSelection  
   # $treeview_play->get_selection->unselect_all;                  
	           
   # encode:
   # if $check_change_properties not active and file is already normalized and has the same extension_input then make copy, otherwise the file will be encoded.
   if ( $normalize_button->get_active ) {       
             
      if ( $extension_input eq $extension_output and ( $already_normalized or abs($adjust) <= $insensibility ) and not $check_change_properties->get_active ){
           # Then make a copy, don't need to encode. Note that 'cda' never satisfy this conditons
	   same_extension_overwrite(%args);
      }
      else { # $file_cda always satisfy this conditon
           $normalize_button->set_label("stop encoding");
	   change_font_for_all_child($window_font_name,$normalize_button);
	   insert_msg(" --- encoding ---\n" , "small-green");
	   
           if    ( $button_output_mp3->get_active ) { $args{file_output} = $args{file_mp3};  encode_wav_to_mp3(%args); }
          #if    ( $button_output_mp3->get_active ) { $args{file_output} = $args{file_mp3};  encode_wav_to_wma(%args); }
	  
	   elsif ( $button_output_mp4->get_active ) { $args{file_output} = $args{file_mp4};  encode_wav_to_mp4(%args); }
	   elsif ( $button_output_mpc->get_active ) { $args{file_output} = $args{file_mpc};  encode_wav_to_mpc(%args); }
	   elsif ( $button_output_ogg->get_active ) { $args{file_output} = $args{file_ogg};  encode_wav_to_ogg(%args); }
	   elsif ( $button_output_ape->get_active ) { $args{file_output} = $args{file_ape};  encode_wav_to_ape(%args); }
	   elsif ( $button_output_flac->get_active) { $args{file_output} = $args{file_flac}; encode_wav_to_flac(%args);}
	   elsif ( $button_output_wav->get_active ) { $args{file_output} = $args{file_wav};  encode_wav_to_wav(%args); }  # actually, don't need to encode
	   
	   finalize_process(%args);
      } 
   }
}


## stop a process by the pid number
# getppid Returns the process id of the parent process.
sub StopProcessing {  # I see dvd2dvix3pass code with some changes 
   my ($pid,$mesg,$file_wav) = @_;
   ## get lame (or normalize, ...) pid
   ## try to kill pid+1, else pid
   #print ("\n $mesg which pid = $pid\n");
   if( $pid >= 0 )  # if some $pid >=0 then some process is running
   {
	   ## kill the lame/normalize/... PID
	   ++$pid;
	   my $processeskilled = kill 9, $pid;
	   if( $processeskilled == 0 )
	   {
	      --$pid;
	      print "STOP:: pid ".($pid+1)." failed, trying kill pid $pid \n";
	      $processeskilled = kill 9, $pid;
	      if( $processeskilled == 0 )
	      {   print "Could not $mesg : pid = $pid\n";}
           }
   }
   #remove wav file if button_del_wav is active and $file_wav exist
   if ($check_button_del_wav->get_active and -e filename_from_unicode "$directory_output/$file_wav" ){ 	    
      my @cmd = ( 'rm', '-f', $directory_output.'/'.$file_wav );	      
      exec_cmd_system2(@cmd);
	    
   }		
   # In the case of stop normalize process, a file like _normAAAAAA is created,
   # them it will be removed, if it exist.	my $file_norm =~ /^\_norm(\w){6}$/i;
   if ( -e filename_from_unicode "$directory_output/_normAAAAAA" ){	    
      my @cmd = ( 'rm', '-f', $directory_output.'/_normAAAAAA' );	      
      exec_cmd_system2(@cmd);	    
   }
   $status_bar->push($context_id, $mesg);
   insert_msg("$mesg", "small-red");
   insert_msg("\n" , "small");
   return -1; # set (pid = -1) assignnig to a stopped process
}

sub kill_prog { # using the command "ps" ; not used
   my $prog = shift;
   my $ps_path = find_prog( Progs => "ps", Comment => "NO_COMMENT");
   return if $ps_path eq "";		
   my $output = exec_cmd_system($ps_path);		
   while( $output =~ /(\d+)\s+pts.*$prog/g ){  # 1874 pts/3    00:00:00 bash    
      kill 9,$1;  # print "kill pid number $1 of $prog\n";  
   }   
}

###--------------------------------------------------###

# Create "Quit" button using the icon and text from 
# the specified stock item, see Gtk2::Stock
# print ( "Stoks: ",Gtk2::Stock->list_ids ,"\n");
$button_quit = Gtk2::Button->new;
$button_quit->add( DrawIcons('gtk-quit','button') );
$tooltips->set_tip( $button_quit, $langs{tip121} ) if $show_all_tooltips;
$button_quit->signal_connect( "clicked", \&Quit );
#$button_quit->set_size_request( 70, -1 );
$hbox_normalize->pack_start( $button_quit, $false, $true, 0 );
#$button_quit->modify_bg ('normal', $color_blue);
#$button_quit->set( 'focus-on-click' => $false, 'relief' => 'none' );
$button_quit->show();

#####----------------T a b l e _ down--------------#####
###--------------------------------------------------###

my $da_arrow_dec = Gtk2::DrawingArea->new;
# set a minimum size
$da_arrow_dec->set_size_request (78, 20); 
$table_down->attach ($da_arrow_dec, 0, 1, 0, 1, 'fill', 'shrink', 0, 0);
$da_arrow_dec->signal_connect (expose_event => \&draw_arrow_dec);		
$da_arrow_dec->show;
 
$change_fonte = $true;
my $size_input;

sub draw_arrow_dec { # decoder
   my ($widget, $event, @data) = @_;   # $widget = $da = Gtk2::DrawingArea
  				          	   				          
   # to expose this event  
   if ( $extension_input eq 'other' ){ draw_input_output($da_arrow_dec,undef,"mp3","wav"); } # default
   else { draw_input_output($da_arrow_dec,undef,("$extension_input","wav")); }
    
   return $true;
}

my $width_lay;  my $height_lay; # to determine the font size

sub draw_input_output {
   my ($widget, $event, @data) = @_;   # $widget = $da = Gtk2::DrawingArea
  				          
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width = $widget->allocation->width ;   
    
   my $gc = Gtk2::Gdk::GC->new ($widget->window); #  ($widget->window) = Gtk2::Gdk::Drawable
   my $color = Gtk2::Gdk::Color->new (184*256, 211*256, 193*256); # #B8D3C1 = 184 211 193 (RGB)
   $gc->set_rgb_fg_color ($color);
   my $gc1 = Gtk2::Gdk::GC->new ($widget->window); #  ($widget->window) = Gtk2::Gdk::Drawable
   my $color1 = Gtk2::Gdk::Color->new (100*256, 100*256, 200*256); #RGB = 85 90 190
   $gc1->set_rgb_fg_color ($color1);   
   my $purple = Gtk2::Gdk::Color->parse ('purple');
   my $blue = Gtk2::Gdk::Color->parse ('blue');
   my $color3 = Gtk2::Gdk::Color->parse ('#E6EDBD');	
   
   $widget->window->draw_rectangle ($gc, $true, 0, 0, $width, $height); 					        				      				   
   
   my $border = 5;  
   my $width_a = $height - 2*$border;
   # arrow
   $widget->window->draw_rectangle ($gc1, $true, $width/2 - 7, $height/2 - 2, 8, 4); 
   $widget->window->draw_polygon ($gc1, $true, 
                                  $width/2, $height - $border, 
				  $width/2, $border,
                                  $width/2 + $width_a, $height/2 );
   	   				         
   my $layout = $widget->create_pango_layout ("");
   my $context = $layout->get_context;
   my $fontdesc = $context->get_font_description;
   $fontdesc->set_family ("Sans");
   
   if ( $change_fonte eq $true ){ # find the nice size and change the font only one time 
      my $min_width = 20;
      $width_lay = $min_width;
      $size_input = 2;
      while ( $width_lay <= $min_width ){  # to determine the minimum size
         $fontdesc->set_size ( $size_input * PANGO_SCALE );
         $layout->set_text ("wav"); # only to get its width and height
         ($width_lay, $height_lay) = $layout->get_pixel_size;   	 
	 $size_input += 1 if ($width_lay <= $min_width) ;
      } 
      $change_fonte = $false;
   } 
   else{ $fontdesc->set_size ( $size_input * PANGO_SCALE ); } 
   
   #print " input = $data[0] ;; output = $data[1] ;; size = ",$size_input-1,"\n"; 
       
   $layout->set_text ($data[0]); # $data = "mp3"
   ($width_lay, $height_lay) = $layout->get_pixel_size; 
   $widget->window->draw_layout_with_colors ($gc1, 2, $height/2 - $height_lay/2, $layout, $blue, $color);
   
   $layout->set_text ($data[1]); # $data = "wav"
   ($width_lay, $height_lay) = $layout->get_pixel_size; 
   $widget->window->draw_layout_with_colors ($gc1, $width - $width_lay - 2, $height/2 - $height_lay/2, $layout, $blue, $color); 
       
   return $true;
}

########-------------Progress-Bar----------------#######

# Create the Gtk2::ProgressBar to decode
$pbar = Gtk2::ProgressBar->new;
#$table_down->attach_defaults ($pbar, 1, 4, 0, 1);
$table_down->attach($pbar,  1, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$pbar->set_size_request( 420, 24 ); # width, height 
#$pbar->set_text($file_mp3);
$pbar->set_orientation('left_to_right');
$pbar->show;


my $da_norm = Gtk2::DrawingArea->new;
# set a minimum size
$da_norm->set_size_request (76, 20); 
$table_down->attach ($da_norm, 0, 1, 1, 2, 'fill', 'shrink', 0, 0);
$da_norm->signal_connect (expose_event => \&draw_norm);		
$da_norm->show;

$change_fonte_norm = $true;
my $size_norm;
 
sub draw_norm {
   my ($widget, $event, @data) = @_;   # $widget = $da = Gtk2::DrawingArea
  				          
   my $height = $widget->allocation->height;  # height of $widget $da
   my $width = $widget->allocation->width ;   
    
   my $gc = Gtk2::Gdk::GC->new ($widget->window); #  ($widget->window) = Gtk2::Gdk::Drawable
   my $color = Gtk2::Gdk::Color->new (184*256, 211*256, 193*256); # #B8D3C1 = 184 211 193 (RGB)
   $gc->set_rgb_fg_color ($color);
   my $gc1 = Gtk2::Gdk::GC->new ($widget->window); #  ($widget->window) = Gtk2::Gdk::Drawable
   my $color1 = Gtk2::Gdk::Color->new (100*256, 100*256, 200*256); #RGB = 100 100 200
   $gc1->set_rgb_fg_color ($color1);   
   my $purple = Gtk2::Gdk::Color->parse ('purple');
   my $blue = Gtk2::Gdk::Color->parse ('blue');
   my $color3 = Gtk2::Gdk::Color->parse ('#E6EDBD');	
   	   				      
   $widget->window->draw_rectangle ($gc, $true, 0, 0, $width, $height); 					        				      				   
   
   my $border = 5;  
   my $width_a = 10;  
   # arrow
   $widget->window->draw_rectangle ($gc1, $true, $width/2 - 6, $height/2 - 2, 8, 4); 
   $widget->window->draw_polygon ($gc1, $true, 
                                  $width/2 - $width_a/2 +5, $height - $border, 
				  $width/2 - $width_a/2 +5, $border,
                                  $width/2 + $width_a/2 +5, $height/2 );  
   
   my $layout = $widget->create_pango_layout ("");
   my $context = $layout->get_context;
   my $fontdesc = $context->get_font_description;
   $fontdesc->set_family ("Sans");
   
   if ( $change_fonte_norm eq $true ){ # find the nice size and change the font only one time 
      my $min_width = 60;
      $width_lay = $min_width;
      $size_norm = 2;
      while ( $width_lay <= $min_width ){  # to determine the minimum size
         $fontdesc->set_size ( $size_norm * PANGO_SCALE );
         $layout->set_text ("normalize"); # only to get its width and height
         ($width_lay, $height_lay) = $layout->get_pixel_size; 
         $size_norm = $size_norm + 1;  
      } 
      $change_fonte_norm = $false;
   } 
   else{ $fontdesc->set_size ( ($size_norm - 1) * PANGO_SCALE ); } 
   
   $layout->set_text ("normalize"); 
   ($width_lay, $height_lay) = $layout->get_pixel_size; 
   $widget->window->draw_layout_with_colors ($gc1, $width/2 - $width_lay/2, $height/2 - $height_lay/2, $layout, $blue, $color); 
      
   return $true;
}


# Create the Gtk2::ProgressBar to normalize
$pbar_n = Gtk2::ProgressBar->new;
$pbar_n->set_size_request( 420, 24 ); # width, height 
#$table_down->attach_defaults ($pbar_n, 1, 4, 1, 2);
$table_down->attach($pbar_n,  1, 4, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$pbar_n->set_orientation('left_to_right');
$pbar_n->show;

my $da_arrow_enc = Gtk2::DrawingArea->new;
# set a minimum size
$da_arrow_enc->set_size_request (76, 20); 
$table_down->attach ($da_arrow_enc, 0, 1, 2, 3, 'fill', 'shrink', 0, 0);
$da_arrow_enc->signal_connect (expose_event => \&draw_arrow_enc);		
$da_arrow_enc->show;
 
sub draw_arrow_enc {
   my ($widget, $event, @data) = @_;   # $widget = $da = Gtk2::DrawingArea  				         
    
   # to expose this event   
   draw_input_output($da_arrow_enc,undef,("wav","$extension_output"));
    
   return $true;
}

# Create the Gtk2::ProgressBar to encode
$pbar_encode = Gtk2::ProgressBar->new;
$pbar_encode->set_size_request( 420, 24 ); # width, height 
#$table_down->attach_defaults ($pbar_encode, 1, 4, 2, 3);
$table_down->attach($pbar_encode,  1, 4, 2, 3, ['expand','fill'], 'shrink', 0, 0);
$pbar_encode->set_orientation('left_to_right');
$pbar_encode->show;


##-----------------------------------------------------##
## ----------------- hbox + TextView ----------------- ##
# output command : debug textview
$vbox_text = new Gtk2::VBox;
$frame_debug->add( $vbox_text );
$vbox_text->set_border_width(2);
$vbox_text->show;

# on hbox we put a button_clear_debug
$hbox_text = new Gtk2::HBox;
$vbox_text->pack_start( $hbox_text, $false, $false, 0 );
$hbox_text->show;

# Create a centering alignment object;
$align = Gtk2::Alignment->new(0.0, 0.5, 0, 0);
$hbox_text->add($align);
$align->show;

# debug clear button
$button_clear = Gtk2::Button->new;
$button_clear->add( DrawIcons('gtk-clear','button') );
$tooltips->set_tip( $button_clear, $langs{tip122} ) if $show_all_tooltips;
$button_clear->signal_connect( "clicked", \&textview_clear);
$button_clear->set( 'focus-on-click' => $false, 'relief' => 'none' );
$align->add($button_clear);
$button_clear->show;

sub textview_clear { 
       my $buffer = $textview->get_buffer;
       # delete buffer   -  $buffer->delete ($start, $end)
       # " (start, end) = $buffer->get_bounds  -  Retrieves the first and 
       # last iterators in the buffer, i.e. the entire buffer lies within 
       # the range (start,end). " 
       $textview->get_buffer->delete( $buffer->get_bounds );
       # $iter = $buffer->get_iter_at_offset (0); # get start of buffer  
}

##--------------------TextView-------------------------##

# Construct an command output text
$textview = new Gtk2::TextView;
$textview->set_wrap_mode('char'); # 'none', char, word
# or $textview->set_editable($false);
$textview->set (editable => $false, cursor_visible => $false);
$textview->show;

$scrolled = new Gtk2::ScrolledWindow( undef, undef );
$scrolled->set_policy( 'automatic', 'always' );  # 'never', 'automatic'
$scrolled->set_size_request( -1, 130 );
$scrolled->add($textview);
$scrolled->set_shadow_type('GTK_SHADOW_IN'); # 'in' , 'GTK_SHADOW_IN'

$vbox_text->add($scrolled);
$scrolled->show;

# see <man Gtk2::TextBuffer>
# $buffer = Gtk2::TextBuffer->new;
$buffer = $textview->get_buffer;
$buffer->create_tag ("italic",       'foreground' => "red", 
                                    #'background' => "yellow",
                                    justification => 'center', 
                                            style => 'italic');
$buffer->create_tag ("small",        'foreground' => "blue", 
                                    'size-points' => "10");				    
$buffer->create_tag ("small-green",  'foreground' => "green",
                                    justification => 'center',
                                    'size-points' => "10");
$buffer->create_tag ("small-black",  'foreground' => "black",
                                    justification => 'center',
                                    'size-points' => "10");
$buffer->create_tag ("black",        'foreground' => "black",
                                    justification => 'left',
                                    'size-points' => "10");
$buffer->create_tag ("purple",       'foreground' => "purple",
                                    justification => 'left',
                                    'size-points' => "10");				    				    
$buffer->create_tag ("red",          'foreground' => "red",
                                    justification => 'left',
                                    'size-points' => "11");				    			      
$buffer->create_tag ("small-red",    'foreground' => "red",
                                    justification => 'center', 
                                    'size-points' => "10");
$buffer->create_tag ("bg_yellow",    'foreground' => "blue",
                                     'background' => "yellow", 
                                    'size-points' => "11");				    
$buffer->create_tag ("small-ini",  'foreground' => "red",
                                    justification => 'left',
                                    'size-points' => "20");				    
				    			      			      
# "get start of buffer; each insertion will revalidate the
# iterator to point to just after the inserted text."
$iter = $buffer->get_iter_at_offset (0);
$buffer->insert_with_tags_by_name ($iter, "gnormalize", "italic");
$buffer->insert_with_tags_by_name ($iter, " $VERSION \n\n" , "small");
#$buffer->insert ($iter , " - author: $AUTHOR");

# see /usr/share/doc/perl-Gtk2-1.054/examples/thread_usage.pl
# see <man Gtk2::TextIter>, <man Gtk2::Gdk::Threads>

sub insert_msg {    # scrolls down the text in the textboxes
        my $msg = shift;
	my $tag_name = shift;
	# (start, end) = $buffer->get_bounds
	$buffer = $textview->get_buffer;
	$iter = $buffer->get_end_iter;  # or $iter = $buffer->get_bounds;
	# $iter = $textview->get_buffer->get_end_iter;
	if ($tag_name) {
                $buffer->insert_with_tags_by_name($iter, $msg, $tag_name);}
        else {  $buffer->insert($iter, $msg);} # if don't have tag
	
	return if ( $button_info_type != 2 ); # if debug button is not active, return	
	#$text_view->scroll_to_iter ($iter, $within_margin,$use_align, $xalign, $yalign)
	$textview->scroll_to_iter($iter, 0.0, $true, 0.00, 1.00) if $iter;	
	while (Gtk2->events_pending()) { Gtk2->main_iteration()}; # to update
}

# only for illustration
sub get_text {
	my $buffer = shift->get_buffer;
	$buffer->get_text ($buffer->get_start_iter, $buffer->get_end_iter, $true);
	# print (get_text($textview) );
}

#####--------------------------------------------------#####
#####------------------ Subroutines -------------------#####

sub button_with_4_phases {
   my ( $self, $adjust ) = @_;
   
   $button_info_type += $adjust;   # set the new value; $adjust = 0 or 1.
   #print "button_info_type = $button_info_type ; adjust = $adjust\n";
   
   $align_hold_2_buttons->remove ($align_hold_2_buttons->child);  # always remove one button
   
   if ( $button_info_type == 1 ){
      $frame_prog_bar->show;       # show the Progress_Bar Frame
      $align_hold_2_buttons->add ($button_show_info);
      $tooltips->set_tip( $button_show_info, $langs{tip119} ) if $show_all_tooltips;
   }
   elsif ( $button_info_type == 2 ){ # $frame_debug->show;  
      $align_hold_2_buttons->add ($button_hide_info);
      $tooltips->set_tip( $button_hide_info, $langs{tip120} ) if $show_all_tooltips;
      resize_window();
   }
   elsif ( $button_info_type == 3 ){
      $align_hold_2_buttons->add ($button_hide_info);
      $tooltips->set_tip( $button_hide_info, $langs{tip118} ) if $show_all_tooltips;
      resize_window();
   }
   elsif ( $button_info_type == 4 or $button_info_type == 0 ){
      $frame_prog_bar->hide;
      $align_hold_2_buttons->add ($button_show_info);
      $tooltips->set_tip( $button_show_info, $langs{tip117} ) if $show_all_tooltips;
      $button_info_type = 0; # return to inicial value 
   }   
}
button_with_4_phases(0,0); # '0' to not change the $button_info_type value


# Show or hide the frame_debug that show some output commands,
# and hold the notebook size constant without shrink.
sub resize_window {  
    my $width  = $window->allocation->width;    # get main window width
    my $height = $window->allocation->height;   # get main window height 
          
    # get $frame_debug height ; for the first time, always '$frame_debug->allocation->height < 10' is true
    my $height_fd = $frame_debug->allocation->height;
    $height_fd = $frame_debug->allocation->height < 10 ? 177 : $height_fd;  # 177 pixel is the minimum size 
    
    #$vpaned->child1_resize ($false); # "child1_resize" determines whether the first child should expand when $paned is resized.  
    #print "\nfora:     width = $width ; height = $height ; height_fd = ",$frame_debug->allocation->height,"\n";
   
    if ( $button_info_type == 2 ){
       my $pos = $vpaned->get_position;                              
       $window->resize ( $width, $height + $height_fd ); # ($width, $height)
       $frame_debug->show;
       $vpaned->set_position ($pos);
       #print "-->ativo: width = $width ; height = ",$height + $height_fd," ; height_fd = $height_fd\n";
    }
    elsif ( $button_info_type == 3 ){
       $frame_debug->hide;
       return if $frame_debug->allocation->height < 10;
       $window->resize ( $width, $height - $height_fd );
       #print "desativo: width = $width ; height = ",$height - $height_fd," ; height_fd = ",$frame_debug->allocation->height,"\n";
       #$vpaned->set_position ($height);
    }  
    #$vpaned->compute_position ($allocation, $child1_req, $child2_req);   
    $vpaned->compute_position (0, $vbox_up->allocation->height, $vbox_down->allocation->height);
    #$vpaned->child1_resize ($true);
    
    # boolean = $widget->get_child_visible
    #if ($frame_debug->get_child_visible){print "oooi\n";}
}

####----------------------------------------------------####

#####---------------- Programs Path -------------------#####

# sub inspirated from normalize
sub find_prog {  # Find a valid path for the program
    
    # See Perl Cookbook, 2nd Edition, Ch. 10.7
    my %args = (         # default value
                Progs    => undef,          # array with program name: name1::name2::name3:: ... = (name1,name2,name3,...)
		Comment  => "",             # show one message/comment                
                @_,      # argument pair list goes here
	       );
    my @progs = split(/::/, $args{Progs});  # an Array for elements in hash // Odd number of elements in hash assignment
    my $path = undef;
    my $fullpath;
    my $prog;    
    #foreach $prog (@progs){ print "\$prog = $prog\n"; }
    
    @_ = split(/:/, $ENV{PATH});       # get the system executable paths

    LOOP:foreach $prog (@progs){      	       
        for (@_) {                     # $_ is an element of @_        
	   ($_ .= "/") unless (/\/$/); # put a "/" at the end of path
	   # print " S = $_ \n";
	   $fullpath = $_.$prog;
	   if (-x $fullpath) {         # if (-x file) : file is executable by effective uid/gid.
	      $path = $fullpath;
	      last LOOP;               # abandon the 'foreach' LOOP
	   }
        }
    }
    if ( $args{Comment} eq "NO_COMMENT" ) { return $path; }
    
    foreach $prog (@progs){
       if ( not defined $path ) {
          insert_msg( $langs{msg023}, "black");
          insert_msg("$prog" , "red");
          insert_msg( $langs{msg024}." $args{Comment}\n" , "black");
       }
    }
    return $path;
}


sub verify_all_paths {
    $os = exec_cmd_system( 'uname -s' ); # operational system name: $os = Linux

    # see <man Gtk2::version>
    # the GtkFileChooser, new in gtk+ 2.6.0 and first supported in
    # Gtk2-Perl at 1.100, is available.
    my $Gtk2_version_boolean = Gtk2->CHECK_VERSION (2, 6, 0); # boolean
    my ($Gtk2_version_MAJOR, $Gtk2_version_MINOR, $Gtk2_version_MICRO) = Gtk2->GET_VERSION_INFO;
    my $Gtk2_version = $Gtk2_version_MAJOR.".".$Gtk2_version_MINOR.".".$Gtk2_version_MICRO;    
    my $Gtk2_Perl_version = $Gtk2::VERSION;   
   
    if ( $Gtk2_Perl_version < 1.100 or not $Gtk2_version_boolean ) {
       insert_msg( "Found Gtk2 (version = $Gtk2_version) and Gtk2_Perl (version = $Gtk2_Perl_version).", "black");
       insert_msg( "\n$langs{msg079}\n" , "red");
       insert_msg( "   Gtk2 version >= 2.6.0 ; Gtk2_Perl version >= 1.100\n\n", "red");
    }

    $lame_path = find_prog( Progs => 'lame', Comment => $langs{msg025} );
    #print " lame_path = $lame_path \n";
    unless ($lame_path) { $button_output_mp3->set_sensitive($false); }
    
    $oggenc_path = find_prog( Progs => "oggenc", Comment => $langs{msg026} );
    #print " oggenc_path = $oggenc_path \n";
    unless ($oggenc_path) { $button_output_ogg->set_sensitive($false); }
    
    $mpcenc_path = find_prog( Progs => "mppenc", Comment => $langs{msg027} );
    unless ($mpcenc_path) { $button_output_mpc->set_sensitive($false);}
    
    $ape_path = find_prog( Progs => "mac", Comment => $langs{msg028} );
    unless ($ape_path) { $button_output_ape->set_sensitive($false);  }
    
    $flac_path = find_prog( Progs => "flac", Comment => $langs{msg029} );
    unless ($flac_path) { $button_output_flac->set_sensitive($false);}
    
    $faac_path = find_prog( Progs => "faac", Comment => $langs{msg030} );
    unless ($faac_path) { $button_output_mp4->set_sensitive($false);}    
    
    if (not defined $lame_path   and $extension_output eq 'mp3') {$extension_output = 'ogg'; }
    if (not defined $oggenc_path and $extension_output eq 'ogg') {$extension_output = 'mpc'; }
    if (not defined $mpcenc_path and $extension_output eq 'mpc') {$extension_output = 'ape'; }
    if (not defined $ape_path    and $extension_output eq 'ape') {$extension_output = 'flac';}
    if (not defined $flac_path   and $extension_output eq 'flac'){$extension_output = 'mp4'; }
    if (not defined $faac_path   and $extension_output eq 'mp4') {$extension_output = 'wav'; }
    
    if    ($extension_output eq 'mp3'  and $lame_path   ) {$button_output_mp3->set_active( $true ); }  #padr�o - ativo
    elsif ($extension_output eq 'ogg'  and $oggenc_path ) {$button_output_ogg->set_active( $true ); }
    elsif ($extension_output eq 'mpc'  and $mpcenc_path ) {$button_output_mpc->set_active( $true ); }
    elsif ($extension_output eq 'ape'  and $ape_path    ) {$button_output_ape->set_active( $true ); }
    elsif ($extension_output eq 'flac' and $flac_path   ) {$button_output_flac->set_active( $true );}
    elsif ($extension_output eq 'mp4'  and $faac_path   ) {$button_output_mp4->set_active( $true ); }
    elsif ($extension_output eq 'wav') {$button_output_wav->set_active( $true );}
    else  {$normalize_button->set_sensitive($false);} # do nothing!!
    
    $metaflac_path = find_prog( Progs => "metaflac");
       
    # 'normalize-audio' is a link used on Ubuntu Linux to 'normalize'
    # $normalize_path = find_prog( Progs => 'normalize::normalize-audio', Comment => $langs{msg031} );
    
    # 'gnormalize-wavegain' is a link used on Suse Linux to 'wavegain'
    $wavegain_path = find_prog( Progs => 'wavegain::gnormalize-wavegain', Comment => $langs{msg031} );    
    unless ($wavegain_path) {
       $norm_type = "None";
       $ComboBox_Norm_Type->set_active(2); # 2 set to "None"
       $ComboBox_Norm_Type->set_sensitive($false);
       $spinner->set_sensitive($false);
    }
    
    $oggdec_path = find_prog( Progs => "oggdec", Comment => $langs{msg032} );
    
    $mpcdec_path = find_prog( Progs => "mppdec", Comment => $langs{msg033} );
    
    $faad_path = find_prog( Progs => "faad", Comment => $langs{msg034} );
    
    $cdparanoia_path = find_prog( Progs => "cdparanoia");
    unless ($cdparanoia_path) {	
	$ripper = "cdda2wav";
	ComboBox_select_this_text(\$ComboBox_rip,\@rippers,\$ripper);
	$ComboBox_rip->set_sensitive($false);
    } 
    $cdda2wav_path = find_prog( Progs => "cdda2wav", Comment => "NO_COMMENT" );
    unless ($cdda2wav_path) {
	$ripper = "cdparanoia";	
	ComboBox_select_this_text(\$ComboBox_rip,\@rippers,\$ripper);
	$ComboBox_rip->set_sensitive($false);	
    }  
    
    $vorbiscomment_path = find_prog( Progs => "vorbiscomment");
    
    if (not $use_external_cddbget){ insert_msg( "$langs{msg082}\n", "black"); } 
    if (not $use_external_MP3Info){ insert_msg( "$langs{msg083}\n", "black"); }     
    
    #---- mp3 players ----# ;
    $madplay_path = find_prog( Progs => "madplay", Comment => "NO_COMMENT" );
    $mpg123_path  = find_prog( Progs => "mpg123",  Comment => "NO_COMMENT" ); 
    $mpg321_path  = find_prog( Progs => "mpg321",  Comment => "NO_COMMENT" );
    $mplayer_path = find_prog( Progs => "mplayer", Comment => "NO_COMMENT" );
    
    $all_mp3_player{"mpg321"}  = $true if $mpg321_path;
    $all_mp3_player{"mpg123"}  = $true if $mpg123_path;
    $all_mp3_player{"madplay"} = $true if $madplay_path;
    $all_mp3_player{"mplayer"} = $true if $mplayer_path;
        
    foreach my $key (sort keys %all_mp3_player) {
       $player_mp3 = $key if ( not $all_mp3_player{"$player_mp3"} );
       #print "The value of <$key> is <$all_mp3_player{$key}> ;; player_mp3 = $player_mp3\n"; 
    }
    
    if ( not %all_mp3_player ){ # no mp3 player was found 
       find_prog( Progs => "mpg123::mpg321::madplay::mplayer", Comment => "MP3 files can't be played!" );
    }
    
    #---- mp4 players ----#      
    $all_mp4_player{"mplayer"} = $true if $mplayer_path;
       
    foreach my $key (sort keys %all_mp4_player) {
       $player_mp4 = $key if ( not $all_mp4_player{"$player_mp4"} ); 
    }
    
    #---- mpc players ----#    
    $all_mpc_player{"mplayer"} = $true if $mplayer_path;
    $all_mpc_player{"mpcdec"}  = $true  if $mpcdec_path;
       
    foreach my $key (sort keys %all_mpc_player) {
       $player_mpc = $key if ( not $all_mpc_player{"$player_mpc"} ); 
    }
    
    if ( not %all_mpc_player ){ # no mpc player was found
       find_prog( Progs => "mpcdec::mplayer", Comment => "MPC files can't be played!" );  
    }
    
    #---- ogg players ----# ;
    $ogg123_path  = find_prog( Progs => "ogg123", Comment => "NO_COMMENT" );
    
    $all_ogg_player{"mplayer"} = $true if $mplayer_path;
    $all_ogg_player{"ogg123"}  = $true if $ogg123_path;
    
    foreach my $key (keys %all_ogg_player) {
       $player_ogg = $key if ( not $all_ogg_player{"$player_ogg"} ); 
    }
    
    if ( not %all_ogg_player ){ # no ogg player was found
       find_prog( Progs => "ogg123::mplayer", Comment => "OGG files can't be played!" );  
    }
    
    #---- ape players ----#
    $play_path  = find_prog( Progs => "play",  Comment => "NO_COMMENT" ); # play from sox
    $aplay_path = find_prog( Progs => "aplay", Comment => "NO_COMMENT" );
    
    $all_ape_player{"mplayer"} = $true if $mplayer_path;
    $all_ape_player{"mac"}     = $true if ($ape_path and $play_path);
    $all_ape_player{"aplay"}   = $true if ($ape_path and $aplay_path);
       
    foreach my $key (keys %all_ape_player) {
       $player_ape = $key if ( not $all_ape_player{"$player_ape"} ); 
    }
    
    unless ( %all_ape_player ){ # no ape player was found
       find_prog( Progs => "mac::play::aplay::mplayer", Comment => "APE files can't be played!" ); 
    }   	
    
    #---- flac players ----#
    $flac123_path = find_prog( Progs => "flac123", Comment => "NO_COMMENT" );
    
    $all_flac_player{"mplayer"} = $true if $mplayer_path;
    $all_flac_player{"flac123"} = $true if $flac123_path;
       
    foreach my $key (sort keys %all_flac_player) {
       $player_flac = $key if ( not $all_flac_player{"$player_flac"} ); 
    }
    
    if ( not %all_flac_player ){ # no flac player was found
       find_prog( Progs => "flac123::mplayer", Comment => "FLAC files can't be played!" );  
    }
    
    #---- wav players ----#      
    $all_wav_player{"mplayer"} = $true if $mplayer_path;
    $all_wav_player{"aplay"}   = $true if $aplay_path;
    $all_wav_player{"play"}    = $true if $play_path;
       
    foreach my $key (sort keys %all_wav_player) {
       $player_wav = $key if ( not $all_wav_player{"$player_wav"} ); 
    }
    
    if ( not %all_wav_player ){ # no wav player was found
       find_prog( Progs => "mplayer::aplay::play", Comment => "WAV files can't be played!" );  
    }
    
    #---- ----------- ----#
    
    $amixer_path = find_prog( Progs => "amixer", Comment => "Can not set volume level!" );
    $nice_path   = find_prog( Progs => "nice", Comment => "Can not modify scheduling priority!" );
}

sub cdplayer_available { # Audio CD player uses gnormalize::cdplay or Audio::CD or cdcd.
   my @cdplayers = ();
   $cdcd_path = find_prog( Progs => "cdcd", Comment => "NO_COMMENT" );
   
   if ( $cdcd_path and not -e filename_from_unicode "$home/.cdcdrc" ){ 	
      insert_msg( "\n$langs{msg036}\n" , "black");
      insert_msg( "$langs{msg037}\n" , "black");     
   }
   if ( $use_audiocd eq $false and not defined $cdcd_path and $os !~ /Linux/i ){
      insert_msg( $langs{msg038} , "black");
      insert_msg("Audio::CD" , "red");
      insert_msg("\".\n" , "black");
      $cdcd_path = find_prog( Progs => "cdcd", Comment => $langs{msg035} ); 
   }
   
   # $cdplayer = "Audio::CD" or "cdcd" or "gnormalize::cdplay"  
   if ($os =~ /Linux/i       ) { push @cdplayers, "gnormalize::cdplay";}
   if ($use_audiocd eq $true ) { push @cdplayers, "Audio::CD";  }
   if ($cdcd_path            ) { push @cdplayers, "cdcd";       }

   return @cdplayers;
}

verify_all_paths();
@all_cdplayer = cdplayer_available();
Make_ComboBox_cdplayer();


#####-------------- Output Directory Selection --------------#####
#####------------------------ start -------------------------#####

my $file_dialog_output;
sub dir_selection_output {
   # repair the standard cancel label
   my @items = ( { stock_id => "gtk-cancel", label => "_Cancel"     } );
   Gtk2::Stock->add (@items);  # Register our stock items
   
   $file_dialog_output = Gtk2::FileChooserDialog->new( "Choose the Output Directory" , 
                                                       undef, 'open',
					               'gtk-cancel' => 'cancel',
                                                       'gtk-ok' => 'ok');

   # On Unix, the assumption of GLib and GTK+ by default is that filenames on 
   # the filesystem are encoded in UTF-8 rather than the encoding of the locale; (Release notes for GTK+ 2.6)
   # Output = gtk_func->set_text(Input), Output and Input should be in unicode on the perl level. 
   
   # filename_to_unicode  : convert local encoding --> unicode.
   # filename_from_unicode: convert unicode --> local encoding.   
   
   # filename_display_name is used with filename that need to display in gtk+ and guaranteed 
   # to return valid utf8, but the conversion is not necessary reversible. See 'man Glib'.   
   
   #_utf8_on($directory_output); # Turn on the UTF8 flag so Perl don't try to convert the some "$string1$string2" to utf8.
   
   #print "\n dir_selection_output --> 1\$directory_output = ", $directory_output,"\n";
   #$directory_output = encode('utf8',$directory_output);
   my $current_folder = $entry_dir_output->get_text;  # '$entry_dir_output->get_text' are in unicode reversible    
   $current_folder    = $home if not -d filename_from_unicode $current_folder;
					     
   # "you first need to convert filename from the local encoding to unicode." (see <man Glib>)					     					        
   $file_dialog_output->set_current_folder(  filename_from_unicode $current_folder ); #abrir no lacal especfico
          
   # Gtk2::FileChooserAction : 'select-folder', 'open', 
   $file_dialog_output->set_action ('select-folder'); # directory selection only                   
   if ($file_dialog_output->run eq 'ok') {
      
      $directory_output = $file_dialog_output->get_filename;               # '$file_dialog_output->get_filename' are in unicode reversible
      eval { $directory_output = filename_to_unicode $directory_output; }; # To remove Wide character
      
      verify_writable_dir( $directory_output );      
       
      $entry_dir_output->set_text( $directory_output );
      $tooltips->set_tip( $entry_dir_output, $directory_output ) if $show_all_tooltips;          
      
      #print "\n dir_selection_output --> 2\$directory_output = ", $directory_output,"\n"; 
      insert_msg("\n dir_selection_output --> \$directory_output = $directory_output\n" , "small"); #print on debug textview 
   };
   $file_dialog_output->destroy;
}

sub verify_writable_dir {
   my $dir = shift;
      
   if ( not -w filename_from_unicode $dir ){ 
         $status_bar->push($context_id, " $dir ".$langs{msg012} );
	 $directory_output = $home;
	 $entry_dir_output->set_text( $directory_output );
         $tooltips->set_tip( $entry_dir_output, $directory_output ) if $show_all_tooltips;
   }
   else{ $status_bar->push($context_id, " " ); }
}

#####------------------------ final -------------------------#####
#####-------------- Output Directory Selection --------------#####


#####------------------- Directory Selection ----------------#####
#####------------------------ start -------------------------#####

sub dir_selection {

   # repair the standard cancel label
   my @items = ( { stock_id => "gtk-cancel", label => "_Cancel"     } );
   Gtk2::Stock->add (@items);  # Register our stock items
   
   my $fd_msg = $langs{msg087};

   # Create a new file selection widget
   # See file:///usr/share/gtk-doc/html/gtk/GtkFileChooserDialog.html,
   # /usr/share/doc/perl-Gtk2-1.080/examples/file_chooser.pl
   # or <man Gtk2::FileChooserDialog> and <man Gtk2::FileChooser>
   # clicking the 'gtk-cancel' button will emit the "response" signal with the given response_id.
   $file_dialog = Gtk2::FileChooserDialog->new( $fd_msg , 
                                                undef, 'open',
					        'gtk-cancel' => 'cancel',						
                                                'gtk-ok' => 'ok');   						
					     
   ###----------------------- Filters -----------------------###
   # Unfortunately Gtk2::FileFilter don't have the 'insensitive case' option!!!

   my $filter_all = Gtk2::FileFilter->new;
   $filter_all->set_name ('All files');
   $filter_all->add_pattern ('*');
   $file_dialog->add_filter ($filter_all);

   my $filter_mp3 = Gtk2::FileFilter->new;
   $filter_mp3->set_name ('.mp3'); # 2 ** 2 = 4 combinations
   $filter_mp3->add_pattern ('*.mp3');   $filter_mp3->add_pattern ('*.mP3');
   $filter_mp3->add_pattern ('*.Mp3');   $filter_mp3->add_pattern ('*.MP3');
   $file_dialog->add_filter ($filter_mp3);

   my $filter_mp4 = Gtk2::FileFilter->new;
   $filter_mp4->set_name ('.mp4'); # All 2 ** 2 = 4 combinations for mp4
   $filter_mp4->add_pattern ('*.mp4');   $filter_mp4->add_pattern ('*.mP4');
   $filter_mp4->add_pattern ('*.Mp4');   $filter_mp4->add_pattern ('*.MP4');
   $filter_mp4->add_pattern ('*.M4A');   $filter_mp4->add_pattern ('*.m4a'); # for m4a
   $filter_mp4->add_pattern ('*.M4a');   $filter_mp4->add_pattern ('*.m4A');
   $filter_mp4->add_pattern ('*.aac');   $filter_mp4->add_pattern ('*.AAC'); # for aac
   $file_dialog->add_filter ($filter_mp4);

   my $filter_mpc = Gtk2::FileFilter->new;
   $filter_mpc->set_name ('.mpc');
   $filter_mpc->add_pattern ('*.mpc');   $filter_mpc->add_pattern ('*.MPC');
   $filter_mpc->add_pattern ('*.mpp');   $filter_mpc->add_pattern ('*.MPP');
   $filter_mpc->add_pattern ('*.mp+');   $filter_mpc->add_pattern ('*.MP+');
   $file_dialog->add_filter ($filter_mpc);

   my $filter_ogg = Gtk2::FileFilter->new;
   $filter_ogg->set_name ('.ogg'); # All 2 ** 3 = 8 combinations
   $filter_ogg->add_pattern ('*.ogg');   $filter_ogg->add_pattern ('*.Ogg');
   $filter_ogg->add_pattern ('*.oGg');   $filter_ogg->add_pattern ('*.ogG');
   $filter_ogg->add_pattern ('*.OGg');   $filter_ogg->add_pattern ('*.OgG');
   $filter_ogg->add_pattern ('*.oGG');   $filter_ogg->add_pattern ('*.OGG');
   $file_dialog->add_filter ($filter_ogg);

   my $filter_ape = Gtk2::FileFilter->new;
   $filter_ape->set_name ('.ape'); # There are 2 ** 3 = 8 combinations
   $filter_ape->add_pattern ('*.ape');   $filter_ape->add_pattern ('*.APE');
   $filter_ape->add_pattern ('*.Ape');   $filter_ape->add_pattern ('*.aPe');
   $filter_ape->add_pattern ('*.apE');   $filter_ape->add_pattern ('*.APe');
   $filter_ape->add_pattern ('*.aPE');   $filter_ape->add_pattern ('*.aPe');
   $file_dialog->add_filter ($filter_ape);

   my $filter_flac = Gtk2::FileFilter->new;
   $filter_flac->set_name ('.flac'); # There are 2 ** 4 = 16 combinations
   $filter_flac->add_pattern ('*.flac');   $filter_flac->add_pattern ('*.FLAC');
   $filter_flac->add_pattern ('*.Flac');   $filter_flac->add_pattern ('*.fLac');
   $filter_flac->add_pattern ('*.flAc');   $filter_flac->add_pattern ('*.flaC');
   $filter_flac->add_pattern ('*.FLac');   $filter_flac->add_pattern ('*.FlAc');
   $filter_flac->add_pattern ('*.FlaC');   $filter_flac->add_pattern ('*.fLAc');
   $filter_flac->add_pattern ('*.fLaC');   $filter_flac->add_pattern ('*.flAC');
   $filter_flac->add_pattern ('*.FLAc');   $filter_flac->add_pattern ('*.FLaC');
   $filter_flac->add_pattern ('*.FlAC');   $filter_flac->add_pattern ('*.fLAC');

   $file_dialog->add_filter ($filter_flac);

   my $filter_wav = Gtk2::FileFilter->new;
   $filter_wav->set_name ('.wav'); # There are 2 ** 3 = 8 combinations
   $filter_wav->add_pattern ('*.wav');   $filter_wav->add_pattern ('*.WAV');
   $filter_wav->add_pattern ('*.Wav');   $filter_wav->add_pattern ('*.waV');
   $filter_wav->add_pattern ('*.wAv');   $filter_wav->add_pattern ('*.WAv');
   $filter_wav->add_pattern ('*.WaV');   $filter_wav->add_pattern ('*.wAV');
   $file_dialog->add_filter ($filter_wav);

   ###----------------------- Filters -----------------------###
   my $current_folder = $entry_dir_input->get_text;                           # '$entry_dir_output->get_text' are in unicode reversible      
   $current_folder    = $home if not -d filename_from_unicode $current_folder;
   
   $file_dialog->set_current_folder( filename_from_unicode $current_folder ); # to open at specific local
      
   # Gtk2::FileChooserAction : 'select-folder', 'open', 
   $file_dialog->set_action ('select-folder'); # directory selection only 
           
   $check_button_recursively = Gtk2::CheckButton->new ( $langs{name008} );  #16jun2008
   $check_button_recursively->set_active($recursively);   
   $check_button_recursively->signal_connect( "clicked", sub { $recursively = $check_button_recursively->get_active? 1 : 0 ; } );
   $tooltips->set_tip( $check_button_recursively, $langs{tip107} ) if $show_all_tooltips;
   $check_button_recursively->show;   
      
   # Create the label for "set_extra_widget".
   $label_pct = Gtk2::Label->new("0.0%");
   $label_pct->show;
      
   # Create the Gtk2::ProgressBar to read file info for "set_extra_widget".
   $progbar_files_info = Gtk2::ProgressBar->new; 
   $progbar_files_info->set_text( $directory_base );
   $progbar_files_info->set_orientation('left_to_right');
   $progbar_files_info->show;
      
   # Add  $label_pct and  $progbar_files_info into  $vbox_extra_widget
   my $vbox_extra_widget = Gtk2::VBox->new( $false, 8 );
   $vbox_extra_widget->add($check_button_recursively);
   $vbox_extra_widget->add($label_pct);
   $vbox_extra_widget->add($progbar_files_info);
   $vbox_extra_widget->show;           
      
   # Add  $vbox_extra_widget into $file_dialog
   $file_dialog->set_extra_widget ($vbox_extra_widget);    
      
   $file_dialog->signal_connect( "selection-changed", sub {      
      my $selected_dir = $file_dialog->get_filename; # '$file_dialog->get_filename' is in local encoding ??
      eval { $selected_dir = filename_to_unicode $selected_dir; };
      
      $file_dialog->set_show_hidden ($false);
      # $file_dialog->set('use-preview-label' => $true ); 
	
      $entry_dir_input->set_text($selected_dir);	 
      $progbar_files_info->set_text( $selected_dir );      
      $tooltips->set_tip( $entry_dir_input, $selected_dir) if $show_all_tooltips;
      # print "\$selected_dir = $selected_dir\n"; 
   });
            
   if ( $file_dialog->run eq 'ok' ) {
      
      # $directory_base is used to find 'directory_ramain' with remove_directory_base() 
      $directory_base = $file_dialog->get_filename;                     # '$file_dialog_output->get_filename' are in unicode reversible
      eval { $directory_base = filename_to_unicode $directory_base; };  # To remove Wide character
   
      my $msg = ($check_button_recursively->get_active) ? $langs{msg086}: $langs{msg088};
      insert_msg( "\n$msg: $directory_base\n\n" , "small");            
   
      #print "\n dir_selection --> \$directory_base = $directory_base\n";   
      fill_with_all_informations($directory_base);  
   };    
   $file_dialog->destroy;
}

#####------------------------ final -------------------------#####
#####------------------- Directory Selection ----------------#####

sub fill_with_all_informations {
   my $dir_path = shift;  # directory                   
   
   make_array_of_files($dir_path);  # make an array of files with only supported extensions: *.mp3 , *.mp4*, *.mpc, *.ogg ...      
   if (@array_of_files <= 0){ 
      $tooltips->set_tip( $entry_f, $langs{msg063} ) if $show_all_tooltips;  # entry at beginning
      return;
   }
   #for (@array_of_files) { print "$_\n"; }
   fill_treeview_files_to_be_played();
   
   $normalize_button->set_label("normalize");
   change_font_for_all_child($window_font_name,$normalize_button);
}

sub determine_directory_and_filename_and_extension {  # filepath = (directory/)(filename)

   my %args = (  @_,  # argument pair list goes here
	      );
   my $row      = $args{row};   
   my $filepath = defined $row ? $files_info[$row]{filepath} : $args{filepath} ;
   
   return unless defined $filepath;   
   
   $filepath                   =~ s/\/{2,}/\//g;       # change two or more '//' character for one '/'        
   (my $filename = $filepath)  =~ s/.*\/(.*)/$1/g;     # (path/)(filename): copy and get the (filename)        
   (my $dir      = $filepath)  =~ s/(.*\/).*/$1/g;     # (path/)(filename): copy and get the (path/)   
   $dir                        =~ s/(\/.+)\/{1,}$/$1/; # remove the '/' character from final, if it exists, unless '/'.
   
   # determine the directory and file   ;; see 'man File::Basename' and 'fileparse'

   # determine the input/extension ;; example: $filename = 'Music.MP3' or 'Music.flac'
    
   if    ( $filename =~ /\.mp3$/i            ){ $extension_input = 'mp3';  }  # for files like: music.Mp3, music.MP3  or music.mP3
   elsif ( $filename =~ /\.(mp4|m4a|aac)$/i  ){ $extension_input = 'mp4';  } 
   elsif ( $filename =~ /\.(mpc|mpp|mp\+)$/i ){ $extension_input = 'mpc';  }  # for files like: music.mpc, .mpp, MPC, MPp ...  	  
   elsif ( $filename =~ /\.ogg$/i            ){ $extension_input = 'ogg';  }  # for files like: music.OGG, music.OgG  or music.oGG or ...       
   elsif ( $filename =~ /\.ape$/i            ){ $extension_input = 'ape';  } 
   elsif ( $filename =~ /\.flac$/i           ){ $extension_input = 'flac'; }
   elsif ( $filename =~ /\.cda$/i            ){ $extension_input = 'cda';  }
   elsif ( $filename =~ /\.wav$/i            ){ $extension_input = 'wav'   } 	  
   else                                       { $extension_input = 'other';}

   # get all file extensions from original filename
   
   (my $file_mp3  = $filename) =~ s/\.((.){3}|flac)$/.mp3/i; # to obtain the filename with appropriate extension_input
   (my $file_mp4  = $filename) =~ s/\.((.){3}|flac)$/.mp4/i; # '(.){3}' is the same as '...'
   (my $file_ogg  = $filename) =~ s/\.((.){3}|flac)$/.ogg/i;
   (my $file_mpc  = $filename) =~ s/\.(...|flac)$/.mpc/i;
   (my $file_ape  = $filename) =~ s/\.(...|flac)$/.ape/i;
   (my $file_flac = $filename) =~ s/\.(...|flac)$/.flac/i;
   (my $file_cda  = $filename) =~ s/\.(...|flac)$/.cda/i; 
   (my $file_wav  = $filename) =~ s/\.(...|flac)$/.wav/i;   
		  
   # return to the real extension_input name; for that cases *.mP3, Mp3, ...		  
   if    ( $extension_input eq 'mp3' ){ $file_mp3  = $filename; } 
   elsif ( $extension_input eq 'mp4' ){ $file_mp4  = $filename; } 
   elsif ( $extension_input eq 'mpc' ){ $file_mpc  = $filename; }
   elsif ( $extension_input eq 'ogg' ){ $file_ogg  = $filename; } # return to original extension_input     
   elsif ( $extension_input eq 'ape' ){ $file_ape  = $filename; }
   elsif ( $extension_input eq 'flac'){ $file_flac = $filename; }
   elsif ( $extension_input eq 'cda' ){ $file_cda  = $filename; }
   elsif ( $extension_input eq 'wav' ){ $file_wav  = $filename; }
		  
   $entry_f->set_text( $filename ); # refresh file to normalize
   $tooltips->set_tip( $entry_f, $filename) if $show_all_tooltips;   
   $entry_dir_input->set_text( $dir );    
   $tooltips->set_tip( $entry_dir_input, "$dir") if $show_all_tooltips;   	     
   
   return ( row        => $row, extension_input => $extension_input,            	    
	    filename   => $filename,  directory => $dir,	         
	    filepath   => $dir . '/' . $filename,
	    	              
            file_mp3   => $file_mp3,  file_mp4  => $file_mp4,  file_mpc   => $file_mpc,
	    file_ogg   => $file_ogg,  file_ape  => $file_ape,  file_flac  => $file_flac, 
	    file_cda   => $file_cda,  file_wav  => $file_wav,
	  );   
}

sub make_directory_final { # when normalizing recursively or not.
   my %args = ( @_ );    
   my $file_wav = $args{file_wav}; my $dir = $args{directory}; my $row = $args{row};       
   
   $directory_final = "$directory_output/$files_info[$row]{directory_remain}"; # where all the files will be saved
   $directory_final =~ s/\/{2,}/\//g; # change the '//' character for '/' 
   $directory_final =~ s/\/{1,}$//;   # remove the '/' character from final if it exists. 
   
   if ( not -d filename_from_unicode $directory_final ){      	      
      my @cmd = ( 'mkdir', '-p', $directory_final );	      
      insert_msg("\n@cmd\n" , "small"); #print on debug textview
      exec_cmd_system2(@cmd); 
   }  
   #print " make_directory_final --> directory = $dir \ndirectory_base = $directory_base\n";
   #print " make_directory_final --> directory_remain = $args{directory_remain} \ndirectory_final = $directory_final\n\n";  
}

sub refresh_input_output_arrows {  # draw arrows
   
   if    ( $extension_input eq 'mp4' ){  draw_input_output($da_arrow_dec,undef,("mp4","wav")); }
   elsif ( $extension_input eq 'mpc' ){  draw_input_output($da_arrow_dec,undef,("mpc","wav")); }
   elsif ( $extension_input eq 'ogg' ){  draw_input_output($da_arrow_dec,undef,("ogg","wav")); }
   elsif ( $extension_input eq 'ape' ){  draw_input_output($da_arrow_dec,undef,("ape","wav")); }   
   elsif ( $extension_input eq 'flac'){  draw_input_output($da_arrow_dec,undef,("flac","wav"));}
   elsif ( $extension_input eq 'wav' ){  draw_input_output($da_arrow_dec,undef,("wav","wav")); }
   elsif ( $extension_input eq 'cda' ){  draw_input_output($da_arrow_dec,undef,("cda","wav")); }
   else  {                               draw_input_output($da_arrow_dec,undef,("mp3","wav")); } # default
   	
   if ( $extension_input eq 'mp3' or $extension_input  eq 'mpc'  or 
        $extension_input eq 'ape' or $extension_input  eq 'flac' or
        $extension_input eq 'wav' or ($extension_input eq 'ogg' and $vorbiscomment_path ne "") ) {
	
        $status_bar->push($context_id, " $extension_input ".$langs{msg066} );
   }
}

####--------------------------------------------------####

sub set_extension_output {
  
   if ($button_output_mp3->get_active) { $extension_output = 'mp3'; }
   if ($button_output_mp4->get_active) { $extension_output = 'mp4'; }
   if ($button_output_mpc->get_active) { $extension_output = 'mpc'; }
   if ($button_output_ogg->get_active) { $extension_output = 'ogg'; }
   if ($button_output_ape->get_active) { $extension_output = 'ape'; }
   if ($button_output_flac->get_active){ $extension_output = 'flac';}
   if ($button_output_wav->get_active) { $extension_output = 'wav'; }
   
   encode_choice_sensitive();
   
   my $row  = $files_info[0]{get_selection_row} || 0;
   my %hash = determine_directory_and_filename_and_extension(row => $row);
   set_output_and_refresh_progress_bar(%hash);      
   #print "\$extension_output = $extension_output ; \$row = $row\n";
}   

sub set_output_and_refresh_progress_bar {
   my %args = ( @_,     # argument pair list goes here
	      );
   my $extension_input = $args{extension_input};
   my $row = $args{row};
        
   return if ( not defined $extension_input or $extension_input eq 'other' );   
   
   my $file_mp3 = $args{file_mp3}; my $file_mp4 = $args{file_mp4};  my $file_mpc = $args{file_mpc}; 
   my $file_ogg = $args{file_ogg}; my $file_ape = $args{file_ape};  my $file_flac= $args{file_flac}; 
   my $file_cda = $args{file_cda}; my $file_wav = $args{file_wav};
   
   $pbar->set_fraction(0);
   $pbar_n->set_fraction(0);
   $pbar_encode->set_fraction(0);
     
   if   ( $extension_input eq 'wav' ){ $pbar->set_text(" "); }
   else { $pbar->set_text(reduce_length_size($file_wav));    }
   
   
   $pbar_n->set_text(reduce_length_size($file_wav));
   draw_input_output($da_arrow_enc,undef,("wav",$extension_output));
      
   if ($button_output_mp3->get_active) { 
       $frame21->set_label("lame ".$langs{msg077});       
       ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_mp3);
       ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_mp3,\$encode_type{$extension_output}); # recover the last encode_type value              
       $pbar_encode->set_text(reduce_length_size($file_mp3));
   }
   if ($button_output_mp4->get_active) { 
       $frame21->set_label("faac ".$langs{msg077});       
       ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_mp4);
       ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_mp4,\$encode_type{$extension_output});       
       $pbar_encode->set_text(reduce_length_size($file_mp4));
   }
   if ($button_output_mpc->get_active) { 
       $frame21->set_label("mppenc ".$langs{msg077});      
       ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_mpc);
       ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_mpc,\$encode_type{$extension_output});       
       $pbar_encode->set_text(reduce_length_size($file_mpc));
   }
   if ($button_output_ogg->get_active) { 
       $frame21->set_label("oggenc ".$langs{msg077});      
       ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_ogg);
       ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_ogg,\$encode_type{$extension_output});
       $pbar_encode->set_text(reduce_length_size($file_ogg));
   }  
   if ($button_output_ape->get_active) { 
       $frame21->set_label("ape ".$langs{msg077});
       $pbar_encode->set_text(reduce_length_size($file_ape));
   }
   if ($button_output_flac->get_active) {
       $frame21->set_label("flac ".$langs{msg077});
       $pbar_encode->set_text(reduce_length_size($file_flac));
   }   
   if ($button_output_wav->get_active) { 
       $frame21->set_label("wav ".$langs{msg077});
       $pbar_encode->set_text(" ");
   }         
   
   $status_bar->push($context_id, " ");    
}

#####------------------------------------------#####
# calcule the space to be reduced to obtain a standard string'size
# we note that the char numbers are widthest than letters for Sans font type.
# substr string, pos, [n, replacement]
# Extracts and returns a substring n characters long, starting at character 
# position pos, from a given string.
sub reduce_length_size{
    my $string = shift;
    my $max_length = shift || 160;
    my $length = length( $string );
    my $sub = $length - $max_length;
    #print("\n add = $add\n");
    if ($sub < 0 ){$sub = 0 ;}
    $string = substr($string,  $sub); # cut, remove $sub bytes
    #print("\n  string = $string\n");
    return $string;
}


#####-------------vetor-com-arquivos--------------#####
#####----- array of mp3, mp4, mpc, ... files -----#####

sub eval_to_unicode {
   my $filepath_local   = shift;	
   my $filepath_unicode = undef;
   
   #my $filepath = filename_from_unicode $filepath if( ! -e $filepath );
   
   eval { $filepath_unicode = filename_to_unicode $filepath_local;   };    #  All input data MUST be convertted to unicode reversible  
   if ($@) { #$filepath_unicode = filename_display_name $filepath_local;   # 'filename_display_name' convert to unicode not reversible!
             #$filepath_unicode = $filepath_local;                         #  change nothing!
             warn "\nTry to read the file <$filepath_local>, maybe some Wide character: $!"; 
           } 
   return $filepath_unicode;
}

sub eval_from_unicode { # not used 
   my %args = ( row      => undef,
                filepath => undef,
                @_,      # argument pair list goes here
	      );
   my $row = $args{row}; my $filepath = $args{filepath};
   
   my $filepath_local = filename_from_unicode $filepath;                                   # convert filename_from_unicode to local encoding
   if( ! -e $filepath_local ) { $filepath_local = $files_info[ $row ]{filepath_local}; }   # get original filename encoding
    
   return $filepath_local;
}

# Find recursively all files. See <man perlfunc> and Recipe 9.7 from Perl Cookbook, 2nd Edition.
sub make_array_of_files {
    my $directories = shift; # $directories could be an array @directories
    # no warnings; 
    my @all_filepath = ();    
     
    #print "\n make_array_of_files --> \$directories = $directories\n";     

    # use File::Find; # see <man File::Find>
    # $File::Find::dir is the current directory name,
    # $_ is the current filename within that directory
    # $File::Find::name is the complete pathname to the file.
    # $File::Find::prune = 1; # prune to true to tell find not to descending into the directory.
    
    find {
       #no_chdir => 1, # stops find from descending into directory during processing
       #bydepth  => 1, # to visit all files beneath a directoty before the directory itself       
       #no_chdir => $check_button_recursively->get_active ? $false : $true,
       
       wanted => sub {
	  my $filepath = $File::Find::name;	    
	  
	  if ( $File::Find::dir ne $directories and not $check_button_recursively->get_active ){ return; } # not find recursively
	  
          if ( not -r $filepath ){ return; }  # -r : File is readable by effective uid/gid.
	  if ( -d $filepath ){ return; }      # -d : File is a directory
	  
	  push @all_filepath, eval_to_unicode($filepath);
	  #push @all_filepath, $filepath;
       } 
    } =>  filename_from_unicode $directories; # convert $directories from unicode to local encoding    
    
    # Directory Selection with some Filter
    my $filter;    
    eval { $filter = $file_dialog->get_filter->get_name; };  
    if (defined $filter){
       $filter = undef if ( $filter !~ /^\.(mp3|mp4|mpc|ogg|ape|flac|wav)$/i ); # 'All files' have undef filter  
    }
    
    @array_of_files = (); # empty , reset the array of files
    for (my $i = 0; $i <= $#all_filepath; $i++){
       #print_local ("filename[$i] = $all_filepath[$i] \n");
       #print "filter = $filter ; filename[$i] = $all_filepath[$i] \n";
       my $file = $all_filepath[$i];
       next unless defined $file;
       
       if (defined $filter){          
	  if    ( $filter eq '.mp4' and $file =~ /\.(mp4|m4a|aac)$/i  ){ push @array_of_files, $file; }
	  elsif ( $filter eq '.mpc' and $file =~ /\.(mpc|mpp|mp\+)$/i ){ push @array_of_files, $file; }
	  elsif ( $file =~ /$filter$/i ){ push @array_of_files, $file; }	   
       }
       #/i option: case-insensitive search  ;;  get all supported files
       elsif ( $file =~ /\.mp3$/i or $file =~ /\.ogg$/i or $file =~ /\.ape$/i or $file =~ /\.flac$/i or 
               $file =~ /\.wav$/i or $file =~ /\.(mp4|m4a|aac)$/i or $file =~ /\.(mpc|mpp|mp\+)$/i ){
          push @array_of_files, $file;	  	   
       }       
    }    
    
    @array_of_files = sort_full_path_names(@array_of_files);
    
    if ( @array_of_files <= 0 ){ # There is no supported file!
       insert_msg( "$langs{msg090}\n", "small-red");
       $status_bar->push($context_id, $langs{msg090} );
       return $false;   
    }           
       
    if ( $check_button_recursively->get_active ){
           insert_msg( "$langs{msg001}\n" , "small-black");}
    else { insert_msg( "$langs{msg002}\n" , "small-black");}
    
    for (my $i=1;$i<=@array_of_files;$i++){  # @array_of_files is the size of array @array_of_files
       $i = sprintf ("%02d", $i);
       # print on debug textview
       insert_msg( "($i): $array_of_files[$i-1] \n", "small")  if ($i % 2 == 1); # alternating colors
       insert_msg( "($i): $array_of_files[$i-1] \n", "purple") if ($i % 2 == 0);
    }
    insert_msg("-----*****-----\n" , "small-black");            
    
    return @array_of_files;
}

###----------- add files to treeview --------------###
###------------------- start ----------------------###

# The selected file is always the first array element if supported
sub put_selected_file_to_first_position {  # not used!
   my $file = shift; # selected_file
   
   unless ( $file =~ /\.mp3$/i or $file =~ /\.ogg$/i or $file =~ /\.ape$/i or $file =~ /\.flac$/i or 
        $file =~ /\.wav$/i or $file =~ /\.(mp4|m4a|aac)$/i or $file =~ /\.(mpc|mpp|mp\+)$/i ){ 
      return;   
   }
   # unshift ARRAY,LIST   : "Prepends list to the front of the array, and returns the new number of elements in the array". 
   unshift @array_of_files, $file; 
}


sub fill_treeview_files_to_be_played {

   #my $model = $treeview_play->get_model; #get the old model from Gtk2::TreeView
   #$model->clear;  # clear the old model - see <man Gtk2::ListStore> 

   my $model = create_model_files_to_be_played();  # add new files to tree model  
   
   #print "\nfill_treeview_files_to_be_played --> 1 \n";
           
   $treeview_play->set_model($model);              # add the new model 
   count_artists_and_album_already_played(update_model_artist => $false, update_model_album => $false);
   add_columns( show_play => $true);               # add columns to the treeview_play
   make_artist_and_album_treeview_column( make_artist_column => $true, make_album_column => $true, array_with_tracks => \@files_info );
   
   $button_unselec->set_sensitive($true);
   $button_selec->set_sensitive($true); 
   $da->set_sensitive($true);
   @rows_already_played = ();
   
   #get_selection_tree(); # select the first file and get info from file    
   
   return unless $playing_music;
   color_the_selected_tracks_and_scroll( select_color => 'playing' );            	   
}

fill_treeview_files_to_be_played();	
	
###------------------- final ----------------------###	
###----------- add files to treeview --------------###

sub sort_full_path_names{
    my @array = @_;   
    # For example:
    # $array[0] = '/tmp/teste/teste4/mus.mp3'
    # $array[1] = '/tmp/teste/teste2/teste4/mus.mp3'
    # $array[2] = '/tmp/mus.mp3'
    # First, sort this array in ascending order by number of '/' character.
    # Then, sort in case-insensitively mode.
    
    # sort case-insensitively : @articles = sort {uc($a) cmp uc($b)} @files; (see man perlfunc)
    # multiple comparisons in the routine and separate them with ||.
    # See Perl Cookbook, 2nd Edition. Chap. 4.16; 10.18 for help;
    #my $teste = '/tmp/teste/teste2/teste4/mus.mp3'; $teste =~ s/[^\/]//g; print "teste = $teste\n"; # output:  teste = /////
    # first compare the number of directory character '/'.
    
    sub compare_dir {
       (my $temp1 = $a) =~ s/[^\/]//g; # remove all character but '/' 
       (my $temp2 = $b) =~ s/[^\/]//g;
       #if ( $temp1 eq $temp2 ){return $false;} # print "temp1 = $temp1 ;; temp2 = $temp2\n";      
       $temp1 cmp $temp2 # sort them in ascending order by number of '/' character.
    } 
    @array = sort { compare_dir() || uc($a) cmp uc($b) } @array;
    return @array;
}

#####----------- get and show mp3/mp4/ogg ... info --------#####      	   			   

sub get_info_from_file {
   my %args = ( show_tag => $true,
                @_,     # argument pair list goes here
	      );
   my $extension_input = $args{extension_input};
   my $filepath   = $args{filepath};
   my $row = $args{row};   
   return if ($extension_input eq 'other' or $extension_input eq 'cda');
     
   #print "get_info_from_file --> \$row = $row ;; \$extension_input = $extension_input ;; \$filepath = $filepath\n";

   #my $fh = encode("utf8",$file_mp3);
   #print ("fh = $fh\n");
   #my $fh2 = decode("utf8",$fh);
   #print ("fh2 = $fh2\n");
   
   %metadata = (); # clear all tags and technical informations (metadata)
   
   # set init value "" for all 8 tags  
   $metadata{title}   = "";
   $metadata{artist}  = "";
   $metadata{album}   = "";
   $metadata{comment} = "";
   $metadata{genre}   = "";
   $metadata{track}       = "";
   $metadata{total_track} = "";
   $metadata{year}        = "";   
   
   # set init value for all 7 technical informations:
   $metadata{technical_info}  = "MPEG";
   $metadata{bitrate}         = 160;
   $metadata{bitrate_nominal} = 160 if ( $extension_input eq 'ogg' );
   $metadata{bitrate_average} = $true;
   $metadata{frequency}       = 0;  
   $metadata{mode}            = "";
   $metadata{length}          = ""  if ( $extension_input ne 'cda' );
   $metadata{fileSize}        = 0;
   
   #------------------------mp3--------------------------#
   # Only show the mp3 info for a file whose extension_input is .mp3
   if ( $files_info[$row]{extension_input} eq 'mp3' ){
      #read_ID3v1_mp3_tag($file_mp3);      
      #$bitrate_average = read_Xing_mp3_tag($file_mp3);
      read_mp3_info_tag(%args);
   }    
   #------------------------mp4--------------------------#
   # Only show the mp4 info for a file whose extension_input is .mp4
   elsif ( $files_info[$row]{extension_input} eq 'mp4' ){	
      get_mp4_info_from_file(%args);          
   }      
   #------------------------mpc--------------------------#
   # Only show the mpc info for a file whose extension_input is .mpc
   elsif ( $files_info[$row]{extension_input} eq 'mpc' ){
      show_APE_tag(%args);   
      show_mpc_info(%args);
   }   
   #------------------------ogg--------------------------#
   # Only show the ogg info for a file whose extension_input is .ogg
   elsif ( $files_info[$row]{extension_input} eq 'ogg' ){
      show_ogg_tag(%args);
      show_ogg_info(%args);
      #get_ogg_info_from_file();
   } 
   #------------------------ape--------------------------#
   # Only show the ape info for a file whose extension_input is .ape
   elsif ( $files_info[$row]{extension_input} eq 'ape' ){     
      show_APE_tag(%args); 
      show_ape_info(%args);
   }  
   #------------------------flac-------------------------#
   # Only show the flac info for a file whose extension_input is .flac
   elsif ( $files_info[$row]{extension_input} eq 'flac' ){    
      show_flac_info(%args);
   }     
   #------------------------wav--------------------------#
   elsif ( $files_info[$row]{extension_input} eq 'wav' ){
      show_APE_tag(%args);
      show_wav_info(%args);      
   }
   
   #---------- update the all info for one $row ---------# 
   
   # get all technical informations:
   $files_info[$row]{technical_info}  = $metadata{technical_info};
   $files_info[$row]{bitrate}         = $metadata{bitrate};  # more precise value
   $files_info[$row]{bitrate_nominal} = $metadata{bitrate_nominal} if ( $extension_input eq 'ogg' );
   $files_info[$row]{bitrate_average} = $metadata{bitrate_average};   
   $files_info[$row]{frequency}       = $metadata{frequency};  
   $files_info[$row]{mode}            = $metadata{mode};
   $files_info[$row]{length}          = $metadata{length}         if ( $extension_input ne 'cda' );
   #$files_info[$row]{cda_total_time}  = $metadata{cda_total_time} if ( $extension_input eq 'cda' );
   $files_info[$row]{fileSize}        = $metadata{fileSize};   
      
   # get the 8 tags   
   $files_info[$row]{title}   = $metadata{title};
   $files_info[$row]{artist}  = $metadata{artist};  
   $files_info[$row]{album}   = $metadata{album}; 
   $files_info[$row]{comment} = $metadata{comment};
   $files_info[$row]{year}    = $metadata{year};  
   $files_info[$row]{genre}   = $metadata{genre};
   $files_info[$row]{track}       = $metadata{track}; # track = track_number
   $files_info[$row]{total_track} = $metadata{total_track};
   
   #print "\n get_info_from_file --> title = $files_info[$row]{title} ;; bitrate = $metadata{bitrate} ;; bitrate_average = $metadata{bitrate_average} ;; \$row = $row\n";
   
   set_tag_info($row) if $args{show_tag};
   
   # remove the decimals numbers: 146.5  --> 146
   $files_info[$row]{bitrate} = sprintf("%.0f", number_value( $metadata{bitrate} ) ); #Kbitrate 
}

sub set_tag_info {
   my $row = shift;
   return unless defined $row;
   
   #print " set_tag_info -->1 row = $row ;; title = $files_info[$row]{title} ;; track = $files_info[$row]{track}\n";
   
   # Set all 7 technical informations on the tab entries:        
   $frame31->set_label ( uc($files_info[$row]{extension_input}) . " Info" );     
   $label_mpeg->set_label ( $files_info[$row]{technical_info} );
   $label_freq->set_label ( $files_info[$row]{frequency} ? "$langs{name041}: $files_info[$row]{frequency} Hz" : "$langs{name041}:" );    
   $label_mode->set_label ( ($files_info[$row]{extension_input} eq 'mp3' ? $langs{name031} : $langs{name043}) . ": $files_info[$row]{mode}" );
   $label_time->set_label ( $files_info[$row]{extension_input} ne 'cda' ? "$langs{name042}: $files_info[$row]{length}" : "$langs{name042}: $files_info[$row]{length} ($files_info[$row]{cda_total_time})" );
   $label_size->set_label ( $files_info[$row]{fileSize} ? "$langs{name048}: $files_info[$row]{fileSize} MB" : "$langs{name048}:" );
   
   if ( $files_info[$row]{extension_input} eq 'mp3' and $files_info[$row]{bitrate} ){      
      $label_kbps->set_label ( ($files_info[$row]{bitrate_average} ? 'Variable' : 'Constant') . "\nBitrate: $files_info[$row]{bitrate} Kb/s");
   }       
   elsif ( $files_info[$row]{extension_input} eq 'ogg' ){
      $label_kbps->set_label ("Bitrate: $files_info[$row]{bitrate} Kb/s\nNominal : $files_info[$row]{bitrate_nominal} Kb/s");
   }
   elsif ( $files_info[$row]{extension_input} eq 'cda' ){
      $label_kbps->set_label ( $files_info[$row]{bitrate} ? "Bitrate: 1411.2 Kb/s" : "Bitrate:" );
   } 
   else {     
      $label_kbps->set_label ( $files_info[$row]{bitrate} ? "Bitrate: $files_info[$row]{bitrate} Kb/s" : "Bitrate:" ); 
   }

   # To not execute the 'sub change_tag'
   $abandon_change_tag = $true; # if '$abandon_change_tag eq $true' then force to abandon the 'sub change_tag'      
   
   # Set all 8 tags  on the tab entries:
   $entry_title->set_text( $files_info[$row]{title} )                 if defined $files_info[$row]{title};
   #$entry_title->set_text( filename_from_unicode $files_info[$row]{title} )                 if defined $files_info[$row]{title};
   $entry_artist->set_text( $files_info[$row]{artist} )               if defined $files_info[$row]{artist};
   $entry_album->set_text( $files_info[$row]{album} )                 if defined $files_info[$row]{album};
   $entry_year->set_text( $files_info[$row]{year} )                   if defined $files_info[$row]{year};
   $entry_tn->set_text( $files_info[$row]{track} )                    if defined $files_info[$row]{track};
   $entry_tt->set_text( $files_info[$row]{total_track} )              if defined $files_info[$row]{total_track};
   $entry_comment->set_text( $files_info[$row]{comment} )             if defined $files_info[$row]{comment};
   $ComboBoxEntry_genre->child->set_text( $files_info[$row]{genre} )  if defined $files_info[$row]{genre};
   
   $abandon_change_tag = $false; # if '$abandon_change_tag eq $true' then force to abandon the 'sub change_tag'
   
   #print " set_tag_info -->2 row = $row ;; title = $files_info[$row]{title} ;; track = $files_info[$row]{track}\n";
   $button_save_tag->set_sensitive($false);
}

#  Perl in a Nutshell - OReilly - By Ellen Siever, Stephen Spainhour & Nathan Patwardhan
#  See too: <man perlfunc>
	
	# read (filehandle, $var, length [,offset]);
	# "Attempts to read length bytes of data into variable $var from the specified filehandle.
	# The offset, if specified, says where in the variable $var to start putting bytes, 
	# so that you can do a read into the middle of a string."
	
	# unpack ("template", string);
        # "Takes a string representing a data structure and expands it into a list value, 
	# returning the list value. (unpack does the reverse of pack.) In a scalar context, 
	# it can be used to unpack a single value. The template ... specifies the order and 
	# type of the values to be unpacked. "
	    
	# pack ("template", list);
        # "Takes a list of values and packs it into a binary structure, returning the string 
	# containing the structure. The template is a sequence of characters that give the 
	# order and type of values, as follows:
	# C : An unsigned char value
	# x : A null byte
	# Each character may optionally be followed by a number that gives a repeat count.
	# Field specifiers may be separated by whitespace, which will be ignored."
	
	# This i a example of content of mp3 file:
        # ID3
	# 
	# 
	# 

	# GripTYER
	# 


sub show_mpc_info {
   my %args = ( @_ );
   my $extension_input = $args{extension_input}; my $filepath = $args{filepath}; my $row = $args{row};
   return unless $extension_input eq 'mpc';

    my $header;
    my $Streamversion; 
    my $buffer;
    
    use constant MPCHEADERFLAG => 'MP+';
    
    my @profileNames = (
		'na', "Unstable/Experimental", 'na', 'na',
		'na', "below Telephone", "below Telephone", "Telephone",
		"Thumb", "Radio", "Standard", "Xtreme",
		"Insane", "BrainDead", "above BrainDead", "above BrainDead"
    );

    my @samplFreq = qw(44100 48000 37800 32000);
    
    open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";
    
    binmode IN;
    $fileSize = -s filename_from_unicode $filepath;
    
    # Read musepack header.
    read (IN, $header, 3); # 3 byte for 'MP+'

    if ($header ne MPCHEADERFLAG) { return $false; }
    
    # read one byte
    read IN, $Streamversion, 1;    
    $Streamversion = unpack "C", $Streamversion;
    #print "Streamversion = $Streamversion\n";
    if ( $Streamversion < 7 ){ return; } # Musepack SV version supported
    
    # read 4 byte
    read IN, $buffer, 4;    
    my $frame_count = unpack "L", $buffer;
    # print "frame_count = $frame_count\n";
    
    read IN, $buffer, 4; # for Stream Flags ;; 4 bytes = 4 * 8 bits = 32 bits
        
    my $StreamFlags = reverse unpack "b32", $buffer;  #  'b' : A bit string (ascending bit order inside each byte)
    #print "StreamFlags = $StreamFlags\n";  
    
    my $profile = bin2dec(substr($StreamFlags, 8, 4)); # get the profile number
    #print "profile = $profile ;; bin = ",substr($StreamFlags, 8, 4),"\n";    
    $Frequency = $samplFreq[bin2dec(substr($StreamFlags, 14, 2))];
    
    read IN, $buffer, 12;
        
    $buffer = unpack "L", substr($buffer,8);  # remove 8 byte, remain 4 byte
    $buffer = sprintf( "%032b", $buffer ); # convert $StreamFlags to binary base with 32 digits   
    
    my $lastValidSamples = bin2dec(substr($buffer, 1, 11));
    #print "profile = $profile ;; samplFreq = $Frequency ;; lastValidSamples = $lastValidSamples \n";
        
    my $totalSamples = ($frame_count - 1)*32*36 + $lastValidSamples;
    my $totalSeconds = $totalSamples/$Frequency;
       
    my $bitrate = 8 * $fileSize / $totalSeconds; # 8*$filesize = size in bit
    
    $totalSeconds = sprintf("%.0f",$totalSeconds);    
    # convert x seconds to hour:min:sec format
    my ($hour,$min,$sec) = sec_to_time($totalSeconds);    # return ($hour,$min,$sec);
    
    #print "bitrate = $bitrate ;; time = $hour:$min:$sec ;; totalSeconds = $totalSeconds\n"; 

    close(IN);
    
    # if $bitrate > 500 kp/s
    if ($bitrate> 500000){$profile = 15;}  # correct the bug of mppenc whem q = 10.0
    $profile = $profileNames[$profile];
    
    $Streamversion = sprintf("%0.1f",$Streamversion);
    $Technical_Info = "Stream: v$Streamversion\nProfile: '$profile'";  
    $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ;
    $bitrate_original = sprintf("%0.1f",$bitrate/1000);
    $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes    
    $Frequency = sprintf("%.0f",$Frequency);
    
    
   $encode = 'average';
   $bitrate_average = $true;
   $mode_channel = 2;   
   
   # get all technical informations:
   $metadata{technical_info}  = $Technical_Info;
   $metadata{bitrate}         = $bitrate_original;
   $metadata{bitrate_nominal} = 160;               # only for ogg
   $metadata{bitrate_average} = $bitrate_average;  # $true or $false
   $metadata{frequency}       = $Frequency;  
   $metadata{mode}            = $mode_channel;
   $metadata{length}          = $Time_Min_Sec if ( $extension_input ne 'cda' );
   $metadata{fileSize}        = $fileSize;
       
    
    # SV 7.0 Header - Item    Size ( 1 byte = 8 bit )
    # Preample                  3 bytes 'MP+'
    
    # Streamversion             1 byte
    
    #                                   StreamMinorVersion 4 bits
    #                                   StreamMajorVersion 4 bits
    #                                               sum =  8 bits = 1 byte
    # FrameCount                4 bytes 
    
    # Stream Flags              4 bytes
      
    #                                   IntensityStereo  1 bit
    #                                   MidSideStereo    1 bit 
    #                                   MaxBand          6 bits
    #                                   Profile          4 bits
    #                                   Link             2 bits 
    #                                   SampleFreq       2 bits
    #                                   MaxLevel        16 bits
    #                                             sum = 32 bits = 4 bytes  
    # TitleGain                 2 bytes
    # TitlePeak                 2 bytes
    # AlbumGain                 2 bytes
    # AlbumPeak                 2 bytes
    # 
    # TrueGapless               1 bit
    # LastFrameLength          11 bits 
    # ...
            
    # tell    Returns the current position in bytes for FILEHANDLE,
    # sysread FILEHANDLE,SCALAR,LENGTH,OFFSET  ;; Returns the number of bytes actually read
    # syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET  
    # substr EXPR,OFFSET,LENGTH,REPLACEMENT  ;; Extracts a substring out of EXPR and returns it.
}

sub show_ape_info {
   my %args = ( @_ );
   my $extension_input = $args{extension_input}; my $filepath = $args{filepath}; my $row = $args{row};
   return unless $extension_input eq 'ape';

    my $header;
    my $buffer;
    
    my $CompressionLevel; my $Channels; my $HeaderBytes;
    my $TerminatingBytes; my $TotalFrames; my $FinalFrameBlocks;
    my $BlocksPerFrame; my $BitsPerSample;
    
    use constant APEHEADERFLAG => 'MAC ';
    
    use constant COMPRESSION_LEVEL_FAST  =>          '1000';
    use constant COMPRESSION_LEVEL_NORMAL =>         '2000';
    use constant COMPRESSION_LEVEL_HIGH   =>         '3000';
    use constant COMPRESSION_LEVEL_EXTRA_HIGH =>     '4000';
    use constant COMPRESSION_LEVEL_INSANE_HIGH   =>  '5000';
    use constant COMPRESSION_LEVEL_BRAINDEAD_HIGH => '6000';
    
    my @CompLevel = ( 'n', 'Fast', 'Normal', 'High', 'Extra High',
                      'Insane', 'BrainDead' );
    
    open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";
    
    binmode IN;
    $fileSize = -s filename_from_unicode $filepath;
    #print "fileSize = $fileSize bytes\n";
    
    # Read ape header.
    read (IN, $header, 4); # 4 byte for 'MAC '

    if ($header ne APEHEADERFLAG) { return $false; }
    
    read IN, my $version, 2;  # 2 byte for version  
    $version = unpack "S", $version;
    $version = sprintf( "%.2f", $version/1000 ); 
    $version = number_value($version); 
    #print "version = $version\n";
       
    if ( $version < 3.98 ) { # old header format for APE
    
       read IN, $CompressionLevel, 2;  # 2 byte for CompressionLevel 
       $CompressionLevel = unpack "S", $CompressionLevel;
       #print "CompressionLevel = $CompressionLevel\n";
    
       read IN, $Channels, 4;  # 2 byte = 16 bits, for Channels 
       $Channels = unpack "S", substr($Channels, 2, 2);  # don't read flags not used
       #print "Channels = $Channels\n";
    
       read IN, $Frequency, 4;  # 4 byte for SampleRate
       $Frequency = unpack "L", $Frequency;
       #print "Samples per second(Frequency):= $Frequency\n";
    
       read IN, $HeaderBytes, 4;  # 4 byte for HeaderBytes
       $HeaderBytes = unpack "L", $HeaderBytes;
       #print "HeaderBytes = $HeaderBytes\n";
    
       read IN, $TerminatingBytes, 4;  # 4 byte for TerminatingBytes
       $TerminatingBytes = unpack "L", $TerminatingBytes;
       #print "TerminatingBytes = $TerminatingBytes\n";
     
       read IN, $TotalFrames, 4;  # 4 byte for TotalFrames
       $TotalFrames = unpack "L", $TotalFrames;
       #print "TotalFrames = $TotalFrames\n";
    
       read IN, $FinalFrameBlocks, 4;  # 4 byte for FinalFrameBlocks
       $FinalFrameBlocks = unpack "L", $FinalFrameBlocks;
       #print "FinalFrameBlocks = $FinalFrameBlocks\n";
       
    }
    
    $BlocksPerFrame = (($version >= 3.90) || (($version >= 3.80) && ($CompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH))) ? 0x12000 : 0x02400;
    if ($version >= 3.95){$BlocksPerFrame = 0x48000; } # 0x48000 (hex) = 294912 (decimal)
    
    if ( $version >= 3.98 ) {  # current header format for APE files
    
       # 8 bytes = 4 bytes for 'MAC ' + 4 bytes for version
       #$APE_DESCRIPTOR, 44; # 4*7 + 16 (MD5) = 44 bytes
       #  total = 52 bytes = 8 + 44
       seek(IN, 8 + 4, 0);
       
       read IN, $HeaderBytes, 4;  # 4 byte for HeaderBytes
       $HeaderBytes = unpack "L", $HeaderBytes;
       #print "HeaderBytes = $HeaderBytes\n";
       
       #  total = 52 bytes = 8 + 44
       seek(IN, 52, 0);
       
       read IN, $CompressionLevel, 2;  # 2 byte for CompressionLevel 
       $CompressionLevel = unpack "S", $CompressionLevel;
       #print "CompressionLevel = $CompressionLevel\n";
       
       read IN, my $FormatFlags, 2;  # 2 byte for FormatFlags (not used)
       
       read IN, $BlocksPerFrame, 4;  # 4 byte for BlocksPerFrame
       $BlocksPerFrame = unpack "L", $BlocksPerFrame;
       #print "BlocksPerFrame = $BlocksPerFrame\n";
       
       read IN, $FinalFrameBlocks, 4;
       $FinalFrameBlocks = unpack "L", $FinalFrameBlocks;
       #print "FinalFrameBlocks = $FinalFrameBlocks\n";
       
       read IN, $TotalFrames, 4; 
       $TotalFrames = unpack "L", $TotalFrames;
       #print "TotalFrames = $TotalFrames\n";
       
       read IN, $BitsPerSample, 2;  # 2 byte for BitsPerSample
       $BitsPerSample = unpack "S", $BitsPerSample;
       #print "BitsPerSample = $BitsPerSample\n";
       
       read IN, $Channels, 2;  # 2 byte for Channels 
       $Channels = unpack "S", $Channels; 
       #print "Channels = $Channels\n";
    
       read IN, $Frequency, 4;  # 4 byte for SampleRate
       $Frequency = unpack "L", $Frequency;
       #print "Samples per second(Frequency):= $Frequency\n";
    
    } 

    close(IN);
    
    # from src/MACLib/APEHeader.cpp  ;; Total Samples = $TotalBlocks
    my $TotalBlocks = ($TotalFrames == 0) ? 0 : ($TotalFrames - 1) * $BlocksPerFrame + $FinalFrameBlocks ;
    my $totalSeconds = $TotalBlocks/$Frequency;
       
    my $bitrate = ($totalSeconds <= 0) ? 0 :  ($fileSize - $HeaderBytes) * 8 / $totalSeconds;  # 8*$filesize = size in bit
    $bitrate = sprintf("%.1f",$bitrate/1000);    
    
    $totalSeconds = sprintf("%.0f",$totalSeconds);    
    # convert x seconds to hour:min:sec format
    my ($hour,$min,$sec) = sec_to_time($totalSeconds);    # return ($hour,$min,$sec);
    
    #print "Kbitrate = $bitrate ;; time = $hour:$min:$sec ;; totalSeconds = $totalSeconds\n";    
    
    $Frequency = sprintf("%.0f", $Frequency );        
    #my $Compression_ratio = sprintf("%.0f", ($bitrate/1411.2) * 100 );  # approximate value
    $Technical_Info = "MAC version: $version\nComp: " . $CompLevel[$CompressionLevel/1000] ; # . "\nCompression:~ $Compression_ratio%";    
    $mode_channel = $Channels;
    $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ;
    $bitrate_original = $bitrate;
    $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes
    
    
   $encode = 'average';
   $bitrate_average = $true;  
   
   # get all technical informations:
   $metadata{technical_info}  = $Technical_Info;
   $metadata{bitrate}         = $bitrate_original;
   $metadata{bitrate_nominal} = 160;               # only for ogg
   $metadata{bitrate_average} = $bitrate_average;  # $true or $false
   $metadata{frequency}       = $Frequency;  
   $metadata{mode}            = $mode_channel;
   $metadata{length}          = $Time_Min_Sec if ( $extension_input ne 'cda' );
   $metadata{fileSize}        = $fileSize;
    
    #----------------------------OLD APE files-----------------------------#
    
    # APE header structure for old APE files (version <= 3.97) : APEHeader.h and APEHeader.cpp
         
    # APE Header - Item    Size ( 1 byte = 8 bits ) -    Type     - Total 32 bytes - see <man perlfunc>
    # Preample                  4 bytes 'MAC '          char c
    # version                   2 bytes    'S' unsigned int16   # version number * 1000 (3.81 = 3810)
    # CompressionLevel          2 bytes                 int16
    # FormatFlags               2 bytes                 int16   # any format flags (for future use)
    # Channels                  2 bytes                 int16   # the number of channels (1 or 2)
    # SampleRate                4 bytes    'L' unsigned int32   # the sample rate (typically 44100)
    # HeaderBytes               4 bytes                 int32   # the bytes after the MAC header that compose the WAV header
    # TerminatingBytes          4 bytes                 int32   # the bytes after that raw data (for extended info) 
    # TotalFrames               4 bytes                 int32   # the number of frames in the file
    # FinalFrameBlocks          4 bytes                 int32   # the number of samples in the final frame   
    
    
    #----------------------------NEW APE files-----------------------------#    
    
    # APE header structure for new APE files (version >= 3.98) : from src/MACLib/MACLib.h
    
    #JUNK - any amount of "junk" before the APE_DESCRIPTOR (so people that put ID3v2 tags on the files aren't hosed)
    #APE_DESCRIPTOR - defines the sizes (and offsets) of all the pieces, as well as the MD5 checksum
    #APE_HEADER - describes all of the necessary information about the APE file
    
    #APE_DESCRIPTOR structure (file header that describes lengths, offsets, etc.)
    # char    cID[4];                             // should equal 'MAC '
    # uint16  nVersion;                           // version number * 1000 (3.81 = 3810)
    # uint32  nDescriptorBytes;                   // the number of descriptor bytes (allows later expansion of this header)
    # uint32  nHeaderBytes;                       // the number of header APE_HEADER bytes
    # uint32  nSeekTableBytes;                    // the number of bytes of the seek table
    # uint32  nHeaderDataBytes;                   // the number of header data bytes (from original file)
    # uint32  nAPEFrameDataBytes;                 // the number of bytes of APE frame data
    # uint32  nAPEFrameDataBytesHigh;             // the high order number of APE frame data bytes
    # uint32  nTerminatingDataBytes;              // the terminating data of the file (not including tag data)
    # uint8   cFileMD5[16];                       // the MD5 hash of the file (see notes for usage... it's a littly tricky)
    
    #APE_HEADER structure (describes the format, duration, etc. of the APE file)
    # uint16    nCompressionLevel;                 // the compression level (see defines I.E. COMPRESSION_LEVEL_FAST)
    # uint16    nFormatFlags;                      // any format flags (for future use)
    # uint32    nBlocksPerFrame;                   // the number of audio blocks in one frame
    # uint32    nFinalFrameBlocks;                 // the number of audio blocks in the final frame
    # uint32    nTotalFrames;                      // the total number of frames
    # uint16    nBitsPerSample;                    // the bits per sample (typically 16)
    # uint16    nChannels;                         // the number of channels (1 or 2)
    # uint32    nSampleRate;                       // the sample rate (typically 44100)
     
      
    #-------------------------------INFO----------------------------------#      
    
    #  fill the APE info structure (see APE_3.96b8_Source.tar.bz2  :  Monkey/Source/MACLib/APEInfo.cpp)
    #m_APEFileInfo.nBlocksPerFrame       = ((APEHeader.nVersion >= 3900) || ((APEHeader.nVersion >= 3800) && (APEHeader.nCompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH))) ? 0x12000 : 0x02400;
    #                                        if ((APEHeader.nVersion >= 3950)) m_APEFileInfo.nBlocksPerFrame = 0x48000;
    #m_APEFileInfo.nBitsPerSample        = (m_APEFileInfo.nFormatFlags & MAC_FORMAT_FLAG_8_BIT) ? 8 : ((m_APEFileInfo.nFormatFlags & MAC_FORMAT_FLAG_24_BIT) ? 24 : 16);
    #m_APEFileInfo.nBytesPerSample       = m_APEFileInfo.nBitsPerSample / 8;
    #m_APEFileInfo.nBlockAlign           = m_APEFileInfo.nBytesPerSample * m_APEFileInfo.nChannels;
    #m_APEFileInfo.nTotalBlocks          = (APEHeader.nTotalFrames == 0) ? 0 : ((APEHeader.nTotalFrames -  1) * m_APEFileInfo.nBlocksPerFrame) + APEHeader.nFinalFrameBlocks;
    #m_APEFileInfo.nWAVHeaderBytes       = (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER) ? sizeof(WAVE_HEADER) : APEHeader.nHeaderBytes;
    #m_APEFileInfo.nWAVTerminatingBytes  = int(APEHeader.nTerminatingBytes);
    #m_APEFileInfo.nWAVDataBytes         = m_APEFileInfo.nTotalBlocks * m_APEFileInfo.nBlockAlign;
    #m_APEFileInfo.nWAVTotalBytes        = m_APEFileInfo.nWAVDataBytes + m_APEFileInfo.nWAVHeaderBytes + m_APEFileInfo.nWAVTerminatingBytes;
    #m_APEFileInfo.nLengthMS             = int((double(m_APEFileInfo.nTotalBlocks) * double(1000)) / double(m_APEFileInfo.nSampleRate));
    #m_APEFileInfo.nAverageBitrate       = (m_APEFileInfo.nLengthMS <= 0) ? 0 : int((double(m_APEFileInfo.nAPETotalBytes) * double(8)) / double(m_APEFileInfo.nLengthMS));
    #m_APEFileInfo.nDecompressedBitrate  = (m_APEFileInfo.nBlockAlign * m_APEFileInfo.nSampleRate * 8) / 1000; 
}


sub show_flac_info {
   my %args = ( @_ );
   my $extension_input = $args{extension_input}; my $filepath = $args{filepath}; my $row = $args{row};
   return unless $extension_input eq 'flac';

    my $header; 
    my $buffer;
    
    use constant FLACHEADERFLAG => 'fLaC'; # FLAC__STREAM_SYNC_STRING
    
    my @block_type = ( 'STREAMINFO', 'PADDING', 'APPLICATION', 'SEEKTABLE', 
                       'VORBIS_COMMENT', 'CUESHEET', 'reserved' );
    
    open(IN, filename_from_unicode $filepath ) or die "Can't open <$filepath>: $!, stopped";
    
    binmode IN;
    $fileSize = -s filename_from_unicode $filepath;
    
    # Read flac header.
    read (IN, $header, 4); # 4 byte for 'fLaC'

    if ($header ne FLACHEADERFLAG) { return $false; }
    
    # METADATA_BLOCK_HEADER (4 bytes)
    # A block header that specifies the type and size of the metadata block data.
    
    #-------------------------------------------------#
    my $vorbis_comment;
    my $flag = 0;
    my $it = 0;  # to avoid infinite loop
    
    while ( $flag == 0 and $it < 9 )  # Search for vorbis_comment
    {    
       # METADATA_BLOCK_HEADER (4 bytes)
       # A block header that specifies the type and size of the metadata block data.
       read IN, $buffer, 4;  # 4 byte (=32 bits)
       $buffer = unpack "B32", $buffer;  
       $flag = bin2dec(substr($buffer, 0, 1)); # flag: = 1 if last metadata, 0 otherwise
       $buffer = substr($buffer, 1); # remove the first 1 bit
       #print "flag = $flag\n";

       my $b_type = bin2dec(substr($buffer, 0, 7));
       $buffer = substr($buffer, 7); # remove the first 7 bits, remain 24 bits
       #print "block_type = $block_type[$b_type]\n";
    
       my $block_size = bin2dec($buffer);
       #print "block_size = $block_size bytes\n";
    
       # METADATA_BLOCK PADDING or APPLICATION or SEEKTABLE or VORBIS_COMMENT
       read IN, $buffer, $block_size;  # read $block_size bytes to buffer
         
       if ( $block_type[$b_type] eq 'VORBIS_COMMENT' ){
          $vorbis_comment = $buffer;
	  #print "vorbis = $buffer\n";
	  read_vorbis_comment_tag($vorbis_comment,$extension_input);  
       }
       $it = $it +1;      
    }    
    #-------------------------------------------------#
    
    # 8 bytes = 4 bytes for ''fLaC' + 4 bytes for first block_header
    seek(IN, 4 + 4, 0);
    
    # METADATA_BLOCK_STREAMINFO (34 bytes)
    # b   A bit string (ascending bit order inside each byte, like vec()).
    # B   A bit string (descending bit order inside each byte).  - see <man perlfunc>
    
    read IN, my $min_blocksize, 2;  # 2 bytes = 16 bits for min_blocksize
    $min_blocksize = bin2dec(unpack "B16", $min_blocksize);  
    #print "min_blocksize = $min_blocksize\n";
    
    read IN, my $max_blocksize, 2;  # 2 bytes for max_blocksize
    $max_blocksize = bin2dec(unpack "B16", $max_blocksize);
    #print "max_blocksize = $max_blocksize\n";
    
    read IN, my $min_framesize, 3;  # 3 bytes = 24 bits for min_framesize
    $min_framesize = unpack "B24", $min_framesize;  
    $min_framesize = bin2dec($min_framesize);
    #print "min_framesize = $min_framesize\n";
    
    read IN, my $max_framesize, 3;  # 3 bytes = 24 bits for max_framesize
    $max_framesize = unpack "B24", $max_framesize;  
    $max_framesize = bin2dec($max_framesize);
    #print "max_framesize = $max_framesize\n";
    
    read IN, $buffer, 8;  # 8 bytes = (20+3+5+36) bits = 64 bits 
    $buffer = unpack "B64", $buffer;  
    $Frequency = bin2dec(substr($buffer, 0, 20)); #SampleRate frequency
    $buffer = substr($buffer, 20); # remove the first 20 bits
    #print "sample_rate = $Frequency\n";
      
    my $Channels = 1 + bin2dec(substr($buffer, 0, 3));
    $buffer = substr($buffer, 3); # remove the first 3 bits
    #print "Channels = $Channels\n";
    
    my $bits_per_sample = 1 + bin2dec(substr($buffer, 0, 5));
    $buffer = substr($buffer, 5); # remove the first 5 bits
    #print "bits_per_sample = $bits_per_sample\n";
    
    my $Total_samples = bin2dec(substr($buffer, 0, 36));
    #print "Total_samples = $Total_samples\n";
    
    read IN, $buffer, 16; # 16 bytes for MD5 signature

    close(IN);

    my $totalSeconds = $Total_samples/$Frequency;        
    my $bitrate = ($totalSeconds <= 0) ? 0 :  $fileSize * 8 / $totalSeconds;  
    $bitrate = sprintf("%.1f",$bitrate/1000);
    my $Compression_ratio = 100 * $fileSize / ($bits_per_sample / 8 * $Channels * $Total_samples);
    $Compression_ratio = sprintf("%.2f",$Compression_ratio);
    
    $totalSeconds = sprintf("%0.0f",$totalSeconds);    
    # convert x seconds to hour:min:sec format
    my ($hour,$min,$sec) = sec_to_time($totalSeconds);    # return ($hour,$min,$sec);
    
    #print "bitrate = $bitrate ;; time = $hour:$min:$sec ;; totalSeconds = $totalSeconds\n"; 
    #print "Compression_ratio = $Compression_ratio\n";
    
    $Frequency = sprintf("%.0f", $Frequency ); 
    $Technical_Info = "Compression: $Compression_ratio%";    
    $mode_channel = $Channels;
    $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ;
    $bitrate_original = $bitrate;
    $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes
   
   $encode = 'average';
   $bitrate_average = $true;    
   
   # get all technical informations:
   $metadata{technical_info}  = $Technical_Info;
   $metadata{bitrate}         = $bitrate_original;
   $metadata{bitrate_nominal} = 160;               # only for ogg
   $metadata{bitrate_average} = $bitrate_average;  # $true or $false
   $metadata{frequency}       = $Frequency;  
   $metadata{mode}            = $mode_channel;
   $metadata{length}          = $Time_Min_Sec if ( $extension_input ne 'cda' );
   $metadata{fileSize}        = $fileSize;
   

# See flac-1.1.2/doc/html/format.html#metadata_block_streaminfo
         
# FLAC Header -         Size ( 1 byte = 8 bits ) -      Type     - Total 4 bytes 
    # Preample                  4 bytes 'fLaC          char c

# METADATA_BLOCK_HEADER           Size          Type       - Total 4 bytes 
    # Flags   (1 byte)                  
    #                           1 bit                           #'1' if this block is the last metadata block before the audio blocks, '0' otherwise.
    #			      + 7 bits                          # 0 : STREAMINFO ;; 1 : PADDING ;; 2 : APPLICATION ;; 3 : SEEKTABLE ;; 4 : VORBIS_COMMENT
    #   		      = 8 bits = 1 byte  B8            
    # Length                    3 bytes          B24            # Length (in bytes) of metadata to follow (does not include the size of the METADATA_BLOCK_HEADER)

# METADATA_BLOCK_STREAMINFO       Size          Type       - Total 34 bytes 

    # min_blocksize             2 bytes          B16            # The minimum block size (in samples) used in the stream. 
    # min_blocksize             2 bytes          B16            # (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream.
    # min_framesize             3 bytes          B24            # The minimum frame size (in bytes) used in the stream. May be 0 to imply the value is not known.
    # max_framesize             3 bytes          B24       
    # sample_rate              20 bits           B20            # Sample rate in Hz. Though 20 bits are available, the maximum sample rate is limited by the structure of frame headers to 1048570Hz.
    # Channels                  3 bits           B3             # (number of channels) - 1. FLAC supports from 1 to 8 channels
    # bits_per_sample           5 bits           B5             # (bits per sample) - 1. FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample.
    # Total samples            36 bits                          # 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels. 
    # MD5 signature            16 bytes

## NOTES: FLAC specifies a minimum block size of 16 and a maximum block size of 65535, meaning 
## the bit patterns corresponding to the numbers 0-15 in the minimum blocksize and maximum blocksize fields are invalid.

}

sub read_vorbis_comment_tag {  # to 'ogg' and 'flac' files
   my ($vorbis_comment, $extension_input) = @_;
   
   my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 
   my $Total_Track = ""; my $Genre="";

   # field_name = field_value, field_value_length
   
   # from vorbis-tools-1.1.1/ogginfo/ogginfo2.c
   # "Xiphophorus libVorbis I 20000508", "1.0 beta 1 or beta 2"
   # "Xiphophorus libVorbis I 20001031", "1.0 beta 3"
   # "Xiphophorus libVorbis I 20010225", "1.0 beta 4"
   # "Xiphophorus libVorbis I 20010615", "1.0 rc1"
   # "Xiphophorus libVorbis I 20010813", "1.0 rc2"
   # "Xiphophorus libVorbis I 20011217", "1.0 rc3"
   # "Xiphophorus libVorbis I 20011231", "1.0 rc3"
   # "Xiph.Org libVorbis I 20020717", "1.0"
   # "Xiph.Org libVorbis I 20030909", "1.0.1"
   # "Xiph.Org libVorbis I 20040629", "1.1.0 rc1"
   # "Xiph.Org libVorbis I 20070622", "1.2.0"

   
   # The first thing in the comment is the vendor ID size, followed by a UTF8 string with the vendor ID.
   my $vendor_size = substr($vorbis_comment,0,4); # 4 bytes = 32 bits
   $vendor_size = unpack "L",$vendor_size;
   #print "vendor_size = $vendor_size\n";  
   my $vendor  = substr($vorbis_comment, 4, $vendor_size + 4);    # read the vendor
   #print "vendor = $vendor \n";
   $vorbis_comment  = substr($vorbis_comment, $vendor_size + 4);  # cut, remove
   
   if ( $vendor =~ /20010615/ ){ $vendor = '1.0rc1';    }
   elsif ( $vendor =~ /20010813/ ){ $vendor = '1.0rc2'; }
   elsif ( $vendor =~ /20011217/ or $vendor =~ /20011231/ ){ $vendor = '1.0rc3'; }
   elsif ( $vendor =~ /20020717/ ){ $vendor = '1.0';    }
   elsif ( $vendor =~ /20030909/ ){ $vendor = '1.0.1';  }
   elsif ( $vendor =~ /20040629/ ){ $vendor = '1.1.0rc1';  }
   elsif ( $vendor =~ /20050304/ ){ $vendor = '1.1.1';  }
   elsif ( $vendor =~ /20070622/ ){ $vendor = '1.2.0';  }
   else { $vendor =""; }
   if ( $extension_input eq 'ogg' ) { $Technical_Info = "OGG Vorbis $vendor"; $metadata{technical_info}  = $Technical_Info; }
  
   # Next the number of fields in the comment vector.
   my $item_count = substr($vorbis_comment,0,4);
   $item_count = unpack "L",$item_count;
   #print "item_count = $item_count\n";
   $vorbis_comment  = substr($vorbis_comment, 4);    # cut, remove
   
   # Each comment field is in the format "key=value" in a UTF8 string and has
   # 4 bytes before the text starts that gives the length.
   my $tagLen;
   my ($tag_key, $tag_val);
   my %taghash = (); 

   for (my $i=0;$i<$item_count;$i++)
   {
        $tagLen = substr($vorbis_comment,0,4); # read 4 bytes for size/length
	$tagLen = unpack "L",$tagLen;
	#print "tagLen = $tagLen\n";
	$vorbis_comment = substr($vorbis_comment,4);        # cut, remove 4 bytes
	
	my $comment = substr($vorbis_comment,0,$tagLen);    # read $tagLen bytes
        $vorbis_comment = substr($vorbis_comment,$tagLen);  # cut, remove $tagLen bytes
	
	if ($comment =~ /^(.*?)=/) { $tag_key = $1; }  # = separation
	#$tag_key =~ tr/A-Z/a-z/; #lower case
	$tag_key = lc($tag_key);  #lower case
        $comment =~ s/^.*?=//;

	$tag_val = decode("utf8",$comment);	

	#print "tag_key = $tag_key ;; tag_val = $tag_val ;; vorbis_comment = $vorbis_comment\n"; 
	# Fill the hash
	$taghash{$tag_key} = $tag_val;
	if ( length($vorbis_comment) <= 0 ){last;}
   }   
   # framing bit or framing_flag
   #my $framing_bit = bin2dec( unpack "B8",substr($vorbis_comment,0,1) ); # read 1 byte = 8 bits
   #print "framing_bit = $framing_bit ;;\n";   
   
   if ( defined($taghash{date})    ){ $Year = $taghash{date};     }
   if ( defined($taghash{artist})  ){ $Artist = $taghash{artist}; }
   if ( defined($taghash{title})   ){ $Title = $taghash{title};   }
   if ( defined($taghash{genre})   ){ $Genre = $taghash{genre};   }
   if ( defined($taghash{album})   ){ $Album = $taghash{album};   }
   
   if ( defined($taghash{tracknumber})  ){ $Track_Number = $taghash{tracknumber};   }
   if ( $Track_Number =~ /(\d+)\/(\d+)/ ){ $Track_Number = $1 ; $Total_Track = $2 ; }
   
   if ( defined($taghash{description}) ){ $Comment = $taghash{description};                                }
   if ( defined($taghash{comment}) and not defined($taghash{description}) ){ $Comment = $taghash{comment}; }

   $Track_Number = remove_change_10_chars($Track_Number);
   $Total_Track  = remove_change_10_chars($Total_Track);
    
   # get all the 8 tags  
   $metadata{title}   = remove_change_10_chars($Title);
   $metadata{artist}  = remove_change_10_chars($Artist);
   $metadata{album}   = remove_change_10_chars($Album);
   $metadata{comment} = remove_change_10_chars($Comment);
   $metadata{genre}   = remove_change_10_chars($Genre);
   $metadata{track}       = $Track_Number =~ /^\d+$/ ? sprintf("%02d", $Track_Number ) : "" ; # "%02d": leading zero
   $metadata{total_track} = $Total_Track  =~ /^\d+$/ ? sprintf("%02d", $Total_Track  ) : "" ;  
   $metadata{year}        = $Year =~ /^\d{1,4}$/ ? sprintf("%04d", $Year ) : "" ;   

# See: file:///usr/share/doc/libvorbis0-devel-1.1.0/Vorbis_I_spec.html  
# The comment header:
#  1) [vendor_length] = read an unsigned integer of 32 bits (= 4 bytes)
#  2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
#  3) [user_comment_list_length] = read an unsigned integer of 32 bits
#  4) iterate [user_comment_list_length] times {
#       5) [length] = read an unsigned integer of 32 bits
#       6) this iteration's user comment = read a UTF-8 vector as [length] octets
#     }
#  7) [framing_bit] = read a single bit as boolean
#  8) if ( [framing_bit] unset or end-of-packet ) then ERROR
#  9) done.

}

sub show_ogg_info {
   my %args = ( @_ );
   my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath};
      
   return unless $extension_input eq 'ogg';

    my $header;
    my $buffer;
    
    use constant OGGHEADERFLAG => 'OggS';
    
    my @block_type = ( 'STREAMINFO', 'PADDING', 'APPLICATION', 'SEEKTABLE', 
                       'VORBIS_COMMENT', 'CUESHEET', 'reserved' );
    
    open(OGG, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";
    
    binmode OGG;
    $fileSize = -s filename_from_unicode $filepath;
    
    # Read ogg header.
    read (OGG, $header, 4); # 4 byte for 'OggS'

    if ($header ne OGGHEADERFLAG) { return $false; }
       
    ##------------------------##
    # Search for the first header containing Identification header ( $header_type_flag == 1 ). 
    my $byte = 25; # at least equal to 28 bytes
    my $string = "";  
    my $myseek = sub {
		my $n = $_[0] || 6;   # read 6 bytes for one loop to search for 'vorbis' string
		$byte += $_[1] || 1;  # advance 1 byte for one loop
		seek OGG, $byte, 0;
		read OGG, $string, $n;
    };
    while ($string ne 'vorbis') {
	&$myseek(6,1);
	if ($byte > 8*1024) { return $false; }
    }
    #print "byte = $byte\n";
    ##------------------------##
    my $first_frame_size = $byte - 1;  # 28 is the more likely value.

    seek OGG, $first_frame_size, 0;    # set read to $first_frame_size ( at least equal to 28 bytes). 
    
    # Identification header (type = 1)
    read (OGG, my $header_type, 1); # read 1 byte      
    $header_type = bin2dec(unpack "B8",$header_type);  # header_type = 1 indicates the Identification header.
    #print "header_type = $header_type\n";
    if ($header_type != 1){return;}
    
    read (OGG, $header, 6); # read + 6 bytes  for 'vorbis'
    
    read (OGG, my $vorbis_version, 4); # read 4 bytes = 32 bits
    $vorbis_version = unpack "L",$vorbis_version;
    if ($vorbis_version != 0){return $false;}
    #print "vorbis_version = $vorbis_version\n";
    
    read (OGG, my $audio_channels, 1); # read 1 byte = 8 bits
    $audio_channels = bin2dec(unpack "B8",$audio_channels);
    if ($audio_channels < 1){return $false;}
    #print "audio_channels = $audio_channels\n";
    
    read (OGG, $Frequency, 4); # read 4 bytes
    $Frequency = unpack "L",$Frequency;
    if ($Frequency < 1){return $false;}
    #print "Frequency = $Frequency\n";
    
    read (OGG, my $bitrate_maximum, 4); # read 4 bytes
    $bitrate_maximum = unpack "L",$bitrate_maximum;
    #print "bitrate_maximum = $bitrate_maximum\n";
    
    read (OGG, $bitrate_nominal, 4); # read 4 bytes
    $bitrate_nominal = unpack "L",$bitrate_nominal;
    if ($bitrate_nominal <= 0){return $false;}
    #print "bitrate_nominal = $bitrate_nominal\n";
    
    read (OGG, my $bitrate_minimum, 4); # read 4 bytes
    $bitrate_minimum = unpack "L",$bitrate_minimum;
    #print "bitrate_minimum = $bitrate_minimum\n";
    
    read (OGG, my $blocksize, 1); # read 1 byte = 8 bits = (4 + 4) bits    
    
    $blocksize = unpack "B8",$blocksize;
    #print "blocksize = $blocksize \n";
 
    # "1 << x" is equal to "2 exponent to x = 2 ** x" valid for x=2^n, n=0,1,2,... .
    #my $exp0 = bin2dec(substr($blocksize, 4, 4));
    #my $exp1 = bin2dec(substr($blocksize, 0, 4));
    #my $blocksize_0 = 1 << $exp0; # read the first 4 bits    
    #my $blocksize_1 = 1 << $exp1; # read the last 4 bits 
    
    #print "exp0 = $exp0 ;; exp1 = $exp1 ;; blocksize_0 = $blocksize_0 ;; blocksize_1 = $blocksize_1\n";
    #if ($blocksize_0 < 8){return $false;}
    #if ($blocksize_1 < $blocksize_0){return $false;}       
    
    # See /usr/share/doc/libvorbis0-devel-1.1.0/Vorbis_I_spec.html
    # Seek for the last header complete:
    # -The granule position of the first pages containing only headers is zero.
    # -The granule position of pages containing Vorbis audio is in units of PCM audio samples (per channel; 
    #  a stereo stream's granule position does not increment at twice the speed of a mono stream).
    # -The granule position of a page represents the end PCM sample position of the last packet completed 
    #  on that page. A page that is entirely spanned by a single packet (that completes on a subsequent page) 
    #  has no granule position, and the granule position is set to '-1'.
    
    # To find the length of the file see http://wiki.xiph.org/VorbisStreamLength/
    # Seek for the first header containing Vorbis audio.
    
    my $firstGranulePosition = 0;
   
    my $header_type_flag = 0; 
    my $complete = 0; # init value
    $string = "";
    $byte = -1;   
    $myseek = sub {
		my $n = $_[0] || 4;   # read 4 bytes for one loop
		$byte += $_[1] || 1;  # advance 1 byte for one loop
		seek OGG, $byte, 0;
		read OGG, $string, $n;
    };
    # Search for the first header containing Vorbis audio ( $header_type_flag == 1 ).
    # This occur when $firstGranulePosition != 0
    while ( $complete <= 8 and $firstGranulePosition == 0 ){
       while ($string ne 'OggS') {
	   &$myseek(4,1);
	   if ($byte > 32*1024) { return $false; }
       }
       $string = "";
       $byte += 1;
       $complete += 1;
       
       read (OGG, my $stream_structure_version, 1);
       read (OGG, $header_type_flag, 1);
       # first page of logical bitstream (bos) when $header_type_flag = 3
       $header_type_flag = bin2dec(unpack "B8",$header_type_flag);
       
       read (OGG, $firstGranulePosition, 8); # 8 bytes = 64 bits
       $firstGranulePosition = unpack "L2",$firstGranulePosition;
       #print "firstGranulePosition = $firstGranulePosition; ";
       #print "header_type_flag = $header_type_flag ; complete = $complete ; byte = $byte\n";
       
       #read (OGG, my $stream_serial_number, 4); # 4 bytes
       #read (OGG, my $page_sequence_no, 4); # 4 bytes
       #$page_sequence_no = unpack "L",$page_sequence_no;
       #print "page_sequence_no = $page_sequence_no\n";
    }
    # remove the bytes of the first n headers without Vorbis audio.
    my $total_data_length = $fileSize - $byte + 1;
    
    $complete = 0;
    $string = "";
    $byte = 3;   
    $myseek = sub {
		my $n = $_[0] || 4;   # read 4 bytes for one loop
		$byte += $_[1] || 1;  # advance 1 byte for one loop
		seek OGG, -$byte, 2;  # Set FileHandle $byte bytes from the end of file 
		read OGG, $string, $n;
    };  
    # Search for the last header OggS containing Vorbis audio  
    while ( $complete <= 0 ){ # 0: last header OggS
       while ($string ne 'OggS') {
	   &$myseek(4,1);
	   if ($byte > 32*1024) { return $false; }
       }
       #print "complete = $complete ;; byte = $byte\n";
       $string = "";
       $byte += 1;
       $complete += 1;
    }   
    my $current_position = tell OGG; 
    #print "byte = $byte ;; current_position = $current_position\n";  	
    
    read (OGG, my $stream_structure_version, 1);
    $stream_structure_version = bin2dec(unpack "B8",$stream_structure_version);
    read (OGG, $header_type_flag, 1);
    # last page of logical bitstream (eos) when $header_type_flag = 5.
    $header_type_flag = bin2dec(unpack "B8",$header_type_flag);
    #print "header_type_flag = $header_type_flag\n";
    
    
    # 0x12 0x34 0x56 0x78     # big-endian 4 bytes
    # 0x78 0x56 0x34 0x12     # little-endian
    read (OGG, my $lastGranulePosition, 8); # 8 bytes = 64 bits
    $lastGranulePosition = unpack "L2",$lastGranulePosition;
    #print "lastGranulePosition = $lastGranulePosition\n";
    
    my $Total_Samples = $lastGranulePosition ; #  - $firstGranulePosition;
    if ($Total_Samples < 1){return $false;}
    
    my $totalSeconds = $Total_Samples / $Frequency;    
    $bitrate_original = ( $total_data_length * 8 ) / $totalSeconds;  
    #print "totalSeconds = $totalSeconds ;; Kbitrate_original = $bitrate_original ;; total_data_length = $total_data_length\n";  
    $totalSeconds = sprintf("%0.0f",$totalSeconds);    
    # convert x seconds to hour:min:sec format
    my ($hour,$min,$sec) = sec_to_time($totalSeconds);    # return ($hour,$min,$sec);
    
    $Frequency = sprintf("%.0f", $Frequency );           
    $mode_channel = $audio_channels;    
    $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ;
    $bitrate_original = sprintf("%.1f", $bitrate_original/1000 ); #Kbitrate
    $bitrate_nominal = sprintf("%.0f", $bitrate_nominal/1000 ); #Kbitrate
    $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes ; 2**10 = 1024
    #print "fileSize = $fileSize MB \n";    
       
    close(OGG);

   #$Technical_Info = "OGG Vorbis";
   $bitrate_average = $true;   
   
   # get all technical informations:
   # $metadata{technical_info}  = $Technical_Info; see 'sub read_vorbis_comment_tag'
   $metadata{bitrate}         = $bitrate_original;
   $metadata{bitrate_nominal} = $bitrate_nominal;  # only for ogg
   $metadata{bitrate_average} = $bitrate_average;  # $true or $false
   $metadata{frequency}       = $Frequency;  
   $metadata{mode}            = $mode_channel;
   $metadata{length}          = $Time_Min_Sec if ( $extension_input ne 'cda' );
   $metadata{fileSize}        = $fileSize;
    
    return $true;
    
#  See: file:///usr/share/doc/libvorbis0-devel-1.0.1/Vorbis_I_spec.html 

#       file:///usr/share/doc/libogg-1.1.2/framing.html
# byte value:                                         byte value:
#  0  0x4f 'O'  capture_pattern                        18  0xXX LSB          page sequence no
#  1  0x67 'g'                                         19  0xXX 
#  2  0x67 'g'                                         20  0xXX
#  3  0x53 'S'                                         21  0xXX MSB
#  4  0x00      stream_structure_version               22  0xXX LSB          page checksum 
#  5  bitflags  header_type_flag                       23  0xXX
#  6  0xXX LSB  absolute granule position              24  0xXX
#  7  0xXX                                             25  0xXX MSB
#  8  0xXX                                             26  0x00-0xff         page_segments
#  9  0xXX                                             27  0x00-0xff (0-255) segment_table (containing packet lacing values)
# 10  0xXX
# 11  0xXX
# 12  0xXX
# 13  0xXX MSB
# 14  0xXX LSB  stream serial number
# 15  0xXX
# 16  0xXX
# 17  0xXX MSB

# absolute granule position: The position specified is the total samples encoded. 

# 5  bitflags: 0x01: unset = fresh packet
#      	               set = continued packet
#	       0x02: unset = not first page of logical bitstream
#                      set = first page of logical bitstream (bos)
#	       0x04: unset = not last page of logical bitstream
#                      set = last page of logical bitstream (eos)

# A Vorbis bitstream begins with three header packets. The header packets are, in order, 
# the identification header, the comments header, and the setup header.

# Each header packet begins with the same header fields.
#    1) [packet_type] : 8 bit value = 1 byte
#    2) 0x76, 0x6f, 0x72, 0x62, 0x69, 0x73: the characters 'v','o','r','b','i','s' as six octets
# Identification header is type 1, the comment header type 3 and the setup header type 5 (these types 
# are all odd as a packet with a leading single bit of '0' is an audio packet). The packets must occur 
# in the order of identification, comment, setup.

#  Identification header (header_type = 1)        L: An unsigned long value (32 bits).
# 1) [vorbis_version] = read 32 bits as unsigned integer
# 2) [audio_channels] = read 8 bit integer as unsigned
# 3) [audio_sample_rate] = read 32 bits as unsigned integer
# 4) [bitrate_maximum] = read 32 bits as signed integer
# 5) [bitrate_nominal] = read 32 bits as signed integer
# 6) [bitrate_minimum] = read 32 bits as signed integer
# 7) [blocksize_0] = 2 exponent (read 4 bits as unsigned integer)
# 8) [blocksize_1] = 2 exponent (read 4 bits as unsigned integer)
# 9) [framing_flag] = read one bit

# The comment header (header_type = 3):
# The setup header (header_type = 5):

}

sub show_ogg_tag {
   my %args = ( @_ );
   my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath};
   return unless $extension_input eq 'ogg';
    
    open(VORBIS, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";
    binmode VORBIS;    
    
    # To find the second 'vorbis' that contain comment header (header_type = 3)
    # and the third 'vorbis' to get the size of comment header.
    my $header_type = 0;
    my $find_comment_header = $false;
    my $vorbis_comment_size = 0;
    my $loop = 0; # init value
    my $string = "";
    my $byte = -1;   
    my $myseek = sub {
		my $n = $_[0] || 6;   # read 6 bytes for one loop
		$byte += $_[1] || 1;  # advance 1 byte for one loop
		seek VORBIS, $byte, 0;
		read VORBIS, $string, $n;
    };
    while ( $loop <= 2 and  $header_type != 5 ){
       while ($string ne 'vorbis') {
	   &$myseek(6,1);
	   if ($byte > 8*1024) { return $false; }
       } 
       # The comment header (header_type = 3):
       seek VORBIS, $byte -1, 0;       # goes back one byte of string 'vorbis' to read [packet_type]      
       read (VORBIS, $header_type, 1); # read 1 byte      
       $header_type = bin2dec(unpack "B8",$header_type);
       #print "header_type = $header_type ;; byte = $byte ;; loop = $loop\n"; 
       
       # $header_type == 1 for the first 'vorbis' that contain Identification header vorbis
       if ($header_type == 3){ # header_type = 3 indicates comment header.
          $find_comment_header = $true;
	  $vorbis_comment_size = $byte; # get the start position of comment header
       }    
       $string = "";
       $byte += 1;
       $loop += 1;
    }
    if ($find_comment_header eq $false){return $false;}
    seek VORBIS, $vorbis_comment_size, 0;
    # remove 1 (because '$byte += 1;') and 1 (packet_type) and 6 (because 'vorbis')
    $vorbis_comment_size = ($byte - 1 - 1 - 6 ) - $vorbis_comment_size;
    if ($vorbis_comment_size <= 0){return $false;}
    #print "vorbis_comment_size = $vorbis_comment_size  \n";
    
    read (VORBIS, my $header, 6); # read + 6 bytes  for 'vorbis'
    #print "VORBIS = $header ;; header_type = $header_type\n";
    
    # read $vorbis_comment whose length is $vorbis_comment_size.
    read (VORBIS, my $vorbis_comment, $vorbis_comment_size );
    read_vorbis_comment_tag($vorbis_comment,$extension_input);
    #print "vorbis_comment = $vorbis_comment;;";

    close(VORBIS);
    return $true;
}


# only obtain info from ogg files
sub get_ogg_info_from_file { # not more used
   my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 
   my $Total_Track = ""; my $Genre=""; my $Frequency = 0; my $mode_channel = ""; my $Time_Min_Sec = ""; 
   my $bitrate_average = $true; my $bitrate_original = 160; my $fileSize = 0;

   my $ogginfo_path = '/usr/bin/ogginfo';

   if ($ogginfo_path eq "") {
       insert_msg("None informations about \"ogg\" format because can't find \"" , "black");
       insert_msg("ogginfo" , "red");
       insert_msg("\" in executable path.\n\n" , "black");
       return $false;
   }
   
   my $cmd; # command

   $cmd = "$ogginfo_path -v \"$directory/$file_ogg\" ";
	    
   my $res = open (OGGINFO, filename_from_unicode "$cmd 2>&1 |" ) ;
   
   ## pid process of ogginfo 
   if( !defined($res) ) {
	    $status_bar->push($context_id, " Could not find ogginfo!");
	    return $false;
   }
   
   $/="\r"; ## start of loop   
   while(<OGGINFO>){ 
               
            #New logical stream (#1, serial: 424f22ae): type vorbis
            #Vorbis headers parsed for stream 1, information follows...
            #Version: 0
            #Vendor: Xiph.Org libVorbis I 20030909 (1.0.1)
            #Channels: 2
            #Rate: 44100

            #Nominal bitrate: 112.001000 Kb/s        or  Nominal bitrate: 112,001000 Kb/s
            #Upper bitrate: 0.320000 Kb/s
            #Lower bitrate: 0.064000 Kb/s
            #User comments section follows...
            #        comment=gnormalize Fix value=30
            #        title=Vinheta do Capeta
            #        artist=Almir Sater
            #        genre=Folk
            #        date=1885
            #        album=Instrumental
            #        tracknumber=3
            #Vorbis stream 1:
            #        Total data length: 814983 bytes
            #        Playback length: 0m:56s
            #        Average bitrate: 115.015600 kbps
            #Logical stream 1 ended

            # discover if the bitrate of mp3 file is variable 

            if( $_ =~ /Channels?:\s+(\d+)\n/i ){ $mode_channel = $1;}
	    if( $_ =~ /Rate:\s+(\d+)\n/i ){ 
	              my $fq = sprintf("%0.0f", $1 );  
		      $Frequency = $fq; }
	    if( $_ =~ /Nominal\sbitrate:\s+(\d+[\.,]\d+)\s.*\n/i ){ 
		      my $br = sprintf("%0.0f",number_value($1) );
		      $br = number_value($br);
		      #print (" br = $br ;; 1 = $1\n");
		      $bitrate_original = $br; }
	    if( $_ =~ /\s+Playback\slength:\s+(.*)\n/i ){ $Time_Min_Sec = $1 ; }
	    $Time_Min_Sec =~ s/[hms]//ig;
	    if( $_ =~ /\s+genre=(.*)\n/i ) { $Genre = $1 ;  }
	    if( $_ =~ /\s+title=(.*)\n/i ) { $Title = $1 ;  } 
	    if( $_ =~ /\s+artist=(.*)\n/i ){ $Artist = $1 ; } 
	    if( $_ =~ /\s+album=(.*)\n/i ) { $Album = $1 ;  } 
	    if( $_ =~ /\s+(date|year)=(.*)\n/i ){ $Year = $2 ; }
	    if( $_ =~ /\s+tracknumber=\s*(\d+)\/?(\d+)?\n/i ){ $Track_Number = $1 ;   }
	    if( $_ =~ /\s+tracknumber=\s*(\d+)\/(\d+)\n/i ){ $Total_Track = $2 }	    
	    if( $_ =~ /\s+comment=(.*)\n/i ){ $Comment = $1 ;  }
	    $Technical_Info = "OGG Vorbis"; 
	    $bitrate_average = $true; 
   }
   $/="\n"; ## final of loop
   close(OGGINFO);
}

sub show_wav_info {
   my %args = ( @_ );
   my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath};
   return unless $extension_input eq 'wav';

    my $header; 
    my $buffer;
    
    use constant WAVHEADERFLAG => 'RIFF';
    
    open(WAV, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";
    
    binmode WAV;

    $fileSize = -s filename_from_unicode $filepath;  # $fileSize = $FileLength + 8 = $DataLength + 44
    #print "fileSize = $fileSize\n";
    
    # Read WAV header.
    read (WAV, $header, 4); # 4 byte for 'RIFF'

    if ($header ne WAVHEADERFLAG) { return $false; }
    
    read (WAV, my $FileLength, 4); # read 4 bytes = 32 bits
    $FileLength = unpack "L",$FileLength;
    #print "FileLength = $FileLength\n";  # $FileLength = $DataLength + 36
        
    read (WAV, my $FormatTag, 8); # read 8 bytes     
    #print "FormatTag = $FormatTag\n";
    if ($FormatTag ne 'WAVEfmt '){ return $false;}
    
    read (WAV, my $FormatLength, 4); # read 4 bytes = 32 bits
    $FormatLength = unpack "L",$FormatLength;
    #print "FormatLength = $FormatLength\n";
    
    read (WAV, my $DataFormat, 2); # read 2 byte = 16 bits
    
    read (WAV, my $Channels, 2); # read 2 byte = 16 bits
    $Channels = unpack "S",$Channels; # 00000010 00000000
    #$Channels = ( bin2dec(unpack "B16",$Channels) ) >> 8 ;  
    #$Channels =  bin2dec( substr ( (unpack "B16",$Channels) , 0 , 8 ) ) ;   
    #print "NumChannels = $Channels\n";
        
    read (WAV, $Frequency, 4); # read 4 bytes
    $Frequency = unpack "L",$Frequency;
    #print "Frequency = $Frequency\n";
    $Frequency = sprintf("%.0f", $Frequency ); #Kbitrate
    
    read (WAV, my $BytesPerSecond, 4); # read 4 bytes
    $BytesPerSecond = unpack "L",$BytesPerSecond;
    #print "BytesPerSecond = $BytesPerSecond\n";
    $bitrate_original = sprintf("%.1f", ($BytesPerSecond * 8)/1000 ); #Kbitrate
    
    read (WAV, my $BlockAlignment, 2); # read 2 byte = 16 bits
    
    read (WAV, my $BitsPerSample, 2); # read 2 byte = 16 bits
    $BitsPerSample = unpack "S",$BitsPerSample; # Sample Size
    
    $mode_channel = "$Channels\n($BitsPerSample bits)";
    
    read (WAV, my $char, 4); # read 4 bytes     
    #print "char = $char\n";
    if ($char ne 'data'){ return $false;}
    
    read (WAV, my $DataLength, 4); # read 4 bytes
    $DataLength = unpack "L",$DataLength;
    # 2352 = bytes per frame, "raw" mode ;; 1 sec have 75 frames = 75 * 2352 bytes = 176400 bytes
    #print "DataLength = $DataLength\n";
    
    my $totalSeconds = int($DataLength / $BytesPerSecond) ;  
    #my $totalSeconds2 = sprintf("%0.3f",$DataLength / $BytesPerSecond); print "\n\$totalSeconds2 = $totalSeconds2 \n";
         
    # convert x seconds to hour:min:sec format
    my ($hour,$min,$sec) = sec_to_time($totalSeconds);    # return ($hour,$min,$sec);
    $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ;
    $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes ; 2**10 = 1024
    
   $Technical_Info = "WAV";
   $encode = 'average';
   $bitrate_average = $true;   
   
   # get all technical informations:
   $metadata{technical_info}  = $Technical_Info;
   $metadata{bitrate}         = $bitrate_original;
   $metadata{bitrate_nominal} = 160;               # only for ogg
   $metadata{bitrate_average} = $bitrate_average;  # $true or $false
   $metadata{frequency}       = $Frequency;  
   $metadata{mode}            = $mode_channel;
   $metadata{length}          = $Time_Min_Sec if ( $extension_input ne 'cda' );
   $metadata{fileSize}        = $fileSize;

# See Linux::CDROM::Cookbook and http://www.sonicspot.com/guide/wavefiles.html
# ------------ WAV header ----------- #
# total size = 44 bytes
#struct {
#   char        RiffTag[4]; 	// 'RIFF'
#   int32_t     FileLength;     //  Filesize - 8
#   char	FormatTag[8];	// 'WAVEfmt '
#   int32_t	FormatLength;	// 16 for PCM
#   int16_t	DataFormat;     // Compression Code: (1) for PCM/uncompressed raw sample values ;; (2) for Microsoft ADPCM ; ...
#   int16_t	NumChannels;    // Mono = 1, Stereo = 2 etc.
#   int32_t	SampleRate;     // 8000, 44100 etc.
#   int32_t	BytesPerSecond; // == SampleRate * BlockAlignment
#   int16_t	BlockAlignment; // == NumChannels * BitsPerSample/8
#   int16_t	BitsPerSample;  // 8 bits, 16 bits, ... This value specifies the number of bits used to define each sample.
#   char	DataTag[4];	// 'data'
#   int32_t	DataLength;     // == NumSamples * NumChannels * BitsPerSample/8. This is the number of bytes in the data.
#} header = {
#            "RIFF", 0, "WAVEfmt ",
#            16, 1, 2, 44100, 176400, 4, 16,
#            "data", 0
#};    
# ------------ WAV header ----------- #

# $totalSeconds = $DataLength / $BytesPerSecond;
# $totalSamples = $Frequency * $totalSeconds;

}


sub read_ID3v1_mp3_tag { # not used
    my $fname = shift;
    my $filepath = $directory."/".$fname; 
    my $buffer;
    
    my ($title, $artist, $album, $year, $comment, $tracknum, $genre);    

    if ($filepath !~ /\.mp3$/i) { return $false;}
    
    open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";
    
    binmode IN;
    $fileSize = -s filename_from_unicode $filepath;    
    
    seek(IN,-128, 2);  # Set FileHandle 128 byte from the end of file 
    read(IN, $buffer, 128, 0); # read 128 byte to $buffer
	  
    my $preamble = substr($buffer,0,3); # read 3 byte 
    return unless $preamble eq 'TAG';
    $buffer = substr($buffer, 3);  # remove 3 byte
    
    $tracknum = unpack "C", substr($buffer, 123, 1);
    
    # get TAG to variables
    if ( defined($tracknum) ){
           ( $title, $artist, $album, $year, $comment, $tracknum, $genre ) = unpack "a30a30a30a4a28xCC", $buffer;}
    else { ( $title, $artist, $album, $year, $comment, $genre )            = unpack "a30a30a30a4a30C", $buffer;
             $tracknum = "";
    }    
    print "title = $title ;; artist = $artist ;; album = $album ;; year = $year  ;; comment = $comment \n"; 
    print "track number = $tracknum ;; genre = $genre ;; fileSize = $fileSize\n";  
    return ($title, $artist, $album, $year, $comment, $tracknum, $genre);   
}

sub save_ID3v1_mp3_tag { 
    my ( $filepath, $title, $artist, $album, $year, $comment, $tracknum, $genre) = @_;        
    my $buffer; my $ID3v1 = "";
    
 
    # see 'sub eval_to_unicode'
    $filepath = filename_from_unicode $filepath;         # convert filename_from_unicode to local encoding
    #if( ! -e $filepath ) { $filepath = $files_info[$row]{filepath_local}; }   # get original filename encoding
         
	     
    
    my $char = $id3tag_character; # encode could be 'iso-8859-1' or 'utf8'.
    
    $genre = get_genre_number($genre) || '12'; # 12 Other : default	
    #print "genre_number = $genre_number ;; Genre = $Genre\n";
    
    $title = encode($char,$title);  $artist  = encode($char,$artist);
    $album = encode($char,$album);  $comment = encode($char,$comment);
    $genre = encode($char,$genre);
    if ( not ($year =~ /^\d+$/ or $year eq "") ){return;}
    
    # See 'man perlopentut' for "+<" to specify both read and write access
    #open(IN, '+<', filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";
    open(IN, '+<', $filepath ) || die "Can't open <$filepath>: $!, stopped";
    
    binmode IN;        
    seek(IN,-128, 2);          # Set FileHandle 128 byte from the end of filepath 
    read(IN, $buffer, 128, 0); # read 128 byte to $buffer
	  
    my $preamble = substr($buffer,0,3); # read 3 byte
    if ( $preamble ne 'TAG' ){ seek(IN, 0, 2); } # go to the end of filepath
    else{ seek(IN,-128, 2);} #overwrite, clobber
    
    # save TAG to filepath, overwrite if it exist
    if ( $tracknum =~ /^\d+$/ ) {
                $tracknum = $tracknum > 255 ? 255 : $tracknum; # must be an integer from 1 and 255
		$ID3v1 = pack "a3a30a30a30a4a28xCC", 'TAG', $title, $artist, $album, $year, $comment, $tracknum, $genre; }
    else {
		$ID3v1 = pack "a3a30a30a30a4a30C", 'TAG', $title, $artist, $album, $year, $comment, $genre;
    } 
    syswrite ( IN, $ID3v1, 128 ); 
    close(IN);
}


sub read_Xing_mp3_tag { # Not used
    my $fname = shift;
    my $filepath = $directory."/".$fname;  
    my $buffer;
    my $off = -1; my $byte = "" ; my $try_harder = 4096;
    my $frames = 0;  $fileSize = 0; 

    if ($filepath !~ /\.mp3$/i) { return $false;}
    
    open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";
    
    binmode IN;  
    
    # check first three bytes for 'ID3'
    seek IN, 0, 0;
    read IN, $buffer, 3;
    
    if ($buffer eq 'ID3'){    
       # get ID3v2 tag length from bytes 7-10
       my $tag_size = 10;	# include ID3v2 header size
       seek IN, 6, 0;
       read IN, $buffer, 4;
       $tag_size += ID3_GET_SIZE28($buffer);  
       print "tagsize = $tag_size\n";       
       $off = $tag_size;
    }   
    # For Xing headers, see "http://home.pcisys.net/~melanson/codecs/mp3extensions.txt"
    # Xing headers are often added to VBR (variable bit rate) MP3   

    my $myseek = sub {
		my $n = $_[0] || 4;  # read 4 bytes for one loop
		$off += $_[1] || 1;  # advance 1 byte for one loop
		seek IN, $off, 0;
		read IN, $byte, $n;
    };
    while ($byte ne 'Xing') {
		&$myseek;
		if ($off > $try_harder) { return $false; }
		#print "byte = $byte ;; off = $off\n";
    }    	    
    print "preamble_xing = $byte ;; off = $off\n";
        
    &$myseek(4,4);
    my $flags = unpack_head($byte);
    
    if ($flags & 1) {
		&$myseek(4,4);
		$frames = unpack_head($byte);
    }
    if ($flags & 2) {
		&$myseek(4,4);
		$fileSize = unpack_head($byte);
    }
    
    print "frames = $frames ;; fileSize = $fileSize\n";
    $Frequency = 48000;
    
    my $timePerFrame = 32*36;  #32*36 = 1152
    my $totalSamples = $frames * $timePerFrame;
    my $totalSeconds = $totalSamples/$Frequency;
    my $bitrate = 8 * $fileSize / $totalSeconds; # 8*$filesize = size in bit
    
    $totalSeconds = sprintf("%0.0f",$totalSeconds);    
    # convert x seconds to hour:min:sec format
    my ($hour,$min,$sec) = sec_to_time($totalSeconds);    # return ($hour,$min,$sec);    
    
    $bitrate = sprintf("%0.0f",$bitrate/1000);
    print "Kbitrate = $bitrate ;; time = $hour:$min:$sec ;; totalSeconds = $totalSeconds\n";           
    
   return $true;   
}

# from MPEG::MP3Info
sub unpack_head { unpack('l', pack('L', unpack('N', $_[0]))); }

# from MP3::Info
sub read_mp3_info_tag {
   my %args = ( @_ );
   my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath};
   return unless $extension_input eq 'mp3';
   
   my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 
   my $Total_Track = ""; my $Genre=""; my $Frequency = 0; my $mode_channel = ""; my $Time_Min_Sec = ""; 
   my $bitrate_average = $true; my $bitrate_original = 160; my $fileSize = 0;
    
    $filepath = filename_from_unicode $filepath;

    # see 'sub eval_to_unicode'
    #my $filepath = filename_from_unicode $files_info[$row]{filepath};         # convert filename_from_unicode to local encoding
    #if( ! -e $filepath ) { $filepath = $files_info[$row]{filepath_local}; }   # get original filename encoding
    #$filepath = eval_from_unicode( row => $row , filepath => $args{filepath} );    
  

    
    ## MP3::Info - Copyright (c) 1998-2005 Chris Nandor.
    my $mp3;
    
    if ( $use_external_MP3Info  ) {               # use external MP3::Info
       $mp3 = MP3::Info->new($filepath);         
       get_mp3tag($filepath);
       get_mp3info ($filepath);                          # The conversion to unicode will be made bellow.
       use_mp3_utf8($false);                         # Force MP3::Info to NOT return TAG info in UTF-8.
    }
    else {                                        # use internal MP3::Info
       $mp3 = MP3::Info::Internal->new($filepath);
       MP3::Info::Internal::get_mp3tag($filepath);
       MP3::Info::Internal::get_mp3info ($filepath);
       MP3::Info::Internal::use_mp3_utf8($false);    # Force MP3::Info to NOT return TAG info in UTF-8.
       MP3::Info::Internal::use_winamp_genres();
    }    
    
    # eval : see <man perlfunc>
    eval { $mp3->title;   }; if ($@){warn "\n$filepath: $@";} else{$Title = $mp3->title   if (defined $mp3->title);}              
    eval { $mp3->artist;  }; unless ($@){$Artist  = $mp3->artist  if (defined $mp3->artist);}
    eval { $mp3->album;   }; unless ($@){$Album   = $mp3->album   if (defined $mp3->album);}
    eval { $mp3->year;    }; unless ($@){$Year    = $mp3->year    if (defined $mp3->year);}
    eval { $mp3->comment; }; unless ($@){$Comment = $mp3->comment if (defined $mp3->comment);}
    eval { $mp3->genre;   }; unless ($@){$Genre   = $mp3->genre   if (defined $mp3->genre);}       
    eval { $mp3->tracknum;}; unless ($@){$Track_Number = $mp3->tracknum if (defined $mp3->tracknum);}
    
    
    # %tag_v2 is a hash with id3v2 mp3 tag
    my $tag_v2 = get_mp3tag($filepath, 2, 2) if $use_external_MP3Info; # get_mp3tag (FILE, tag VERSION, RAW_V2)
    #for (sort keys %$tag_v2){
    #   next unless (defined $tag_v2->{$_} and defined $MP3::Info::v2_tag_names{$_});
    #   printf "=== %4s (%s): %s\n", $_, $MP3::Info::v2_tag_names{$_}, $tag_v2->{$_};
    #   $metadata{$_} = "$tag_v2->{$_}";
    #}   
    # %metadata is a hash with metadata (tag) and technical information 
    # "\0XXX\0Some Lyrics\0" such that XXX is the Language ( print chr($Lyric) ); and remove the last NULL(s).         
    ($metadata{'Lyrics'}    = "$tag_v2->{'USLT'}") =~ s/\0+$// if (defined $tag_v2->{'USLT'});
    $metadata{'Encoded by'} = "$tag_v2->{'TENC'}"              if (defined $tag_v2->{'TENC'});
    $metadata{'Composer'}   = "$tag_v2->{'TCOM'}"              if (defined $tag_v2->{'TCOM'});    
    $metadata{'Length'}     = "$tag_v2->{'TLEN'}"              if (defined $tag_v2->{'TLEN'});
    
        
    if( $Track_Number =~ /(\d+)\/(\d+)/ ){ $Track_Number = $1 ; $Total_Track = $2 ; }    
    
    if ($Genre =~ /(\d+)/){ $Genre = $1; }   # if <genre = name (number)> --> get <genre = number>
        
    # if $Genre is a number, get its reference name
    if ($Genre =~ /^\d+$/){ $Genre = $genre_hash{"$Genre"}; }  # $genre_hash{"32"}
       
    #($Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Genre) = read_ID3v1_mp3_tag($file_mp3);
    
    eval { $bitrate_average = $mp3->vbr; }; unless ($@){$bitrate_average = $mp3->vbr if (defined $mp3->vbr); } 
    eval { $Frequency = $mp3->frequency; }; unless ($@){$Frequency = $mp3->frequency if (defined $mp3->frequency); }            
    $Frequency = sprintf("%.0f", 1000*$Frequency ); 
    if ($Frequency < 1000){warn "\nCould not read the Frequency from file: $filepath";}
    
    my @channel_mode = ('stereo','joint stereo','dual channels','mono');  # mono = single channel
    my $mode = 0;          # (0 = stereo, 1 = joint stereo, 2 = dual channel, 3 = single channel)
    eval { $mode = $mp3->mode; };
    $mode_channel = $@ ? print "Error!" : $channel_mode[$mode];
    
    eval { $mp3->time; };    unless ($@){$Time_Min_Sec = $mp3->time if (defined $mp3->time);}
    eval { $mp3->bitrate; }; unless ($@){$bitrate_original = $mp3->bitrate if (defined $mp3->bitrate);}  
    
    $fileSize = -s $filepath;
    $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes
    
    my $version = ""; my $layer = " Error";
    eval { $version = $mp3->version  }; unless ($@){$version = $mp3->version if (defined $mp3->version);}
    eval { $layer   = $mp3->layer    }; unless ($@){$layer = $mp3->layer if (defined $mp3->layer);}   
    
   # Must convert all input data to unicode.
   if (1){
      foreach ( $Title, $Artist, $Album, $Comment, $Genre, $Year, $Track_Number, $Total_Track, 
              $metadata{'Lyrics'}, $metadata{'Encoded by'}, $metadata{'Composer'}, $metadata{'Length'} ){
             
         if ( not utf8::is_utf8($_) and defined $_ and $_ ne "" ) {
            #print "Is not utf8: \"$_\".\n";
            eval { $_ = filename_to_unicode $_; } ; # convert to unicode and remove Wide character         
         }       
         #if ( utf8::is_utf8($_) and defined $_ and $_ ne "" ) { print "Is utf8: \"$_\".\n"; }
      }
   }        
    
    $Technical_Info = "MPEG$version/layer$layer";
    
    $Track_Number = remove_change_10_chars($Track_Number);
    $Total_Track  = remove_change_10_chars($Total_Track);             
    
   # get all the 8 tags  
   $metadata{title}   = remove_change_10_chars($Title); 
   $metadata{artist}  = remove_change_10_chars($Artist);
   $metadata{album}   = remove_change_10_chars($Album);
   $metadata{comment} = remove_change_10_chars($Comment);
   $metadata{genre}   = remove_change_10_chars($Genre); 
   $metadata{track}       = $Track_Number =~ /^\d+$/ ? sprintf("%02d", $Track_Number ) : "" ; # "%02d": leading zero
   $metadata{total_track} = $Total_Track  =~ /^\d+$/ ? sprintf("%02d", $Total_Track  ) : "" ;  
   $metadata{year}        = $Year =~ /^\d{1,4}$/ ? sprintf("%04d", $Year ) : "" ;   
   
   # get all 7 technical informations:
   $metadata{technical_info}  = $Technical_Info;
   $metadata{bitrate}         = $bitrate_original;
   #$metadata{bitrate_nominal} = 160;              # only for ogg
   $metadata{bitrate_average} = $bitrate_average;  # $true or $false
   $metadata{frequency}       = $Frequency;  
   $metadata{mode}            = $mode_channel;
   $metadata{length}          = $Time_Min_Sec if ( $extension_input ne 'cda' );
   $metadata{fileSize}        = $fileSize;  
   
   #print "\n read_mp3_info_tag --> \$bitrate_average = $bitrate_average\n";
}

sub get_mp4_info_from_file {
   my %args = ( @_ );
   my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath};     
   return unless $extension_input eq 'mp4';
   
   my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 
   my $Total_Track = ""; my $Genre=""; my $Frequency = 0; my $mode_channel = ""; my $Time_Min_Sec = ""; 
   my $bitrate_average = $true; my $bitrate_original = 160; my $fileSize = 0;

   if ($faad_path eq "") {
       insert_msg("None informations about \"mp4\" format because can't find \"" , "black");
       insert_msg("faad" , "red");
       insert_msg("\" in executable path.\n\n" , "black");
       return $false;
   }
   my $totalSeconds = 0;
   $bitrate_original = 0;
   $bitrate_average = $true;
       
   $fileSize  = -s filename_from_unicode $filepath;
   
   (my $filepath2  = $filepath ) =~ s/"/\\"/g;  # change all " characters by \"	
   # Use 'filename_from_unicode' to convert from unicode to local encoding.
   $filepath2  = filename_from_unicode $filepath2;			
   _utf8_on($filepath2);  # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'.
   
   my $cmd = "$faad_path -i \"$filepath2\" ";   
	    
   my $res = open (INFO, "$cmd 2>&1 |" ) or die "Can't get info $cmd: $!";
  
   while(<INFO>){ 
            # LC AAC  106.939 secs, 2 ch, 44100 Hz   
            # or 'MAIN AAC        114.966 secs, 2 ch, 44100 Hz'
	    # or  'ADTS, 315.815 sec, 125 kbps, 44100 Hz' for AAC format

            #tool: FAAC 1.24 beta (Jun  8 2004) UNSTABLE
            #artist: Johann Sebastian Bach nome bem grando mximo teste
            #title: Prelude (Suite n.1)  
            #album: Suites para violoncelo n.1 e n.2
            #track: 3
            #totaltracks: 12
            #date: 2005
            #genre: Bossa Nova
            #comment: gnormalize Fix value=30
            
	    if( $_ =~ /AAC\s+(\d+[\.,]\d+)\ssecs?,\s(\d+)\sch,\s+(\d+)\sHz\n/i ){ 
	       $Time_Min_Sec = $1; # total seconds   	       
	       $mode_channel = $2;
	       my $fq = sprintf("%.0f", $3 );  
	       $Frequency = $fq;
	       $Technical_Info = "MPEG4 MP4/M4A"; 
	    }
	    if( $_ =~ /ADTS,\s+(\d+[\.,]\d+)\ssecs?,\s(\d+)\skbps,\s+(\d+)\sHz\n/i ){ 
	       $Time_Min_Sec = $1; # total seconds  
	       $bitrate_original = $2;
	       $mode_channel = '2';
	       my $fq = sprintf("%.0f", $3 );  
	       $Frequency = $fq;
	       $Technical_Info = "MPEG2 AAC";
	    }
	    if( $_ =~ /^artist:\s+(.*)$/mi ){ $Artist = $1 ; } # //m: '.' matches any character except "\n". See <man perlretut>
	    if( $_ =~ /^title:\s+(.*)$/mi  ){ $Title  = $1 ; }
	    if( $_ =~ /^album:\s+(.*)$/mi  ){ $Album  = $1 ; } 
	    if( $_ =~ /^track:\s+(\d+)$/mi ){ $Track_Number = $1 ; }
	    if( $_ =~ /^totaltracks:\s+(\d+)$/mi ){ $Total_Track = $1 }	
	    if( $_ =~ /^(date|year):\s+(\d+)$/mi ){ $Year = $2 ; }
	    if( $_ =~ /^genre:\s+(.*)$/mi   ){ $Genre   = $1 ; }    
	    if( $_ =~ /^comment:\s+(.*)$/mi ){ $Comment = $1 ; } 
   }
   close(INFO);
      
   my $bitrate = ($Time_Min_Sec <= 0) ? 0 :  ($fileSize * 8) / ($Time_Min_Sec * 1000);
   $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes  
   $bitrate_original = ($bitrate_original > 0) ? $bitrate_original : $bitrate; 
   $bitrate_original = sprintf("%.0f",$bitrate_original); 
   
   my $TotalSeconds = sprintf("%.0f",$Time_Min_Sec); 
   my ($hour,$min,$sec) = sec_to_time($TotalSeconds);    # return ($hour,$min,$sec);
   $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ;
   
   
   # Must convert all input data to unicode.
   if (1){
      foreach ( $Title, $Artist, $Album, $Comment, $Genre, $Year, $Track_Number, $Total_Track ){
             
         if ( not utf8::is_utf8($_) and defined $_ and $_ ne "" ) {
            #print "Is not utf8: \"$_\".\n";
            eval { $_ = filename_to_unicode $_; } ; # convert to unicode and remove Wide character         
         }       
         #if ( utf8::is_utf8($_) and defined $_ and $_ ne "" ) { print "Is utf8: \"$_\".\n"; }
      }
   }     
   
   $Track_Number = remove_change_10_chars($Track_Number);
   $Total_Track  = remove_change_10_chars($Total_Track);
   
   # get all the 8 tags  
   $metadata{title}   = remove_change_10_chars($Title);
   $metadata{artist}  = remove_change_10_chars($Artist);
   $metadata{album}   = remove_change_10_chars($Album);
   $metadata{comment} = remove_change_10_chars($Comment);
   $metadata{genre}   = remove_change_10_chars($Genre);
   $metadata{track}       = $Track_Number =~ /^\d+$/     ? sprintf("%02d", $Track_Number ) : "" ; # "%02d": leading zero
   $metadata{total_track} = $Total_Track  =~ /^\d+$/     ? sprintf("%02d", $Total_Track  ) : "" ;  
   $metadata{year}        = $Year         =~ /^\d{1,4}$/ ? sprintf("%04d", $Year         ) : "" ;   
   
   # get all technical informations:
   $metadata{technical_info}  = $Technical_Info;
   $metadata{bitrate}         = $bitrate_original;
   $metadata{bitrate_nominal} = 160;               # only for ogg
   $metadata{bitrate_average} = $bitrate_average;  # $true or $false
   $metadata{frequency}       = $Frequency;  
   $metadata{mode}            = $mode_channel;
   $metadata{length}          = $Time_Min_Sec if ( $extension_input ne 'cda' );
   $metadata{fileSize}        = $fileSize;
}

$buffer->create_tag ("id3tag",      'foreground' => 'blue',    # see <man Gtk2::TextTag> for more options
                                     'background' => '#B8D3C1', # #B8D3C1 = 184 211 193 (RGB)
                                  'justification' => 'center',
                                      left_margin => 0,
				            style => 'normal',
				        wrap_mode => 'word',
					    scale => '1',
					   family => 'Courier',
					  # family => 'Terminal',
				          # family => 'Fixed',
                                    'size-points' => '11');


sub save_ID3v2_mp3_tag { 
    my ( $filepath, $title, $artist, $album, $year, $comment, $track, $Total_Track, $genre) = @_;        
    my $tmpfile; my $copy; my $ID3v2 = ""; 
    my $buf_size = 2048*1024;       # the bigger the faster  
    my $need_rewrite_file = $false; # to avoid rewriting the entire file
    
    use constant MP3HEADERFLAG => 'ID3';
    
    my $unsync = 0; my $ext_header = 0; my $experimental = 0; my $footer = 0;
    # Masks for TAGS FLAGS
    use constant ID3FLAG_USYNC => '10000000'; # Unsynchronisation       - (10000000) binary (bite 7) (the first bit)
    use constant ID3FLAG_EXT   => '01000000'; # Extended header         - (01000000) binary (bite 6) (the second bit) 
    use constant ID3FLAG_EXP   => '00100000'; # Experimental indicator  - (00100000) binary (bite 5) (the third bit)
    use constant ID3FLAG_FOOT  => '00010000'; # Footer present          - (00010000) binary (bite 4)
    
    if ( $Total_Track ne "" and $Total_Track =~ /^\d+$/ and $Total_Track >= $track ){ $track = $track."/".$Total_Track; }
    
    #my $genre_number = get_genre_number($genre);	
    # $genre .= " [$genre_number]" if (defined $genre_number);           
    
    my $enc_title   = $title;    
    my $enc_artist  = $artist;   
    my $enc_album   = $album;   
    my $enc_comment = $comment;
    my $enc_genre   = $genre;    
    my $enc_track   = $track;    
    my $enc_year    = $year;
    
    my $enc_Encoded  = $metadata{'Encoded by'} if ($metadata{'Encoded by'});
    my $enc_Lyrics   = $metadata{'Lyrics'}     if ($metadata{'Lyrics'});
    my $enc_Composer = $metadata{'Composer'}   if ($metadata{'Composer'});
    my $enc_Length   = $metadata{'Length'}     if ($metadata{'Length'});
    
    my $char = $id3tag_character; # encode could be 'iso-8859-1' or 'utf8'.
    
    if ( 1 ) {
    
       $enc_title   = encode($char,$title);    
       $enc_artist  = encode($char,$artist);   
       $enc_album   = encode($char,$album);   
       $enc_comment = encode($char,$comment);
       $enc_genre   = encode($char,$genre);    
       $enc_track   = encode($char,$track);    
       $enc_year    = encode($char,$year);
    
       $enc_Encoded  = encode($char,$metadata{'Encoded by'}) if ($metadata{'Encoded by'});
       $enc_Lyrics   = encode($char,$metadata{'Lyrics'})     if ($metadata{'Lyrics'});
       $enc_Composer = encode($char,$metadata{'Composer'})   if ($metadata{'Composer'});
       $enc_Length   = encode($char,$metadata{'Length'})     if ($metadata{'Length'});    
    }    
     
    my $sz_tit = length($enc_title); # get size in byte
    my $sz_art = length($enc_artist);
    my $sz_alb = length($enc_album);
    my $sz_com = length($enc_comment);
    my $sz_gen = length($enc_genre);
    my $sz_tra = length($enc_track);
    my $sz_yea = length($enc_year); 
    
    my $sz_enc = length($enc_Encoded)   if ($metadata{'Encoded by'});        
    my $sz_lyr = length($enc_Lyrics)    if ($metadata{'Lyrics'});
    my $sz_cps = length($enc_Composer)  if ($metadata{'Composer'});   
    my $sz_len = length($enc_Length)    if ($metadata{'Length'});    
	    
    my $tagSize = 0;	    
    do { 
         use bytes; 
	 if ($year         ne ""){ $tagSize += 10 + 1 + $sz_yea;         }   # More 10 (= header frame size) + 1 null  
	 if ($track        ne ""){ $tagSize += 11 + $sz_tra;             }
         if ($genre        ne ""){ $tagSize += 11 + $sz_gen;             }	 
	 if ($artist       ne ""){ $tagSize += 11 + $sz_art;             }
	 if ($album        ne ""){ $tagSize += 11 + $sz_alb;             }
	 if ($title        ne ""){ $tagSize += 11 + $sz_tit;             }
	 if ($metadata{'Encoded by'}){ $tagSize += 11 + $sz_enc;             }
	 if ($metadata{'Composer'}  ){ $tagSize += 11 + $sz_cps;             }
	 if ($metadata{'Length'}    ){ $tagSize += 11 + $sz_len;             }
	 if ($comment  ne ""        ){ $tagSize += 10 + 1 + 3 + 1 + $sz_com; }   # 5 for <nul>XXX<nul>$comment, Language = 'XXX'
	 if ($metadata{'Lyrics'}    ){ $tagSize += 10 + 1 + 3 + 1 + $sz_lyr; }   # 5 for <nul>XXX<nul>$Lyric, such that Language = 'XXX'
    };
    
    # 4.11.   Comments (see id3v2.3.0.txt)
    # <Header for 'Comment', ID: "COMM">
    # Text encoding          $xx
    # Language               $xx xx xx
    # Short content descrip. <text string according to encoding> $00 (00)
    #  The actual text        <full text string according to encoding>
        
    # ID3v2.3.0 tags:
    #	'TIT2' => 'TITLE'    ;; 'TPE1' => 'ARTIST',
    #   'TALB' => 'ALBUM'    ;; 'TYER' => 'YEAR',
    #	'COMM' => 'COMMENT'  ;; 'TRCK' => 'TRACKNUM',
    # 	'TCON' => 'GENRE'    ;; 'USLT' => 'Unsychronized lyric/text transcription'
    #    TENC Encoded by 
    #    TSSE Software/Hardware and settings used for encoding
    #    TLEN Length - The 'Length' frame contains the length of the audiofile in milliseconds,
    #    TDAT Date   - The 'Date' frame is a numeric string in the DDMM format containing the date for the recording.
    
    # see <man perlopentut>
    open(FILE, '+<', filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";   
    
    binmode FILE;        
    seek(FILE, 0 , 0);  
    
    read FILE, my $header, 3;  
    if ( $header ne MP3HEADERFLAG ){ $need_rewrite_file = $true; } 
    
    read FILE, my $bytes, 2; 
    my ($major_version, $minor_version) = unpack 'c c', $bytes;
    # print " verso ID3v2.$major_version.$minor_version\n";
    
    read FILE, my $flag, 1; # flag has 1 byte = 8 bits
    my @bits = split //, unpack 'b8', $flag;
    if ($major_version >= 3) { # for ID3v2.3 or ID3v2.4 ...
		$unsync       = $bits[7];   # my $buffer = unpack 'b8', $flag;  $unsync = substr($buffer, 7, 1);
		$ext_header   = $bits[6];
		$experimental = $bits[5];
		$footer       = $bits[4] if $major_version == 4;
    }
    #print "unsync = $unsync ;; ext_head = $ext_header;; exp = $experimental;; footer = $footer \n";
    
    read FILE, my $original_sz, 4;   
    $original_sz = $need_rewrite_file ? 512 : ID3_GET_SIZE28($original_sz); # if don't have ID3 tag
    #print "original size = $original_sz ;; tagSize = $tagSize\n";        
    
#    Overall tag ID3v2.4.0 - version structure:

#     +-----------------------------+
#     |      Header (10 bytes)      |
#     +-----------------------------+
#     |       Extended Header       |
#     | (variable length, OPTIONAL) |
#     +-----------------------------+  The size is excluding the frame header ('total frame size' - 10 bytes)
#     |   Frames (variable length)  |  and stored as a 32 bit synchsafe integer only if version >= ID3v2.4.0
#     +-----------------------------+
#     |           Padding           |  Use padding where possible to avoid rewriting the entire
#     | (variable length, OPTIONAL) |  file if the metadata size changes. Paddings are null bytes.
#     +-----------------------------+
#     | Footer (10 bytes, OPTIONAL) |  Padding and a footer together are not allowed by the specifications.  
#     +-----------------------------+

#  ID3v2 header  - The ID3v2 tag header, which should be the first information in the file, is 10 bytes as follows:
#     ID3v2/file identifier      "ID3"
#     ID3v2 version              $03 00
#     ID3v2 flags                %abcd0000
#     ID3v2 size             4 * %0xxxxxxx

#  The ID3v2 tag size is the sum of the byte length of the extended header, the padding and the frames after unsynchronisation. 
#  If a footer is present this equals to ('total size' - 20) bytes, otherwise ('total size' - 10) bytes.
#  The ID3v2 tag size is stored as a 32 bit synchsafe integer, making a total of 28 effective bits (representing up to 256MB).
#  Synchsafe integers are integers that keep its highest bit (bit 7) zeroed, making seven bits out of eight available. 
#  Thus a 32 bit synchsafe integer can store 28 bits of information. 
#  Example: 255 (%11111111) encoded as a 16 bit synchsafe integer is 383 (%00000001 01111111).

#  Since the ID3v2 tag doesn't contain a valid syncsignal, no software will attempt to play the tag. If, for any
#  reason, coincidence make a syncsignal appear within the tag it will be taken care of by the 'unsynchronisation scheme'.
#  Only 28 bits are used in the size description to avoid the introducuction of 'false syncsignals'.

#  ID3v2 flags                %abcd0000
#  a - Unsynchronisation      (bit 7)
#  b - Extended header        (bit 6)
#  c - Experimental indicator (bit 5)
#  d - Footer present         (bit 4)
     
    # Dont't use synchsafe integer for frame size with ID3v2.3.0!!!
    #my $sz_tit_pack = ID3_SET_SIZE28( $sz_tit + 1);
    my $sz_yea_pack = reverse pack 'L', ( $sz_yea + 1);  # The size is excluding the frame header ('total frame size' - 10 bytes)  
    my $sz_tra_pack = reverse pack 'L', ( $sz_tra + 1);  # If the frame size >= 128, then (length != length_sync)
    my $sz_gen_pack = reverse pack 'L', ( $sz_gen + 1); 
    my $sz_art_pack = reverse pack 'L', ( $sz_art + 1);
    my $sz_alb_pack = reverse pack 'L', ( $sz_alb + 1);  # + 1 null
    my $sz_tit_pack = reverse pack 'L', ( $sz_tit + 1);
    my $sz_enc_pack = reverse pack 'L', ( $sz_enc + 1) if (defined $sz_enc);
    my $sz_cps_pack = reverse pack 'L', ( $sz_cps + 1) if (defined $sz_cps);
    my $sz_len_pack = reverse pack 'L', ( $sz_len + 1) if (defined $sz_len);
    my $sz_com_pack = reverse pack 'L', ( $sz_com + 1 + 4);  # 4 for XXX<nul>
    my $sz_lyr_pack = reverse pack 'L', ( $sz_lyr + 1 + 4) if (defined $sz_lyr);  # 4 for XXX<nul>
  
    # see <man perlfunc> 
    # b: A bit string (ascending bit order inside each byte)
    # B: A bit string (descending bit order inside each byte).
    my $tagVersion = pack('C C', 3, 0 );              # version ID3v2.3.0 (for more compatibility)
    #my $tagFlags   = pack('B8', ID3FLAG_FOOT );      # has a footer - optional --   
    my $tagFlags   = pack('B8', 0 ); 
    my $tagFlagsFrame   = pack('B8 B8', 0, 0 ); 
    my $min_size   = maximum($tagSize,$original_sz);  # print "-->min_size = $min_size\n";
    if ( $original_sz < $tagSize ){                   # my personal choice, min_size multiple of 512
       $need_rewrite_file = $true;
       $min_size   = int($tagSize/512) * 512 + 512;   # print "min_size = $min_size ;; tagSize = $tagSize\n"; 
    }                                                
    my $padding    = $min_size - $tagSize;            # print "padding = $padding\n"; # note that, always $padding >= 1 .
    my $tagSize_pack  = ID3_SET_SIZE28($min_size);    # $tagSize = n * 512 for n = 1,2,3,...  
    my $total_size = $min_size + 10;                  # + 10 (if header) + 10 (if footer)         
        
    $ID3v2  = pack "a3a2a1a4", 'ID3', $tagVersion, $tagFlags, $tagSize_pack;  #Header    
       $ID3v2 .= pack "a4a4a2x1a${sz_tit}", 'TIT2', $sz_tit_pack, $tagFlagsFrame, ,$enc_title   if ($title ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_art}", 'TPE1', $sz_art_pack, $tagFlagsFrame, ,$enc_artist  if ($artist ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_alb}", 'TALB', $sz_alb_pack, $tagFlagsFrame, ,$enc_album   if ($album ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_gen}", 'TCON', $sz_gen_pack, $tagFlagsFrame, ,$enc_genre   if ($genre ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_yea}", 'TYER', $sz_yea_pack, $tagFlagsFrame, ,$enc_year    if ($year ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_tra}", 'TRCK', $sz_tra_pack, $tagFlagsFrame, ,$enc_track   if ($track ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_enc}", 'TENC', $sz_enc_pack, $tagFlagsFrame, ,$enc_Encoded             if ($metadata{'Encoded by'});
       $ID3v2 .= pack "a4a4a2x1a${sz_cps}", 'TCOM', $sz_cps_pack, $tagFlagsFrame, ,$enc_Composer            if ($metadata{'Composer'});
       $ID3v2 .= pack "a4a4a2x1a${sz_len}", 'TLEN', $sz_len_pack, $tagFlagsFrame, ,$enc_Length              if ($metadata{'Length'});
       $ID3v2 .= pack "a4a4a2x1a3x1a${sz_com}", 'COMM', $sz_com_pack, $tagFlagsFrame, ,'XXX', ,$enc_comment if ($comment ne "");
       $ID3v2 .= pack "a4a4a2x1a3x1a${sz_lyr}", 'USLT', $sz_lyr_pack, $tagFlagsFrame, ,'XXX', ,$enc_Lyrics  if ($metadata{'Lyrics'});
    $ID3v2 .= pack "x${padding}";
    #$ID3v2 .= pack "a3a2a1a4", '3DI', $tagVersion, $tagFlags, $tagSize_pack;  #Footer is optional
    
    # ID3
    
    if ( $need_rewrite_file eq $true ){            
       my $n = $$;
       while (1) { # make one temp file
       
          my $dir  = -d filename_from_unicode $directory_output ? $directory_output : $home ;	  
          $tmpfile = "$dir/gnormalize-".$n.".temp";
	  	 
          if ( open(TEMP, ">", filename_from_unicode $tmpfile ) ) { last; }
	  if ( not -w filename_from_unicode $tmpfile ){ $status_bar->push($context_id, " $tmpfile ".$langs{msg012} ); die " $tmpfile ".$langs{msg012}; }
          $n++;
       }
       syswrite(TEMP, $ID3v2, $total_size );
       
       if ( $header ne MP3HEADERFLAG ){ seek(FILE, 0, 0); } # go to begining of file
       else { seek(FILE, $original_sz + 10, 0); }           # to ignore the old ID3tagv2 at begining of file 
    
       # sysread FILEHANDLE,SCALAR,LENGTH,OFFSET  -- Returns the number of bytes actually read, 0 at end of file,
       while ( my $ret = sysread(FILE, $copy, $buf_size) ) {    
	  syswrite(TEMP, $copy, $ret ); # make copy from FILE and paste to TEMP file
       }
       close(FILE);
       close(TEMP);
       
       # To delete a file, use unlink : unlink ( "$filepath" ) or die "Can't delete $filepath: $!\n";
       # Don't use rename (see man perlfunc) because rename c funtion fails on diferent mounted file systems.
       # rename($tmpfile, $filepath) || die "Can't rename temp file, leaving in $tmpfile, stopped";        
       my @cmd = ( 'mv', '-f', $tmpfile, $filepath ); # move (overwrite) the filepath       
       exec_cmd_system2(@cmd);       
       #print "use the temp file ; total size = $total_size ; original_sz = $original_sz\n"; 
    }
    else{ 
       seek(FILE, 0 , 0);                       # go to begining of filepath
       syswrite ( FILE, $ID3v2, $total_size );  # syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET
       close(FILE);  
       #print "total size = $total_size\n"; 
    }
    
    #####-------------Print-Beautiful-Tag-------------#####
    print_beautiful_tag( Intro    => "ID3v2.3.0 MP3 Tag (encode: $char)",
                         filepath => $filepath,   Title  => $title,   Artist   => $artist,
			 Album    => $album,      Year   => $year,    Comment  => $comment,
			 Genre    => $genre,      Track  => $track,
                       );           
}

sub print_beautiful_tag {    
    my %args = ( @_,  # argument pair list goes here
	       );
    my $intro  = $args{Intro};   my $title = $args{Title};  my $artist    = $args{Artist};    
    my $album  = $args{Album};   my $year  = $args{Year};   my $comment   = $args{Comment};    
    my $genre  = $args{Genre};   my $track = $args{Track};  my $filepath  = $args{filepath};  

    insert_msg("\n$intro" , "small-black");
    
    $title = "Title : \"$title\" ";     $artist = "Artist  : \"$artist\"";
    $album = "Album : \"$album\" ";    $comment = "Comment : \"$comment\"";
    $genre = "Genre : \"$genre\" ";       $year = "Year    : \"$year\"";
    
    ###----------------------------------------------###  
    # floor() and fmod() - See 'man POSIX'
    my $Total = maximum( 50 , floor( $window->allocation->width / 10 ) ) ; # max horizontal value
    $Total -= 1 if ( fmod($Total,2) != 0 );     # choose $Total always an even number.        
    
    # get length
    my $l_tit = length( $title );     my $l_art = length( $artist  );
    my $l_alb = length( $album );     my $l_com = length( $comment );
    my $l_gen = length( $genre );     my $l_yea = length( $year    );
    
    # get maximum from left and right side.
    my $max_left = maximum ($l_tit,    $l_alb);    my $max_right = maximum ($l_art,     $l_com);
    $max_left    = maximum ($max_left, $l_gen);    $max_right    = maximum ($max_right, $l_yea);
    
    # if ($max_left + $max_right) is an odd number, then add +1 and make it an even number.
    $max_left  += 1 if ( fmod( $max_left + $max_right, 2 ) != 0 and $max_left < $max_right ); 
    $max_right += 1 if ( fmod( $max_left + $max_right, 2 ) != 0 and $max_left > $max_right );
    
    $Total  = maximum ( $Total, $max_left + $max_right ); # $Total is always an even number.     
        
    my $dif_left = $max_left - floor($Total/2);    my $dif_right = $max_right - floor($Total/2);
    #print "\$Total = $Total ; \$max_left = $max_left ; \$max_right = $max_right ; \$dif_left = $dif_left ; \$dif_right = $dif_right\n";
    
    my $size_left  = floor($Total/2);  # initial value that can be changed
    my $size_right = floor($Total/2);
    
    if ( $dif_left > 0 and $dif_right < 0 ) { $size_left += $dif_left  ; $size_right -= $dif_left  ; }
    if ( $dif_left < 0 and $dif_right > 0 ) { $size_left -= $dif_right ; $size_right += $dif_right ; } 
    
    ###----------------------------------------------###    
    
    my $Intro    = "File  : \"";  # has size equal to 9 spaces
    my $filep    =  $filepath . "\" (Track : $track)";
    my $l_path   = length( $filep );
    
    # set "..." like ".../file/path/for/long/filepath" if necessary.
    my $cut_file =  $l_path > $Total - 9 ? "..." . reduce_length_size($filep, $Total - 9 - 3) : $filep ;    
    $Intro      .=  $cut_file; 
    
    ###----------------------------------------------###          
    
    my $Intro2   = sprintf ("%-${Total}s", $Intro   );    # s: spaces, see perlfunc - sprintf. 
    my $title2   = sprintf ("%-${size_left}s",  $title   );    my $artist2  = sprintf ("%-${size_right}s",  $artist  );    
    my $album2   = sprintf ("%-${size_left}s",  $album   );    my $comment2 = sprintf ("%-${size_right}s",  $comment );    
    my $track2   = sprintf ("%-${size_left}s",  $genre   );    my $year2    = sprintf ("%-${size_right}s",  $year    );        
        
    insert_msg("\n$Intro2\n",         "id3tag"); #print on debug textview
    insert_msg("${title2}${artist2}\n", "id3tag"); # 50 + 2 + 50 = 102 spaces
    insert_msg("${album2}${comment2}\n","id3tag");
    insert_msg("${track2}${year2}",     "id3tag");
    insert_msg("\n", "small");
}

# For 32 bit synchsafe integer - The Synchsafe integers are integers that keep 
# its highest bit (bit 7) zeroed, making seven bits out of eight available.
sub ID3_SET_SIZE28 {  # 32 bit synchsafe. See <man perlop>
    my $size = shift;
    my ($a, $b, $c, $d);
    #  Example1: 255 (%11111111) encoded as a 16 bit synchsafe integer is 383 (%00000001 01111111).
    #  Example2: 128 (%10000000) encoded as a 16 bit synchsafe integer is 256 (%00000001 00000000).
    # The bit-shift operators (<< and >>) : 16 >> 1 = 8 , that is:  16 = (10000) in binary goes to 8 = (01000)
    # 255 >> 1 is equal to 127, because : 255 = (11111111)    goes to    127 = (01111111)
    # $x >> 1 : every bit of the value stored in $x is shifted one place to the right.
    # $x & $y : - The values are converted to an integer, if necessary;  
    #           - Each bit of the left operand is compared to the corresponding bit of the right operand;
    #           - If a pair of corresponding bits both have the value 1, the correponding bit of the
    #             result is set to 1. Otherwise, the corresponding bit of the result is set to 0.						
						
    $d = $size & 0x7f;
    $c = ( $size >>  7 ) & 0x7f;  # 0x7f (hexadecinal, base 16) = 127 (decimal, base 10) = 01111111 (binary, base 2)
    $b = ( $size >> 14 ) & 0x7f;  # 0x7f = 127 = 01111111
    $a = ( $size >> 21 ) & 0x7f;
    
    $size = pack "C C C C", $a, $b, $c, $d;   # $a, $b, $c and $d are in decimal base.
				
    #$a = sprintf( "%08b", $a ); # convert to binary base with 8 digits 
    #$b = sprintf( "%08b", $b ); # convert to binary base with 8 digits 
    #$c = sprintf( "%08b", $c ); # convert to binary base with 8 digits 
    #$d = sprintf( "%08b", $d ); # convert to binary base with 8 digits 
    #my $temp = "$a"."$b"."$c"."$d"; # binary with 32 digits 
    #print "decimal = ",oct( "0b$temp" ),"\n";     
    #print "binary (32 bits) = $a $b $c $d \n";

    return $size;
}
# ID3_SET_SIZE28(2**13 + 2**14 + 2**15); # for test

sub ID3_GET_SIZE28 {
    my ($x1, $x2, $x3, $x4) = unpack("C C C C", shift );    
    my $size = ($x4 & 0x7f) + ( ($x3 & 0x7f) << 7 ) + ( ($x2 & 0x7f) << 14 ) + ( ($x1 & 0x7f) << 21 );
    # my $size = $x4 + ($x3 << 7) + ($x2 << 14) + ($x1 << 21);
    # if $x3 = 00000001    then   $x3 << 7   =  10000000 (binary) = 128 (decimal)
            
    #the same result with:
    #my @array = reverse unpack 'C4', shift;
    #foreach my $i (0 .. 3) { $size += $array[$i] * 128 ** $i; } 
    
    #print "x1 = $x1 ;; x2 = $x2 ;; x3 = $x3 ;; x4 = $x4 ;; size = $size\n";     
    return $size;
}

sub remove_ID3v2_mp3_tag{ #not used
    my $fh; my $tag_size; my $file;
    
    my $buf ||= 4096*1024;  # the bigger the faster
    seek $fh, 0, 2;
    my $eof = tell $fh;
    my $off = $tag_size;

    while ($off < $eof) {
       seek $fh, $off, 0;
       read $fh, my($bytes), $buf;
       seek $fh, $off - $tag_size, 0;
       print $fh $bytes;
       $off += $buf;
    }
    truncate $fh, $eof - $tag_size or die "Can't truncate '$file': $!";
}


sub show_APE_tag {
   my %args = ( @_ );
   my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath};
   #return if (not $extension_input eq 'ape' and not $extension_input eq 'mpc' and not $extension_input eq 'wav' ); 
   return unless ( $extension_input =~ /(mpc|ape|wav)/i );
   
   my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 
   my $Total_Track = ""; my $Genre="";
    
    my $APEtag; my $APEtag_footer; my $Preample;
    my $version; my $tag_size; my $item_count;
    my $tag_flags;
    
    open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";

	# read APETAGEX footer, if it exist
	# split /PATTERN/,EXPR,LIMIT
	# seek FILEHANDLE,POSITION,WHENCE
	seek(IN,-32, 2);  # read ( 8 + 4 * 4 + 8 ) = 32 byte from the end of file	
	read(IN, $APEtag_footer, 32, 0); 
	
	$Preample = substr($APEtag_footer,0,8);
	if ( $Preample ne 'APETAGEX' ){ return $false; }
	#print "Preample = $Preample\n";
        $APEtag_footer = substr($APEtag_footer, 8 );

        $version = substr($APEtag_footer,0,4);
        $version = unpack "L",$version;
        #print "version = $version\n";
        $APEtag_footer = substr($APEtag_footer,4);
    
        $tag_size = substr($APEtag_footer,0,4);
        $tag_size = unpack "L",$tag_size;
        #print "tag_size = $tag_size bytes\n";
        $APEtag_footer = substr($APEtag_footer,4);
    
        $item_count = substr($APEtag_footer,0,4);
        $item_count = unpack "L",$item_count;
        #print "item_count = $item_count\n";
        $APEtag_footer = substr($APEtag_footer,4);
    
        $tag_flags = substr($APEtag_footer,0,4);
	
        my @bits = split //, unpack 'b32', $tag_flags;
	my $Contains_Header   = $bits[31];   # @bits is an array ;; the first bit is $bits[0]
	my $Contains_Footer   = $bits[30];
	my $Is_Header         = $bits[29];
	
	#print "Contains_Header = $Contains_Header ;; Contains_Footer = $Contains_Footer ;; Is_Header = $Is_Header\n";
	
	seek(IN,-$tag_size, 2);  # set $tag_size bytes from the end of file	
	read(IN, $APEtag, $tag_size - 32 , 0); # don't read the last 32 bytes

    close(IN);   

    my $tagLen;
    my ($tag_key, $tag_val);
    my %taghash = ();
    my $tag_copy = $APEtag; 

    for (my $i=0;$i<$item_count;$i++){
        $tagLen = substr($APEtag,0,4);
	$tagLen = unpack "L",$tagLen;
        $APEtag = substr($APEtag,8);
	#print "tagLen = $tagLen ;; APEtag = $APEtag\n";
	
	if ($APEtag =~ /^(.*?)\0/) { $tag_key = $1; }  # \0 = 
	#$tag_key =~ tr/A-Z/a-z/; #lower case
	$tag_key = lc($tag_key);  #lower case
        $APEtag =~ s/^.*?\0//;    #remove tag_key\0

        $tag_val = substr $APEtag, 0, $tagLen; # read
	$tag_val = decode("utf8",$tag_val);	
        $APEtag  = substr $APEtag, $tagLen;    # cut, remove

	#print "tag_key = $tag_key ;; tag_val = $tag_val \n"; 
	$taghash{$tag_key} = $tag_val;         # Fill the hash
	if ( length($APEtag) <= 0 ){last;}
    } 
    #print "Album = ",$taghash{Album},"\n\n";
    #for my $key (keys %taghash) { print "$key => $taghash{$key}\n"; }
    
    if ( defined($taghash{year})    ){ $Year    = $taghash{year};    }
    if ( defined($taghash{artist})  ){ $Artist  = $taghash{artist};  }
    if ( defined($taghash{title})   ){ $Title   = $taghash{title};   }
    if ( defined($taghash{comment}) ){ $Comment = $taghash{comment}; }
    if ( defined($taghash{genre})   ){ $Genre   = $taghash{genre};   }
    if ( defined($taghash{album})   ){ $Album   = $taghash{album};   }
    if ( defined($taghash{track})   ){ $Track_Number = $taghash{track}; }    
    
    if ( defined($taghash{'encoded by'}) ){ $metadata{'Encoded by'} = $taghash{'encoded by'}; }
    if ( defined($taghash{'lyrics'})     ){ $metadata{'Lyrics'}     = $taghash{'lyrics'};     }
    if ( defined($taghash{'composer'})   ){ $metadata{'Composer'}   = $taghash{'composer'};   }
    
    if( $Track_Number =~ /(\d+)\/(\d+)/ ){ $Track_Number = $1 ; $Total_Track = $2 ; }
    
   $Track_Number = remove_change_10_chars($Track_Number);
   $Total_Track  = remove_change_10_chars($Total_Track);
    
   # get all the 8 tags  
   $metadata{title}   = remove_change_10_chars($Title);
   $metadata{artist}  = remove_change_10_chars($Artist);
   $metadata{album}   = remove_change_10_chars($Album);
   $metadata{comment} = remove_change_10_chars($Comment);
   $metadata{genre}   = remove_change_10_chars($Genre);
   $metadata{track}       = $Track_Number =~ /^\d+$/ ? sprintf("%02d", $Track_Number ) : "" ; # "%02d": leading zero
   $metadata{total_track} = $Total_Track  =~ /^\d+$/ ? sprintf("%02d", $Total_Track  ) : "" ;  
   $metadata{year}        = $Year =~ /^\d{1,4}$/ ? sprintf("%04d", $Year ) : "" ;   
}


sub remove_apetag {
   my %args = ( @_ );
   my $row = $args{row}; my $filepath = $args{filepath};    
   
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};
   
   my $tag_size; my $tag_flags; my $APEfooter; my $preamble;
   
   print "remove_apetag --> Could not find the file: \"$filepath\"\n" if( ! -e filename_from_unicode $filepath );
   if (not -s filename_from_unicode $filepath) { $@ = "File is empty"; return undef; }
	    
   # see <man perlopentut>
   open(APE, "+<", filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped";
	    	    
   binmode APE;
	    
   seek(APE,-32, 2);  # Set FileHandle 32 byte from the end of file
   read(APE, $APEfooter, 32, 0); # read 32 byte to $APEfooter
	    
   $preamble = substr($APEfooter,0,8);
   $preamble = unpack "a8",$preamble;
   if ( $preamble ne 'APETAGEX' ){ return; }
   #print "preamble = $preamble\n";
   $APEfooter = substr($APEfooter,8 + 4);  # + 4 byte (version)	    
    
   $tag_size = substr($APEfooter,0,4);
   $tag_size = unpack "L",$tag_size;
   $APEfooter = substr($APEfooter,4 + 4);  # + 4 byte (Item Counts)
   #print "tag_size = $tag_size\n"; 
	    
   $tag_flags = substr($APEfooter,0,4);
	
   my @bits = split //, unpack 'b32', $tag_flags;
   my $Contains_Header   = $bits[31];   # @bits is an array ;; the first bit is $bits[0]
   my $Contains_Footer   = $bits[30];
   my $Is_Header         = $bits[29];
	
   #print "Contains_Header = $Contains_Header ;; Contains_Footer = $Contains_Footer ;; Is_Header = $Is_Header\n";
	
   if ($Contains_Header){ $tag_size = $tag_size + 32; } # 32 bytes of headear
	    	    
   seek (APE, -$tag_size, 2);
   my $file_size = tell APE;  # file_size - APEtag_size : get the current position
	    
   #read(APE, $APEfooter, $tag_size, 0);
   #print "tell = $file_size  ;; APEtag = $APEfooter\n";
	    
   truncate APE, $file_size or warn "Can't truncate \"$filepath\": $!";
   
   close(APE);
	    
   # see <man perlfunc>	     	     
   # tell    Returns the current position in bytes for FILEHANDLE,
   # truncate FH,LENGTH : Truncates the file opened on FILEHANDLE to the specified length.
   # sysread FILEHANDLE,SCALAR,LENGTH,OFFSET  ;; Returns the number of bytes actually read
   # syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET	    	    	    
   
   #print "\n ---> remove_apetag ;; \$row = $row ;;  \$filepath = $filepath ;; \$Title = $Title\n";	   		
}

sub write_apetag { # 18Mai2008    
   my %args = ( @_ );   
   my $row = $args{row}; my $filepath = $args{filepath};
   
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};
   
   my $Track; 
   if ( $Total_Track ne "" and $Total_Track =~ /^\d+$/ and $Total_Track >= $Track_Number ){ $Track = $Track_Number."/".$Total_Track; }
   else { $Track = $Track_Number; }       
    
   my $char = 'utf8'; # encode to utf8    
    
   my $enc_Title   = encode($char,$Title);    
   my $enc_Artist  = encode($char,$Artist);   
   my $enc_Album   = encode($char,$Album);   
   my $enc_Comment = encode($char,$Comment);
   my $enc_Genre   = encode($char,$Genre);    
   my $enc_Track   = encode($char,$Track);    
   my $enc_Year    = encode($char,$Year);
   
   my $enc_Composer = encode($char,$metadata{'Composer'})   if ($metadata{'Composer'});
   my $enc_Encoded  = encode($char,$metadata{'Encoded by'}) if ($metadata{'Encoded by'});      
   my $enc_Length   = encode($char,$metadata{'Length'})     if ($metadata{'Length'});
   my $enc_Lyrics   = encode($char,$metadata{'Lyrics'})     if ($metadata{'Lyrics'});

   my $tail; my $tag;  my $tag_size;	    	    
	    
   # Masks for TAGS FLAGS
   use constant Contains_Header => 0x80000000; # hexdecimal 0x80 = 128 decimal = (10000000) binary (bite 8)
   use constant Contains_Footer => 0x40000000; # hexdecimal 0x40 =  64 decimal = (01000000) binary (bite 7)
   use constant Is_Header       => 0x20000000; # hexdecimal 0x20 =  32 decimal = (00100000) binary (bite 6)
   
   print "write_apetag --> Could not find the file: \"$filepath\"\n" if( ! -e filename_from_unicode $filepath );	    
   if (not -s filename_from_unicode $filepath ) { print "File <$filepath> is empty: $@"; return undef; }
	    
   open(APETAG, ">>", filename_from_unicode $filepath ) or die "Can't open <$filepath>: $!, stopped";    
   binmode APETAG; 

   seek APETAG, 0, 2; # go to end of file : 2 to set it to EOF (End Of File)
	    
   my $sz_tit = length($enc_Title);   # get size in byte
   my $sz_art = length($enc_Artist);
   my $sz_alb = length($enc_Album);	    
   my $sz_com = length($enc_Comment);
   my $sz_gen = length($enc_Genre);	     
   my $sz_tra = length($enc_Track);
   my $sz_yea = length($enc_Year);
   
   my $sz_cps = length($enc_Composer)  if ($metadata{'Composer'});       	    
   my $sz_enc = length($enc_Encoded)   if ($metadata{'Encoded by'});   
   my $sz_len = length($enc_Length)    if ($metadata{'Length'});
   my $sz_lyr = length($enc_Lyrics)    if ($metadata{'Lyrics'});
	    
   my $tagTotalSize = 32;  # + 32 bytes (Footer)
   my $items = 0;	    
   do { 
      use bytes; 
      if ($enc_Title     ne ""){ $items ++; $tagTotalSize += 8 + length('Title') + 1 + $sz_tit; }
      if ($enc_Artist    ne ""){ $items ++; $tagTotalSize += length('Artist')  + $sz_art + 9;   }
      if ($enc_Album     ne ""){ $items ++; $tagTotalSize += length('Album')   + $sz_alb + 9;   }	       
      if ($enc_Comment   ne ""){ $items ++; $tagTotalSize += length('Comment') + $sz_com + 9;   }	
      if ($enc_Genre     ne ""){ $items ++; $tagTotalSize += length('Genre')   + $sz_gen + 9;   }       
      if ($enc_Track     ne ""){ $items ++; $tagTotalSize += length('Track')   + $sz_tra + 9;   }	       	       
      if ($enc_Year      ne ""){ $items ++; $tagTotalSize += length('Year')    + $sz_yea + 9;   }
      
      if ($metadata{'Composer'}  ){ $items ++; $tagTotalSize += length('Composer')   + $sz_cps + 9; }
      if ($metadata{'Encoded by'}){ $items ++; $tagTotalSize += length('Encoded by') + $sz_enc + 9; }      
      if ($metadata{'Length'}    ){ $items ++; $tagTotalSize += length('Length')     + $sz_len + 9; }
      if ($metadata{'Lyrics'}    ){ $items ++; $tagTotalSize += length('Lyrics')     + $sz_lyr + 9; }
   };
	    
   # L: An unsigned long value. --- see <man perlfunc>
   my $tagVersion      = pack('L', 2000 ); # 2000: version
   $tagTotalSize       = pack('L', $tagTotalSize );  #  footer + all tag items
   my $tagTotalItems   = pack('L', $items ); # 7 items : year,track,artist,...,comment
   my $tagGlobalFlags  = pack('L', Is_Header + Contains_Header + Contains_Footer );
   my $tagGlobalFlags2 = pack('L', Contains_Header + Contains_Footer );
 
   # initial - header
   # APETAGEX
	    	    
   print APETAG pack "a8a4a4a4a4x8", 'APETAGEX', $tagVersion, $tagTotalSize, $tagTotalItems, $tagGlobalFlags;
   	    
      if ($enc_Title    ne ""){ print APETAG pack "a8a6a${sz_tit}", pack('L', $sz_tit ), 'Title',   $enc_Title;   }
      if ($enc_Artist   ne ""){ print APETAG pack "a8a7a${sz_art}", pack('L', $sz_art ), 'Artist',  $enc_Artist;  }
      if ($enc_Album    ne ""){ print APETAG pack "a8a6a${sz_alb}", pack('L', $sz_alb ), 'Album',   $enc_Album;   }	    
      if ($enc_Comment  ne ""){ print APETAG pack "a8a8a${sz_com}", pack('L', $sz_com ), 'Comment', $enc_Comment; }
      if ($enc_Genre    ne ""){ print APETAG pack "a8a6a${sz_gen}", pack('L', $sz_gen ), 'Genre',   $enc_Genre;   }	    
      if ($enc_Track    ne ""){ print APETAG pack "a8a6a${sz_tra}", pack('L', $sz_tra ), 'Track',   $enc_Track;   }	    	    
      if ($enc_Year     ne ""){ print APETAG pack "a8a5a${sz_yea}", pack('L', $sz_yea ), 'Year',    $enc_Year;    }
	
      if ($metadata{'Composer'}  ){ print APETAG pack "a8a9a${sz_cps}", pack('L', $sz_com ), 'Composer',   $enc_Composer;}
      if ($metadata{'Encoded by'}){ print APETAG pack "a8a11a${sz_enc}",pack('L', $sz_enc ), 'Encoded by', $enc_Encoded; }            
      if ($metadata{'Length'}    ){ print APETAG pack "a8a7a${sz_len}", pack('L', $sz_len ), 'Length',     $enc_Length;  }
      if ($metadata{'Lyrics'}    ){ print APETAG pack "a8a7a${sz_lyr}", pack('L', $sz_lyr ), 'Lyrics',     $enc_Lyrics;  }     
      	    
   print APETAG pack "a8a4a4a4a4x8", 'APETAGEX', $tagVersion, $tagTotalSize, $tagTotalItems, $tagGlobalFlags2;

   # final - footer
   #APETAGEX

# from taglib-1.3.1: taglib/ape/ape-tag-format.txt  --- Member of APE Tag 2.0
# http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
#/===========================================================================\
#| Preamble       | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' }     |
#|----------------|---------|------------------------------------------------|
#| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000     |
#|----------------|---------|------------------------------------------------|
#| Tag Size       | 4 bytes | Tag size in bytes including footer and all tag |
#|                |         | items excluding the header (for 1.000          |
#|                |         | compatibility)                                 |
#|----------------|---------|------------------------------------------------|
#| Item Count     | 4 bytes | Number of items in the tag                     |
#|----------------|---------|------------------------------------------------|
#| Tag Flags      | 4 bytes | Global flags                                   |
#|----------------|---------|------------------------------------------------|
#| Reserved       | 8 bytes | Must be zeroed                                 |
#\===========================================================================/


#                           APE Tag Flags
#/=================================================================\
#| Contains Header | Bit 31      | 1 - has header | 0 - no header  |
#|-----------------|-------------|---------------------------------|
#| Contains Footer | Bit 30      | 1 - has footer | 0 - no footer  |
#|-----------------|-------------|---------------------------------|
#| Is Header       | Bit 29      | 1 - is header  | 0 - is footer  |
#|-----------------|-------------|---------------------------------|
#| Undefined       | Bits 28 - 3 | Undefined, must be zeroed       |
#|-----------------|-------------|---------------------------------|
#| Encoding        | Bits 2 - 1  | 00 - UTF-8                      |
#|                 |             | 01 - Binary Data *              |
#|                 |             | 10 - External Reference **      |
#|                 |             | 11 - Reserved                   |
#|-----------------|-------------|---------------------------------|
#| Read Only       | Bit 0       | 1 - read only  | 0 - read/write |
#\=================================================================/

# http://www.hydrogenaudio.org/musepack/klemm/www.personal.uni-jena.de/%7Epfk/mpp/sv8/apevalue.html
# APE Tags Header  32 byte
# APE Tag Item 1   10 byte   : APE tags items should be sorted ascending by size.
# APE Tag Item 2   10 byte
# ...
# APE Tag Item n   10 byte
# APE Tags Footer  32 byte


#                          Item:  length key value
# APE Tag Item:   4 byte : Length len of the assigned value in bytes
#	    	  4 byte : Item flags
#	    	  m byte : Item key, can contain ASCII characters from 0x20 (Space) up to 0x7E (Tilde)
#	    	  1 byte : Item key terminator   0x00
#	    	  len byte : Item value, can be binary data or UTF-8 string
		     		     
   close(APETAG);	
   #print "size = ",bin2dec(unpack('B32', '' )),"\n";	#219	
   #print "genre = $Genre ;; size = $sz_gen \n";
   #$tagGlobalFlags2 = bin2dec( unpack('B32', '�' ) );
   #$tagGlobalFlags2 =  pack('L', TF_HAS_HEADER );
   #$tagGlobalFlags2 = bin2dec( unpack('B32', $tagGlobalFlags2 ) );
   #print "tagGlobalFlags2 = $tagGlobalFlags2 ;;\n";	
	    
   #print "\n ---> write_apetag ;; \$row = $row ;; \$filepath = $filepath ;; \$Title = $Title ;; \$Album = $Album\n";

    #####-------------Print-Beautiful-Tag-------------#####
    print_beautiful_tag( Intro    => "APE Tag 2.0 (encode: utf8)",
                         filepath => $filepath,  Year     => $Year,
			 Title    => $Title,     Artist   => $Artist,
			 Album    => $Album,     Comment  => $Comment,
			 Genre    => $Genre,     Track    => $Track,
                       ); # if ( $extension_input !~ /(wav)/ );	        
}	

sub bin2dec {
	# see <man perlfunc>
	return unpack ('N', pack ('B32', substr(0 x 32 . shift, -32)));
}


sub get_genre_number{
    my $genre = shift;
    my $genre_number; # 12 Other : default

    if ( $genre =~ /^\d+$/ ){  # if $Genre is a number
        $genre_number = $genre; 
    }       
    else{ # if $genre is a reference name, get its number
        for my $key (keys %genre_hash) {
           # print "$key => $genre_hash{$key}\n";
	   if ( uc($genre_hash{$key}) eq uc($genre) ){
	      $genre_number = $key;
	      last;
	   }
        } 
    }
    return $genre_number;
}


sub ppaths{ # print all selected paths
  my $tree_selection = $treeview_play->get_selection;
  my $model = $treeview_play->get_model;    
  my @paths = $tree_selection->get_selected_rows; # sel = Gtk2::TreePath
  
  foreach my $path (@paths) {
     $iter = $model->get_iter($path);
     next unless $iter;
  
     my $selected = $model->get_value($iter,COLUMN_FILE); # track number
     my $row = $selected - 1;  # $track-1;
     my $filepath = $files_info[$row]{filepath};    
     my $extension_input = $files_info[$row]{extension_input};
     my $title = $files_info[$row]{title};
     print "\$filepath = $filepath ; \$extension_input = $extension_input ; \$title = $title\n";
  } 
}

# save_tag button of table31
sub save_tag {  # sub cell_edited {
   
   # get selected row  from 'sub get_selection_tree' that will be used by 'sub change_tag' and 'sub save_tag'
   my $row = $files_info[0]{get_selection_row};
   
   return unless defined $row;
   
   my $filepath = $files_info[$row]{filepath};   
   my $extension_input = $files_info[$row]{extension_input};   
   my %hash = determine_directory_and_filename_and_extension(row => $row);
 
   my $cmd;
   
   # the hash %temp_tags has temporary variables only used on 'sub change_tag'.
   $files_info[$row]{title}       = $temp_tags{title};
   $files_info[$row]{artist}      = $temp_tags{artist};
   $files_info[$row]{album}       = $temp_tags{album};
   $files_info[$row]{comment}     = $temp_tags{comment};
   $files_info[$row]{genre}       = $temp_tags{genre};
   $files_info[$row]{track}       = $temp_tags{track};
   $files_info[$row]{total_track} = $temp_tags{total_track};
   $files_info[$row]{year}        = $temp_tags{year};  
   
   Set_this_changes_on_Treeview($filepath,$row)     if ($files_info[$row]{extension_input} ne 'cda');
   Set_this_changes_on_Treeview_cda($filepath,$row) if ($files_info[$row]{extension_input} eq 'cda');
      
   my $Title   = $temp_tags{title};
   my $Artist  = $temp_tags{artist};
   my $Comment = $temp_tags{comment};
   my $Album   = $temp_tags{album};
   my $Genre   = $temp_tags{genre};
   my $Year    = $temp_tags{year};
   my $Track_Number = $temp_tags{track};
   my $Total_Track  = $temp_tags{total_track};   

   #print "\n sub save_tag --->1 \$row = $row \$filepath = $filepath ;; \$Title = $Title ;; \$Album = $Album\n";
        
    #verify if the choosed file is valid
    if ( $extension_input eq 'mp3' ){		
       
        save_ID3v2_mp3_tag($filepath, $Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Total_Track, $Genre );	 
              
        save_ID3v1_mp3_tag($filepath, $Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Genre );	             
    }      
    if ( $extension_input eq 'ogg' ){
       if ($vorbiscomment_path eq "") {
          $status_bar->push($context_id, " vorbiscomment can't be found!");
          return $false;
       }       
       my   @cmd_tag = ( $vorbiscomment_path, '--raw', '-t', "title=$Title", '-t', "artist=$Artist" );
       push @cmd_tag,  ( '-t', "genre=$Genre", '-t', "date=$Year", '-t', "album=$Album" );
       if ( $Total_Track ne "" and $Total_Track >= $Track_Number ) { 
               push @cmd_tag, ( '-t', "tracknumber=$Track_Number/$Total_Track" ); }
       else { push @cmd_tag, ( '-t', "tracknumber=$Track_Number" );              }
       push @cmd_tag,  ( '-t', "description=$Comment", '-t', "comment=$Comment", '-w', filename_from_unicode $filepath );

       exec_cmd_system3(@cmd_tag);	            
    }    
    if ( $extension_input eq 'flac' ){
       if ($metaflac_path eq "") {
          $status_bar->push($context_id, " metaflac can't be found!");
          return $false;
       }       
       exec_cmd_system2( $metaflac_path, '--remove-all-tags', $filepath );
 
       # tag commands -- to see the entries: metaflac --list music.flac
       # obsolete,  deprecated: --show-vc-field=Title ;; --set-vc-field=Title=
       # --no-utf8-convert  decode("utf8",$1)
       
       my   @cmd = ( $metaflac_path, '--no-utf8-convert', "--set-tag=Title=$Title", "--set-tag=Artist=$Artist" );       
       push @cmd,  ( "--set-tag=Album=$Album", "--set-tag=Date=$Year", "--set-tag=Description=$Comment", "--set-tag=Comment=$Comment" );       
       if ($Total_Track ne "" and $Total_Track >= $Track_Number){	     
       	      push @cmd, ( "--set-tag=Tracknumber=$Track_Number/$Total_Track" ); }	     
       else { push @cmd, ( "--set-tag=Tracknumber=$Track_Number" );              }       
       push @cmd, ( "--set-tag=Genre=$Genre", filename_from_unicode $filepath );
              
       exec_cmd_system3(@cmd);
       #print "\n save_tag --> \@cmd = @cmd\n";       	
    }
    if ( $extension_input =~ /(mpc|ape|wav)/ ){   
       remove_apetag (%hash);   	    
       write_apetag (%hash);
    } 
    
    my $info_cddb = "";
    if ( $extension_input eq 'cda' ){
       $info_cddb = save_cddb_info_to_home($row); # save info to "$home/.cddb/ ($dir/) $cddbid"
       $status_bar->push($context_id, " Saved tag to $info_cddb");	    
    }
    else{ $status_bar->push($context_id, " $extension_input".$langs{msg062} ); }
    
    $button_save_tag->set_sensitive($false);
            
    #print "\n sub save_tag --->2 \$row = $row \$filepath = $filepath ;; \$Title = $Title ;; \$Album = $Album\n";
}

sub Set_this_changes_on_Treeview {
   my ($filepath,$row) = @_; 
   my $model = $treeview_play->get_model;
   
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};   
   
   my @rows_with_same_files = ();
   for (my $row2 = 0; $row2 <= $#files_info; $row2++){
       if ($filepath eq $files_info[$row2]{filepath}){ push @rows_with_same_files, $row2; }
   } 
   # print "\@rows_with_same_files = @rows_with_same_files ; \$filepath = $filepath\n";
   
   foreach my $row2 (@rows_with_same_files){      
      my ($iter, $path) = get_iter_path_given_track_art_alb ( value => $row2 + 1, treeview => 'treeview_play', column => COLUMN_FILE );      
      
      # set all the new 8 entries:
      $files_info[$row2]{title}   = $Title;
      $files_info[$row2]{artist}  = $Artist;
      $files_info[$row2]{album}   = $Album;
      $files_info[$row2]{genre}   = $Genre;
      $files_info[$row2]{comment} = $Comment;
      $files_info[$row2]{year}    = $Year;
      $files_info[$row2]{track}       = $Track_Number;
      $files_info[$row2]{total_track} = $Total_Track;
   
      $model->set ($iter, COLUMN_ARTIST, $files_info[$row2]{artist}, # set value on model
                          COLUMN_TITLE,  $files_info[$row2]{title},
		          COLUMN_ALBUM,  $files_info[$row2]{album},
		          COLUMN_TRACK,  $files_info[$row2]{track},  # $Track_Number,
		          COLUMN_YEAR,   $files_info[$row2]{year},
	          ) if $iter;
   }		   
}     

sub Set_this_changes_on_Treeview_cda {
   my ($filepath,$row) = @_; 
   my $model = $treeview_play->get_model;
   
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};
   
   #print "\n Set_this_changes_on_Treeview_cda -->1 \$Title = $Title ;; \$Artist = $Artist ;; \$Album = $Album\n";
   
   # initial values
   if ( $Artist eq "" or not defined $Artist ) { $Artist = "artist"; }
   if ( $Album  eq "" or not defined $Album  ) { $Album  = "album";  }
   if ( $Genre  eq "" or not defined $Genre  ) { $Genre  = "Other";  }
   if ( $Year   eq "" or not defined $Year   ) { $Year   = "";       } 
   
   for (my $row2 = 0; $row2 <= $#files_info; $row2++){
      if ($files_info[$row2]{extension_input} ne 'cda'){last;}      
      my ($iter, $path) = get_iter_path_given_track_art_alb ( value => $row2 + 1, treeview => 'treeview_play', column => COLUMN_FILE );
      
      # set all the new 8 entries:
      $files_info[$row2]{title}   = $Title  if ( $row2 == $row );  # change only the selected row
      $files_info[$row2]{artist}  = $Artist if ( $row2 == $row or $files_info[$row2]{artist} eq 'artist' );      
      $files_info[$row2]{album}   = $Album;
      $files_info[$row2]{genre}   = $Genre;
      $files_info[$row2]{comment} = $Comment;
      $files_info[$row2]{year}    = $Year;
      #$files_info[$row2]{track}       = $Track_Number;
      #$files_info[$row2]{total_track} = $Total_Track;
   
      $model->set ($iter, COLUMN_ARTIST, $files_info[$row2]{artist}, # set value on model
                          COLUMN_TITLE,  $files_info[$row2]{title},
		          COLUMN_ALBUM,  $files_info[$row2]{album},
		          #COLUMN_TRACK, $files_info[$row2]{track},  # $Track_Number,
		          COLUMN_YEAR,   $files_info[$row2]{year},
	          ) if $iter;
   }
   #print "\n Set_this_changes_on_Treeview_cda -->2 \$Title = $Title ;; \$Artist = $Artist ;; \$Album = $Album\n";		   
}       

#####-----------------------------------------------#####

# get_info_from_entries from entry "Tag" of gnormalize for wave files
sub get_info_from_entries { # no more used!
    # get mp3/mp4 ... info to be saved on normalized file
    $Title = $entry_title->get_text;
    $Artist = $entry_artist->get_text;
    $Album = $entry_album->get_text;
    $Year = $entry_year->get_text;  
    
    $Track_Number = ""; $Total_Track = "";
    if ( $entry_tn->get_text =~ /(\d+)/ ) { $Track_Number = $1; } 
    if ( $entry_tt->get_text =~ /(\d+)/ ) { $Total_Track = $1; }
            
    #print " tn = $Track_Number ;; Total_Track = $Total_Track \n";
    $Comment = $entry_comment->get_text;  
    $Genre = $ComboBoxEntry_genre->child->get_text;
}

#####-----------------------------------------------#####

##--------------------- Character ---------------------##

# substitute the command <system()> by this sub routine <exec_cmd_system()>
# see man Encode. utf8, PerlIO, perlrun, ...
sub exec_cmd_system { # need capture the output
   my $cmd = shift;   # $cmd is a string
   my $output;

   open (CM, filename_from_unicode "$cmd 2>&1 |" ) or die "couldn't execute \"$cmd\": $!";
      $/="\r"; ## start of loop
      while(<CM>){ $output = $_; } # $_ is the output of command
      $/="\n"; ## final of loop 
   close(CM);
   return $output; 
}

sub exec_cmd_system2 {
   my @exec_argv = @_;
     
   #$SIG{CHLD} = \&REAPER; # To reap/eliminate dead children ;  see perlipc
   # see man perlfunc, perlfork, perlipc ; Learning Perl 14.6, 3a Ed. ; Perl Cookbook 16.10, 2a. Ed 
   my $child_pid = fork();
   die "fork() failed: $!" unless defined $child_pid;
   
   # convert to local encoding
   for (my $i = 0; $i <= $#exec_argv ; $i++){ $exec_argv[$i] = filename_from_unicode $exec_argv[$i]; }
	
   if( $child_pid == 0 ){ 
      #Child process is here ; child process has a zero value
      open \*STDIN, '>/dev/null';  # see man perlopentut
      open \*STDOUT,'>/dev/null';
      open \*STDERR,'>/dev/null';
      exec @exec_argv;  # see perlfunc
      die "cannot execute $exec_argv[0]: $!\n";	   
   }
   #Parent process is here ; parent process has a nonzero value
   #print "\n exec_cmd_system2 --> \$child_pid = $child_pid ;; \@exec_argv = @exec_argv\n";	
   return; 			
}

sub exec_cmd_system3 { # used by vorbiscomment and metaflac
   my @exec_argv = @_;
   my $child_pid = fork();
   die "fork() failed: $!" unless defined $child_pid;   
	
   if( $child_pid == 0 ){ 
      #Child process is here ; child process has a zero value
      open \*STDIN, '>/dev/null';  # see man perlopentut
      open \*STDOUT,'>/dev/null';
      open \*STDERR,'>/dev/null';
      exec @exec_argv;  # see perlfunc
      die "cannot execute $exec_argv[0]: $!\n";	   
   }	
   return; 			
}

# change, for exemple, '0,49' to '0.49'.
sub number_value{
    my $nvalue = shift;
    $nvalue =~ s/,/./g;
    return $nvalue;
}

sub print_local {
   print filename_from_unicode shift;
}

#####-----------------------------------------------#####

sub minimum {
  my $v1 = shift;
  my $v2 = shift;
  my $min = $v1 < $v2 ? $v1 : $v2 ;
  return $min;
}

sub maximum {
  my $v1 = shift;
  my $v2 = shift;
  my $max = $v1 < $v2 ? $v2 : $v1;
  return $max;
}


# if  ( the extension_input eq extension_output and $check_change_properties is not active
# and $check_button_overwrite is not active then make copy. 
sub same_extension_overwrite {
   my %args = ( @_ );
   my $filepath  = $args{filepath}; my $file_wav = $args{file_wav};
   my $directory = $args{directory};      
   
   my @cmd;
   
   #remove wav file if button_del_wav is active and $file_wav exist
   if ($check_button_del_wav->get_active and -e filename_from_unicode "$directory_output/$file_wav" ){	      
      @cmd = ( 'rm', '-f', $directory_output.'/'.$file_wav );
	      
      insert_msg("@cmd" , "small"); #print on debug textview
      insert_msg("\n" , "small");
	      
      exec_cmd_system2(@cmd);	     
   }
   # if overwrite is active, don't need copy file
   if ( not $check_button_overwrite->get_active and (filename_from_unicode $directory ne filename_from_unicode $directory_final) ){
	 
      # copy the mp3/mp4/ogg ... files (that don't need to normalize) to $directory_final	      	      
      @cmd = ( 'cp', '-f', $filepath, $directory_final );	      
	      
      insert_msg("@cmd\n" , "small"); #print on debug textview
      insert_msg( $langs{msg056} , "small-red"); 
      insert_msg("\n" , "small");
	      
      exec_cmd_system2(@cmd);
   }
   if ( not $already_normalized ) {
      $pbar_n->set_fraction(0) ;	     
      my $sb = $spinner_sensi->get_value;
	     
      if ( abs($adjust) <= $sb and $norm_type ne "None" ){
	     
         $sb = sprintf("%0.2f", $spinner_sensi->get_value);
         $sb = number_value($sb);  # For example, change '0,57' by '0.57'. 
	     
         $pbar_n->set_text( $langs{msg042} );
	 insert_msg( $langs{msg043} , "small"); 
	 insert_msg("|$adjust| <= $sb" , "small-red");
	 insert_msg( $langs{msg044} , "small"); 
	 insert_msg("\n-----*****-----" , "small-black");
	 insert_msg("\n", "small");
      }
      else { $pbar_n->set_text( $langs{msg045} );} # for type = None
   }	
   $pbar_encode->set_fraction(0) ;  
   $pbar_encode->set_text( $langs{msg046} );
   $status_bar->push($context_id, " ");
}

sub finalize_process { #01May2008
   my %args = ( @_ );
   my $row  = $args{row};   
   my $file_wav    = $args{file_wav};  my $filepath = $args{filepath}; my $directory = $args{directory};
   my $file_input  = $args{filename};
   my $file_output = $args{file_output};

   my @cmd;
   #print "\n finalize_process --> \$file_input = $file_input ;; \$file_output = $file_output ;; \$directory = $directory ;; \$directory_final = $directory_final\n";
	
   #remove wav file_input if button_del_wav is active and $file_wav exist and ...
   if ( $check_button_del_wav->get_active and -e filename_from_unicode "$directory_output/$file_wav" and
        (( not $button_output_wav->get_active ) or ( $button_output_wav->get_active and $directory_output ne $directory_final ))  ) {

      @cmd = ( 'rm', '-f', $directory_output.'/'.$file_wav );      
	     
      insert_msg( "\n$langs{msg089}\n" , "small-red"); # "Removing temporary file:"
      insert_msg("@cmd" , "small");
      insert_msg("\n" , "small");
	     
      exec_cmd_system2(@cmd); 
   }	
   # overwrite: yes or not? That is the question.
   # overwrite only if the encoding process have finished, that is, $normalize_button is active
   if ( $normalize_button->get_active and $check_button_overwrite->get_active and 
	-w filename_from_unicode "$directory_final/$file_output" and 
	((-w filename_from_unicode $directory and $extension_input ne $extension_output) or (-w filename_from_unicode $directory.'/'.$file_input and $extension_input eq $extension_output)) and 
	$directory_final ne $directory ){
	     
      @cmd = ( 'mv', '-f', $directory_final.'/'.$file_output, $directory.'/'.$file_input ) if ($extension_input eq $extension_output);
      @cmd = ( 'mv', '-f', $directory_final.'/'.$file_output, $directory )                 if ($extension_input ne $extension_output);
	     
      exec_cmd_system2(@cmd); # overwrite
      insert_msg("\n$langs{msg005}:", "small-red");
      insert_msg("\n@cmd\n", "small");
      
      @cmd = ( 'rmdir', $directory_final );  # 'rmdir' fail if on different mounted file systems.
      exec_cmd_system2(@cmd); # remove the directory_final
      insert_msg("@cmd", "small");
      insert_msg("\n", "small");
   }
   
   if ( $normalize_button->get_active and $check_button_overwrite->get_active and 
	-w filename_from_unicode "$directory_final/$file_output" and 
	not ((-w filename_from_unicode $directory and $extension_input ne $extension_output) or (-w filename_from_unicode $directory.'/'.$file_input and $extension_input eq $extension_output)) and 
	$directory_final ne $directory and $extension_input ne 'cda' ){
 
      my $msg;
      $msg = "mv: cannot move \"$directory_final/$file_output\" to \"$directory/$file_output\": Permission denied" if ($extension_input eq $extension_output);
      $msg = "mv: cannot move \"$directory_final/$file_output\" to \"$directory/\": Permission denied"             if ($extension_input ne $extension_output);
      
      insert_msg("\n$msg", "small-red");
      insert_msg("\n", "small");
   }
   	
   ## set encoding on the final of process
   if ( $normalize_button->get_active ) {  # the normalize button is active
      insert_msg("-----*****-----\n" , "small-green");
      if ($button_output_wav->get_active){ $pbar_encode->set_fraction( 0 ); }
      else { $pbar_encode->set_fraction( 1 ); }
   }
   elsif ( -e filename_from_unicode "$directory_final/$file_output" ) { # if the file exists
      #remove normalized file not finished
      exec_cmd_system2( 'rm', '-f', $directory_final.'/'.$file_output );
   }	
}


# determine the values of 6 encode variables: ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max)
# Don't need to determine $quality

sub encode_settings {
   my %args = ( @_ );
   my $row = $args{row}; my $extension_input = $args{extension_input};
   
   # get some technical informations:
   my $bitrate_original = $files_info[$row]{bitrate};
   my $Frequency = $files_info[$row]{frequency};
   my $bitrate_average = $files_info[$row]{bitrate_average};
   my $mode_channel = $files_info[$row]{mode};

        my ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max);
	
	# button "change properties" active
	if ( $check_change_properties->get_active ){ 
	       $mode = $ComboBox_mode->get_active_text;
	       $encode = $ComboBox_encode_type->get_active_text;   # refresh value	       
	       if    ( $extension_output eq 'mp3' ) { $bitrate = $spinner_bitrate_mp3->get_value_as_int(); }# for $encode = "average"
	       elsif ( $extension_output eq 'mp4' ) { $bitrate = $spinner_bitrate_mp4->get_value_as_int(); }# for $encode = "average"
	       elsif ( $extension_output eq 'ogg' ) { $bitrate = $spinner_bitrate_ogg->get_value_as_int(); }# for $encode = "average"
	       $freq = number_value($ComboBox_freq->get_active_text);
	       # for mp3 constant $bitrate is obtainned from $ComboBox_const_bitrate
	       if ( $encode eq "constant" and $extension_output eq 'mp3' ) { $bitrate = $bitrate_constant;} 
	       $V = $spinner_V->get_value_as_int; # Vmp3
	       $Vmp4 = $spinner_Vmp4->get_value;
	       $Vogg = $spinner_Vogg->get_value;
	       $Vmpc = $spinner_Vmpc->get_value;
	}
	# button "change properties" not active
	# decide if the bitrate of normalized files will be preserved
	else { 
	       $bitrate = $bitrate_original;                          # copy the value of original bitrate
	       $freq = $Frequency;  	       
	       $encode = $bitrate_average ? "average" : "constant" ;  # only this two possibility when button "change properties" is not active
	       
	       if ( $extension_output eq 'mpc' ){
	          # estimating a fuction to find $Vmpc from $bitrate: $Vmpc = f($bitrate)
	          my $x = number_value($bitrate_original);
	          my $adjustm = 0.15*exp(-( ($x-160)^2 )/8000) ;
	          $Vmpc = sprintf("%0.2f", ($x/29)*(1 - $adjustm) - 0.2 ); 
		  $Vmpc = number_value($Vmpc); 
	          #print("bitrate = $x; ajust = $adjustm; Vmpc = $Vmpc \n");
	       } 
	       if ( $extension_input =~ /(wav|cda|ape|flac)/ ){ 
	            $bitrate = 160; 
		    $freq = 44100;
		    $Vogg = $V = 4.0;
		    $Vmpc = 5.0;
		    $Vmp4 = 200;
		    $encode = "average";
	       }	       
	       if ( $extension_input eq 'mp3' and defined $mode_channel ){ $mode = $mode_channel; }
	       else { $mode = 'joint stereo'; } # $mode is only used by encode_wav_to_mp3()
	}
        $Vogg = sprintf("%0.1f", $Vogg ); $Vogg = number_value($Vogg); # only one digit
	$Vmpc = sprintf("%0.1f", $Vmpc ); $Vmpc = number_value($Vmpc);
	
	$vb_Max = $ComboBox_Max->get_active_text; #refresh value
        $vb_Min = $ComboBox_Min->get_active_text;	  
	
	# for MPEG-2   layer III sample frequencies (kHz):  16  24  22.05
        # bitrates (kbps):  8 16 24 32 40 48 56 64 80 96 112 128 144 160
	if ( $freq <= 24000 and $extension_output eq 'mp3') { 
	     $vb_Min = minimum($vb_Min, 160);
	     $vb_Max = minimum($vb_Max, 160);
	     $bitrate = minimum($bitrate, 160);
	}		
	return ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max);
}

##-----------------------CDDB--------------------------##
# See to <man CDDB_get>
# Read the Album, Artist and Track Titles

sub get_cddb_info_from_internet { #26Abr2008
	
        my %config;
	my $CDDB_server = $entry_CDDB_server->get_text;
	my $cddb_port = $spinner_cddb_port->get_value;
	my $cddb_transport = $ComboBox_cddb_transport->get_active_text;
	my %cd;

        # following variables just need to be declared if different from defaults
        $config{CDDB_HOST}=$CDDB_server;             # set cddb host ;; default = "freedb.freedb.org"
        $config{CDDB_PORT}=$cddb_port;               # set cddb port
        $config{CDDB_MODE}=$cddb_transport;          # set cddb mode: cddb or http
        $config{CD_DEVICE}="$audiodevice_path";      # set cd device
	
	my $cddbid = $use_external_cddbget ? get_discids($audiodevice_path)->[0] : CDDB_get::Internal::get_discids($audiodevice_path)->[0];
        $cddbid = sprintf("%08x", $cddbid);
	#print "\n\n get_cddb_info_from_internet --> \$cddbid = $cddbid\n\n ";

        # user interaction welcome?
        $config{input}=0;   # 1: ask user if more than one possibility
                            # 0: no user interaction		    	    
        
	my $info_cddb = "";
	my $msg;
	
	# ($Title,$Artist,$Album,$Comment,$Year,$Track_Number,$Total_Track,$Genre) ARE NOT Global variables
	# all the 8 tags
        my $Title   = "";
        my $Artist  = "artist";        
        my $Album   = "album";
        my $Genre   = "Other";
	my $Comment = "";
        my $Year    = "";
        my $Track_Number = "";
        my $Total_Track  = "";
	
	$info_cddb = get_cddb_info_from_home(); # return the cddb filename
	if ( $info_cddb ne "" and not $check_button_overwrite_cddb->get_active ){
	   $msg = $langs{msg020} . $info_cddb;
	   return ( msg => $msg ); # not overwrite
	}
	else{
	   eval {%cd = $use_external_cddbget ? get_cddb(\%config) : CDDB_get::Internal::get_cddb(\%config);};    # get info from internet
	   if($@) { 
	      if ( $info_cddb ne "" ) { $msg = $langs{msg071} . "$info_cddb."; }
	      else { $msg = $langs{msg072}; }  # " cddb: can't connect to internet!";
	      return ( msg => $msg );          # not overwrite
	   }
	}
	$Artist = $cd{artist};     $Artist = remove_change_10_chars($Artist);
	$Album  = $cd{title};      $Album  = remove_change_10_chars($Album);
	$Genre  = $cd{genre};      $Genre  = remove_change_10_chars($Genre);
	$Year   = $cd{year};       $Year   = remove_change_10_chars($Year);
        $Total_Track = $cd{tno};   $Total_Track  = remove_change_10_chars($Total_Track);	
	
	# initial values
        if ( $Artist eq "" or not defined $Artist ) { $Artist = "artist"; }
        if ( $Album  eq "" or not defined $Album  ) { $Album  = "album";  }
        if ( $Genre  eq "" or not defined $Genre  ) { $Genre  = "Other";  }
        if ( $Year   eq "" or not defined $Year   ) { $Year   = "";       }
				
	my $model = $treeview_play->get_model;
		
        for (my $row=0; $row<=$Total_Track; $row++){
  
	  my $track = sprintf("%02d", $row+1);
          my $titulo = $cd{track}->[$row];   # foreach my $titulo ( @{$cd{track}} ) {
	  $titulo = remove_change_10_chars($titulo);
	  
          my $iter  = $model->get_iter_from_string ("$row");
      
          # set all the new 8 entries:	  
	  
	  eval { $titulo = filename_to_unicode $titulo; };
          $files_info[$row]{title}    = $titulo;
	  
	  eval { $Artist = filename_to_unicode $Artist; };
          $files_info[$row]{artist}   = $Artist; 
	  
	  eval { $Album = filename_to_unicode $Album; };	       
          $files_info[$row]{album}    = $Album;
	  
	  eval { $Genre = filename_to_unicode $Genre; };
          $files_info[$row]{genre}    = $Genre;	  
	  
          #$files_info[$row]{comment} = $Comment;
          $files_info[$row]{year}     = $Year;
          #$files_info[$row]{track}       = $Track_Number;
          #$files_info[$row]{total_track} = $Total_Track;
   
          $model->set ($iter, COLUMN_ARTIST, $files_info[$row]{artist}, # set value on model
                              COLUMN_TITLE,  $files_info[$row]{title},
		              COLUMN_ALBUM,  $files_info[$row]{album},
		             #COLUMN_TRACK,  $files_info[$row]{track},  # $Track_Number,
		              COLUMN_YEAR,   $files_info[$row]{year},
	              ) if $iter;
        }
	save_cddb_info_to_home(0); # save info to "$home/.cddb/ ($dir/) $cddbid"			      
}


##-----------------------------------------------------## 

sub save_cddb_info_to_home {	#26jan2008
   my $row = shift;
   return if ($files_info[$row]{extension_input} ne 'cda');
	
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};
	
	my $info_cddb = undef; #filename of $info_cddb saved at $home
	
	# Get ID number of CD.
	my $cddbid = $use_external_cddbget ? get_discids($audiodevice_path)->[0] : CDDB_get::Internal::get_discids($audiodevice_path)->[0];
	$cddbid = sprintf("%08x", $cddbid);
	
	#print "\n\n save_cddb_info_to_home --> \$cddbid = $cddbid\n\n ";
	
	# -d : if file is a directory
	if ( -d filename_from_unicode "$home/.cddb" ){			
	   opendir(DIR, filename_from_unicode "$home/.cddb" ) or die "couldn't execute opendir: $!\n";;  #search for $home/.cddb/$Genre/ directory
	      while (my $direct = readdir(DIR)) {
	      next if $direct eq ".";
	      next if $direct eq "..";
	      if ( -e filename_from_unicode "$home/.cddb/$direct/$cddbid" ){
	         $info_cddb = "$home/.cddb/$direct/$cddbid";
	         last;
	      }
	   }
	   closedir(DIR);
	}
	# make the directory "$home/.cddb/$Genre" if it not exist
	# if the file "$home/.cddb/$direct/$cddbid" don't exist, make the file "$home/.cddb/$Genre/$cddbid".
	if ( not defined $info_cddb ){		 
	   my @cmd = ( 'mkdir', '-p', $home.'/.cddb/'.$Genre ); # create the directory .cddb/$Genre		 
           exec_cmd_system2(@cmd);	   
      
	   $info_cddb = "$home/.cddb/$Genre/$cddbid";
	   insert_msg("Saved cddb file to $info_cddb", "small");
           insert_msg("\n", "small");
	}
	
	my $first_artist = $files_info[0]{artist};
	my $DiscArtist   = $first_artist;	
	my $multi_artist = $false;	
	
	for (my $row=0; $row <= $#files_info ; $row++){         # determine if the CD is multi artist
	   if ($files_info[$row]{extension_input} ne 'cda'   ){last;}
           if ($files_info[$row]{artist}    eq 'artist'){next;}
	   if ( uc($first_artist) ne uc($files_info[$row]{artist}) ){$multi_artist = $true;}	   	     
        }
		
	# See 'man perlopentut' for '+>' to specify both read and write access	
	open( CDDB, '+>', "$info_cddb" ) or die "Can not write to $info_cddb: $!";
	   print CDDB "# created by gnormalize - version $VERSION\n";
	   print CDDB "# homepage: $HOMEPAGE\n\n";
	   print CDDB "DISCID=$cddbid\n";
	   print CDDB "DTITLE=$DiscArtist / $Album\n";
	   print CDDB "DYEAR=$Year\n";
	   print CDDB "DGENRE=$Genre\n";
	
	   # fill the music titles	and artist name
	   for (my $row=0; $row <= $#files_info ; $row++){
	      if ($files_info[$row]{extension_input} ne 'cda'){last;}	   
	      print CDDB "TTITLE$row=$files_info[$row]{title}\n";
	      print CDDB "TARTIST$row=$files_info[$row]{artist}\n" if $multi_artist;
           }
	close CDDB;	
			
	# some programs search for cddbid at "$home/.cddb/$cddbid", then make a symbolic link. 
	# symlink OLDFILE,NEWFILE  ;; see perlfunc
	my $symlink_exists = eval { symlink( $info_cddb,"$home/.cddb/$cddbid" ); 1 };
	if ( $symlink_exists != 1 ){ link $info_cddb,"$home/.cddb/$cddbid"; }		
	
	my $model = $treeview_play->get_model;
	for (my $row=0; $row<=$#files_info;$row++){
	   next if ($files_info[$row]{extension_input} ne 'cda');   
	   my $iter  = $model->get_iter_from_string ("$row");
	   	
	   $files_info[$row]{filepath} = make_filepath_format_for_cda($row);
	   $files_info[$row]{filename} = make_filename_format_for_cda($row);     
           $files_info[$row]{directory_remain} = remove_directory_base($audiodevice_path,$files_info[$row]{filepath}); # mar2008 
	   
	   $model->set ($iter, COLUMN_FILEPATH, $files_info[$row]{filepath},
			       COLUMN_FILENAME, $files_info[$row]{filename},			       			       
	               ) if $iter; 
	}	

	my %hash = determine_directory_and_filename_and_extension(row => $row);
	set_output_and_refresh_progress_bar(%hash); 
	
	show_scrolling_text(); # Display the "Artist - Title - Album ..."
	make_artist_and_album_treeview_column( make_artist_column => $true, make_album_column => $true, array_with_tracks => \@files_info );
	
	#print "\n save_cddb_info_to_home --> \$DiscArtist = $DiscArtist ;; \$Album = $Album\n";
	
	return $info_cddb; # the filename 
}

##-----------------------------------------------------##  

# Get cddb info and return the cddb filename
sub get_cddb_info_from_home { 
        my $model = $treeview_play->get_model;
	my $info_cddb = ""; #filename

        # Get ID number and track number of CD.	
	my $cddbid = $use_external_cddbget ? get_discids($audiodevice_path)->[0] : CDDB_get::Internal::get_discids($audiodevice_path)->[0];	
	$cddbid = sprintf("%08x", $cddbid);	
	my $tracks = $use_external_cddbget ? get_discids($audiodevice_path)->[1] : CDDB_get::Internal::get_discids($audiodevice_path)->[1];	
	#print "cddbid = $cddbid ;; tracks = $tracks ;; home - $home \n";
	
	# -d : if file is a directory
	if ( -d "$home/.cddb" ){
	   opendir(DIR, "$home/.cddb" ) or die "couldn't execute opendir: $!\n";  #search for $genre/$cddbid file
	   while (my $dir = readdir(DIR)) {
		next if $dir eq ".";
		next if $dir eq "..";
		if ( -e filename_from_unicode "$home/.cddb/$dir/$cddbid" ){
		   $info_cddb = "$home/.cddb/$dir/$cddbid";
		   #print "-->dir = $dir ;; info_cddb = $info_cddb\n";
		   last;
		}
		#print "dir = $dir ;; info_cddb = $info_cddb\n";
	   }
	   closedir(DIR);
	}
        
	# the file "$home/.cddb/$cddbid" have less preference than "$home/.cddb/$dir/$cddbid"
	if ( -e filename_from_unicode "$home/.cddb/$cddbid" and $info_cddb eq "" ){$info_cddb = "$home/.cddb/$cddbid";}
	if ( $info_cddb eq "" ){ return $info_cddb;} # no file found
	#print "\$info_cddb = $info_cddb\n";	
	
	#input:	
	#DISCID=29107b14
        #DTITLE=Alceu Valenca / Focus
        #DYEAR=1999
        #DGENRE=unknown
        #DID3=12
        #TTITLE0=Estacao da luz
	#TARTIST0=Claudio    # if have multi artist
        #TTITLE1=petalas
	#TARTIST1=Alceu
        #TTITLE2=leque moleque
	#TARTIST2=Jo�o
	
	# ($Title,$Artist,$Album,$Comment,$Year,$Track_Number,$Total_Track,$Genre) ARE NOT Global variables
	# all the 8 tags
        my $Title   = "";
        my $Artist  = "artist";        
        my $Album   = "album";
        my $Genre   = "Other";
	my $Comment = "";
        my $Year    = "";
        my $Track_Number = "";
        my $Total_Track  = "";
	
	my @ttitle; my @tartist;
	
	## 26jan2008
	open( INFOCDDA, "<", $info_cddb ) or die "Can't open <$info_cddb>: $!, stopped";     # read from file	
	while( <INFOCDDA> )                                # Get Artist/Album/Year/Genre/title info. 
	{    
	     if ($_ =~ /DTITLE=\s*(.*)\s*\/\s*(.*)\s*\n/gi){ 
	        $Artist = remove_whitespace_character($1); 
	        $Album  = remove_whitespace_character($2); }	     	     
	     if ($_ =~ /DYEAR=(\d{4})\n/i){ $Year = $1; }
	     if ($_ =~ /DGENRE=(.*)\n/i){ $Genre = $1; }	     
	     if ($_ =~ /TITLE(\d+)=(.*)\n/i){ $ttitle[$1] = remove_whitespace_character($2); }	     
	     if ($_ =~ /ARTIST(\d+)=(.*)\n/i){ $tartist[$1] = remove_whitespace_character($2); } #multi artist	     	     	     
	}
	close(INFOCDDA);	
		
	# initial values
	if ( $Artist eq "" or not defined $Artist ) { $Artist = "artist"; }
	if ( $Album  eq "" or not defined $Album  ) { $Album  = "album";  }
	if ( $Genre  eq "" or not defined $Genre  ) { $Genre  = "Other";  }
	if ( $Year   eq "" or not defined $Year   ) { $Year   = "";       }
	
	$Artist = remove_change_10_chars($Artist);
	$Album  = remove_change_10_chars($Album);
	$Genre  = remove_change_10_chars($Genre);
	$Year   = remove_change_10_chars($Year);
	
	eval { $Album = filename_to_unicode $Album; };
	eval { $Genre = filename_to_unicode $Genre; };
	
	for (my $row=0; $row<=$#files_info;$row++){
	
	   next if ($files_info[$row]{extension_input} ne 'cda');   
	   my $iter  = $model->get_iter_from_string ("$row");	   
	   	   	   
	   $files_info[$row]{comment}     = "";	   	   
	   $files_info[$row]{genre}       = $Genre;	   
	   $files_info[$row]{total_track} = $#files_info + 1; # $Total_Track	   
	   
	   my $art = defined $tartist[$row] ? $tartist[$row] : $Artist;
	   $art    = remove_change_10_chars($art);
	   eval { $art = filename_to_unicode $art; };	   	   
	   $files_info[$row]{artist} = $art;
           $model->set ($iter, COLUMN_ARTIST, $files_info[$row]{artist});
	      
	   if (	defined $ttitle[$row] ){	   
	      $ttitle[$row] = remove_change_10_chars( $ttitle[$row] );
	      eval { $ttitle[$row] = filename_to_unicode $ttitle[$row]; };	   	   
	      $files_info[$row]{title} = $ttitle[$row];
              $model->set ($iter, COLUMN_TITLE, $files_info[$row]{title});	   	      	      	
	   }
	   	   	   
	   $files_info[$row]{album} = $Album;
           $model->set ($iter, COLUMN_ALBUM, $files_info[$row]{album});
	   
	   $files_info[$row]{year} = $Year;
           $model->set ($iter, COLUMN_YEAR, $files_info[$row]{year});	     	   
	}
	for (my $row=0; $row<=$#files_info;$row++){
	   if ($files_info[$row]{extension_input} ne 'cda'){next;}
	   
	   my $iter  = $model->get_iter_from_string ("$row");
	   	
	   $files_info[$row]{filepath} = make_filepath_format_for_cda($row);
	   $files_info[$row]{filename} = make_filename_format_for_cda($row);     
           $files_info[$row]{directory_remain} = remove_directory_base($audiodevice_path,$files_info[$row]{filepath}); # mar2008 
	   
	   $model->set ($iter, COLUMN_FILEPATH, $files_info[$row]{filepath},
			       COLUMN_FILENAME, $files_info[$row]{filename},			       			       
	               ) if $iter; 
	}
	return $info_cddb;	
}

sub remove_whitespace_character {
   my $char = shift;
   $char =~ s/^\s*//;  # remove the \s whitespace character at the first position.
   $char =~ s/\s*$//;  # remove the \s whitespace character at the end position.
   $char =~ s/\s+/ /g; # replace more than one \s whitespace character by only one.
   return $char;
}

##-----------------------------------------------------##

#  cda --> wav   ; rip audio cd with cdparanoia

sub refresh_cda { 
        $audiodevice_path = $entry_cda->get_text; # /dev/hdc or /dev/cdrom or ...
        stop_playing_music();		
	
	# make 3 arrays with frames of audio cd and return $total_frames number.
	# The 3 arrays are @length, @music_sector and @start_sector.
	my %hash = length_music_sector();
	my $total_frames = $hash{total_frames} if $hash{total_frames};
	my $msg = $hash{msg} if $hash{msg};	
	
	print filename_from_unicode "\n\n ---> \$msg = $msg\n\n" if $msg;
	#print "\n\$ ---> total_frames = $total_frames\n\n" if $total_frames;
	
	# get the old model from Gtk2::TreeView
        # clear the old model - see <man Gtk2::ListStore>	
	$treeview_play->get_model->clear;
	$treeview_album->get_model->clear;
        $treeview_artist->get_model->clear;
	
	#print "\n refresh_cda ---> aqui\n";

	# create the new tree model
        my $model = create_model_audio_cd(@length); # and fill the @files_info
	
	# refresh tree view
        $treeview_play->set_model($model);
	count_artists_and_album_already_played(update_model_artist => $false, update_model_album => $false);
   
        # add columns to the tree view
        add_columns(show_file => $false, show_play => $false);

	if ( defined $files_info[0]{filepath} and $total_frames > 0 ){ # exist, at least, one audiocd track	
	   $force_unselect_all_tracks = $false; # to select all tracks
	   unselect_cda();  # subroutine that select all tracks
	   $button_unselec->set_sensitive($true);
	   $button_selec->set_sensitive($true);
	   if ( defined $cdcd_path or $use_audiocd eq $true or $os =~ /Linux/i ){	   
	      $da->set_sensitive($true);
	      @rows_already_played = ();
	      $go_forward = $false;
	      $go_back = $false;	            
	      $have_current_track = audio_cd_have_current_track($audiodevice_path) 
	                            if ($use_audiocd and $cdplayer eq "Audio::CD");				      		    
	   }
	   $normalize_button->set_label("rip + normalize + encode");
	   change_font_for_all_child($window_font_name,$normalize_button);	   	   
	   
	   $button_save_tag->set_sensitive($false); 
	   
	   my %hash_cddb;
	   
	   if ( $check_button_cddb->get_active ){
	      $status_bar->push($context_id, $langs{msg068} ); # " Getting information from cddb ...";
	      while (Gtk2->events_pending()) { Gtk2->main_iteration()};
	      %hash_cddb = get_cddb_info_from_internet();
	      $msg = $hash_cddb{msg};
	   }
	   else { $msg = $langs{msg069}; }
	   
	   get_selection_tree(); # select the first file and get info from file      	   	      	   
	   
	   print_cdparanoia_output($total_frames);
	   show_scrolling_text(); # Display the "Artist - Title - Album ..."           	   			   	   
	}
	else { entry_cda_change(); }
	
	make_artist_and_album_treeview_column( make_artist_column => $true, make_album_column => $true, array_with_tracks => \@files_info );
	
	# verify if some ripper is available.
	if ( $ripper eq "cdparanoia" and not $cdparanoia_path ){
           $status_bar->push($context_id, $langs{msg073} );
           $extension_input = 'error';
           return $false;
        }
	elsif ( $ripper eq "cdda2wav" and not $cdda2wav_path ){
           $status_bar->push($context_id, $langs{msg074} );
           $extension_input = 'error';
           return $false;
        }
	# show final msg 
	$status_bar->push($context_id, $msg ) if $msg; 		
}

sub entry_cda_change {
   $button_selec->set_sensitive($false);
   $button_unselec->set_sensitive($false);
   $da->set_sensitive($false);
   $extension_input = 'error'; # rip audio cd is not possible   
   stop_playing_music();
   #if ( defined($timer) ){ Glib::Source->remove($timer);} # quit loop, see <man Glib::MainLoop>
   
   # erase all info      
   
   # clear the old model - see <man Gtk2::ListStore>
   $treeview_play->get_model->clear;
   $treeview_album->get_model->clear;
   $treeview_artist->get_model->clear;
   
   my $row = 0;
   
   # erase all technical informations:
   $files_info[$row]{extension_input} = 'mp3';
   $files_info[$row]{technical_info}  = "MPEG";  # standard value
   $files_info[$row]{bitrate_original}  = 160;   # standard value if "change properties" is not active 
   $files_info[$row]{bitrate_average}  = $true;  # $true or $false
   $files_info[$row]{mode} = '';
   $files_info[$row]{length} = '';
   $files_info[$row]{bitrate} = undef;
   $files_info[$row]{frequency} = undef;
   $files_info[$row]{fileSize} = undef;
   
   # erase all the 8 tags   
   $files_info[$row]{title}  = "";
   $files_info[$row]{artist}  = "";  
   $files_info[$row]{album}  = ""; 
   $files_info[$row]{track}  = ""; # track = track_number
   $files_info[$row]{total_track}  = ""; 
   $files_info[$row]{comment}  = "";
   $files_info[$row]{year}  = "";  
   $files_info[$row]{genre}  = "";
   
   set_tag_info($row); 
   
   # erase progress bar names
   $pbar->set_text(" ");          $pbar->set_fraction(0); 
   $pbar_n->set_text(" ");        $pbar_n->set_fraction(0);
   $pbar_encode->set_text(" ");   $pbar_encode->set_fraction(0);
      
   my %hash = determine_directory_and_filename_and_extension(row => $row); 
   refresh_input_output_arrows();
   $status_bar->push($context_id, "" );
      
   $normalize_button->set_label("normalize");
   
   @files_info = ();              # reset the array
   %albums_already_played = ();   # reset the hash whose key is only the played album name
   %artists_already_played = ();  # reset the hash whose key is only the played artist name
   @length = ();         # array of music length
   @music_sector = ();   # array of relative frames
   @start_sector = ();   # absolute frames - 150 (offset)
   $selected_row = 0;            
}

sub length_music_sector { # make this 3 arrays
   @length = ();       # array of music length
   @music_sector = (); # array of relative frames
   @start_sector = (); # absolute frames - 150
   my $total_frames = 0;
   my $msg;
   my $channel;
   
   if ($os =~ /Linux/i) {
	$toc_audiocd = gnormalize::cdplay::read_toc($cdplayer); # toc of audiocd, array of reference
        if ( not $toc_audiocd ){ # can't read the cdrom drive
	   $button_selec->set_sensitive($false);
           $da->set_sensitive($false);
	   $msg = $langs{msg067}."$audiodevice_path.";
	   return ( total_frames => $total_frames, msg => $msg );
	}	   
        my $total_track = $toc_audiocd->[0]->{total_track};
	$channel = 2;
        for (my $i = 1; $i <= $total_track; $i++) {
           my $min = $toc_audiocd->[$i]->{min};
           my $sec = $toc_audiocd->[$i]->{sec};
           push @length ,"$min:$sec" ;  
           push @music_sector ,$toc_audiocd->[$i]->{frames};       # for relative frames
           push @start_sector ,$toc_audiocd->[$i]->{begin_frames}; # for absolute frames - 150 (gap)
        }	   
	$total_frames = $toc_audiocd->[0]->{total_frames}; 	   	   
   }
   elsif ( defined $cdparanoia_path ){ # use cdparanoia for other operational system
   
        #my $cdparanoia_path = '/usr/bin/cdparanoia';
	
	# cdda2wav  dev=/dev/hdc  -J -v toc
	# $cdda2wav_path  dev=$audiodevice_path  -J -v toc
	
	$status_bar->push($context_id, $langs{msg021} );	
	while (Gtk2->events_pending()) { Gtk2->main_iteration()};
	
	$priority = $spinner_pri->get_value;
	
	# -Q --query  Perform  CDROM  drive autosense, query and print the CDROM table
        # of contents, then quit.
         	
	my $cmd = "$nice_path -n $priority $cdparanoia_path  -Q -d $audiodevice_path ";	
	
	my $list = exec_cmd_system($cmd);

	if ( $list =~ /Unable\sto\sopen\sdisc/is or $list =~ /Unable\sto\sopen\scdrom\sdrive/is ){
	   $button_selec->set_sensitive($false);
           $da->set_sensitive($false);
	   $msg = $langs{msg067}."$audiodevice_path.";
	   return ( total_frames => $total_frames, msg => $msg );
	}
	#output:	
	# Table of contents (audio tracks only):
        #track        length               begin        copy pre ch
        #===========================================================
        #  1.    11900 [02:38.50]        0 [00:00.00]    no   no  2
        #  2.    21945 [04:52.45]    11900 [02:38.50]    no   no  2
	#  3.    18505 [04:06.55]    33845 [07:31.20]    no   no  2
	# 18.    15580 [03:27.55]   259607 [57:41.32]    no   no  2
	# <man perlrequick or man perlretut>
	
	# @length is an array with length of the songs
	while( $list =~ /\s*\d+\.\s+(\d+)\s+\[(.*):(\d+\.\d+)\]\s+(\d+)\s+\[.*\]\s+\w+\s+\w+\s+(\d+)/g )
	{   
	   my $sec = number_value(sprintf("%02d", $3 )); # 02d: leading zero
	   push @length ,"$2:$sec" ;  
	   push @music_sector , $1; 
	   push @start_sector , $4;
	   $channel = $5;
	}			
	# Audio CD Total Time
	# 23.    18012 [04:00.12]   322529 [71:40.29]    no   no  2
        #TOTAL  340541 [75:40.41]    (audio only)
	while( $list =~ /TOTAL\s+(\d+)\s+\[(\d+):(\d+\.\d+)\]\s+/g ) {       
	   $total_frames = $1;
	}	
   } # cdparanoia , final
   
   # Get the $fileSize
   my $totalbytes = $total_frames * 2352 ; 
   push @start_sector, $total_frames;
   $audio_cd_fileSize = sprintf("%.1f", $totalbytes/(1024*1024) );   
   $audio_cd_channel = $channel;   
   
   # Audio CD size
   # see /usr/include/linux/cdrom.h
   # CD_FRAMES            75 /* frames per second */
   # CD_FRAMESIZE_RAW   2352 /* bytes per frame, "raw" mode */
   # 1 second have 75 frames, that have 75*2352 bytes = 75*2352*8 bits = 1 411 200 bits = 1411.2 kbits
   # So, the bitrate of an audio cd is equal to 1411.2 kb/s .

   my $minTot = $total_frames / (60 * 75);
   my $secTot = ($total_frames / 75) % 60;
   $minTot = sprintf ( "%02d", $minTot);
   $secTot = sprintf ( "%02d", $secTot);
   $audio_cd_total_time = "$minTot:$secTot";
   $audio_cd_total_time = time_to_sec($audio_cd_total_time);

   # convert x seconds to hour:min:sec format
   my ($hourT,$minT,$secT) = sec_to_time($audio_cd_total_time);    # return ($hour,$min,$sec);  
   
   $audio_cd_total_time = $hourT > 0 ? "$hourT:$minT:$secT" : "$minT:$secT" ; 
   
   #for (my $i=0;$i<@length;$i++){ print "i=$i ; length=$length[$i] ; $music_sector[$i] ; $start_sector[$i] \n"; }
   return ( total_frames => $total_frames, msg => $msg );
}

$buffer->create_tag ("paranoia",     'foreground' => 'blue',    # see <man Gtk2::TextTag> for more options
                                     'background' => '#B8D3C1', # #B8D3C1 = 184 211 193 (RGB)
                                  'justification' => 'center',
                                      left_margin => 0,
				            style => 'normal',
				        wrap_mode => 'word',
					    scale => '1.1',
					   family => 'Courier',
					  # family => 'Terminal',
				          # family => 'Fixed',
                                    'size-points' => '11');

sub print_cdparanoia_output {
   my $total_frames = shift || 0;
   
   my $art = $files_info[0]{artist}; # [0] is the first artist
   my $alb = $files_info[0]{album};
   
   insert_msg("\n$art / $alb" , "small-black");

   insert_msg("\nTable of contents (audio tracks only):      \n" , "paranoia");
   insert_msg("track        length               begin     \n" , "paranoia");
   insert_msg("============================================\n" , "paranoia");

   for (my $track = 1; $track <= @music_sector; $track++) {  
      my $frames = $music_sector[$track-1];       # for relative frames
      my $begin_frames = $start_sector[$track-1]; # for absolute frames - 150 (gap)
      
      my $minf = sprintf ( "%02d", $frames / (60 * 75) );
      my $secf = sprintf ( "%02d", ($frames / 75) % 60 );
      my $fraf = sprintf ( "%02d", $frames % 75 );
      
      my $minb = sprintf ( "%02d", $begin_frames / (60 * 75) );
      my $secb = sprintf ( "%02d", ($begin_frames / 75) % 60 );
      my $frab = sprintf ( "%02d", $begin_frames % 75 );
     
      # $track = " " x ( 3 - length($track) ) . $track; # the same result
      $track  = sprintf ("%3s", $track  );  # s: spaces, see perlfunc.
      $frames = sprintf ("%7s", $frames );
      $begin_frames = sprintf ("%7s", $begin_frames );       
      
      insert_msg("$track.  $frames [$minf:$secf.$fraf]  $begin_frames [$minb:$secb.$frab]\n" , "paranoia");
   }
   my $mint = sprintf ( "%02d", $total_frames / (60 * 75) );
   my $sect = sprintf ( "%02d", ($total_frames / 75) % 60 );
   my $frat = sprintf ( "%02d", $total_frames % 75 );
   $total_frames = sprintf ("%7s", $total_frames );
   
   insert_msg("TOTAL $total_frames [$mint:$sect.$frat]    (audio only)    \n", "paranoia");

   # like 'cdparanoia -Q'
   #printf "%3d.  %7ld [%02d:%02d.%02d]  %7ld [%02d:%02d.%02d]\n", $track, 
   #     $frames, ($frames / (60 * 75)), (($frames/75)%60), ($frames % 75),
   #     $begin_frames, ($begin_frames/(60*75)), (($begin_frames/75)%60), ($begin_frames % 75);	      
}
  
sub add_columns {
   my %args = ( show_filepath  => $column_show_filepath,
                show_filename  => $column_show_filename,
                show_rip       => $false,
                show_play      => $false,
		show_file      => $column_show_file,
		show_artist    => $column_show_artist,
		show_album     => $column_show_album,
		show_track     => $column_show_track,
		show_bitrate   => $column_show_bitrate,		
		show_year      => $column_show_year,
		show_frequency => $column_show_frequency,		
		show_extension => $column_show_extension,
		treeview       => $treeview_play,
                @_,             # argument pair list goes here
	      );
  my $treeview = $args{treeview};  
  my @all_columns = $treeview->get_columns; # Retuns an array of columns.
  foreach my $col (@all_columns){ $treeview->remove_column($col); }  
  
  
  # column for fixed toggles
  my $renderer_rip = Gtk2::CellRendererToggle->new;
  $renderer_rip->signal_connect (toggled => \&fixed_toggled);
  $renderer_rip->set_data (column => COLUMN_RIP);

  my $column_rip = Gtk2::TreeViewColumn->new_with_attributes ("rip", $renderer_rip, active => COLUMN_RIP, 
                                                              'cell-background-gdk' => COLUMN_COLOR);
  # set this column to a fixed sizing (of 40 pixels)  ; 
  # $column_rip->set_sizing ('fixed'); $column_rip->set_fixed_width (40);
  $column_rip->set_resizable ($true);
  $column_rip->set_min_width (34);
  $column_rip->set (alignment => 0.5, 'clickable' => $true);  # 'clickable' : Whether the header can be clicked
  $column_rip->signal_connect ( clicked => \&unselect_cda);           

  my $all_track_is_cda = $true;
  for (my $row = 0; $row <= $#files_info ; $row++){
     last if (not defined $files_info[0]{extension_input});
     if ($files_info[$row]{extension_input} ne 'cda' ){ $all_track_is_cda = $false; last; };
  };    
  $column_rip->set_title( $all_track_is_cda ? "rip" : $langs{name065} );
  $treeview->insert_column ($column_rip, COLUMN_RIP); 
     
    
  if ( $args{show_file} ){
     # file column
     my $renderer_file = Gtk2::CellRendererText->new;
     $renderer_file->set ('font' => $window_font_name, 'xalign' => 0.5);
     $renderer_file->set_data (column => COLUMN_FILE);
     
     my $column_file = Gtk2::TreeViewColumn->new_with_attributes ($langs{name007}, $renderer_file, text => COLUMN_FILE, 
                                                                  'cell-background-gdk' => COLUMN_COLOR);
     $column_file->set_min_width (40);
     $column_file->set_resizable ($true);
     $column_file->set (alignment => 0.5); # Alignment of the column header text
     $column_file->set_sort_column_id (COLUMN_FILE);
     $treeview->insert_column ($column_file, COLUMN_FILE);
  }  
  
  if ( $args{show_artist} ){
     # artist column
     $renderer_artist = Gtk2::CellRendererText->new;
     #$renderer_artist->signal_connect (edited => \&cell_edited);
     $renderer_artist->set_data (column => COLUMN_ARTIST);
     $renderer_artist->set ('font' => $window_font_name, style => 'italic', scale => '0.9');
  
     my $column_artist = Gtk2::TreeViewColumn->new_with_attributes ($langs{name046}, $renderer_artist, text => COLUMN_ARTIST,
                                                                    #editable => $true,
								    'cell-background-gdk' => COLUMN_COLOR); 
     $column_artist->set_resizable ($true);
     $column_artist->set_expand ($true);     # this column expand to max width      
     #$column_artist->set_sizing ('fixed'); $column_artist->set_fixed_width (300);     
     $column_artist->set (alignment => 0.0); # Alignment of the column header text
     $column_artist->set_sort_column_id (COLUMN_ARTIST);
     $treeview->insert_column ($column_artist, COLUMN_ARTIST);
  }    	

  # title column
  $renderer_title = Gtk2::CellRendererText->new;
  #$renderer_title->signal_connect (edited => \&cell_edited);
  $renderer_title->set_data (column => COLUMN_TITLE);
  $renderer_title->set ('font' => $window_font_name, style => 'italic', scale => '0.9');
      
  my $column_title = Gtk2::TreeViewColumn->new_with_attributes ($langs{name047}, $renderer_title, text => COLUMN_TITLE,
                                                                 #editable => $true ,
								'cell-background-gdk' => COLUMN_COLOR);  
  $column_title->set_resizable ($true);
  #$column_title->set_min_width (220);
  $column_title->set (alignment => 0.0);
  $column_title->set_expand ($true);  # this column expand to max width
  #$column_title->set_sizing ('fixed'); $column_title->set_fixed_width (300);  
  $column_title->set_sort_column_id (COLUMN_TITLE);
  $treeview->insert_column ($column_title, COLUMN_TITLE);  
     
  if ( $args{show_album} ){
     # album column
     $renderer_album = Gtk2::CellRendererText->new;
     $renderer_album->set_data (column => COLUMN_ALBUM);
     $renderer_album->set ('font' => $window_font_name, style => 'italic', scale => '0.9');
     
     my $column_album = Gtk2::TreeViewColumn->new_with_attributes ($langs{name053}, $renderer_album, text => COLUMN_ALBUM,
                                                                   'cell-background-gdk' => COLUMN_COLOR);
     $column_album->set_resizable ($true);
     #$column_album->set_min_width (100);
     $column_album->set (alignment => 0.0); # Alignment of the column header text
     $column_album->set_expand ($true);  # this column expand to max width
     $column_album->set_sort_column_id (COLUMN_ALBUM);
     $treeview->insert_column ($column_album, COLUMN_ALBUM);
  }  
  
  if ( $args{show_track} ){  
     # column for tracks
     $renderer_track = Gtk2::CellRendererText->new;
     $renderer_track->set ('font' => $window_font_name, 'xalign' => 0.5);
     $renderer_track->set_data (column => COLUMN_TRACK);
  
     my $column_track = Gtk2::TreeViewColumn->new_with_attributes ($langs{name045}, $renderer_track, text => COLUMN_TRACK, 
                                                                   'cell-background-gdk' => COLUMN_COLOR);      
     $column_track->set_min_width (40);
     $column_track->set_resizable ($true);
     $column_track->set (alignment => 0.5); # Alignment of the column header text
     $column_track->set_sort_column_id (COLUMN_TRACK);
     #$column_track->set_expand ($true);
     $treeview->insert_column ($column_track, COLUMN_TRACK);
  }
  
  # length column
  $renderer_length = Gtk2::CellRendererText->new;
  $renderer_length->set ('font' => $window_font_name, 'xalign' => 0.5);
  my $column_length = Gtk2::TreeViewColumn->new_with_attributes ($langs{name044}, $renderer_length, text => COLUMN_LENGTH, 
                                                              'cell-background-gdk' => COLUMN_COLOR);
  $column_length->set_min_width (50);
  $column_length->set_resizable ($true);
  $column_length->set (alignment => 0.5); # Alignment of the column header text
  $column_length->set_sort_column_id (COLUMN_LENGTH);
  $treeview->insert_column ($column_length, COLUMN_LENGTH);
  
  if ( $args{show_bitrate} ){
     # bitrate column
     my $renderer_bitrate = Gtk2::CellRendererText->new;
     $renderer_bitrate->set_data (column => COLUMN_BITRATE);
     $renderer_bitrate->set ('font' => $window_font_name, 'xalign' => 0.5);
     
     my $column_bitrate = Gtk2::TreeViewColumn->new_with_attributes ("Bitrate", $renderer_bitrate, text => COLUMN_BITRATE, 
                                                                   'cell-background-gdk' => COLUMN_COLOR);
     $column_bitrate->set_min_width (50);
     $column_bitrate->set_resizable ($true);
     $column_bitrate->set_expand ($false);     
     $column_bitrate->set (alignment => 0.5); # Alignment of the column header text
     $column_bitrate->set_sort_column_id (COLUMN_BITRATE);
     $treeview->insert_column ($column_bitrate, COLUMN_BITRATE);
  }   
  if ( $args{show_year} ){
     my $renderer_year = Gtk2::CellRendererText->new;
     $renderer_year->set_data (column => COLUMN_YEAR);
     $renderer_year->set ('font' => $window_font_name, 'xalign' => 0.5);
     
     my $column_year = Gtk2::TreeViewColumn->new_with_attributes ($langs{name049}, $renderer_year, text => COLUMN_YEAR,
                                                               'cell-background-gdk' => COLUMN_COLOR);
     $column_year->set_resizable ($true);
     $column_year->set (alignment => 0.5); # Alignment of the column header text
     $column_year->set_min_width (50);
     $column_year->set_sort_column_id (COLUMN_YEAR);
     $treeview->insert_column ($column_year, COLUMN_YEAR);
  }
  if ( $args{show_frequency} ){
     my $renderer_frequency = Gtk2::CellRendererText->new;
     $renderer_frequency->set_data (column => COLUMN_FREQUENCY);
     $renderer_frequency->set ('font' => $window_font_name, 'xalign' => 0.5);
     
     my $column_frequency = Gtk2::TreeViewColumn->new_with_attributes ($langs{name041}, $renderer_frequency, text => COLUMN_FREQUENCY,
                                                                     'cell-background-gdk' => COLUMN_COLOR);
     $column_frequency->set_resizable ($true);
     $column_frequency->set (alignment => 0.5); # Alignment of the column header text
     $column_frequency->set_min_width (50);
     $column_frequency->set_sort_column_id (COLUMN_FREQUENCY);
     $treeview->insert_column ($column_frequency, COLUMN_FREQUENCY);
  }
  if ( $args{show_filepath} ){
     # filename column
     my $renderer_filepath = Gtk2::CellRendererText->new;
     $renderer_filepath->set_data (column => COLUMN_FILEPATH);
     $renderer_filepath->set ('font' => $window_font_name, scale => '0.9');
     
     my $column_filepath = Gtk2::TreeViewColumn->new_with_attributes ($langs{name050}, $renderer_filepath, text => COLUMN_FILEPATH,
                                                                   'cell-background-gdk' => COLUMN_COLOR);
     $column_filepath->set_resizable ($true);
     $column_filepath->set (alignment => 0.0); # Alignment of the column header text
     $column_filepath->set_expand ($false);     # this column expand to max width
     $column_filepath->set_sort_column_id (COLUMN_FILEPATH);
     $treeview->insert_column ($column_filepath, COLUMN_FILEPATH);
  }
  if ( $args{show_filename} ){
     my $renderer_filename = Gtk2::CellRendererText->new;
     $renderer_filename->set_data (column => COLUMN_FILENAME);
     $renderer_filename->set ('font' => $window_font_name, scale => '0.9');
     
     my $column_filename = Gtk2::TreeViewColumn->new_with_attributes ($langs{name056}, $renderer_filename, text => COLUMN_FILENAME,
                                                                   'cell-background-gdk' => COLUMN_COLOR);
     $column_filename->set_resizable ($true);
     $column_filename->set (alignment => 0.0); # Alignment of the column header text
     $column_filename->set_expand ($false);    # this column expand to max width
     $column_filename->set_sort_column_id (COLUMN_FILENAME);
     $treeview->insert_column ($column_filename, COLUMN_FILENAME);
  }
  if ( $args{show_extension} ){
     # extension column
     my $renderer_extension = Gtk2::CellRendererText->new;
     $renderer_extension->set_data (column => COLUMN_EXTENSION);
     $renderer_extension->set ('font' => $window_font_name, 'xalign' => '0.5');
     
     my $column_extension = Gtk2::TreeViewColumn->new_with_attributes ($langs{name051}, $renderer_extension, text => COLUMN_EXTENSION,
                                                                    'cell-background-gdk' => COLUMN_COLOR);
     $column_extension->set_resizable ($true);
     $column_extension->set_min_width (40);
     $column_extension->set (alignment => 0.5); # Alignment of the column header text
     $column_extension->set_sort_column_id (COLUMN_EXTENSION);
     $treeview->insert_column ($column_extension, COLUMN_EXTENSION);
  }  
}

sub add_columns_album_artist { #08Jun2008
   my %args = ( column_show_play_count => $column_show_play_count,
                @_,  # argument pair list goes here
	      );	       
   my $treeview = $treeview_artist; # COLUMN_PLAY_COUNT = 13, but has column position = 1
   my $treeviewcolumn = $treeview->get_column(1);  # treeviewcolumn = $tree_view->get_column ($n)
   # my $position = $treeviewcolumn->get_sort_column_id;
   #print "COLUMN_PLAY_COUNT = ",COLUMN_PLAY_COUNT," \$treeviewcolumn = $treeviewcolumn\n";
   $treeview->remove_column($treeviewcolumn) if $treeviewcolumn;
    
   if ( $args{column_show_play_count} ){
      # artist play count
      $renderer_artist_play_count = Gtk2::CellRendererText->new;
      $renderer_artist_play_count->set_data (column => COLUMN_PLAY_COUNT);
      $renderer_artist_play_count->set ('font' => $window_font_name, 'xalign' => 0.5, style => 'italic', scale => '0.9');
     
      my $column_artist_play_count = Gtk2::TreeViewColumn->new_with_attributes ($langs{name054}, $renderer_artist_play_count, text => COLUMN_PLAY_COUNT,
                                                                             'cell-background-gdk' => COLUMN_COLOR);
      $column_artist_play_count->set_resizable ($true);
      $column_artist_play_count->set (alignment => 0.0);  # Alignment of the column header text
      $column_artist_play_count->set_expand ($false);     # this column expand to max width
      $column_artist_play_count->set_min_width (50);
      $column_artist_play_count->set (alignment => 0.5);  # Alignment of the column header text
      $column_artist_play_count->set_sort_column_id (COLUMN_PLAY_COUNT);
      $treeview->insert_column ($column_artist_play_count, COLUMN_PLAY_COUNT);
   }
   
   $treeview = $treeview_album;  # COLUMN_PLAY_COUNT = 13, but has column position = 1
   $treeviewcolumn = $treeview->get_column(1);  # treeviewcolumn = $tree_view->get_column ($n)
   $treeview->remove_column($treeviewcolumn) if $treeviewcolumn;

   if ( $args{column_show_play_count} ){
      # album play count
      $renderer_album_play_count = Gtk2::CellRendererText->new;
      $renderer_album_play_count->set_data (column => COLUMN_PLAY_COUNT);
      $renderer_album_play_count->set ('font' => $window_font_name, 'xalign' => 0.5, style => 'italic', scale => '0.9');
     
      my $column_album_play_count = Gtk2::TreeViewColumn->new_with_attributes ($langs{name054}, $renderer_album_play_count, text => COLUMN_PLAY_COUNT,
                                                                            'cell-background-gdk' => COLUMN_COLOR);
      $column_album_play_count->set_resizable ($true);
      $column_album_play_count->set (alignment => 0.0);  # Alignment of the column header text
      $column_album_play_count->set_expand ($false);     # this column expand to max width
      $column_album_play_count->set_min_width (50);
      $column_album_play_count->set (alignment => 0.5);  # Alignment of the column header text
      $column_album_play_count->set_sort_column_id (COLUMN_PLAY_COUNT);
      $treeview_album->insert_column ($column_album_play_count, COLUMN_PLAY_COUNT);
   } 
}

sub fixed_toggled {
  my ($cell, $path_string) = @_;
  my $path = Gtk2::TreePath->new ($path_string); # $path_string is the row number
  
  #my $path = $treeview_play->get_path_at_pos ($path_string);
  
  # this is necessary when the column Track or Length is reordenable or altered.
  my $model = $treeview_play->get_model;
  my $iter = $model->get_iter($path);
  #print ("model = ",$model->get ($iter)," \n");
  my $file = $model->get_value($iter,COLUMN_FILE);
  
  #my $row = ($path->get_indices)[0];
  my $row = $file-1;
   
  # change the boolean value
  $files_info[$row]{rip} ^= 1;  # set new value
  $model->set ($iter, COLUMN_RIP, $files_info[$row]{rip});
}

sub cell_edited { # not more used  15Apr2008
  my ($cell, $path_string, $new_text) = @_;
  # $path_string is the row number
  #print (" path_string = $path_string \n");
  my $path = Gtk2::TreePath->new_from_string ($path_string);

  my $column = $cell->get_data ("column"); #column number = 2 for title
  my $model = $treeview_play->get_model;
  my $iter = $model->get_iter ($path);
  
  my $track = $model->get_value($iter,COLUMN_FILE); # track number
  #my $track2 = $files_info[$row]{track}; # Note that this don't work
  my $row = $track-1;
  #my $row = ($path->get_indices)[0];
  
  my $filepath = $files_info[$row]->{filepath};
  if ( not -w filename_from_unicode $filepath and $files_info[$row]->{extension_input} ne 'cda' ){ 
     $status_bar->push($context_id, " $filepath ".$langs{msg012} );
     return;
  }  
  if ($column == COLUMN_ARTIST) { $entry_artist->set_text( $new_text ); } # this change active sub change_tag
  if ($column == COLUMN_TITLE ) { $entry_title->set_text( $new_text );  }
  
  $model->set ($iter, $column, $new_text); 
  save_tag();
  
  #$status_bar->push($context_id, $langs{msg070} );
  $status_bar->push($context_id, "Changes Saved." );
}

sub unselect_cda { # unselect all tracks; See man Gtk2::ListStore, Gtk2::TreeModel
  my $model = $treeview_play->get_model;
  my $path; my $iter;
  
  if ( @files_info <= 0 ){ return $false; }  
  my $val = $force_unselect_all_tracks ? $false : $true;
  
  $model->foreach( sub{  # model is a $ListStore
     my($ListStore,$path,$iter,$val) = @_;
     my $file = $ListStore->get_value($iter,COLUMN_FILE); 
     $files_info[$file-1]{rip} = $val; 
     $ListStore->set ($iter, COLUMN_RIP, $val);
     return $false; # to don't abandon the loop	  
  }, $val);
  
  $align_selec->remove ($align_selec->child); 
  
  if ( $force_unselect_all_tracks eq $false ){ $align_selec->add ($button_unselec); }
  else { $align_selec->add ($button_selec); }
  
  $force_unselect_all_tracks ^= 1; # change boolean variable
}


# get treeview_play selection/playing/first_row_toggled/first_row files
sub get_selection_tree {	     
  return if ( $normalize_button->get_active );
  
  my $selected  = undef;  my $row_playing = undef; my $first_row_toggled = undef; 
  my $first_row = undef;  my $row = undef;

  my $tree_selection = $treeview_play->get_selection;  # $treeview_play->get_selection is an Gtk2::TreeSelection 
  my $model = $treeview_play->get_model;  
  
  my @paths = $tree_selection->get_selected_rows;      # sel = Gtk2::TreePath
  #my @sel_rows = map $_->to_string, @paths;
  #print "\n s_tree: \@sel_rows = @sel_rows ; np = ",$#paths+1;
  
  if (@paths_button > 0){ # to select the last clicked cell
     foreach my $p (@paths_button){$tree_selection->select_path ($p);}
  } 
  my $path = $paths[0]; # get the first selected path only 
  my $iter = $model->get_iter($path) if $path;
  $selected = ($model->get_value($iter,COLUMN_FILE) - 1) if $iter;  
  
  my %treeview_play_info = get_treeview_play_informations();
  #my @array = @{$treeview_play_info{array_checked}};  # get array_with_files_checked
  $first_row_toggled = $treeview_play_info{array_checked}->[0];
  $row_playing = $treeview_play_info{row_playing};
  $first_row = $treeview_play_info{first_row};
  
  # show info with preference order: $selected -> $row_playing -> $first_row_toggled -> $first_row
  
  $row = undef;
  $row = $selected          if (defined $selected);
  $row = $row_playing       if (defined $row_playing and not defined $row);
  $row = $first_row_toggled if (defined $first_row_toggled and not defined $row);
  $row = $first_row         if (defined $first_row and not defined $row);
  
  # only for print purpose!
  $selected = 'none'          if not defined $selected; 
  $row_playing = 'none'       if not defined $row_playing;
  $first_row_toggled = 'none' if not defined $first_row_toggled; 
  $first_row = 'none'         if not defined $first_row;
  $row = 'none'               if not defined $row;   
  #print "\n \$selected          = $selected \n \$row_playing       = $row_playing \n \$first_row_toggled = $first_row_toggled ";
  #print "\n \$first_row         = $first_row  \n ------------> \$row = $row\n";
  
  return if $row eq 'none';
  
  my $filepath = $files_info[$row]{filepath};
  return unless $filepath;
  
  # save this value that will be used by 'sub change_tag' and 'sub save_tag'
  $files_info[0]{get_selection_row} = $row;  
  my %hash = determine_directory_and_filename_and_extension(row => $row);
  
  # update info
  get_info_from_file(%hash)   if ( $files_info[$row]{extension_input} ne 'cda' );   # get mp3/mp4/mpc/... info and set_tag_info
  set_tag_info($row)          if ( $files_info[$row]{extension_input} eq 'cda' );  
  set_output_and_refresh_progress_bar(%hash);   
  refresh_input_output_arrows();
}

sub get_treeview_play_informations { # 08Abr2008
   my $model = $treeview_play->get_model;   
   my @array_with_files_checked;
   my @array_with_files_unchecked;
   my $row_playing = undef;
   my $first_row = undef;
     
   $model->foreach( sub{  # model is a $ListStore
      my($ListStore,$path,$iter,$val) = @_;
      my $row = $ListStore->get_value($iter,COLUMN_FILE) - 1;
          
      # if the row is toggled, then push it into array
      if ($files_info[$row]{rip} eq $true){ push @array_with_files_checked,   $row; }
      else                                { push @array_with_files_unchecked, $row; }
           
      if ($files_info[$row]{playing}){ $row_playing = $row; }

      $first_row = $row if not defined $first_row;

      return $false; # to don't abandon the loop	  
   });

   return ( array_checked   => \@array_with_files_checked,   # ref to array
            array_unchecked => \@array_with_files_unchecked, # ref to array
            row_playing     => $row_playing,
            first_row       => $first_row,
          );  	  
}
  
sub set_no_color_for_all { # all tracks are unselected
   my $model = $treeview_play->get_model;       
   $model->foreach( sub{  # model is a $ListStore
      my ($ListStore,$path,$iter,$val) = @_;
      my $file = $ListStore->get_value($iter,COLUMN_FILE); 
      my $row = $file - 1;
      $files_info[$row]{played} = 0;
      $files_info[$row]{playing} = $false;
      $model->set ($iter, COLUMN_COLOR, undef) if $iter; # 'untaggle' the played music 
      return $false; # to don't abandon the loop	 
   });
   
   $model = $treeview_artist->get_model;      
   $model->foreach( sub{  # model is a $ListStore
      my ($ListStore,$path,$iter,$val) = @_;
      my $artist = $ListStore->get_value($iter,COLUMN_ARTIST); 
      #$artists_already_played{uc($artist)} = 0;     # Set False to the artist already played
      $model->set ($iter, COLUMN_COLOR, undef) if $iter; # 'untaggle' the played music 
      return $false; # to don't abandon the loop	 
   });
   
   $model = $treeview_album->get_model;      
   $model->foreach( sub{  # model is a $ListStore
      my ($ListStore,$path,$iter,$val) = @_;
      my $album = $ListStore->get_value($iter,COLUMN_ALBUM); 
      #$albums_already_played{uc($album)} = 0;       # Set False to the album already played
      $model->set ($iter, COLUMN_COLOR, undef) if $iter; # 'untaggle' the played music 
      return $false; # to don't abandon the loop	 
   });
}	 

sub color_the_selected_tracks_and_scroll {  # color the selected track, artist and album

   my %args = ( select_color   => 'playing', # ('no_color','playing','played')
                scroll         => $true,
		color_artist   => $true,
		color_album    => $true,
		set_rip        => $true,  
		row            => $selected_row,	
                @_,            # argument pair list goes here
	      );      	      	           
   my ($iter,$path,$color,$model);
   #while (Gtk2->events_pending()) {Gtk2->main_iteration()}; # to update   
   
   if ( $args{color_artist} ){  # color the compound artist name 'art1 & art2' and scroll only to the first artist name
      $model = $treeview_artist->get_model;
      my @artists = return_artist_name($files_info[$args{row}]); # 'art1 & art2' return (art1,art2)
      
      my $art_playcount_min = $artists[0]; # first artist
      foreach my $artist ( @artists ){
         last unless defined  $artists_already_played{ uc($artist) };
         $art_playcount_min = $artist if ( $artists_already_played{ uc($artist) } < $artists_already_played{ uc($art_playcount_min) } );
      }
      
      foreach my $artist ( @artists ){      

         if    ( $args{select_color} eq 'no_color' and not $artists_already_played{ uc($artist) }  ){  $color = undef;                     }
         elsif ( $args{select_color} eq 'playing'                                                  ){  $color = $color_row_playing;        }
         #elsif ( $args{select_color} eq 'played'  and $artists_already_played{ uc($artist) } >= 1 ){  $color = $color_row_already_played; }
	 else {  $color = $color_row_already_played; }	 
	 
	 ($iter, $path) = get_iter_path_given_track_art_alb ( value => $artist, treeview => 'treeview_artist', column => COLUMN_ARTIST );	 
         $model->set ( $iter, COLUMN_COLOR, $color ) if $iter;  # to color the selected artist line
 	   
         next if ( uc($artist) ne uc($art_playcount_min) ); # only scroll to the artist with minimum play_count or to the first artist.         
         $treeview_artist->scroll_to_cell($path, undef, $true ,0.50, 0.50) if ($path and $args{scroll});         
      }
   }
   
   if ( $args{color_album} ){ 
      $model = $treeview_album->get_model;
      my $album = return_album_name( $files_info[$args{row}] );  # if no album name, create a guess name from filepath  
   
      if    ( $args{select_color} eq 'no_color' and not $albums_already_played{ uc($album) }  ){  $color = undef;                     }
      elsif ( $args{select_color} eq 'playing'                                                ){  $color = $color_row_playing;        }
      #elsif ( $args{select_color} eq 'played'   ){  $color = $color_row_already_played; }
      else                                                                                     {  $color = $color_row_already_played; }
      	             
      ($iter, $path) = get_iter_path_given_track_art_alb ( value => $album, treeview => 'treeview_album', column => COLUMN_ALBUM );      
      
      # Now, scroll to the selected album:
      $model->set ( $iter, COLUMN_COLOR, $color ) if $iter;        # to color the selected album line	       
      $treeview_album->scroll_to_cell($path, undef, $true ,0.50, 0.50) if ($path and $args{scroll});
   }      
   
   $model = $treeview_play->get_model;
   ($iter, $path) = get_iter_path_given_track_art_alb ( value => $args{row} + 1, treeview => 'treeview_play', column => COLUMN_FILE );      
   
   $treeview_play->scroll_to_cell($path, undef, $true ,0.50, 0.50) if ($path and $args{scroll});
   
   if ( $args{select_color} eq 'no_color' ){      
      $files_info[$args{row}]{rip} = $true if $args{set_rip};     # change the boolean value
      $files_info[$args{row}]{played} = 0;
      $files_info[$args{row}]{playing} = $false;
      $color = undef;
      $treeview_play->set_drag_dest_row ($path, 'into-or-before') if $path; # select the last played track 
   }
   elsif ( $args{select_color} eq 'playing' ){
      $files_info[$args{row}]{rip} = $true;
      $files_info[$args{row}]{played} = 0;
      $files_info[$args{row}]{playing} = $true;
      $color = $color_row_playing;
   }
   elsif ( $args{select_color} eq 'played' ){
      $files_info[$args{row}]{rip} = $false;
      $files_info[$args{row}]{played} = 1;
      $files_info[$args{row}]{playing} = $false;
      $color = $color_row_already_played;      
      $treeview_play->set_drag_dest_row ($path, 'into-or-before') if $path; # select the last played track 
   }
      
   $model->set ($iter, COLUMN_RIP, $files_info[$args{row}]{rip},  #'untaggle' the played music
                       COLUMN_COLOR, $color) if $iter;            # color the $selected_row
   #print "file = ",$args{row}," ; select_color = $args{select_color} ; scroll = $args{scroll} \n";
   
   #print "\n\n color_the_selected_tracks_and_scroll --> row = $args{row} ;; select_color = $args{select_color}\n";
    
   $treeview_play->get_selection->unselect_all; # [[$treeview_play->get_selection]] is an Gtk2::TreeSelection
   get_selection_tree() if ($args{select_color} eq 'playing');	
   
   #count_artists_and_album_already_played() if ($args{select_color} eq 'playing');
}

#my ($iter, $path) = get_iter_path_given_track_art_alb ( value => $track, treeview => 'treeview_play', column => COLUMN_FILE );

sub get_iter_path_given_track_art_alb { # 14Jun2008 - See man Gtk2::ListStore, Gtk2::TreeModel - Without Loops
   my %args = (  treeview  => 'treeview_play',     # default value
		 value     => $selected_row + 1,   # value can be track/artist/album/.
		 column    => COLUMN_FILE,
                 @_,       # argument pair list goes here
              );
   return unless defined $args{treeview};
   my ($model, $path, $iter, $row, $value, $value_cmp);
   my $debug = $false;  # to print messages
   
   print "--> \$value = $args{value} in $args{treeview}.\n" if $debug;
   $value = uc( $args{value} );   # value can be track/artist/album/.

   if    ($args{treeview} eq 'treeview_play'  ) { $model = $treeview_play->get_model;   $row = $treeview_play_rows  { $value - 1 };  }  # row = track - 1
   elsif ($args{treeview} eq 'treeview_artist') { $model = $treeview_artist->get_model; $row = $treeview_artist_rows{ $value     };  }
   elsif ($args{treeview} eq 'treeview_album' ) { $model = $treeview_album->get_model;  $row = $treeview_album_rows { $value     };  }
      
   #$path = Gtk2::TreePath->new ( $row ); # get $path given/knowing the row number    
   $path = Gtk2::TreePath->new_from_string ($row) if defined $row;  
   $iter = $model->get_iter ($path) if defined $path; # See 'man Gtk2::TreeModel'
   
   # Now, test the results. If not equal, then use Brute-Force search!
   $value_cmp = defined $iter ? $model->get_value($iter,$args{column}) : 'undef_iter';
      
   if ( $value ne uc($value_cmp) or not defined $iter ) { # search_iter_path_using_brute_force
      print " Error: \$value = $value not equal to \$value_cmp = $value_cmp in $args{treeview}. Use Brute-Force search!\n" if $debug;
      #($iter,$path) = search_iter_path_for_some_element($full_row + 1,$treeview_play,COLUMN_FILE);
      ($iter,$path) = search_iter_path_using_brute_force( value => $value, treeview => $args{treeview}, column => $args{column} );
   }
   print " --- *** ---\n" if ( $args{treeview} eq 'treeview_play' and $debug );    
   return ( $iter, $path );
}

#($iter,$path) = search_iter_path_using_brute_force( value => $artist, treeview => 'treeview_artist', column => COLUMN_ARTIST );

# Find $iter and $path associeted to some file
# This is necessary when the columns Track/Artist/Album/Play Count/ ... are reordenable or altered

sub search_iter_path_using_brute_force { # 14Jun2008 - See man Gtk2::ListStore, Gtk2::TreeModel - Using Loop '$model->foreach('
   my %args = (  treeview  => 'treeview_play',   # default value
		 value     => $selected_row + 1, # value can be track/artist/album/.
		 column    => COLUMN_FILE,
                 @_,       # argument pair list goes here
              );
   return unless defined $args{treeview};
   my ($model, $path, $iter);
   
   if    ($args{treeview} eq 'treeview_play'  ) { $model = $treeview_play->get_model;   %treeview_play_rows   = (); }
   elsif ($args{treeview} eq 'treeview_artist') { $model = $treeview_artist->get_model; %treeview_artist_rows = () ;}
   elsif ($args{treeview} eq 'treeview_album' ) { $model = $treeview_album->get_model;  %treeview_album_rows  = () ;}

   my $row = 0;   
   
   $model->foreach( sub{                      # Brute-Force search
      my($ListStore,$path2,$iter2) = @_;      # model is a $ListStore  
      my $value_found = $ListStore->get_value($iter2,$args{column});
      #my $rrow = ($path2->get_indices)[0];
       
      if ( uc($args{value}) eq uc($value_found) ){  # if the values are equals, the $iter is right
         $path = Gtk2::TreePath->new ($row);
         $iter = $model->get_iter($path);
	 #print "row = $row ; value = $args{value} ; value_found = $value_found ; column = $args{column}\n"; 	 
	 #return $true; # abandon the loop 'foreach'
      }
      
      # Fill with the new values before to alter some column.
      if    ( $args{treeview} eq 'treeview_play'   ) { $treeview_play_rows  { $value_found - 1    } = $row; } # $value_found is track = row + 1
      elsif ( $args{treeview} eq 'treeview_artist' ) { $treeview_artist_rows{ uc( $value_found )  } = $row; }
      elsif ( $args{treeview} eq 'treeview_album'  ) { $treeview_album_rows { uc( $value_found )  } = $row; }
      
      #if    ( $args{treeview} eq 'treeview_artist' ) { print "\$treeview_artist_rows{ $value_found } = $treeview_artist_rows{ uc( $value_found ) } \n"; }
      #elsif ( $args{treeview} eq 'treeview_album'  ) { print "\$treeview_album_rows{  $value_found } = $treeview_album_rows{  uc( $value_found ) } \n"; }      
      
      $row += 1;
      return $false; # to don't abandon the loop	      
   } );
   
   return ($iter,$path);
}

sub search_iter_path_for_some_element { # See man Gtk2::ListStore, Gtk2::TreeModel - Not more used
   my ($value,$treeview,$column) = @_;  # value can be track/artist/album/...
   my $iter; my $path;
   my $model = $treeview->get_model;

   my $row = 0;   
   
   $model->foreach( sub{                      # Brute-Force search
      my($ListStore,$path2,$iter2) = @_;      # model is a $ListStore  
      my $value_found = $ListStore->get_value($iter2,$column);
      
      # $value can be a number or character    
      if ( uc($value) eq uc($value_found) ){  # if the values are equals, the $iter is right
         $path = Gtk2::TreePath->new ($row);
         $iter = $model->get_iter($path);
	 #print "row = $row ; value = $value ; value_found = $value_found ; column = $column\n";	 
	 return $true; # abandon the loop 'foreach'
      }      
      
      $row += 1;
      return $false; # to don't abandon the loop	      
   } );   
   return ($iter,$path);
}


sub REAPER { # To reap/eliminate dead children ;  see perlipc; Programming Perl, 3a Ed., Chap.16
   # If a second child dies while in the signal handler caused by the
   # first death, we won't get another signal. So must loop here else
   # we will leave the unreaped child as a zombie. And the next time
   # two children die we get another zombie. And so on.
   while ( waitpid(-1,WNOHANG) > 0 ){}  # waitpid return "-1" if there is no such child process.
   $SIG{CHLD} = \&REAPER;  # still loathe sysV 
}           

my $selected_row_last_value = -10; #some absurd value
my $extension_last_value = "";

sub play_selection {  # stop and play
  my %args = (  go_back   => $false, # default value
                skip      => undef,
                @_,       # argument pair list goes here
  );
  $extension_last_value = $files_info[$selected_row]{extension_input};      
  stop_playing_music();
  $status_bar->push($context_id, ""); 
  
  if ( not defined $args{skip} ) {  
     # when go_back, the selected_row is already known from @rows_already_played
     if ( not $args{go_back} ){ 
        $selected_row = choose_one_row_to_play(); 
     }
     # $selected_row == -1 when there is none selected track to play
     if ( $selected_row == -1){
        if ($loop_tracks eq $false){
	    $status_bar->push($context_id, $langs{msg022} );  
            $go_forward = $false;
	    show_time();	    		    	     	
        }
        else {
            $force_unselect_all_tracks = $false; # to select all tracks
            unselect_cda();  # subroutine that select all tracks
            $selected_row = choose_one_row_to_play();            
        }
	@rows_already_played = ();
	$selected_row_last_value = -10;
	set_no_color_for_all();	
     }
  }
  if ( $selected_row == -1 ){ return $false; } # If there is no selected track  
  
  $total_time = $files_info[$selected_row]{length} if $selected_row != -1 ; # 2:56:34   02:32
  $total_time = time_to_sec($total_time);
    
  # when cda is playing and the next selected_row is not cda
  if ( $extension_last_value eq 'cda' and $files_info[$selected_row]{extension_input} ne 'cda' ){
     stop_cda(); # don't stop if the next track have cda extension_input      
  }
   
  # xine -A arts -V none -I -H "music.mp3"
  # mac "zzz.ape"  - -d | play -t wav -d /dev/audio -
     
  # see <man SDL> or <man SDL::Cdrom> 
  #use SDL::Cdrom;
  #my $cdrom = SDL::Cdrom->new(0);
  #$cdrom->play();
  
  #my $music = $model->get_value($iter,COLUMN_FILEPATH); #print "music = $music\n";     
  my $music = $files_info[$selected_row]{filepath};  #print "music = $music\n";
  my $buffer = 4 * 1024; # 4MB
  # $device_type = 'arts'; # oss, alsa, arts, esd, jack, nas
  # $device_path = '/dev/sound/adsp';
  my @exec_argv;
  if ($Frequency == 0){ $Frequency = $files_info[$selected_row]{frequency}; }  
  if ( not -e filename_from_unicode $music and $files_info[$selected_row]{extension_input} ne 'cda'  ){
     $files_info[$selected_row]{remove} = $true;
     go_forward();
     return; 
  }  
  if ( defined $args{skip} ) { $count = $args{skip}; } # determine the start time to be played
       
  if ($files_info[$selected_row]{extension_input} eq 'mp3' and ($mpg123_path or $mpg321_path or $madplay_path or $mplayer_path) ){
        
	# $totalSeconds  = $Total_samples/$Frequency  -->  $Total_samples = $totalSeconds * $Frequency;
	# $Total_samples = $frame_count * 32*36       -->  $frame_count = $Total_samples / 32*36 = ($totalSeconds * $Frequency) / 1152;
	my $frame = sprintf ('%.0f', ($count * $Frequency) / 1152 );			
	
        if    ($mpg321_path  and $player_mp3 eq "mpg321" ){ @exec_argv = ($mpg321_path, '-o', $device_type, '-b', $buffer, '-q', '-k', $frame ); }
	elsif ($mpg123_path  and $player_mp3 eq "mpg123" ){ @exec_argv = ($mpg123_path, '-q', '-k', $frame );                                    } 
	elsif ($madplay_path and $player_mp3 eq "madplay"){ @exec_argv = ($madplay_path, '-Q', '-s', $count, '-o', $device_path );               }	
	elsif ($mplayer_path and $player_mp3 eq "mplayer"){ @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', 
	                                  $buffer, '-vo', 'null', '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count ); }
     	
	push  @exec_argv, filename_from_unicode $music;      
  }
  elsif ( $files_info[$selected_row]{extension_input} eq 'mp4' and $mplayer_path ){
        
	@exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 
	              '-really-quiet', '-slave', '-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music );	
  }  
  elsif ($files_info[$selected_row]{extension_input} eq 'mpc' and ($mpcdec_path or $mplayer_path) ){          
	
     if    ($mplayer_path and $player_mpc eq "mplayer" ){
        @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 
	              '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music );     
     } 
     elsif ($mpcdec_path and $player_mpc eq "mpcdec" ){   
        @exec_argv = ($mpcdec_path, '--silent', '--start', $count, filename_from_unicode $music, $device_path ); 
     }		   	        
  }    
  elsif ($files_info[$selected_row]{extension_input} eq 'ogg' and ($ogg123_path or $mplayer_path) ){          
	
     if    ($mplayer_path and $player_ogg eq "mplayer" ){
        @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 
	              '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music );     
     } 
     elsif ($ogg123_path and $player_ogg eq "ogg123" ){   
        @exec_argv = ($ogg123_path, '-d', $device_type, '-b', $buffer, '-q', '-k', $count, filename_from_unicode $music );
     }		   	        
  } 
  elsif ($files_info[$selected_row]{extension_input} eq 'ape' and ( ($ape_path and ($play_path or $aplay_path)) or $mplayer_path ) ){
     
     if    ($mplayer_path and $player_ape eq "mplayer" ){
        @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 
	              '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music );     
     } 
     elsif ( ($ape_path and $play_path) and $player_ape eq "mac" ){   
        # mac "zzz.ape"  - -d | play -t wav -d /dev/audio -
        #@exec_argv = ($ape_path, filename_from_unicode $music, '-', '-d', '|', '/usr/bin/play', '-t', 'wav', '-');
	#my $cmd = "$ape_path \"$music\" - -d | $play_path -t wav -d $device_path - "; 
	my $cmd = "$ape_path \"$music\" - -d | $play_path -t wav - ";
	@exec_argv = ( filename_from_unicode "$cmd" );  
     }
     elsif ( ($ape_path and $aplay_path) and $player_ape eq "aplay" ){   
        # mac "zzz.ape"  - -d | play -t wav -d /dev/audio -
        #@exec_argv = ($ape_path, filename_from_unicode $music, '-', '-d', '|', '/usr/bin/play', '-t', 'wav', '-');
	#my $cmd = "$ape_path \"$music\" - -d | $play_path -t wav -d $device_path - "; 
	my $cmd = "$ape_path \"$music\" - -d | $aplay_path -N -q - ";
	@exec_argv = ( filename_from_unicode "$cmd" );  
     }
  } 
  elsif ($files_info[$selected_row]{extension_input} eq 'flac' and ($flac123_path or $mplayer_path) ){
     
     if    ($mplayer_path and $player_flac eq "mplayer" ){
        @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 
	              '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music );     
     } 
     elsif ($flac123_path and $player_flac eq "flac123" ){   
        $count = 0;
        @exec_argv = ($flac123_path, '-d', $device_type, '-q', filename_from_unicode $music );   
     }
  }
  elsif ($files_info[$selected_row]{extension_input} eq 'wav' and ($aplay_path or $mplayer_path) ){
     
     if    ($mplayer_path and $player_wav eq "mplayer" ){
        @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 
	              '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music );     
     } 
     elsif ($aplay_path and $player_wav eq "aplay" ){   
        $count = 0;
        @exec_argv = ($aplay_path, '-N', '-q', filename_from_unicode $music );   
     }
     elsif ($play_path and $player_wav eq "play" ){   
        $count = 0;
        @exec_argv = ($play_path, filename_from_unicode $music );   
     }
  }	   
   	          
  if ($files_info[$selected_row]{extension_input} ne 'cda' and @exec_argv >=1){  
        $SIG{CHLD} = \&REAPER; # To reap/eliminate dead children ;  see perlipc
        # see man perlfunc, perlfork, perlipc ; Learning Perl 14.6, 3a Ed. ; Perl Cookbook 16.10, 2a. Ed 
        defined($pid_player = fork) or die "Can't fork: $!";
        if( $pid_player == 0 ){ 
           #Child process is here ; child process has a zero value
	   open \*STDIN, '>/dev/null';
	   open \*STDOUT,'>/dev/null';
	   open \*STDERR,'>/dev/null';
	   exec @exec_argv;  # see perlfunc
	   die "cannot play audio: $!\n";	   
        }
        #Parent process is here ; parent process has a nonzero value
        #waitpid($pid,0);		
  } 
  #print "count = $count ; pid_player = $pid_player; exec_argv = @exec_argv\n";	  
  
  if ($files_info[$selected_row]{extension_input} eq 'cda'){     
        # umount the audio cd drive if possible. This is need to play EXTRA CD.
        exec_cmd_system("umount $audiodevice_path" );
     
        if ($cdplayer eq "cdcd"){
	   my @cmd = ( $cdcd_path, '-d', $audiodevice_path, 'play', $selected_row + 1, $selected_row + 1 );
           exec_cmd_system2(@cmd);	   
        }
        elsif ( $cdplayer eq "gnormalize::cdplay" ){
	   gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1);
        }
        elsif ( $cdplayer eq "Audio::CD" ){ # libcdaudio  ;; Audio::CD ;; see <man Audio::CD>
	   $audiocd = Audio::CD->init("$audiodevice_path");
           $audiocd->play_track($selected_row + 1, $selected_row + 1);
        }
	#print "using command to play cdrom: cmd = $cmd\n";
  }	   
  # draw scrolling text     
  if ($selected_row != $selected_row_last_value){ show_scrolling_text(); }
  $selected_row_last_value = $selected_row;  
     
  $playing_music = $true;
  #while (Gtk2->events_pending()) {Gtk2->main_iteration()};  
  
  # Now, scroll to the selected artist
  color_the_selected_tracks_and_scroll( select_color => 'playing' );
  count_artists_and_album_already_played(update_model_artist => $true, update_model_album => $true);

  # see <man Glib::MainLoop>  
  # integer = Glib::Timeout->add ($interval, $callback, $data=undef, $priority=G_PRIORITY_DEFAULT)    
  if ( defined($timer) ){ Glib::Source->remove($timer);}  # to not duplicate the MainLoop
  $timer = Glib::Timeout->add (500, \&change_count, $total_time); # 250 milliseconds = 0.250 second
  # integer = Glib::IO->add_watch ($fd, $condition, $callback, $data=undef, $priority=G_PRIORITY_DEFAULT)

}
# use constant INTERVAL	=> 1000; # for cd player; 250 milliseconds = 0.250 second

sub choose_filter { # filter can be artist, album, genre, ...  See 'sub change_filter'
   my $hash = shift;
   return unless $use_filter; # $use_filter == 0
   
   my $play_tracks_from_different_albums  = $true  if $use_filter == 1;
   my $play_tracks_from_different_artists = $true  if $use_filter == 2;
   my $play_tracks_from_different_genres  = $true  if $use_filter == 3;
   my $play_tracks_from_different_years   = $true  if $use_filter == 4;           
   
   return return_album_name ($hash) if $play_tracks_from_different_albums  and defined $hash->{album};
   return return_artist_name($hash) if $play_tracks_from_different_artists and defined $hash->{artist};   
   return $hash->{genre}            if $play_tracks_from_different_genres  and defined $hash->{genre};
   return $hash->{year}             if $play_tracks_from_different_years   and defined $hash->{year};
}

      # Making Hashes of Arrays (Perl Cookbook, Chap. 11.2)
      # $hash{'a artist'} = [3,4,7, ..., n]; # anonymous array 
      # To append a new value: push @{ $hash{'a artist'} }, $row;
      # To obtain an array without repeated values: my %unique = map {$_ => 1}, @numbers; 

# Make array with all selected rows that will be played. 'sub choose_one_row_to_play' returns the selected_row number.
sub choose_one_row_to_play { # 06Jun2008
   my $random_row = -1; # get by $selected_row
   my $debug = $false;  # to print messages
       
   my %treeview_play_info = get_treeview_play_informations();
   my @rows_checked = @{$treeview_play_info{array_checked}};  # get array_with_files_checked
   #my $first_row_toggled = $rows_to_play[0];
   #my $row_playing = $treeview_play_info{row_playing};
   #my $first_row = $treeview_play_info{first_row};
   
   # The array '@rows_unchecked' will be used to get rows already played, but '@rows_already_played' would be used too.
   # '@rows_unchecked' have more informations, because '@rows_already_played' is always erased whenever quit from gnormalize.
   my @rows_unchecked = @{$treeview_play_info{array_unchecked}};  # To fill with the unchecked rows;
   print "\n\@rows_unchecked = @rows_unchecked\n" if $debug;      
   
   my @rows_to_play = @rows_checked;  
   
   if ( $use_filter and @rows_checked >= 1 and @rows_unchecked >= 1 ) {  # Add loops with 2*O(N) efficiency order.              
      
      my %available_artists = ();       # To find all available artists to play 
      foreach my $row (@rows_checked){  # It has 1*O(N) efficiency order.
         my @artists = map { uc($_) } choose_filter($files_info[$row]);	     	  
	 foreach my $art (@artists) { $available_artists{$art}++; }  # Add +1 to the available_artists	 
      }        
      my $num_dif_artists = keys %available_artists;      # How can I know how many entries are in a hash? See 'man perlfaq4'.
            
      my %artists_played = ();                            # Used to filter, such that 'filter' can be artist, album, genre, ...      
      #foreach my $row_played (@rows_already_played) {
      foreach my $row_played (@rows_unchecked) { # Permutations like (A B C D)(C A D B)(D A B C)(D ...
             
         my @art_played = map { uc($_) } choose_filter($files_info[$row_played]);	     	  
	 foreach my $art (@art_played) { $artists_played{$art}++; }  # Add +1 to the artist already played.
	 if ($debug) { foreach my $art (@art_played) { print "\n\$row_played = $row_played ; played $artists_played{$art} time(s) --> {$art} \n"; } }
      } 
       
      my $minimum = $#rows_checked + 100;             # Choose one great value
      foreach my $art ( keys %available_artists ) {   # To find the minimum play times value
	 if (not $artists_played{$art}) { $minimum = 0 ; last; }   # played 0 times
	 $minimum = $artists_played{$art} if $artists_played{$art} < $minimum;
      }
      print "\n\$minimum = $minimum ; " if $debug;

      my @last_artists_played; # To avoid to play the same artist/album sequentially
      if (@rows_already_played >= 1){
         my $last_row_played  = $rows_already_played[$#rows_already_played];
         @last_artists_played = map { uc($_) } choose_filter($files_info[$last_row_played]);
         foreach my $last_artist (@last_artists_played) { $artists_played{$last_artist}++ if ($num_dif_artists > @last_artists_played); }
      }
       
      @rows_to_play = ();                  # Fill with rows to play
      while (@rows_checked >=1 and not @rows_to_play >= 1) {   # if not select any rows_to_play, then $minimum += 1;
         foreach my $row (@rows_checked){  # It has 1*O(N) efficiency order.
         
	    my @artists = map { uc($_) } choose_filter($files_info[$row]);	     	  
	    foreach my $art (@artists) { 
	       if (not $artists_played{$art} or $artists_played{$art} <= $minimum) { push @rows_to_play, $row; last; } # use 'last' to not duplicate rows.
	    }     
         }
         print "\@rows_to_play = @rows_to_play ; \@last_artists_played = @last_artists_played ; \$num_dif_artists = $num_dif_artists ; \$minimum_new = $minimum\n" if $debug;
         $minimum += 1;
      }      
   }          
       
   # to remove one element from front of @array -- see perlfunc : splice
   if ( @rows_to_play >= 1 ){  # exist at least one element
      if ( $play_random eq $true ){ 
	     my $rand = int( rand(@rows_to_play) ); # pick one random element: 0<= rand < @rows_to_play number
	     #print " rand[0 to $#rows_to_play] = $rand ;; all rows = @rows_to_play\n";
	     $random_row = splice(@rows_to_play, int( $rand ), 1); # pull one random element of @array
      }
      else { $random_row = splice(@rows_to_play, 0, 1);} # pull the first element of @array
   }
   
   #print " random_row = $random_row ;; rows_to_play = @rows_to_play\n";
   return $random_row ; # return $row that will be played
}


# This is a loop for  "$timer = Glib::Timeout->add (250, \&change_count, $total_time);"
# at sub play_selection the show the time when button "play" is pressed.
my $count_blink = 0; # blink when paused.
sub change_count { # the main loop    

  # play all tracks  - go to next track
  if ( ($count >= $total_time or $go_forward eq $true) and $playing_music and $files_info[$selected_row]{extension_input} eq 'cda') {
     go_forward();
  }
  elsif ( defined $pid_player and $playing_music and $files_info[$selected_row]{extension_input} ne 'cda') {
     if ( waitpid($pid_player, WNOHANG) < 0 or $go_forward eq $true ){ go_forward(); }
  } 
  if ( $go_back eq $true and @rows_already_played > 0 ) { 
     go_back();
  }
  $count = $count + 0.500 if ( not $pause ); # count is a number for seconds elapsed.
  
  $count_blink += 0.500;  
  get_current_track_and_time() if ( $files_info[$selected_row]{extension_input} eq 'cda' );
  # need show time only if the count change its value.
  #if ( int($last_count) != int($count) or int($count) == 0 ){ show_time(); }
  show_time();

  return $true; # if return is $false; then stop Glib::Timeout
}

sub go_forward {
     $go_forward = $true;
     my $row_played = $selected_row;
                
     push @rows_already_played, $row_played;  # if the row was played completely, then push it to @rows_already_played 
     #print "--> rows_already_played = @rows_already_played  \n";

     # To color the selected artist:
     color_the_selected_tracks_and_scroll( select_color => 'played', scroll => $false, row => $row_played );
			 
     play_selection(go_forward => $true);   # stop and play                  
     $go_forward = $false;
}

sub go_back {
     $go_back = $true;   
     my $row_playing = $selected_row;     
         
     #print "antes -- rows_already_played = @rows_already_played  \n";
     $selected_row = splice(@rows_already_played, -1);      # remove the last element from @array
     #print "depois -- rows_already_played = @rows_already_played ;; selected_row = $selected_row\n";
     
     # To color the selected artist:
     color_the_selected_tracks_and_scroll( select_color => 'no_color', scroll => $false, row => $row_playing );
     
     play_selection(go_back => $true); # stop and play
     $go_back = $false;  
}

sub get_current_track_and_time {
  my $current_track; my $frame; my $status; my $current_position;
  my $abs_start_frame = $start_sector[$selected_row] + 150;      # absolute start frame, 150 is the offset (gap) of first frame.
  my $abs_final_frame = $start_sector[$selected_row + 1] + 150;  # absolute final frame for the selected track
  if ( $selected_row == -1 ){ return $true; } # If there is no selected row
   
  if ( $cdplayer eq "Audio::CD" ){
     if ( not $have_current_track ){ return $true; } 
     my $info = $audiocd->stat;
     $status = $info->mode;
     if ( $status == 0 ){ $playing_music = $true;    }
     if ( $status == 1 ){ $pause = $true; return $true; } else { $pause = $false; }
     if ( $status == 2 ){ $go_forward = $true; } # completed
     if ( $status == 3 ){ stop_playing_music();  } # stop
     if ( $status > 3 or $status < 0 ){ entry_cda_change();  }  # Error
     
     # status = 0 (playing) ;;  status = 1 (paused) ;;  status = 2 (completed)
     # status = 3 (NOSTATUS) ;; status = 4 (INVALID) ;; status = 5 (ERROR) ;; See /usr/include/cdaudio.h
              
     my ($minutes, $seconds, $frames) = $info->time; # Returns the current disc play time
     $current_position = ($minutes * 60 + $seconds) * 75 + $frames; # absolute frame position                
  }
  elsif ( $cdplayer eq "gnormalize::cdplay" ){ 
     my $info = gnormalize::cdplay::Info();
     if ( not $info ){ entry_cda_change(); return; } # Get Status Error
     $status = $info->{status};
     
     if ( $status eq 'play'      ){ $playing_music = $true;    }
     if ( $status eq 'paused'    ){ $pause = $true; return $true; } else { $pause = $false; }
     if ( $status eq 'completed' ){ $go_forward = $true;    } # completed
     if ( $status eq 'no_status' ){ stop_playing_music();   } # stop
     
     #my($minutes, $seconds) = ( $info->{min}, $info->{sec} ); # don't use this because it shows regressive time!
     $current_position = $info->{frame_abs}; # absolute frame position                           
  } 
  elsif ( $cdplayer eq "cdcd" ){ # not used, because cdcd consume so much process resource
     return $true;
     # status: Playing n7 01:10.25/track 20:28.52/disc     
     my $cmd = "cdcd -d $audiodevice_path status";     
     my $status = exec_cmd_system($cmd);
     if ( $status =~ /Playing n(\d+)\s+(\d*:?\d+:\d+[\.,]\d+)\/track\s+(\d*:?\d+:\d+[\.,]\d+)\/disc/i ){
        my $current_track = $1;
        $count = time_to_sec($2);
	#print " track = $1 ;; 2 = $2 ;; time_to_sec = ",time_to_sec($2)," ;; 3 = $3 \n";
     } 
     if ($status =~ /Stopped/i){ stop_playing_music(); }         
  }
  
  $frame = $current_position - $abs_start_frame; 
  $frame = 0 if $frame < 0;
  #$count = number_value(sprintf("%02.2f", ($frame / 75 )));          
  $count = int($frame / 75) if not $pause; # get the new value, number of seconds = frame / 75 
  
  #$current_track = $info->{current_track}; # this is not correct on the boundary region between tracks.
  $current_track = get_current_track();     # Recompile and install Audio-CD-0.04-changed.tar.gz  for "Audio::CD"
  
  #print "count=$count;current_track=$current_track;selected_row=$selected_row;status=$status;".
  #      "frame=$frame;current_position=$current_position\n";   
    
  my $before_end       = $abs_final_frame - 2 * 75; # remaining 2 sec. See sub play_cdrom_msf().
  my $start_next_frame = $abs_final_frame + 40;  
  
  #if ( $current_position > $before_end and $current_track == $selected_row ) { $go_forward = $true; }
  # The boundary region where the regressive time and next track is showed. I want to avoid this.    
  if ( $current_position > $before_end and $current_position <= $start_next_frame ){ $current_track = $selected_row + 1; } 
    
  if ( $current_track != $selected_row + 1 ){ # If another program changes the selected track.         
     my ($iter, $path) = get_iter_path_given_track_art_alb ( value => $current_track, treeview => 'treeview_play', column => COLUMN_FILE );     
        
     $treeview_play->scroll_to_cell($path, undef, $true ,0.50, 0.50) if $path;
     $count = 0;
  }    
  $selected_row = $current_track - 1 if $current_track > 0;      
  return $true; # if return is $false; then stop the Glib::Timeout loop
}

sub get_current_track{
   my $total_track = $#start_sector + 1;
   #my $total_track = $toc_audiocd->[0]->{total_track};
   my $current_track = $total_track;     # start value is the total audio track number
   my $current_position;
   my $offset_frame = 150;
   
   if ( $cdplayer eq "gnormalize::cdplay" ){ 
      $current_position = gnormalize::cdplay::Info()->{frame_abs}; # absolute frame position
   }
   elsif ( $cdplayer eq "Audio::CD" ){
      my $info = $audiocd->stat;
      my ($minutes, $seconds, $frames) = $info->time; # Returns the current disc play time
      $current_position = ($minutes * 60 + $seconds) * 75 + $frames;
   }
   
   for(my $track=1; $track < $total_track; $track++){
      #if ($current_position < $toc_audiocd->[$track]->{frames_abs}){ $current_track = $track; last; }
      # 150 is the offset (gap) of first frame. So (absolute frames) = ($start_sector[$track] + 150) .
      if ( $current_position < $start_sector[$track] + $offset_frame ){ $current_track = $track; last; } 
   }  
   return $current_track;
}


my $pct_last_value = 0;

sub show_time{       # show time on display
  if ( $playing_music eq $false ){ return; }
   
  $total_time = $files_info[$selected_row]{length} if $selected_row != -1 ;
  $total_time = time_to_sec($total_time);
  
  my $show_time  = $total_time; # one track total time
  my $show_count = $count;      # relative position
  
  if ($show_time > 0){
     # draw lapsed time ; show only not repeated value
     my $pct = number_value( sprintf("%.2f", $show_count/$show_time) );
     if ($pct != $pct_last_value and $pct <= 1){ draw_lapsed_time($da, undef, "$pct"); }
     $pct_last_value = $pct;
  }
  
  if ($selected_row != $selected_row_last_value){ show_scrolling_text(); }
  $selected_row_last_value = $selected_row;
  
  stop_playing_music() if (not defined $pid_player and $files_info[$selected_row]{extension_input} ne 'cda');  	  
  
  if ( $show_time_abs and $cdplayer eq "gnormalize::cdplay" and $files_info[$selected_row]{extension_input} eq 'cda' ){  
     #my $current_position = gnormalize::cdplay::Info()->{frame_abs}; # absolute frame position     
     $show_count = int ( ( gnormalize::cdplay::Info()->{frame_abs} - $toc_audiocd->[0]->{frames_abs} ) / 75 );  
     $show_time  = int (($toc_audiocd->[0]->{total_frames} / 75 )); # absolute time
  }
  elsif ( $show_time_abs and $cdplayer eq "Audio::CD" and $files_info[$selected_row]{extension_input} eq 'cda' ){
     my $info = $audiocd->stat;
     my ($minutes, $seconds) = $info->time; # Returns the current disc play time
     $show_count = time_to_sec("$minutes:$seconds");     
     ($minutes, $seconds) = $info->length;  # Returns the disc length time
     $show_time  = time_to_sec("$minutes:$seconds");    
  } 
  
  my ($hour,$min,$sec) = sec_to_time($show_count);                     # current time
  my ($hour_r,$min_r,$sec_r) = $show_time >= $show_count ? sec_to_time($show_time - $show_count) : sec_to_time( 0 );  # time remaining
  my ($hour_t,$min_t,$sec_t) = sec_to_time($show_time);                # total time
  
  if ( $pause eq $true and $count_blink % 2 == 0 ){ # blink - piscar
     $min   = -2; $min_r = -2;
     $count_blink = 0 if $count_blink > 1000;
  }
      
  # print "--> hour = $hour ;; min = $min ;; sec = $sec ;; total = $show_time ;; count = $show_count\n"; 
  if ( $show_time_remaining eq $false ){ draw_play_time($da, undef, ($min,$sec,$hour) ); }
  else{ draw_play_time($da, undef, ($min_r,$sec_r,$hour_r) ); }

  return $true;
}

sub stop_cda { # don't stop if the next track have cda extension_input

   if ($cdplayer eq "cdcd") {
      my $cmd = "$cdcd_path -d $audiodevice_path stop ";
      exec_cmd_system($cmd);
   }
   elsif ( $cdplayer eq "gnormalize::cdplay" ){
      gnormalize::cdplay::stop_cdrom();
   }
   elsif ( $cdplayer eq "Audio::CD" ){ # libcdaudio  ;; Audio::CD ;; see <man Audio::CD>
      $audiocd = Audio::CD->init("$audiodevice_path");
      $audiocd->stop;
   }
   $playing_music = $false;
   
   if (@rows_already_played > 0 and 1==2){ #debug
      print "extension_last_value = $extension_last_value ; extension_input = $files_info[$selected_row]{extension_input}\n";
   }
}

sub stop_playing_music{

   my %args = ( select_color   => 'no_color', # ('no_color','playing','played')
                scroll         => $false,
		set_rip        => $false,
		change_color   => $true,	
                @_,            # argument pair list goes here
	      );
   my $cmd;   
   if ( not $playing_music ){ # update the 'cdrom:' entry only if audio cd is not playing
      $audiodevice_path = $entry_cda->get_text(); # /dev/hdc or /dev/cdrom or ...
   }
   if ( defined($timer) ){ Glib::Source->remove($timer);} # quit loop, see <man Glib::MainLoop>
   
   return unless defined $files_info[$selected_row]{extension_input}; 
     
   if ( $playing_music and not ($go_back or $go_forward) and $files_info[$selected_row]{extension_input} eq 'cda' ){
      stop_cda();  # don't stop if the next track have cda extension_input       
   }   

   if ($files_info[$selected_row]{extension_input} ne 'cda' and defined $pid_player){
      #print "pid_player = $pid_player\n";
      kill  9, $pid_player;
      my $pid_mplayer = $pid_player + 1;
      kill  9, $pid_mplayer;
      $pid_player = undef;
      $playing_music = $false;  
   }
   
   draw_buttons(Draw_Play => $true); # play button ->
   $count = 0;
   $count_blink = 0;
   
   if ( not $go_forward and not $go_back ){ # erase the color    
      # To uncolor the selected artist, stopped artist line
      # color_the_selected_tracks_and_scroll( select_color => 'no_color', scroll => $false, set_rip => $false ); # default values
      color_the_selected_tracks_and_scroll( %args ) if $args{change_color};
   }   
}

# convert x seconds to hour:min:sec format
sub sec_to_time{
  my $i = number_value(shift);
  my ($hour,$min,$sec) = (0,0,0);
   
  $min = sprintf("%02d", int($i/60) );  # 02d : leading zero 
  my $remainder =  $i - $min * 60;      # $remainder =  $i % 60 ;; see <man perlop>
  $sec = sprintf("%02d", $remainder ); 
  #print "total_sec = $i --> hour = $hour ;; min = $min ;; sec = $sec\n"; 
  return ($hour,$min,$sec);
}
#sec_to_time('44500,893');

# convert hour:min:sec format to  x seconds.
sub time_to_sec{    # $time = 2:34:01 or 01:06.39
  my $time = shift; 
  my $sec  = 0;
  my $min  = 0;
  my $hour = 0;
  
  if ($time =~ /(\d+):(\d+):(\d+[\.,]?\d*)/){
     $hour = $1;
     $min  = $2;
     $sec  = $3;
  }
  elsif ($time =~ /(\d+):(\d+[\.,]?\d*)/){
     $min  = $1;
     $sec  = $2;
  }
  elsif ($time =~ /(\d+[\.,]?\d*)/){
     $sec  = $1;
  } 
  $sec = sprintf("%02d", number_value($sec) );   # 02.0f : leading zero 
  #print "hour = $hour ;; min = $min ;; sec = $sec ;; time = $time";  
  $time = int( $hour * 3600 + $min * 60 + $sec );
  #print " --> time = $time\n";
  return $time;	  
}
#time_to_sec ( "0:2,7456");

sub rip_audio_cdparanoia { # MAX LENGTH = 230  for filename
        my $track = shift;
	my $file_wav = shift;
	my $row = $track -1;
	#Ripping from sector       0 (track  1 [0:00.00])
        #          to sector   18511 (track  1 [4:06.61])
	
	my $opt = "";
	if ($button_noia1->get_active){ $opt .= "-Z ";}
	if ($button_noia2->get_active){ $opt .= "-z ";}
	if ($button_noia3->get_active){ $opt .= "-Y ";}
	if ($button_noia4->get_active){ $opt .= "-X ";}
		
	my $cmd = "$nice_path -n $priority $cdparanoia_path -d $audiodevice_path -e -w $opt $track ";
	
	my  $file_in   = $directory_output . '/' . $file_wav;	
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"

	insert_msg("." , "small-ini");
	insert_msg("$cmd \"$file_in2\" " , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	# Use 'filename_from_unicode' to convert from unicode to local encoding.
	$file_in2  = filename_from_unicode $file_in2;		
	_utf8_on($file_in2);  # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'.
	$cmd .= " \"$file_in2\" ";	

	my $pid = open( NOIA, "$cmd  2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	$pid_rip_cda = $pid;	
	
	draw_input_output($da_arrow_dec,undef,("cda","wav")); 
	
	my $div = 0; # initial value
	my $saved_value = 0;
	while( <NOIA> ){	
	        #print " fora $_\n";
	        # simple output:
		#outputting to track02.cdda.wav
		##: -2 [wrote] @ 682079
                ##: -2 [wrote] @ 683255
                ##: -2 [wrote] @ 684431
		#Ripping from sector       0 (track  1 [0:00.00])
                #          to sector   18511 (track  1 [4:06.61])
                # (== PROGRESS == [ >                            .| 019261 00 ] == :^D . ==)
		
		if( $_ =~ /\[wrote\]\s+@\s+(\d+)/ )
		{ 
		  $saved_value = $div;
		  # progress = (sector-start)/(end-start);
		  # CD_FRAMESIZE_RAW   2352 /* bytes per frame, "raw" mode */:  1176 = (2352/2)
		  my $sector = $1/1176;  # sector divide by 1176 
		  $div = sprintf("%0.2f", ( $sector - $start_sector[$row] )/$music_sector[$row] ); 
		  $div = number_value($div);     
                  #                            show only not repeated value
		  if ( $pbar->get_fraction() <=1 and $div > $saved_value ){ 
		     $pbar->set_fraction( $div ) ; 
		     my $pct = sprintf("%2d", 100*$div );
		     $status_bar->push($context_id, $langs{msg054}." - $pct%");
		     #print ( " div  = $div ;; $1 / 1176 ;; start = $start_sector[$row] ;; music_sector[$row] = $music_sector[$row]\n");
		  }		  
		}
		while ( Gtk2->events_pending() ) { Gtk2->main_iteration() }
		if ( not $normalize_button->get_active and $pid_rip_cda >= 0 ) { 
		    $pid_rip_cda = StopProcessing($pid_rip_cda, $langs{msg055}, $file_wav );		    
		    exec_cmd_system2( 'rm', '-f', $file_in ); # remove wav file
		    close( NOIA );
		    return $false;
		}
	}
	close( NOIA );
	if ($normalize_button->get_active) {  # if normalize button is active
	    $pbar->set_fraction( 1 ) ; 
	    $pid_rip_cda = -1; # reset rip pid on the final of process
	    return $true;
	}        
}  


sub rip_audio_cdda2wav {
        my $track = shift;
	my $file_wav = shift;
	my $row = $track-1;
	
	my $opt = "";
	if ($button_cdda1->get_active){ $opt .= "-paranoia ";}
	if ($button_cdda2->get_active){ $opt .= "-paraopts=disable ";}
	if ($button_cdda3->get_active){ $opt .= "-paraopts=no-verify ";}	
		
	# cdda2wav -g -no-infofile   dev=/dev/hdc -t 2 track  - see cdda2wav -help or man cdda2wav
	my $cmd = "$nice_path -n $priority $cdda2wav_path dev=$audiodevice_path -x -g -no-infofile $opt -t $track ";
		
	my  $file_in   = $directory_output . '/' . $file_wav;	
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"

	insert_msg("." , "small-ini");
	insert_msg("$cmd \"$file_in2\" " , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	# Use 'filename_from_unicode' to convert from unicode to local encoding.
	$file_in2  = filename_from_unicode $file_in2;		
	_utf8_on($file_in2);  # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'.
	$cmd .= " \"$file_in2\" ";	
	
	my $pid = open( CDRIP, "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";		
	$pid_rip_cda = $pid; ## set rip pid, pid > 0
	
	my $div = 0; # initial value
	my $saved_value = 0;

        ## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <CDRIP> ){	
	        # simple output:
		# 3%
		
		if( $_ =~ /\s+(\d+)%/g )
		{
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 );
		  $div = number_value($div);      
		  #                            show only not repeated value
		  if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 
		     $pbar->set_fraction( $div ) ; 
		     $status_bar->push($context_id, " ripping audio to wav - $1%");
		     #print ( " div  = $div \n");
		  }		  
		}
		if( $_ =~ /100%.*successfully/i ){$pbar->set_fraction(1);}
		
		while ( Gtk2->events_pending() ) { Gtk2->main_iteration() }
		if ( not $normalize_button->get_active and $pid_rip_cda >= 0 ) { 
		    $pid_rip_cda = StopProcessing($pid_rip_cda, " Stop ripping!", $file_wav);		    
		    exec_cmd_system2( 'rm', '-f', $file_in ); # remove wav file		    
		    $/="\n";  # abandon loop
		    close( CDRIP );
		    return $false;
		}
	}
	$/="\n"; ## final of loop
	close( CDRIP );
	
	if ($normalize_button->get_active) {  # if normalize button is active
	    $pbar->set_fraction(1) ; 
	    $pid_rip_cda = -1; # reset rip pid on the final of process
	    return $true;
	}        
}	

##-----------------------------------------------------##
##-----------------------------------------------------##

#  flac --> wav 
sub decode_flac_to_wav {
   my %args = ( @_ );    
   my $file_wav = $args{file_wav};  my $filepath = $args{filepath};
            
        my  $file_in   = $filepath;	
	my  $file_out  = $directory_output . '/' . $file_wav;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "decode_flac_to_wav --> Could not find flac file: $file_in\n" if( ! -e filename_from_unicode $file_in );

	my $cmd = "$nice_path -n $priority  $flac_path -d \"$file_in2\" -f -o \"$file_out2\" ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	my $pid = open( FLACDEC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	$pid_flac_decode = $pid; ## set flac pid, pid > 0
	
	my $div = 0; # initial value
	my $saved_value = 0;

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <FLACDEC> )
	{	
	        #output:
		# 10-Que � feito de voc�.flac: 75% complete

		if( $_ =~ /.*:\s+(\d+)%\scomplete/ )
		{
		  #print "\n<<>> $_ --->1=$1 \n";
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 );
		  $div = number_value($div);
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors

                  #                            show only not repeated value
		  if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 
		     $pbar->set_fraction( $div ) ; 
		     $status_bar->push($context_id, " flac decoding $1%");
		     #print ( " div  = $div \n");
		  }		  
		}
		while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() }
		if ( not $normalize_button->get_active and $pid_flac_decode >= 0 ) { 
		    $pid_flac_decode = StopProcessing($pid_flac_decode, " Stop flac decoding!", $file_wav);
		    exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file			    	    
		    $/="\n";  # abandon loop
		    close( FLACDEC );
		    return $false;
		}		
	}
	$/="\n"; ## final of loop
	close( FLACDEC );

	if ($normalize_button->get_active ) {  # if normalize button is active
	    $pbar->set_fraction( 1 ) ; 
	    $pid_flac_decode = -1;       # reset ape deocde pid on the final of process
	    return $true;
	}
}


#  mp4 --> wav 
sub decode_mp4_to_wav {
   my %args = ( @_ );    
   my $file_wav = $args{file_wav};  my $filepath = $args{filepath};   
   
        my  $file_in   = $filepath;	
	my  $file_out  = $directory_output . '/' . $file_wav;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "decode_mp4_to_wav --> Could not find mp4 file: $file_in\n" if( ! -e filename_from_unicode $file_in );
      	
	my $cmd = "$nice_path -n $priority $faad_path \"$file_in2\" -f 1 -o \"$file_out2\" ";

	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	my $pid = open( FAADDEC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	my $pid_faad_decode = $pid; ## set flac pid, pid > 0
	
	my $div = 0; # initial value
	my $saved_value = 0;

	$/="\r";
	while( <FAADDEC> )
	{	
	        #output:
		# 45% decoding music.mp4.

		if( $_ =~ /^(\d+)%\s+decoding/ )
		{
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 );
		  $div = number_value($div);
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors

                  #                            show only not repeated value
		  if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 
		     $pbar->set_fraction( $div ) ; 
		     $status_bar->push($context_id, " faad decoding $1%");
		  }		  
		}
		while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() }
		if ( not $normalize_button->get_active and $pid_faad_decode >= 0 ) { 
		    $pid_faad_decode = StopProcessing($pid_faad_decode," Stop faad decoding!", $file_wav);
		    exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file		    
		    $/="\n";  # abandon loop
		    close( FAADDEC );
		    return $false;
		}		
	}
	$/="\n"; ## final of loop
	close( FAADDEC );

	if ($normalize_button->get_active ) {  # if normalize button is active
	    $pbar->set_fraction( 1 ) ; 
	    $pid_faad_decode = -1;       # reset ape deocde pid on the final of process
	    return $true;
	}
}


#  ape --> wav  # dependence: mac from APE-3.96b8-3plf-MonkeyAudio.i586.rpm
sub decode_ape_to_wav {
   my %args = ( @_ );    
   my $file_wav = $args{file_wav};  my $filepath = $args{filepath};
   
        my  $file_in   = $filepath;	
	my  $file_out  = $directory_output . '/' . $file_wav;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "decode_ape_to_wav --> Could not find ape file: $file_in\n" if( ! -e filename_from_unicode $file_in );
   
	my $cmd = "$nice_path -n $priority $ape_path  \"$file_in2\" \"$file_out2\" -d ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	# STDIN is file descriptor number 0; STDOUT number 1; and STDERR number 2. 
	# To exchange a command's STDOUT and STDERR, i.e., capture the STDERR 
	# but have its STDOUT come out on our old STDERR:  3>&1 1>&2 2>&3 3>&-
	# 3>&1 : Make a new file descriptor, number 3, be a copy of number 1.
	# d3=d1
	# d1=d2
	# d2=d3
	my $pid = open( APEDEC, filename_from_unicode "$cmd 3>&1 1>&2 2>&3 3>&- |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	$pid_ape = $pid; ## set ape pid, pid > 0
	
	my $div = 0; # initial value
	my $saved_value = 0;
	
	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <APEDEC> )
	{	
	        #output:
		#--- Monkey's Audio Console Front End (v3.96b8) (c) Matthew T. Ashland ---
                #Decompressing ...
                #Progress:  3.0% (357.7 sec remaining, 368.8 sec total)

		if( $_ =~ /^Progress:\s+(\d+[\.,]\d)%\s\((.*remaining).*/i )
		{
		  #print "\n<<>> $_ --->1=$1  --->2=$2\n";
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 );
		  $div = number_value($div);
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors

                  #                            show only not repeated value
		  if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 
		  $pbar->set_fraction( $div ) ; 
		  $status_bar->push($context_id, " ape decoding $1% | $2");
		  #print ( " div  = $div \n");
		  }		  
		}
		while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() }
		if ( not $normalize_button->get_active and $pid_ape >= 0 ) { 
		    $pid_ape = StopProcessing($pid_ape," Stop ape decoding!", $file_wav);
		    exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file		    
		    $/="\n";  # abandon loop
		    close( APEDEC );
		    return $false;
		}		
	}
	$/="\n"; ## final of loop
	close( APEDEC );

	if ($normalize_button->get_active ) {  # if normalize button is active
	    $pbar->set_fraction( 1 ) ; 
	    $pid_ape = -1;        # reset ape deocde pid on the final of process
	    return $true;
	}
}

#  mpc --> wav
sub decode_mpc_to_wav {
   my %args = ( @_ );    
   my $file_wav = $args{file_wav};  my $filepath = $args{filepath};      
      
        my  $file_in   = $filepath;	
	my  $file_out  = $directory_output . '/' . $file_wav;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "decode_mpc_to_wav --> Could not find mpc file: $file_in\n" if( ! -e filename_from_unicode $file_in );

	my $cmd = "$nice_path -n $priority $mpcdec_path  \"$file_in2\" --wav \"$file_out2\" ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");

	## $res = pid of ogg
	my $res = open( MPCDEC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	$pid_mpc_decode = $res; ## set ogg pid, pid > 0
	
	my $div = 0; # initial value
	my $saved_value = 0;

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <MPCDEC> )
	{	
	        #output:		
		# 203.6 kbps,    4:52.68, SV 7.0, Profile 'BrainDead' (Beta 1.14)
                #     1:20.58/    4:52.68 decoded (27.5%)

		if( $_ =~ /\sdecoded\s\((\s*\d*[\.,]\d)%\)/ )
		{
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 );
		  $div = number_value($div);
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors

                  #                            show only not repeated value
		  if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 
		  $pbar->set_fraction( $div ) ; 
		  $status_bar->push($context_id, " mpc decode $1%");
		  #print ( " div  = $div \n");
		  }		  
		}
		while ( Gtk2->events_pending() ) { Gtk2->main_iteration() }
		
		if ( not $normalize_button->get_active and $pid_mpc_decode >= 0 ) { 
	            $pid_mpc_decode = StopProcessing($pid_mpc_decode, " Stop mpc decoding!", $file_wav); 
	            if ( -e filename_from_unicode $file_out ){ 
		       exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file
		    }
		    close( MPCDEC );
		    return $false;
		}
	}
	$/="\n"; ## final of loop
	close( MPCDEC );
	
	if ($normalize_button->get_active ) {  # if normalize button is active
	    $pbar->set_fraction( 1 ) ; 
	    $status_bar->push($context_id, " mpc decode 100%");
	    $pid_mpc_decode = -1;       # reset oggdec pid on the final of process
	    return $true;
	}
}

#  ogg --> wav

sub decode_ogg_to_wav {
   my %args = ( @_ );    
   my $file_wav = $args{file_wav};  my $filepath = $args{filepath};
	
	my  $file_in   = $filepath;	
	my  $file_out  = $directory_output . '/' . $file_wav;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "decode_ogg_to_wav --> Could not find ogg file: $file_in\n" if( ! -e filename_from_unicode $file_in );   
      
	my $cmd = "$nice_path -n $priority $oggdec_path  \"$file_in2\" -o \"$file_out2\" ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");

	my $res = open( OGGDEC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	$pid_ogg_decode = $res; ## set ogg pid, pid > 0
	
	my $div = 0; # initial value
	my $saved_value = 0;

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <OGGDEC> )
	{	
	        #output: 
		# OggDec 1.0
                # Decoding "lix�o-��o ��t�es'a.ogg" to "lix�o-��o ��t�es'a.wav"
		#          [  5.5%]
		#          [ 88.5%]
                #          [100.0%]
		
		if( $_ =~ /^\s*\[(\s*\d*)[\.,](\d)%\]/ )
		{
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 );
		  $div = number_value($div);
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors

                  #                            show only not repeated value
		  if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 
		  $pbar->set_fraction( $div ) ; 
		  $status_bar->push($context_id, " ogg decode $1%");
		  }		  
		}
		while ( Gtk2->events_pending() ) { Gtk2->main_iteration() }
		
		if ( not $normalize_button->get_active and $pid_ogg_decode >= 0 ) { 
	            $pid_ogg_decode = StopProcessing($pid_ogg_decode, " Stop ogg decoding!", $file_wav);		    
		    if ( -e filename_from_unicode $file_out ){ 
		       exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file
		    }
		    close( OGGDEC );		    
		    return $false;
		}
	}
	$/="\n"; ## final of loop
	close( OGGDEC );
	
	if ($normalize_button->get_active) {  # if normalize button is active
	    $pid_ogg_decode = -1;             # reset oggdec pid on the final of process
	    return $true;
	}
}


#  mp3 --> wav

sub decode_mp3_to_wav {
   my %args = ( @_ );    
   my $file_mp3 = $args{file_mp3};   my $file_wav = $args{file_wav};  my $filepath = $args{filepath};              	
	
        my $cmd = "$nice_path -n $priority $lame_path --verbose --decode ";
	
	my  $file_in   = $filepath;	
	my  $file_out  = $directory_output . '/' . $file_wav;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "decode_mp3_to_wav --> Could not find mp3 file: $file_in\n" if( ! -e filename_from_unicode $file_in );	
	
	$cmd .= "\"$file_in2\" \"$file_out2\"";

	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");		
 
	my $pid = open( LAME, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	$pid_lame_decode = $pid; ## set lame pid, pid > 0  see <man perlipc>
	
	my $saved_value = 0;
	my $div = 0;

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <LAME> )
	{	
	        #output: 
                #ID3v2 found. Be aware that the ID3 tag is currently lost when transcoding.
                #input:  almir_sater-instrumental-01_corumb�.mp3
                #        (44.1 kHz, 2 channels, MPEG-1 Layer III)
                #output: almir_sater-instrumental-01_corumb�.mp3.wav  (16 bit, Microsoft WAVE)
                #skipping initial 1105 samples (encoder+decoder delay)
                #Frame#  2806/8937   160 kbps  L  R  

		#print (" $_ \n");
		
		if( $_ =~ /^\s*Frame\#\s+(\d+)\/(\d+)\s+.*/ )
		{
		   my $frames = $1;
	           my $numframes = $2;
		   if ( $2 == 0 ){return;}
		   $saved_value = $div;
		   $div = sprintf("%0.2f", $1/$2 );
		   $div = number_value($div);
		   my $pct = sprintf("%2.0f", $div*100 );
		   if ( $div > 1){ $div = 1;}
		   #next if ($div <= $saved_value);

		   if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 
		      $pbar->set_fraction( $div ) ; 
		      $status_bar->push($context_id, " lame decode $pct%");
		   }
		}
		while ( Gtk2->events_pending() ) { Gtk2->main_iteration() }
		
		if ( not $normalize_button->get_active and $pid_lame_decode >= 0 ) { 
		    # set lamepid to -1 after stop the process
	            $pid_lame_decode = StopProcessing($pid_lame_decode, $langs{msg057}, $file_wav ); 
		    # In the case of stop decode process, always remove file_wav if it exist
	            # because the file_wav is not complete/entire		    
		    if ( -e filename_from_unicode $file_out ){ 
		       exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file
		    }
		    close( LAME );		    
		    return $false;
		}		
	}
	$/="\n"; ## final of loop
	close( LAME );	

	if ($normalize_button->get_active) {  # if normalize button is active
	    $pid_lame_decode = -1;            # reset lame pid on the final of process
	    return $true;
	}
}

sub normalize_wav { #29Abr2008 -- normalize_wav_with_wavegain
   my %args = ( @_ );    
   my $dir = $args{directory};   my $file_wav = $args{file_wav};  my $filepath = $args{filepath}; 
   my $row = $args{row};

   $adjust = 0;
   $already_normalized = $false;		
	
   if ( not -e filename_from_unicode "$directory_output/$file_wav" ) { 
      insert_msg("\n$directory_output/$file_wav : $! \n" , "small-red"); # print on debug textview
      $normalize_button->set_active($false);
      return $false;
   }	
	
   make_directory_final(%args);
   
   # -12.0dB <= $gain <= +12.0dB ; $gain = 0.0dB correspond to 89dB standard value
   $gain = sprintf("%0.2f", $spinner->get_value );
   $gain = number_value($gain);  # For example, change '0,57' by '0.57'.   

   my $Coment = $entry_def_comment->get_text;
   $Coment = remove_change_10_chars($Coment);
   
   if ( $Coment ne "" ) {
      
      my $gain_com = $gain;
      $gain_com = 'Not Normalized' if $norm_type eq 'None';
      $gain_com = '0.00'           if $norm_type eq 'Album';
   			      
      $Coment =~ s/\%gain/$gain_com/ig;   
      $files_info[$row]{comment} = $Coment;  # change comment tag value	
   }
	
   # get the wave total miliseconds ;; 
   # 2352 = bytes per frame, "raw" mode ;; 1 sec have 75 frames = 75 * 2352 bytes = 176400 bytes
   my $fileSize = -s filename_from_unicode "$directory_output/$file_wav"; # $fileSize = $FileLength + 8 = Wav DataLength + 44           
   $metadata{'Length'} = int( ($fileSize - 44) / 176400 * 1000 ) ;        # length of audio file in milliseconds
   #print " Length = $metadata{'Length'} ;; fileSize = $fileSize bytes\n";
				
   my @cmd_args = ( $nice_path, '-n', $priority, $wavegain_path, '-r', '-y' );   

   if    ( $norm_type eq "Track" ) { push @cmd_args, ( '-g', $gain  );   } # add more args to command
   elsif ( $norm_type eq "Album" ) { push @cmd_args, ( '-g', '0.00' );   } # don't implemented yet!
   elsif ( $norm_type eq "None"  ) {  #----------------------------------#
      $pbar_n->set_text( $langs{msg045} );                               #
      insert_msg( $langs{msg041} , "small-red");                         # 
      insert_msg("\n" , "small");                                        #
      $pid_normalize = -1;                                               #
      return;                                                            #
   }#--------------------------------------------------------------------#   	
   
   #my $cmd = "$wavegain_path -r -y -g $gain \"$directory_output/$file_wav\" ";
   my $cmd  = "@cmd_args ";
   
   my $file_in   = $directory_output . '/' . $file_wav;
   (my $file_in2 = $file_in) =~ s/"/\\"/g;  # change all " characters by \"
   print "normalize_wav --> Could not find wav file: $file_in\n" if( ! -e filename_from_unicode $file_in );
   
   $cmd .= " \"$file_in2\"";
             	 
   insert_msg("." , "small-ini");
   insert_msg("$cmd" , "small"); #print on debug textview
   insert_msg("\n" , "small");
 
   my $div = 0;
   my $saved_value = 0;   
   
   $pbar_n->set_text( $langs{msg006} ); # "Analyzing with ReplayGain normalization algorithms ..."
   while (Gtk2->events_pending()) { Gtk2->main_iteration()};  
	
   # see 'man perlfaq8', 'man IPC::Open3' or 'fttp://perldoc.perl.org'.
   # use open3 because it entries ('command', 'args') is Locale-independent (don't have conversion '0.30' to '0,30').
   # use IPC::Open3;
   # use Symbol qw(gensym);
   
   # Let STDOUT go to our own STDERR and capture a program's STDERR:
   # $pid = open3(\*CHLD_IN, \*CHLD_OUT, \*CHLD_ERR,'some cmd and args', 'optarg', ...);
   # my $pid = open3(gensym, ">&STDERR", \*NORMALIZE, @cmd_args) or die "Couldn't execute \"@cmd_args\": $!, stopped\n";   
   
   my $pid = open( NORMALIZE, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";		   
   $pid_normalize = $pid; # set normalize pid   
	
   $/="\r"; ## loop for output - initial
   while( <NORMALIZE> )
   {
      # Analyzing...

      #    Gain   |  Peak  | Scale | New Peak |Left DC|Right DC| Track
      #           |        |       |          |Offset | Offset | Track
      # --------------------------------------------------------------
      #  +6.91 dB |  14245 |  2.22 |    31561 |    0  |     0  | 05-Jo�o Bosco-Escadas da Penha.wav

      # Applying Gain of +6.91 dB to file: 05-Jo�o Bosco-Escadas da Penha.wav
      #This file 100% done     All files  99% done
      # WaveGain Processing completed normally
   
      # No Title Gain adjustment or DC Offset correction required for file:

      # Error renaming '/tmp/wavegain.tmp' to '04.wav' (uh-oh)
      # Error processing GAIN for file - 04.wav
   
      #print "--> $_\n";
		
      if ( $_ =~ /^\s+Applying Gain of ([-+]\d+[.,]\d+) dB to file:/ ){ $adjust = $1; } 
		
      if ( $_ =~ /^This\sfile\s+(\d+)\%\s*done\s+All\sfiles/ )
      {
         $saved_value = $div;
         $div = sprintf("%0.2f", $1/100 );
         $div = number_value($div);
	 if ( $div >= 1 ){ $div = 1;}  # to avoid possible errors

	 #                            show only not repeated value
         if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) {
	    $pbar_n->set_fraction( $div ) ;  
	    $pbar_n->set_text( $langs{msg050} . "${adjust}dB...");
	    $status_bar->push($context_id, $langs{msg051} . "${adjust}dB");
	    $pbar_n->set_orientation('left_to_right');
         }
      }
      if ( $_ =~ /WaveGain Processing completed normally/ )
      {
         $pbar_n->set_fraction( 1 ) ;  
	 $pbar_n->set_text( $langs{msg050} . "${adjust}dB...");
	 $status_bar->push($context_id, $langs{msg051} . "${adjust}dB");
      }	
      #if ( $_ =~ /Error renaming/){ insert_msg("$_" , "small-red"); insert_msg("\n" , "small"); }	
      if ( $_ =~ /No Title Gain adjustment.*required/ ){		  
         $already_normalized = $true;
         $pbar_n->set_fraction( 1 ) ; 
         $pbar_n->set_text( $langs{msg047} );
         insert_msg( $langs{msg048} . "\n", "small-red");
      }
      while (Gtk2->events_pending()) { Gtk2->main_iteration()};
		
      if ( not $normalize_button->get_active and $pid_normalize >= 0 ) { 
         $pid_normalize = StopProcessing($pid_normalize, $langs{msg049}, $file_wav );
         $/="\n";  # abandon loop
      }
   }
   $/="\n"; ## final of loop
   close( NORMALIZE );
   waitpid($pid, 0);        
    
   if ($normalize_button->get_active) {  # if normalize button is active
      if ( not $already_normalized ){
         insert_msg( $langs{msg053}."${adjust}dB." , "black");
	 insert_msg("\n" , "small");
      }
      $pid_normalize = -1;  # reset normalize pid on the final of process
      return $true;
   }
   else {return $false;}   	
}

sub encode_wav_to_wav {  # actualy, don't need to encode because the output is wav!  
   my %args = ( @_ );
   my $row = $args{row}; my $file_wav = $args{file_wav};   
   
   my $file_in  = $directory_output.'/'.$file_wav;
   my $file_out = $directory_final.'/'.$file_wav;
   
   remove_apetag (%args, (filepath => $file_in) );
   $metadata{'Encoded by'} = "WAVEGAIN with gnormalize (http://gnormalize.sourceforge.net)";
   write_apetag  (%args, (filepath => $file_in) );            
	      	 
   my @cmd = ( 'cp', '-f', $file_in, $file_out );
   insert_msg("." , "small-ini");
   insert_msg("@cmd" , "small");      # print on debug textview
   insert_msg("\n" , "small");
   exec_cmd_system2(@cmd);      
   
   if   ($normalize_button->get_active) { return $true; }
   else { return $false;}	    
}

# wav --> ogg
sub encode_wav_to_ogg {    
   my %args = ( @_ );
   my $row = $args{row}; my $file_ogg = $args{file_ogg}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath};
   
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};
      	
	my $bitrate;
	my $mode;
	my $freq;
	
        ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args);

	# bug of oggenc:
        # The command, for example, "oggenc -q 5.5 -m 96 -M 320 music.wav" has a bug for options 
        # -q, -m, and -M, such that -m is minimum allowed bitrate and -M is maximum allowed bitrate.
        # The solution is omit the options -m and -M, so the corrected command is
        # "oggenc -q 5.5 music.wav" used for variable bitrate.
	
	my $cmd = "$nice_path -n $priority  $oggenc_path ";
	
	# oggenc commands
	if ( $encode eq "variable" ){ # VBR (variable bitrate)
	   # m - minimum allowed bitrate - see  <man oggenc>
	   # M - maximum allowed bitrate
	   # q - Variable  BitRate -  -1 <= quality <= 10
	   # min and max: -m $vb_Min -M $vb_Max
	   # $cmd = "$oggenc_path -q $Vogg -m $vb_Min -M $vb_Max "; # bug of oggenc. Don't use -m and -M options
	   $cmd .= "-q $Vogg ";
        }
	else{  # for ABR (average bitrate)
	   $cmd .= "-b $bitrate -m $vb_Min -M $vb_Max "; 
	} 
	$additional_command_ogg = $entry_command_ogg->get_text;
	$cmd .= " --resample \"$freq\" $additional_command_ogg ";
	
	my  $file_in   = $directory_output . '/' . $file_wav;	
	my  $file_out  = $directory_final  . '/' . $file_ogg;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "encode_wav_to_ogg --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in );		  

	$cmd .= " \"$file_in2\" -o \"$file_out2\" ";
	
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	## start encoding
	my $res = open( OGGENC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	$pid_ogg_encode = $res; ## set ogg encode pid
	
	my $saved_value = 0;
	my $div = 0;

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <OGGENC> )
	{  
		## this is output of oggenc:
		
		# Opening with wav module: WAV file reader
                # Encoding "music.wav" to
                #          "music.ogg"
                # at quality 3.00   
		#        [  1.5%] [ 0m13s remaining] |
                #        [ 21.6%] [ 0m08s remaining] /
		#        [ 99.9%] [ 0m00s remaining] -
		# Done encoding file "music.ogg"
                #        File length:  0m 56.0s
                #        Elapsed time: 0m 10.7s
                #        Rate:         5.3075
                #        Average bitrate: 114.4 Kb/s
		
		if( $_ =~ /^\s*\[(\s*\d*[\.,]\d)%\]\s+\[\s*(\d*)m(\d*)s\sremaining\]/ )
		{
		  $saved_value = $div;
		  $div = sprintf("%0.2f", number_value($1)/100 );
		  $div = number_value($div);
		  my $pct = sprintf("%02d", number_value($1) ); # 02d : leading zero
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors

                  #                            show only not repeated value
		  if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 
		  $pbar_encode->set_fraction( $div ) ; 
		  $status_bar->push($context_id, " ogg encode $pct% | time remaining = $2:$3");
		  }		  
		}		
		while ( Gtk2->events_pending() ) { Gtk2->main_iteration() }
		
		if ( not $normalize_button->get_active and $pid_ogg_encode >= 0 ) { 
		    $pid_ogg_encode = StopProcessing($pid_ogg_encode," Stop ogg encoding!", $file_wav);
		    $/="\n";  # abandon loop
		}
	}
	$/="\n"; ## final of loop
	close(OGGENC);	
	
	my   @cmd_tag = ( $vorbiscomment_path, '--raw', '-t', "title=$Title", '-t', "artist=$Artist" );
        push @cmd_tag,  ( '-t', "genre=$Genre", '-t', "date=$Year", '-t', "album=$Album" );
        if ( $Total_Track ne "" and $Total_Track >= $Track_Number ) { 
               push @cmd_tag, ( '-t', "tracknumber=$Track_Number/$Total_Track" ); }
        else { push @cmd_tag, ( '-t', "tracknumber=$Track_Number" );              }
	push @cmd_tag,  ( '-t', "description=$Comment", '-t', "comment=$Comment", '-w' );
       
        if ( $vorbiscomment_path ne "" and $normalize_button->get_active ){
	   insert_msg("." , "small-ini");
	   insert_msg("@cmd_tag \"$file_out2\"" , "small"); #print on debug textview
	   insert_msg("\n" , "small");
	   
	   push @cmd_tag, ( filename_from_unicode $file_out );
	   exec_cmd_system3(@cmd_tag);	
	}
	
	if ($normalize_button->get_active) {  # if normalize button is active
	    $pid_ogg_encode = -1;             # reset pid on the final of process  
            return $true;    }
	else { return $false;}
}


# wav --> mpc
sub encode_wav_to_mpc {
   my %args = ( @_ );
   my $row = $args{row}; my $file_mpc = $args{file_mpc}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath};
   
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};

	my $bitrate;
	my $mode;
	my $freq;
	
        ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args);	
	
	# --nmt x     set NMT value to x dB (dflt:  6.5)
	# smr (signal to mask ratio)
	# --minSMR over 0 db will result in full bandwidth encoding.
	#$cmd = "$mpcenc_path --overwrite --quality $Vmpc --minSMR 0 --nmt 12 --tmn 32 ";
	my $profile = '--standard';
	if ( $Vmpc < 2.5 ){ $profile = '--telephone'; }
	elsif ( $Vmpc < 3.5 ){ $profile = '--thumb';  }
	elsif ( $Vmpc < 4.5 ){ $profile = '--radio';  }
	elsif ( $Vmpc < 5.5 ){ $profile = '--standard'; }
	elsif ( $Vmpc < 6.5 ){ $profile = '--xtreme'; }
	elsif ( $Vmpc < 7.5 ){ $profile = '--insane'; }
	else { $profile = '--braindead'; }
	
	$additional_command_mpc = $entry_command_mpc->get_text;
	
	my $cmd = "$nice_path -n $priority  $mpcenc_path --overwrite $profile $additional_command_mpc ";	
	
	my  $file_in   = $directory_output . '/' . $file_wav;	
	my  $file_out  = $directory_final  . '/' . $file_mpc;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "encode_wav_to_mpc --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in );	
	
	insert_msg("." , "small-ini");
	insert_msg("$cmd \"$file_in2\" \"$file_out2\" " , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	# Use 'filename_from_unicode' to convert from unicode to local encoding.
	$file_in2  = filename_from_unicode $file_in2;	
	$file_out2 = filename_from_unicode $file_out2;		
	_utf8_on($file_in2);  # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'.
	_utf8_on($file_out2); # Turns on the UTF8 flag in $file_out2 string.
	$cmd .= " \"$file_in2\" \"$file_out2\" ";	
	
	# start encoding
	my $res = open( MPCENC, "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";		
	$pid_mpc_encode = $res; # set mpc encode pid
	
	my $saved_value = 0;
	my $div = 0;
	
	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <MPCENC> )
	{  
		## this is output of mppenc:
		#    %|avg.bitrate| speed|play time (proc/tot)| CPU time (proc/tot)| ETA
                #  5.9  119.8 kbps  7.67x     0:17.1    4:52.6     0:02.2    0:38.1     0:35.9
		# 24.4  126.3 kbps  7.49x     1:11.5    4:52.6     0:09.5    0:39.0     0:29.5
                # 24,4
		
		# print "aquiiii: $_\n";
		
		if( $_ =~ /^\s+(\d+[\.,]\d+)\s+.*kbps\s+(\d+[\.,]\d+)x.*(\d+:\d+)/ )
		{ 
		  #print "\n<<>> $_ --->1=$1  --->2=$2  --->3=$3\n";
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 );
		  $div = number_value($div);
		  my $speed = sprintf("%0.1f", $2 );
		  my $pct = sprintf("%02d", $1 ); # 02d : leading zero
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors

                  #                            show only not repeated value
		  if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 
		  $pbar_encode->set_fraction( $div ) ; 
		  # print ( " div  = $div  ; time remain = $3 \n");
		  $status_bar->push($context_id, " mpc encode $pct% | time remaining = $3 | encode speed = $speed");
		  }		  
		}
		while (Gtk2->events_pending()) { Gtk2->main_iteration()};
		
		if ( not $normalize_button->get_active and $pid_mpc_encode >= 0 ) { 
		    $pid_mpc_encode = StopProcessing($pid_mpc_encode," Stop mpc encoding!", $file_wav);
		    $/="\n";  # abandon loop
		}
	}
	$/="\n"; ## final of loop
	close(MPCENC);

        if( -e filename_from_unicode $file_out ) {
		
	   remove_apetag (%args, (filepath => $file_out) );
	   $metadata{'Encoded by'} = "MPCENC with gnormalize (http://gnormalize.sourceforge.net)";	    
	   write_apetag  (%args, (filepath => $file_out) );
        }
        else { print "encode_wav_to_mpc --> Could not find mpc file: $file_out\n"; }	
	
	if ($normalize_button->get_active) {  # if normalize button is active
	    $pid_mpc_encode = -1;             # reset pid on the final of process  
            return $true;    }
	else { return $false;}
}


# wav --> ape
sub encode_wav_to_ape {   
   my %args = ( @_ );
   my $row = $args{row}; my $file_ape = $args{file_ape}; my $file_wav = $args{file_wav};
   
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};   
  
	my $compress = $spinner_compress->get_value_as_int();	
	$additional_command_ape = $entry_command_ape->get_text;
	my $cmd = "$nice_path -n $priority $ape_path $additional_command_ape ";		
	        
	my  $file_in   = $directory_output . '/' . $file_wav;	
	my  $file_out  = $directory_final  . '/' . $file_ape;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "encode_wav_to_ape --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in );	
	

	insert_msg("." , "small-ini");
	insert_msg("$cmd \"$file_in2\" \"$file_out2\" -c$compress " , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	# Use 'filename_from_unicode' to convert from unicode to local encoding.
	$file_in2  = filename_from_unicode $file_in2;	
	$file_out2 = filename_from_unicode $file_out2;		
	_utf8_on($file_in2);  # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'.
	_utf8_on($file_out2); # Turns on the UTF8 flag in $file_out2 string.
	$cmd .= " \"$file_in2\" \"$file_out2\" -c$compress ";
	
	# To exchange a command's STDOUT and STDERR in order to capture the STDERR 
	my $pid = open( APEENC, "$cmd 3>&1 1>&2 2>&3  |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	$pid_ape = $pid; ## set ape pid, pid > 0
	
	my $div = 0; # initial value
	my $saved_value = 0;
	
	$/="\r"; ## loop for output - initial
	while( <APEENC> )
	{	
	        #output:
		#--- Monkey's Audio Console Front End (v3.96b8) (c) Matthew T. Ashland ---
                #Decompressing ...
                #Progress:  3.0% (357.7 sec remaining, 368.8 sec total)

		if( $_ =~ /^Progress:\s+(\d+[\.,]\d)%\s\((.*)\)/ )
		{
		  #print "\n<<>> $_ --->1=$1  --->2=$2\n";
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 );
		  $div = number_value($div);
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors

                  #                            show only not repeated value
		  if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 
		  $pbar_encode->set_fraction( $div ) ; 
		  $status_bar->push($context_id, " ape encoding $1% | $2");
		  #print ( " div  = $div \n");
		  }		  
		}
		while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() }
		if ( not $normalize_button->get_active and $pid_ape >= 0 ) { 
		    $pid_ape = StopProcessing($pid_ape," Stop ape encoding!", $file_wav);
		    $/="\n";  # abandon loop
		}		
	}
	$/="\n"; ## final of loop
	close( APEENC );

        if( -e filename_from_unicode $file_out ) {
	   
	   remove_apetag (%args, (filepath => $file_out) );
	   $metadata{'Encoded by'} = "MAC with gnormalize (http://gnormalize.sourceforge.net)";	    
	   write_apetag  (%args, (filepath => $file_out) );
        }
        else { print "encode_wav_to_ape --> Could not find ape file: $file_out\n"; }
	
	if ($normalize_button->get_active) {  # if normalize button is active
	    $pid_ape = -1;                    # reset pid on the final of process  
            return $true;    }
	else { return $false;}
}

#  wav --> flac 
sub encode_wav_to_flac {
   my %args = ( @_ );
   my $row = $args{row}; my $file_flac = $args{file_flac}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath};
   
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};
    
	my $cmd; # command
	my $bitrate;
	my $mode;
	my $freq;
	my $compress = $spinner_compress_flac->get_value();		
	
        ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args);
	
	$additional_command_flac = $entry_command_flac->get_text;
	$cmd = "$nice_path -n $priority $flac_path -$compress -f $additional_command_flac ";
	
	my  $file_in   = $directory_output . '/' . $file_wav;	
	my  $file_out  = $directory_final  . '/' . $file_flac;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "encode_wav_to_flac --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in );

	insert_msg("." , "small-ini");
	insert_msg("$cmd \"$file_in2\" -o \"$file_out2\"" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	# Use 'filename_from_unicode' to convert from unicode to local encoding.
	$file_in2  = filename_from_unicode $file_in2;	
	$file_out2 = filename_from_unicode $file_out2;		
	_utf8_on($file_in2);  # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'.
	_utf8_on($file_out2); # Turns on the UTF8 flag in $file_out2 string.
	$cmd .= " \"$file_in2\" -o \"$file_out2\" ";

	my $pid = open( FLAC, "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	$pid_flac_decode = $pid; ## set flac pid, pid > 0
	
	my $div = 0; # initial value
	my $saved_value = 0;

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <FLAC> )
	{	
	        #output:options: -P 4096 -b 4608 -m -l 8 -q 0 -r 3,3
                #audio.wav: 51% complete, ratio=0.717

		if( $_ =~ /.*:\s+(\d+)%\scomplete/ )
		{
		  #print "\n<<>> $_ --->1=$1 \n";
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 );
		  $div = number_value($div);
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors

                  #                             show only not repeated value
		  if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 
		     $pbar_encode->set_fraction( $div ) ; 
		     $status_bar->push($context_id, " flac encoding $1%");
		  }		  
		}
		while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() }
		if ( not $normalize_button->get_active and $pid_flac_decode >= 0 ) { 
		    $pid_flac_decode = StopProcessing($pid_flac_decode," Stop flac encoding!", $file_wav);
		    $/="\n";  # abandon loop
		}		
	}
	$/="\n"; ## final of loop
	close(FLAC);		

	# tag commands -- to see the entries: metaflac --list music.flac
	# --no-utf8-convert
	#$Album= encode("utf8",$Album);	
	
	my   @cmd_tag = ( $metaflac_path, '--no-utf8-convert', "--set-tag=Title=$Title", "--set-tag=Artist=$Artist" );       
        push @cmd_tag,  ( "--set-tag=Album=$Album", "--set-tag=Date=$Year", "--set-tag=Description=$Comment", "--set-tag=Comment=$Comment" );       
        if ($Total_Track ne "" and $Total_Track >= $Track_Number){	     
       	       push @cmd_tag, ( "--set-tag=Tracknumber=$Track_Number/$Total_Track" ); }	     
        else { push @cmd_tag, ( "--set-tag=Tracknumber=$Track_Number" );              }       
        push @cmd_tag, ( "--set-tag=Genre=$Genre" );
	
		
	if ( $metaflac_path ne "" and $normalize_button->get_active ){
	   insert_msg("." , "small-ini");
	   insert_msg("@cmd_tag \"$file_out\"" , "small"); #print on debug textview
	   insert_msg("\n" , "small");
	   
	   push @cmd_tag, ( filename_from_unicode $file_out );
	   exec_cmd_system3(@cmd_tag);	
	} 
	 
	if ($normalize_button->get_active) {  # if normalize button is active
	    $pid_flac_decode = -1;            # reset pid on the final of process  
            return $true;    }
	else { return $false;}
}

#  wav --> mp4 
sub encode_wav_to_mp4 {   
   my %args = ( @_ );
   my $row = $args{row}; my $file_mp4 = $args{file_mp4}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath};
   
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};
   my $Comment = $files_info[$row]{comment};
   my $Album   = $files_info[$row]{album};
   my $Genre   = $files_info[$row]{genre};
   my $Year    = $files_info[$row]{year};
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};   
    
	my $cmd; # command
	my $bitrate;
	my $mode;
	my $freq;
	my $compress = $spinner_compress_flac->get_value();	
	
	$Track_Number =~ s/^0*//;   #remove the leading zero
	$Total_Track =~ s/^0*//;
	
	# tag commands for mp4 file 
	my $cmd_tag = " -w";
	if ( $Artist ne ""  ){ $cmd_tag .= " --artist \"$Artist\"";   }
	if ( $Title ne ""   ){ $cmd_tag .= " --title \"$Title\"";     }
	if ( $Album ne ""   ){ $cmd_tag .= " --album \"$Album\"";     }
	if ( $Year ne ""    ){ $cmd_tag .= " --year \"$Year\"";       }
	if ( $Genre ne ""   ){ $cmd_tag .= " --genre \"$Genre\"";     }
	if ( $Comment ne "" ){ $cmd_tag .= " --comment \"$Comment\""; }
	
	if ( $Total_Track ne "" and $Total_Track >= $Track_Number ){ $cmd_tag .= " --track \"$Track_Number/$Total_Track\" "; }	
	else { $cmd_tag .= " --track \"$Track_Number\" "; }
	
        ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args);
	
	$cmd = "$nice_path -n $priority $faac_path -c $freq ";
	# use --no-tns and --no-midslide to play correctly in the Quicktime player
	if ( $encode eq "variable" and $check_change_properties->get_active ){ 
	       $cmd .= " -q $Vmp4 ";    } # VBR (variable bitrate)
	else{  $cmd .= " -b $bitrate "; } # ABR (average bitrate)
	
	if ( $file_mp4 !~ /\.aac$/i ) { $cmd .= " $cmd_tag"; } #tag only for mp4|m4a
	
	$additional_command_mp4 = $entry_command_mp4->get_text;
	$cmd .= " $additional_command_mp4 ";	

        my  $file_in   = $directory_output . '/' . $file_wav;	
	my  $file_out  = $directory_final  . '/' . $file_mp4;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "encode_wav_to_mp4 --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in );
	
	$cmd .= " \"$file_in2\" -o \"$file_out2\" ";

	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");	
	
	my $pid = open( AAC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n";	
	my $pid_faac_encode = $pid; ## set flac pid, pid > 0
	
	my $div = 0; # initial value
	my $saved_value = 0;	

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <AAC> )
	{	
		# output:  frame          | bitrate | elapsed/estim | play/CPU | ETA
		#         300/4944  (  6%)|  240.2  |    1.2/19.4   |    5.90x | 18.3
                #        4944/4944  (100%)|  217.8  |   18.9/18.9   |    6.08x | 0.0

		if( $_ =~ /.*\(\s*(\d+)%\)\|\s+(\d+).*\s+(\d+[\.,]\d+)x\s+\|\s+(\d+[\.,]\d+).*/ )
		{
		  $saved_value = $div;
		  $div = sprintf("%0.2f", $1/100 ); # eg (65%)/100
		  $div = number_value($div);
		  if ( $div > 1){ $div = 1;}  # to avoid possible errors
		  my $bitr = $2;		  
		  my $speed = sprintf("%.1f", $3 );
		  my $time = sprintf("%02d", $4 );
		  my $pct = sprintf("%02d", $1 ); # 02d : leading zero

                  #                             show only not repeated value
		  if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 
		     $pbar_encode->set_fraction( $div ) ; 
		     $status_bar->push($context_id, " encoding $pct% | bitrate = $bitr | time = $time sec | speed = $speed ");
		  }		  
		}
		while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() }
		if ( not $normalize_button->get_active and $pid_faac_encode >= 0 ) { 
		    $pid_faac_encode = StopProcessing($pid_faac_encode," Stop faac encoding!", $file_wav);
		    $/="\n";  # abandon loop
		}		
	}
	$/="\n"; ## final of loop
	close(AAC); 
	 
	if ($normalize_button->get_active) {  # if normalize button is active
	    $pid_faac_encode = -1;            # reset pid on the final of process  
            return $true;    }
	else { return $false;}
}

# wav --> wma : encode with ffmpeg

   # see 'ffmpeg -h'; usage: ffmpeg [[infile options] -i infile]... {[outfile options] outfile}
   # -i filename         input file name
   # -y                  overwrite output files
   # -aq quality         set audio quality (codec-specific)
   # -ar rate            set audio sampling rate (in Hz)
   # -ac channels        set number of audio channels
   # -ab <int>     E..A. set bitrate (in bits/s)
   
   # -title    string    set the title
   # -author   string    set the author
   # -album    string    set the album 
   # -comment  string    set the comment
   # -track    <int>   E.... set the track number
   # -year     <int>   E.... set the year  
   
   # encode: ffmpeg -y -i input.wav  -ab 200k -ar 44100 -ac 2 -title "tito" -author "aut" -album "alb" -comment "com"  -track "3" -year "2008"  output.wma
   # decode: ffmpeg -y -i input.wma  output.wav
   
sub encode_wav_to_wma { # Not used yet
   my %args = ( @_ );
   my $row = $args{row}; my $file_mp3 = $args{file_mp3}; my $file_wav = $args{file_wav};
   
   $file_mp3 = 'output.wma'; 
   
   my $filepath = $args{filepath};			  
   
   # get all the 8 tags
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};   
   my $Album   = $files_info[$row]{album};
   my $Comment = $files_info[$row]{comment};
   my $Year    = $files_info[$row]{year};
   my $Genre   = $files_info[$row]{genre};   
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};
  
   my $bitrate;
   my $mode;
   my $freq;
   
   my  $file_in   = $directory_output . '/' . $file_wav;	
   my  $file_out  = $directory_final  . '/' . $file_mp3;
  (my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
  (my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
   print "encode_wav_to_wma --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in );
   
   # tag commands for wma file 
   my $cmd_tag = " ";
   if ( $Artist ne ""  ){ $cmd_tag .= " -author \"$Artist\"";   }
   if ( $Title ne ""   ){ $cmd_tag .= " -title \"$Title\"";     }
   if ( $Album ne ""   ){ $cmd_tag .= " -album \"$Album\"";     }
   if ( $Year ne ""    ){ $cmd_tag .= " -year \"$Year\"";       }
  #if ( $Genre ne ""   ){ $cmd_tag .= " -genre \"$Genre\"";     }
   if ( $Comment ne "" ){ $cmd_tag .= " -comment \"$Comment\""; }
	
   #if ( $Total_Track ne "" and $Total_Track >= $Track_Number ){ $cmd_tag .= " -track \"$Track_Number/$Total_Track\" "; }	
   #else { $cmd_tag .= " -track \"$Track_Number\" "; }
	
   ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args);
   $additional_command_mp3 = $entry_command_mp3->get_text;
	
   #my $cmd = "$nice_path -n $priority /usr/bin/ffmpeg -y -i \"$file_in2\" -ab ${bitrate}k -ar $freq -ac 2 $cmd_tag $additional_command_mp3 \"$file_out2\" ";
   my $cmd = " /usr/bin/ffmpeg -y -i \"$file_in2\" -ab ${bitrate}k -ar $freq -ac 2 \"$file_out2\"";

   insert_msg("." , "small-ini");
   insert_msg("$cmd" , "small"); #print on debug textview
   insert_msg("\n" , "small");	
	         	
   ## start encoding process	
   my $pid = open( FFMPEG, filename_from_unicode "$cmd 2>&1 |" ) or die "couldn't execute \"$cmd\": $!\n";      		
   $pid_lame_encode = $pid;  # set lame encode pid
	
   my $div = 0;

   $/="\r"; ## loop for output - initial
   while( <FFMPEG> )
   {
      # size=     754kB time=25.1 bitrate= 245.7kbits/s
      # size=    1207kB time=40.3 bitrate= 245.3kbits/s
      print "aquiiii: $_\n";
		
   }
   $/="\n"; ## final of loop
   close( FFMPEG );		 
	 
   if ($normalize_button->get_active) {  # if normalize button is active
      $pid_lame_encode = -1;            # reset pid on the final of process  
      return $true;     }
   else { return $false;}
}


# wav --> mp3 : encode with lame
sub encode_wav_to_mp3 {
   my %args = ( @_ );
   my $row = $args{row}; my $file_mp3 = $args{file_mp3}; my $file_wav = $args{file_wav}; 
   
   my $filepath = $args{filepath};
   #$filepath = filename_from_unicode $filepath if( ! -e $filepath );			  
   
   # get all the 8 tags
   my $Title   = $files_info[$row]{title};
   my $Artist  = $files_info[$row]{artist};   
   my $Album   = $files_info[$row]{album};
   my $Comment = $files_info[$row]{comment};
   my $Year    = $files_info[$row]{year};
   my $Genre   = $files_info[$row]{genre};   
   my $Track_Number = $files_info[$row]{track};
   my $Total_Track  = $files_info[$row]{total_track};
  
   my $bitrate;
   my $mode;
   my $freq;
	
   ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args);
	
   my $cmd = "$nice_path -n $priority $lame_path -q $quality -c ";	
	
   if    ( $encode eq "constant"                                          ){ $cmd .= "--cbr -b $bitrate ";                              } # CBR (constant bitrate)
   elsif ( $encode eq "average"                                           ){ $cmd .= "--abr $bitrate -b $vb_Min -B $vb_Max --nohist ";  } # ABR (average bitrate)
   elsif ( $encode eq "variable" and $check_change_properties->get_active ){ $cmd .= "--vbr-new -V $V -b $vb_Min -B $vb_Max --nohist "; } # VBR (variable bitrate)
	
	# common commands of lame for all options of encode
	$cmd .= "-m \"$mode\" --resample $freq --replaygain-fast ";
	
	$additional_command_mp3 = $entry_command_mp3->get_text;
	$cmd .= " --add-id3v2 --pad-id3v2 $additional_command_mp3 ";		
	
	my  $file_in   = $directory_output . '/' . $file_wav;	
	my  $file_out  = $directory_final  . '/' . $file_mp3;
	(my $file_in2  = $file_in ) =~ s/"/\\"/g;  # change all " characters by \"	
	(my $file_out2 = $file_out) =~ s/"/\\"/g;  # change all " characters by \"	
	print "encode_wav_to_mp3 --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in );
	
	$cmd .= " \"$file_in2\" \"$file_out2\" ";

	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");	
	         	
	## start encoding process	
	my $pid = open( LAME, filename_from_unicode "$cmd 2>&1 |" ) or die "couldn't execute \"$cmd\": $!\n";      		
	$pid_lame_encode = $pid;  # set lame encode pid
	
	my $div = 0;

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <LAME> )
	{  
		## this is output of lame.
		#LAME version 3.96.1 (http://lame.sourceforge.net/)
                #CPU features: MMX (ASM used), 3DNow! (ASM used), SSE
                #Using polyphase lowpass filter, transition band: 17249 Hz - 17782 Hz
                #Encoding almir_sater-instrumental-03_vinheta_do_capeta.wav to lixo.mp3
                #Encoding as 44.1 kHz 128 kbps j-stereo MPEG-1 Layer III (11x) qval=3
                #   Frame          |  CPU time/estim | REAL time/estim | play/CPU |    ETA 
		#   320/2171   ( 7%)|    0:05/    0:09|    0:05/    0:10|   5.8102x|    0:04 
                #  1250/2171   (58%)|    0:05/    0:09|    0:05/    0:10|   5.8102x|    0:04 
		
		# print "aquiiii: $_\n";
		
		if( $_ =~ /^\s.*\s*\(\s*(\d+)%\)\|\s*.*\s+(\d+[\.,]\d+)x\|\s+(\d+\:\d+).*/ )
		{		  
		  $div = sprintf("%0.2f", $1/100 ); # eg (65%)/100
		  $div = number_value($div);
		  #print ( "div = $1 ; speed = $2 \n");
		  my $speed = sprintf("%.1f", $2 );
		  my $time = $3;
		  my $pct = sprintf("%02d", $1 ); # 02d : leading zero

		  if ( $pbar_encode->get_fraction() <=1 and $pid_lame_encode>=0 ) { 
		     $pbar_encode->set_fraction( $div ) ; 
		     $status_bar->push($context_id, " lame encode $pct% | time remaining = $time | encode speed = $speed");
		  }
		}	
		while ( Gtk2->events_pending() ) { Gtk2->main_iteration() }
		
		if ( not $normalize_button->get_active and $pid_lame_encode >= 0 ) { 
		    $pid_lame_encode = StopProcessing($pid_lame_encode, $langs{msg058}, $file_wav );
		    $/="\n";  # abandon loop
		}		
	}
	$/="\n"; ## final of loop
	close( LAME );	
	
	if ($normalize_button->get_active) {	
	   print "encode_wav_to_mp3 --> Could not find mp3 file: $file_out\n" if( ! -e filename_from_unicode $file_out );
	
	   # save the Total_Track in file_mp3 --- lame can not save the tag: 'track/Total_Track' 
	   $metadata{'Encoded by'} = "LAME with gnormalize (http://gnormalize.sourceforge.net)";
	   # to save ID3v2 tag
	   save_ID3v2_mp3_tag($file_out, $Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Total_Track, $Genre);	   	   	   	   
	   	   	              
           save_ID3v1_mp3_tag($file_out, $Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Genre );	   
	}	 
	 
	if ($normalize_button->get_active) {  # if normalize button is active
	    $pid_lame_encode = -1;            # reset pid on the final of process  
            return $true;    }
	else { return $false;}
}

####----------------------Config----------------------####
change_font_for_all_child($window_font_name);
#encode_choice_sensitive();
$notebook->set_current_page ($notebook_page_num);
$notebook2->set_current_page ($notebook_page_num2);

####-----------------------ARGV-----------------------####

sub arguments {

 # Get the parameters from the command line.
 if (@ARGV == 1){      #number of arguments
    my $file = filename_to_unicode $ARGV[0];
       
    if ( ! -e filename_from_unicode $file ){ # if the file not exist
       print "This file not exist: $file\n";
       return; 
    }    
    $file =~ s/(.*\/)//g;      #copy and remove (path)/
    insert_msg( $langs{msg078}.": $file\n\n" , "small");   
    ($directory = $ARGV[0]) =~ s/(.*)\/.*/$1\//g;
       
    if ( $directory !~ /\// ){      # for the case of none directory: 'gnormalize music.mp3'
       $directory = filename_to_unicode "$ENV{'PWD'}"; # $directory = `pwd` 
    }    
    elsif ( $directory !~ /^\// ){  # for the case of directory like that: 'gnormalize some/place/music.mp3'
       $directory = filename_to_unicode "$ENV{'PWD'}/".$directory;
    }     
    #print "file = $file ;; directory = $directory \n";
    fill_with_all_informations($directory . '/' . $file);   
 }
}

arguments();

####---------------------- Quit ----------------------####

# Quit of gnormalize
sub Quit {
   stop_playing_music();
   save_config();
   Gtk2->main_quit; 
   return $true; 
}

#print Claudio1::teste(); # only test
#gnormalize::cdplay::read_toc();
#gnormalize::cdplay::play_cdrom_track();
#gnormalize::cdplay::play_cdrom_msf2();
#gnormalize::cdplay::play_cdrom_msf(8);
#gnormalize::cdplay::pause_cdrom();
#gnormalize::cdplay::resume_cdrom();
#gnormalize::cdplay::eject_cdrom();
#gnormalize::cdplay::multi();
#gnormalize::cdplay::get_vol();
#gnormalize::cdplay::set_vol(11,11,11,11);
#gnormalize::cdplay::cdrom_read_audio();
#print gnormalize::cdplay::msf_to_lba(0,0,0);

#my $info = gnormalize::cdplay::Info();
#print "current track = $info->{current_track}";

#gnormalize::factorial::print2(5);

# Gtk event loop
Gtk2->main; # necess�rio para executar o programa
exit(0);

####--------------------- The End ---------------------####

#-------------------------------------------------#
#------------------ New-Package ------------------# 
# See perlmod, perlmodlib, perltoot
# See Learning Perl Objects, References and Modules, Chapter 2, 1o. Edition, 2003.

#{ # start scope block
#   package Claudio1;  # now in package Claudio1. Only one test
#   use strict;
   # See <man Exporter>

#   sub teste {       # Claudio1::teste
#      print "Claudio1::teste\n";
#   }
#   1;  # don't forget to return a true value from the file
#} # end scope block

#-------------------------------------------------#
#------------------ New-Package ------------------# 

######################-----gnormalize::cdplay-----######################

{ # start scope block 
package gnormalize::cdplay;  # New package to play Audio CD.
use strict;
use Fcntl;

# require Exporter;

# See <man Exporter>
our $VERSION = '0.01';

# See <man perlopentut> and stat() on perlfunc.
# See "Linux::CDROM::Cookbook" (Linux-CDROM-0.01.tar.gz), 
# DOING EVEN MORE section by Tassilo von Parseval

# see /usr/include/linux/cdrom.h
use constant CDROMPAUSE => 0x5301;          # /* Pause Audio Operation */ 
use constant CDROMRESUME => 0x5302;         # /* Resume paused Audio Operation */
use constant CDROMPLAYMSF => 0x5303;        # /* Play Audio MSF (struct cdrom_msf) */
use constant CDROMPLAYTRKIND => 0x5304;     # /* Play Audio Track/index (struct cdrom_ti) */
use constant CDROMREADTOCHDR => 0x5305;     # /* Read TOC header (struct cdrom_tochdr) */
use constant CDROMREADTOCENTRY => 0x5306;   # /* Read TOC entry (struct cdrom_tocentry) */
use constant CDROMSTOP => 0x5307;           # /* Stop the cdrom drive */
use constant CDROMSTART => 0x5308;          # /* Start the cdrom drive */
use constant CDROMEJECT => 0x5309;          # /* Ejects the cdrom media */
use constant CDROM_LEADOUT => 0xAA;         # /* The leadout track is always 0xAA, regardless of # of tracks on disc */
use constant CDROM_AUDIO_COMPLETED => 0x13; # /* audio play successfully completed */
use constant CDROMVOLREAD => 0x5313;        # /* Get the drive's volume setting (struct cdrom_volctrl) */
use constant CDROMVOLCTRL => 0x530a;        # /* Control output volume (struct cdrom_volctrl) */
use constant CDROM_DRIVE_STATUS => 0x5326;  # /* Get tray position, etc. */
use constant CDROM_DISC_STATUS => 0x5327;   # /* Get disc type, etc. */
use constant CDROMSUBCHNL => 0x530b;        # /* Read subchannel data (struct cdrom_subchnl) */
use constant CDROMREADAUDIO => 0x530e;      # /* (struct cdrom_read_audio) */
use constant CDROMREADRAW => 0x5314;        # /* read data in raw mode (2352 Bytes)
use constant CDROMMULTISESSION => 0x5310;   # /* Obtain the start-of-last-session address of multi session disks 
                                            #   (struct cdrom_multisession) */ 
use constant CD_MSF_OFFSET => 150;          # /* MSF numbering offset of first frame */					      
#/* CD-ROM address types (cdrom_tocentry.cdte_format) */
use constant CDROM_LBA => 0x01;             # /* "logical block": first frame is #0 */
use constant CDROM_MSF => 0x02;             # /* "minute-second-frame": binary, not bcd here! */
   
   # /* This struct is used by the CDROMPLAYMSF ioctl */ 
   # struct cdrom_msf 
   # {
   #	__u8	cdmsf_min0;	/* start minute */
   #	__u8	cdmsf_sec0;	/* start second */
   #	__u8	cdmsf_frame0;	/* start frame */
   #	__u8	cdmsf_min1;	/* end minute */
   #	__u8	cdmsf_sec1;	/* end second */
   #	__u8	cdmsf_frame1;	/* end frame */
   # };
   
   # /* Address in either MSF or logical format */
   # union cdrom_addr		
   # {
   #	struct cdrom_msf0	msf;  # 'CCCx' pack whith 32 bits = 4 bytes
   #	int			lba;  # 'i'    pack 
   # };
   
   # /* Address in MSF format */
   # struct cdrom_msf0		
   # {
   #	__u8	minute;
   #	__u8	second;
   #	__u8	frame;
   # };
   
   # /* This struct is used by the CDROMVOLCTRL and CDROMVOLREAD ioctls */
   # struct cdrom_volctrl
   # {
   #	__u8	channel0;
   #	__u8	channel1;
   #	__u8	channel2;
   #	__u8	channel3;
   # };
   
sub msf_to_lba {
    my ($min, $sec, $frame) = @_;
    my $lba = ($min * 60 + $sec) * 75 + $frame - CD_MSF_OFFSET;
    return $lba; # Is equal to $ref_array->[$i]{begin_frames}
}

sub play_cdrom_msf { # Play Audio cdrom on linux ;; Need read_toc() first.
   my $track  =  1; # track to play
   my $delta  =  0; # to advance or go back $delta seconds
   my $position  =  0.00; # 0.00 to 1.00 ; play at relative position into the track
   my $cd_toc = $toc_audiocd; # $toc_audiocd ; to find the frames of the tracks

   # See Perl Cookbook, 2nd Edition, Ch. 10.7
   my %args = (
                Track => 1,     # default value
                Advance => 0,
		Position => 0.00,
                @_,             # argument pair list goes here
	      );
   if ( defined($args{Track}) ){ if ( $args{Track} =~ /^\d+$/ ){ $track = $args{Track}; } }
   else { return; }
   if ( $args{Advance} =~ /^[+-]?\d+$/ ){ $delta = $args{Advance}; }
   #gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1, Position => 0.43);
   if ( $args{Position} =~ /^[\.\d]*$/ ){ $position = $args{Position}; }
   
   my $info = Info(); # Get Status
   if ( not $info ){ return; }
   my $status = $info->{status};
   if ( $status eq 'invalid' or $status eq 'error' ){ return $false; }
	
   my $startframe = $cd_toc->[$track-1]->{frames_abs};
   
   if ( $delta != 0 ){ # advance $delta seconds
      my $new_frame = $info->{frame_abs}  + $delta * 75;  # current absolute frame + delta (seconds)
      if ( $new_frame > $startframe ) { $startframe = $new_frame; }
   }	   
   # 150 = 2*75, the gap before a audio track
   my $endframe = $cd_toc->[$track]->{frames_abs} - 1;
   
   if ( $startframe < 0 or $endframe < 0 or $startframe >= $endframe ){ return $false; }
   if ( $position > 0 and $position <= 1 ){ $startframe = int($startframe + ($endframe - $startframe)*$position);}

   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]";
   
   my $min0   = int( $startframe / (60 * 75) );
   my $sec0   = int( ($startframe % (60 * 75)) / 75 );
   my $frame0 = int( $startframe % 75 );
   my $min1   = int( $endframe / (60 * 75) );
   my $sec1   = int( ($endframe / 75) % 60 );
   my $frame1 = int( $endframe % 75 );
   #print "startframe = $startframe ; endframe = $endframe ;; status = $status ; frames = ",$endframe - $startframe,"\n";
   
   my $cdrom_msf = pack "C6", $min0, $sec0, $frame0, $min1, $sec1, $frame1;  
   
   # See what operations can be performed on your machine at /usr/include/sys/ioctl.h
   # Play Audio CD in MSF struct
   ioctl(CD, CDROMPLAYMSF, $cdrom_msf ) or die "can not play cdrom [$!] [$audiodevice_path]";
   		    
   close(CD);   
}

sub play_cdrom_msf2 { # only for test
   if ( not Info() ){ return; } # Get Status
   
   my $startframe = 202250; # 150: first pre gap
   my $endframe   = 207630;  
   
   if ( $startframe < 0 or $endframe < 0 or $startframe >= $endframe ){ return $false; }

   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]";
   
   my $min0   = int( $startframe / (60 * 75) );
   my $sec0   = int( ($startframe % (60 * 75)) / 75 );
   my $frame0 = int( $startframe % 75 );
   my $min1   = int( $endframe / (60 * 75) );
   my $sec1   = int( ($endframe / 75) % 60 );
   my $frame1 = int( $endframe % 75 );
   #print "startframe = $startframe ; endframe = $endframe ;; status = $status ; frames = $frames \n";
   
   my $cdrom_msf = pack "C6", $min0, $sec0, $frame0, $min1, $sec1, $frame1;  
   
   # See what operations can be performed on your machine at /usr/include/sys/ioctl.h
   # Play Audio CD in MSF struct
   ioctl(CD, CDROMPLAYMSF, $cdrom_msf ) or die "can not play cdrom [$!] [$audiodevice_path]";
   		    
   close(CD);   
}


sub pause_cdrom { # Pause Audio cdrom on linux
   if ( not Info() ){ return; } # Get Status
   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 
   ioctl(CD, CDROMPAUSE, 1 ) or die "can not pause cdrom [$!] [$audiodevice_path]";  		    
   close(CD);   
}

sub resume_cdrom { # Resume Audio cdrom on linux
   if ( not Info() ){ return; } # Get Status
   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 
   ioctl(CD, CDROMRESUME, 1 ) or die "can not resume cdrom [$!] [$audiodevice_path]";  		    
   close(CD);   
}

sub stop_cdrom { # Stop Audio cdrom on linux
   if ( not Info() ){ return; } # Get Status
   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 
   ioctl(CD, CDROMSTOP, 1 ) or die "can not stop cdrom [$!] [$audiodevice_path]";  		    
   close(CD);   
}

sub eject_cdrom { # Eject Audio cdrom on linux
   if ( not Info() ){ return; } # Get Status
   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 
   ioctl(CD, CDROMEJECT, 1 ) or die "can not stop cdrom [$!] [$audiodevice_path]";  		    
   close(CD);   
}

sub set_vol { # Set Volume
   if ( not Info() ){ return; } # Get Status
   # Set Volume
   my $channel0=shift || 0;          #front_left  ; 0 - 255
   my $channel1=shift || $channel0;  #front_right
   my $channel2=shift || $channel0;  #back_left
   my $channel3=shift || $channel0;  #back_right

   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]";
   
   my $volctrl = pack "CCCC", $channel0, $channel1, $channel2, $channel3;		  
   ioctl(CD, CDROMVOLCTRL, $volctrl) or die "can not set volume [$!] [$audiodevice_path]";			  
   
   close(CD);   
}

sub get_vol { # Get Volume
   if ( not Info() ){ return; } # Get Status

   my ($channel0, $channel1, $channel2, $channel3) = ( 0, 0, 0, 0);

   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]";	
   
   # Get Volume   
   my $volctrl = pack "CCCC", $channel0, $channel1, $channel2, $channel3;		  
   ioctl(CD, CDROMVOLREAD, $volctrl) or die "can not read volume [$!] [$audiodevice_path]";
   ($channel0, $channel1, $channel2, $channel3) = unpack "CCCC", $volctrl;
   print "channel0 = $channel0 ; channel1 = $channel1 ; channel2 = $channel2 ; channel3 = $channel3\n";			  
   
   close(CD);   
}

sub multi { # Show if the cdrom have multisession
   #/* This struct is used with the CDROMMULTISESSION ioctl */
   #struct cdrom_multisession
   #{
   #	union cdrom_addr addr; /* frame address: start-of-last-session  
   #	                           (not the new "frame 16"!).  Only valid
   #	                           if the "xa_flag" is true. */
   #	__u8 xa_flag;        /* 1: "is XA disk" */
   #	__u8 addr_format;    /* CDROM_LBA or CDROM_MSF */
   #};
   my ($min, $sec, $frame) = (0, 0, 0);
   my $flag = 0;
   my $cdrom_multi = pack "CCCxCC", $min, $sec, $frame, $flag, CDROM_MSF; # Set the format
   	
   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 
   ioctl(CD, CDROMMULTISESSION, $cdrom_multi ) or die "multisession cdrom [$!] [$audiodevice_path]";  		    
   close(CD);
   ( $min, $sec, $frame, $flag ) = unpack "CCCxC", $cdrom_multi;
   # print "min = $min; sec = $sec ; frame = $frame ; flag = $flag \n";
   # $flag = 1 if multisession
   return $flag;
}

sub Info {  # Inform the absolute and relative time and current track of Audio CD
            # Need read_toc() first

   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or return $false;

   #/* This struct is used by the CDROMSUBCHNL ioctl */
   # struct cdrom_subchnl 
   # {
   #	__u8	cdsc_format;       /* Set CDROM_LBA or CDROM_MSF format */
   #	__u8	cdsc_audiostatus;
   #	__u8	cdsc_adr:	4; /* (4 + 4) bits = 1 byte */
   #	__u8	cdsc_ctrl:	4;
   #	__u8	cdsc_trk;      # track
   #	__u8	cdsc_ind;      # index
   #    3x                     # <padding byte>  
   #	union cdrom_addr cdsc_absaddr; #absolute address
   #	union cdrom_addr cdsc_reladdr; #relative address
   # };
   
   my $cdrom_subchnl = pack "C", CDROM_MSF; # Set the format	  
   ioctl(CD, CDROMSUBCHNL, $cdrom_subchnl) or return $false;
   my ( $cdsc_format, $status, $cdsc_adr_ctrl, $cdsc_trk, $cdsc_ind, 
        $min_abs, $sec_abs, $frame_abs, $min, $sec, $frame ) = unpack "C5x3CCCxCCCx", $cdrom_subchnl; 
   
   # status, see /usr/include/linux/cdrom.h:
   # 21 (decimal) = 0x15 (hexagonal) /* no current audio status to return */
   if    ( $status == 0x00 ) { $status = 'invalid';   }
   elsif ( $status == 0x11 ) { $status = 'play';      }
   elsif ( $status == 0x12 ) { $status = 'paused';    }
   elsif ( $status == 0x13 ) { $status = 'completed'; }
   elsif ( $status == 0x14 ) { $status = 'error';     }
   elsif ( $status == 0x15 ) { $status = 'no_status'; }
   else  { $status = 'no_disc'; }
   
   my %info=();
   
   # $cdsc_trk shows next track at boundary region!
   # See 'sub get_current_track' how to get the correct current track.
   $info{current_track}=$cdsc_trk; #this is not always correct! (when not exist pre gap = 150)
   $info{status}=$status;
   
   $info{min_abs}=$min_abs;
   $info{sec_abs}=$sec_abs;
   $frame_abs = int($frame_abs + $sec_abs*75 + $min_abs*60*75); # current absolute frame
   $info{frame_abs}=$frame_abs;
   #$info{time}=[ $min_abs , $sec_abs , $frame_abs ];
   
   $info{min}=$min;    # It shows regressive time to next track
   $info{sec}=$sec;
   $frame = int($frame + $sec*75 + $min*60*75);                 # current relative frame
   $info{frame}=$frame;
   
   #print "track = $cdsc_trk ; index = $cdsc_ind ; status = $status ; format = $cdsc_format \n";
   #print "(min_abs = $min_abs ; sec_abs = $sec_abs ; frame_abs = $frame_abs) ;; (min = $min ; sec = $sec ; frame = $frame)\n";		  
   
   close(CD);
   
   return \%info; 
}

# See CDDB_get and Linux::CDROM::Cookbook for some sugestions
# See /usr/include/linux/cdrom.h
sub read_toc {
   my $cdplayer = shift; # only show special track for $cdplayer = "gnormalize::cdplay"
   my $device = shift || $audiodevice_path;
 
   my $tochdr="";
   my $debug = 0; # values:0,1,2 ;;   if value==1, show output like 'cdparanoia -Q'

   my $open = sysopen (CD, $device, O_RDONLY | O_NONBLOCK);
   if ( not defined($open) ){ return $false; }

   my $result = ioctl(CD, CDROMREADTOCHDR, $tochdr) ; # or die "can not read toc [$!] [$audiodevice_path]";  
   if ( not defined($result) ){ return $false; } # result = 0 but true
  
   my ($start,$end) = unpack "CC",$tochdr;

   # /* The leadout track is always 0xAA, regardless of # of tracks on disc */
   # The index "CDROM_LEADOUT" 0xAA = 170 (decimal) is the final address of last track.
   my @tracks=();
   for (my $i=$start; $i<=$end;$i++) { push @tracks,$i; }
   push @tracks,0xAA;
  
   # /* Note that only "cdte_track" and "cdte_format" need to be set. All other slots 
   # /* are only used for the return values.
   # /* This struct is used by the CDROMREADTOCENTRY ioctl */
   # struct cdrom_tocentry 
   # {
   #	__u8	cdte_track;
   #	__u8	cdte_adr	:4;    /* two 4-bit wide fields require 1 byte
   #	__u8	cdte_ctrl	:4;
   #	__u8	cdte_format;           /* Set CDROM_LBA or CDROM_MSF format
   #	union cdrom_addr cdte_addr;    /* It's either a "struct cdrom_msf0" or an integer.
   #	__u8	cdte_datamode;
   # };
  
   # /* Address in either MSF or logical format */
   # union cdrom_addr		
   # {
   #	struct cdrom_msf0	msf;
   #	int			lba;
   # };
   
   # /* Address in MSF format */
   # struct cdrom_msf0		
   # {
   #	__u8	minute;
   #	__u8	second;
   #	__u8	frame;
   # };
  
   print "\n     Tracks and absolutes frames:\n\n" if $debug==2;
   
   my @array_toc=();

   foreach my $i (@tracks) { # track 0xAA = 170 get the total frames
    
     #            pack "C       # cdte_track                  Byte 0
     #                  C       # cdte_adr + cdte_ctrl        Byte 1
     #                  C       # cdte_format                 Byte 2
     #                  x       # <padding byte>             
     #                  i       # cdte_addr
     #                  C       # cdte_datamode               Byte 8
     #                          ", track, 0, CDROM_LBA;
    
     # if format = CDROM_MSF, then substitute "i" by "CCCx", both with 32 bits.

    
     my $tocentry=pack "CCCxCCCxC", $i,0,CDROM_MSF;  # Set "cdte_track" and "cdte_format".
     ioctl(CD, CDROMREADTOCENTRY, $tocentry) or die "can not read track $i info [$!] [$audiodevice_path]";
     my ($track, $adr_ctrl, $format, $min, $sec, $frame, $mode) = unpack "CCCxCCCxC", $tocentry;

     my %cdtoc=();
    
     $cdtoc{track}=$track; 
     $cdtoc{min_abs}=$min;
     $cdtoc{sec_abs}=$sec;
     $cdtoc{frame_abs}=$frame;
     my $frames_abs = int($frame+$sec*75+$min*60*75);
     $cdtoc{frames_abs}=$frames_abs; # Absolute position or StartSector
 
     $cdtoc{data} = $false;
    
     # /* bit to tell whether track is data or audio (cdrom_tocentry.cdte_ctrl) */
     # 0x04 (hex) = 4 (dec) = 100 (bin) is equivalent to 0100 0000 = 0x40 (using 8 bits: 4-bits + 4-bits)
     if($adr_ctrl & 0x40) { $cdtoc{data} = $true; } 
     printf "track=%02d ; min=%02d ; sec=%02d ; frame=%02d ; frames_abs=$frames_abs", $track, $min, $sec, $frame if $debug==2;
     if($cdtoc{data} and $debug==2) { print "track $track is data\n"; }
     elsif($debug==2){ print "\n"; }
    
     push @array_toc, \%cdtoc;
   }   
   close(CD);
  
   # Taking a reference to an array (See 'Learning Perl Objects, References and Modules')
   my $ref_array = \@array_toc; 
  
   my $no_cdaudio = $true; # search for at least one audio track
   for (my $i = 0; $i <= $end; $i++) {
      if ( not $ref_array->[$i]->{data}){ 
         $no_cdaudio = $false; 
 	 $start = $i+1;
 	 last;
      }
   }
   if ($no_cdaudio){ return $false; }
  
   # Very Special Case: When CD_MSF_OFFSET ( = $ref_array->[0]->{frames_abs} ) is not equal to 150 frames
   # define CD_MSF_OFFSET       150 /* MSF numbering offset of first frame */
   # For the case when the audio cd don't have the pre gap (with 150 frame) as first track.
   # k3b have this bad option for make audio cds.
   if ( $ref_array->[$start-1]->{frames_abs} > 75*20 and not $ref_array->[$start-1]->{data} and $cdplayer eq "gnormalize::cdplay" ){
      # put one element (one hash) to the front of the array. see perlfunc
      unshift (@array_toc, {frames_abs => 150, data => 0, track => 1, min_abs => 0, sec_abs => 2} );
      $end ++;
   }
   print "\nTable of contents (audio tracks only):\n". #Like 'cdparanoia -Q'
	  "track        length               begin\n".
	  "============================================\n" if $debug==1;
   
   for (my $i = $start; $i <= $end; $i++) {  # find relative frames
   
      # 11400 frames, for CDROMMULTISESSION
      # 11400: multisession offset , adjust the end of last audio track to be in the first session
      if ( $ref_array->[$i]->{data} and not $ref_array->[$i-1]->{data} and multi() ){
         if ( $ref_array->[$i-1]->{frames_abs} < $ref_array->[$i]->{frames_abs} - 11400 ){ 
            $ref_array->[$i]->{frames_abs} -= 11400; 
            $end = $i; # abandon the loop
	 }
      }
      my $frames = $ref_array->[$i]->{frames_abs} - $ref_array->[$i-1]->{frames_abs}; # relative frames inter tracks
      my $begin_frames = $ref_array->[$i-1]->{frames_abs} - 150; # 150 is the offset (gap) of first frame.
     
      my $min = $frames / (60 * 75);
      my $sec = ($frames / 75) % 60;
      $ref_array->[$i]{frames} = $frames;
      $ref_array->[$i]{min} = sprintf ( "%02d", $min);
      $ref_array->[$i]{sec} = sprintf ( "%02d", $sec);
      $ref_array->[$i]{begin_frames} = $begin_frames; # frames_abs - (150 frames = 2 sec of offset)
        
      # like 'cdparanoia -Q'
      printf "%3d.  %7ld [%02d:%02d.%02d]  %7ld [%02d:%02d.%02d]\n", $i, 
              $frames, ($frames / (60 * 75)), (($frames/75)%60), ($frames % 75),
              $begin_frames, ($begin_frames/(60*75)), (($begin_frames/75)%60), ($begin_frames % 75)
	      if $debug==1;
   }
   $ref_array->[0]{total_track} = $end - $start + 1; #set total audio track number, not always equal to $#array_toc
   my $total_frames = $ref_array->[$end]->{frames_abs} - $ref_array->[$start-1]->{frames_abs};
   $ref_array->[0]{total_frames} = $total_frames;
   printf "TOTAL %7ld [%02d:%02d.%02d]    (audio only)\n", $total_frames, ($total_frames/(60*75)),
                                       (($total_frames/75)%60), ($total_frames % 75) if $debug==1;
   print "total audio tracks = $end ; total audio frames = $total_frames \n" if $debug==2;
   print "frame0 end at = $ref_array->[0]->{frames_abs} ; frame1 end at = $ref_array->[1]->{frames_abs}\n" if $debug==2;

   return \@array_toc;
}

# Read Audio cdrom on linux and rip
sub cdrom_read_audio { # Don't work yet!

   my $track   = shift || 8;   # track to rip
   my $nframes = shift || 1;   # 2646 /* The maximum possible returned bytes */ 
   #my $cd_toc = $toc_audiocd; # $toc_audiocd ; to find the frames of the tracks
   my $cd_toc = read_toc();
	
   my $startframe = $cd_toc->[$track-1]->{frames_abs} - 150; #LBA
   
   #/* This struct is used by the CDROMREADAUDIO ioctl */   
   #struct cdrom_read_audio
   #{
   #	union cdrom_addr addr; /* frame address */
   #	__u8 addr_format;      /* CDROM_LBA or CDROM_MSF */
   #	int nframes;           /* number of frames to read at once */ ; 1 <= nframes <= 75
   #	__u8 __user *buf;      /* frame buffer (size: nframes*2352 bytes) */
   #};     # unary * Dereference-address operator. See perlop and perlref
           # Dereferencing means getting at the value that a reference points to.
	   # int *ptr; ptr = &count ; "&" stores the address of count in ptr
	   # total = *ptr;  The value in the address stored in ptr is assigned to total
	   # See 'Advanced Perl Programming', Chap. 1. ;; Programming Perl, 3a. Ed, Chap. 8.3
   # CD_FRAMESIZE_RAW = 2352
   # char *  s : While Perl passes arguments to functions by reference, C passes arguments by value; see perlxstut.
   # default Perl doesn't currently support the const char * type.
   
   # "The stack is a special type of array that is used to pass information to functions and pass return 
   # values from functions back to the calling statement." The Complete Reference 2nd Ed, pag 694.

   # __u8 buff[CD_FRAMESIZE_RAW];
   #cda.buf = (__u8 *)&buff[0];
   #for(i = start_lba; i < end_lba; i++) 
   #{
   #   memset(buff, 0, sizeof(buff));      # see <man memset>
   #   cda.addr.lba = i;
   #   printf("lba: %u\n", i);
   #   ioctl(fd, CDROMREADAUDIO, &cda);
   #   for(n = 0; n < CD_FRAMESIZE_RAW/2; n++){ buff[n] = __swab16(buff[n]);}
   #
   #   write(out, (__u8 *)buff, CD_FRAMESIZE_RAW);
   #}
   #close(fd); close(out);
   
   #use Devel::Pointer;
   #$a = address_of($b);   # a = &b;
   #$b = deref($a);        # b = *a;

   my $format; 
   my $buffer_size = $nframes * 2352;				   
   
   my @buf = ( ); for (my $i=0;$i<2352;$i++){$buf[$i]=1 }  
   my $addr = \@buf;  # reference like '&' unary operator   
   printf "startframe = $startframe; track = $track ; value = $$addr[0] ; buf = $addr, men = %p\n", $addr;   
     
   my $cdrom_rip = pack "iCiC", $startframe, CDROM_LBA, 1 , $$addr[0];  # SCALAR reference 

   sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) 
                     or die "can not open cdrom [$!] [$audiodevice_path]";
   
   ioctl(CD, CDROMREADAUDIO, $cdrom_rip ) 
                     or die "can not rip the audio data from cdrom [$!] [$audiodevice_path]"; 
		       
   ($startframe, $format, $nframes, $addr) = unpack "iCiC", $cdrom_rip;
    
   # leave room for WAV header (44 bytes)
   #seek WAV, 44, 0;
   #print "cdrom_rip = $cdrom_rip; value = $$addr[0]; addr = $addr; startframe = $startframe\n";
   
   open WAV, ">/tmp/track${track}.wav" or die $!;
   binmode WAV;  
   
   #print WAV $cdrom_rip;
   for (my $i=0;$i<2352;$i++){ print WAV $buf[$i]; }
   #syswrite(WAV, $buffer, 2352 );
   close(WAV);
       		    
   close(CD);   
}

1;
} # end scope block


#-------------------------------------------------#
#------------------ New-Package ------------------# 
# See perlmod, perlmodlib, perltoot
# See Learning Perl Objects, References and Modules, Chapter 2, 1o. Edition, 2003.
#{
#   package gnormalize::factorial;    # use C functions
#   use strict;
                                    # See man Inline and Inline::C-Cookbook
   #use Inline C => Config => LIBS => '-lmac';      # libmac	      
   # Perl CODE goes here
   
#   sub print2 {
#      printf "%3d! = %10d\n", $_, factorial($_) for 1..10;
#   }
#   1;
   
   # C CODE goes here
#   use Inline C => Config => LIBS => '-lmac';
#   use Inline C => 
#   "
#      double factorial(double x) {
#         if (x < 2)  return 1;
#         return x * factorial(x - 1);
#      }
#   "
#}


########################-----MP3::Info-----########################	      


{ # start scope block 

package MP3::Info::Internal;

require 5.006;

use overload;
use strict;
use Carp;

use vars qw(
	@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION $REVISION
	@mp3_genres %mp3_genres @winamp_genres %winamp_genres $try_harder
	@t_bitrate @t_sampling_freq @frequency_tbl %v1_tag_fields
	@v1_tag_names %v2_tag_names %v2_to_v1_names $AUTOLOAD
	@mp3_info_fields %rva2_channel_types
);

@ISA = 'Exporter';
@EXPORT = qw(
	set_mp3tag get_mp3tag get_mp3info remove_mp3tag
	use_winamp_genres
);
@EXPORT_OK = qw(@mp3_genres %mp3_genres use_mp3_utf8);
%EXPORT_TAGS = (
	genres	=> [qw(@mp3_genres %mp3_genres)],
	utf8	=> [qw(use_mp3_utf8)],
	all	=> [@EXPORT, @EXPORT_OK]
);

# $Id$
($REVISION) = ' $Revision: 1.19 $ ' =~ /\$Revision:\s+([^\s]+)/;
$VERSION = '1.20';

=pod

=head1 NAME

MP3::Info - Manipulate / fetch info from MP3 audio files

=head1 SYNOPSIS

	#!perl -w
	use MP3::Info;
	my $file = 'Pearls_Before_Swine.mp3';
	set_mp3tag($file, 'Pearls Before Swine', q"77's",
		'Sticks and Stones', '1990',
		q"(c) 1990 77's LTD.", 'rock & roll');

	my $tag = get_mp3tag($file) or die "No TAG info";
	$tag->{GENRE} = 'rock';
	set_mp3tag($file, $tag);

	my $info = get_mp3info($file);
	printf "$file length is %d:%d\n", $info->{MM}, $info->{SS};

=cut

{
	my $c = -1;
	# set all lower-case and regular-cased versions of genres as keys
	# with index as value of each key
	%mp3_genres = map {($_, ++$c, lc, $c)} @mp3_genres;

	# do it again for winamp genres
	$c = -1;
	%winamp_genres = map {($_, ++$c, lc, $c)} @winamp_genres;
}

=pod

	my $mp3 = new MP3::Info $file;
	$mp3->title('Perls Before Swine');
	printf "$file length is %s, title is %s\n",
		$mp3->time, $mp3->title;


=head1 DESCRIPTION

=over 4

=item $mp3 = MP3::Info-E<gt>new(FILE)

OOP interface to the rest of the module.  The same keys
available via get_mp3info and get_mp3tag are available
via the returned object (using upper case or lower case;
but note that all-caps "VERSION" will return the module
version, not the MP3 version).

Passing a value to one of the methods will set the value
for that tag in the MP3 file, if applicable.

=cut

sub new {
	my($pack, $file) = @_;

	my $info = get_mp3info($file) or return undef;
	my $tags = get_mp3tag($file) || { map { ($_ => undef) } @v1_tag_names };
	my %self = (
		FILE		=> $file,
		TRY_HARDER	=> 0
	);

	@self{@mp3_info_fields, @v1_tag_names, 'file'} = (
		@{$info}{@mp3_info_fields},
		@{$tags}{@v1_tag_names},
		$file
	);

	return bless \%self, $pack;
}

sub can {
	my $self = shift;
	return $self->SUPER::can(@_) unless ref $self;
	my $name = uc shift;
	return sub { $self->$name(@_) } if exists $self->{$name};
	return undef;
}

sub AUTOLOAD {
	my($self) = @_;
	(my $name = uc $AUTOLOAD) =~ s/^.*://;

	if (exists $self->{$name}) {
		my $sub = exists $v1_tag_fields{$name}
			? sub {
				if (defined $_[1]) {
					$_[0]->{$name} = $_[1];
					set_mp3tag($_[0]->{FILE}, $_[0]);
				}
				return $_[0]->{$name};
			}
			: sub {
				return $_[0]->{$name}
			};

		no strict 'refs';
		*{$AUTOLOAD} = $sub;
		goto &$AUTOLOAD;

	} else {
		carp(sprintf "No method '$name' available in package %s.",
			__PACKAGE__);
	}
}

sub DESTROY {

}


=item use_mp3_utf8([STATUS])

Tells MP3::Info to (or not) return TAG info in UTF-8.
TRUE is 1, FALSE is 0.  Default is TRUE, if available.

Will only be able to turn it on if Encode is available.  ID3v2
tags will be converted to UTF-8 according to the encoding specified
in each tag; ID3v1 tags will be assumed Latin-1 and converted
to UTF-8.

Function returns status (TRUE/FALSE).  If no argument is supplied,
or an unaccepted argument is supplied, function merely returns status.

This function is not exported by default, but may be exported
with the C<:utf8> or C<:all> export tag.

=cut

my $unicode_module = eval { require Encode; require Encode::Guess };
my $UNICODE = use_mp3_utf8($unicode_module ? 1 : 0);

sub use_mp3_utf8 {
	my $val = shift;
	no warnings;

	$UNICODE = 0;

	if ($val == 1) {

		if ($unicode_module) {
			$Encode::Guess::NoUTFAutoGuess = 1;
			$UNICODE = 1;
		}
	}
	
	return $UNICODE;
}

=pod

=item use_winamp_genres()

Puts WinAmp genres into C<@mp3_genres> and C<%mp3_genres>
(adds 68 additional genres to the default list of 80).
This is a separate function because these are non-standard
genres, but they are included because they are widely used.

You can import the data structures with one of:

	use MP3::Info qw(:genres);
	use MP3::Info qw(:DEFAULT :genres);
	use MP3::Info qw(:all);

=cut

sub use_winamp_genres {
	%mp3_genres = %winamp_genres;
	@mp3_genres = @winamp_genres;
	return 1;
}

=pod

=item remove_mp3tag (FILE [, VERSION, BUFFER])

Can remove ID3v1 or ID3v2 tags.  VERSION should be C<1> for ID3v1
(the default), C<2> for ID3v2, and C<ALL> for both.

For ID3v1, removes last 128 bytes from file if those last 128 bytes begin
with the text 'TAG'.  File will be 128 bytes shorter.

For ID3v2, removes ID3v2 tag.  Because an ID3v2 tag is at the
beginning of the file, we rewrite the file after removing the tag data.
The buffer for rewriting the file is 4MB.  BUFFER (in bytes) ca
change the buffer size.

Returns the number of bytes removed, or -1 if no tag removed,
or undef if there is an error.

=cut

sub remove_mp3tag {
	my($file, $version, $buf) = @_;
	my($fh, $return);

	$buf ||= 4096*1024;  # the bigger the faster
	$version ||= 1;

	if (not (defined $file && $file ne '')) {
		$@ = "No file specified";
		return undef;
	}

	if (not -s $file) {
		$@ = "File is empty";
		return undef;
	}

	if (ref $file) { # filehandle passed
		$fh = $file;
	} else {
		if (not open $fh, '+<', $file) {
			$@ = "Can't open $file: $!";
			return undef;
		}
	}

	binmode $fh;

	if ($version eq 1 || $version eq 'ALL') {
		seek $fh, -128, 2;
		my $tell = tell $fh;
		if (<$fh> =~ /^TAG/) {
			truncate $fh, $tell or carp "Can't truncate '$file': $!";
			$return += 128;
		}
	}

	if ($version eq 2 || $version eq 'ALL') {
		my $v2h = _get_v2head($fh);
		if ($v2h) {
			local $\;
			seek $fh, 0, 2;
			my $eof = tell $fh;
			my $off = $v2h->{tag_size};

			while ($off < $eof) {
				seek $fh, $off, 0;
				read $fh, my($bytes), $buf;
				seek $fh, $off - $v2h->{tag_size}, 0;
				print $fh $bytes;
				$off += $buf;
			}

			truncate $fh, $eof - $v2h->{tag_size}
				or carp "Can't truncate '$file': $!";
			$return += $v2h->{tag_size};
		}
	}

	_close($file, $fh);

	return $return || -1;
}


=pod

=item set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM])

=item set_mp3tag (FILE, $HASHREF)

Adds/changes tag information in an MP3 audio file.  Will clobber
any existing information in file.

Fields are TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE.  All fields have
a 30-byte limit, except for YEAR, which has a four-byte limit, and GENRE,
which is one byte in the file.  The GENRE passed in the function is a
case-insensitive text string representing a genre found in C<@mp3_genres>.

Will accept either a list of values, or a hashref of the type
returned by C<get_mp3tag>.

If TRACKNUM is present (for ID3v1.1), then the COMMENT field can only be
28 bytes.

ID3v2 support may come eventually.  Note that if you set a tag on a file
with ID3v2, the set tag will be for ID3v1[.1] only, and if you call
C<get_mp3tag> on the file, it will show you the (unchanged) ID3v2 tags,
unless you specify ID3v1.

=cut

sub set_mp3tag {
	my($file, $title, $artist, $album, $year, $comment, $genre, $tracknum) = @_;
	my(%info, $oldfh, $ref, $fh);
	local %v1_tag_fields = %v1_tag_fields;

	# set each to '' if undef
	for ($title, $artist, $album, $year, $comment, $tracknum, $genre,
		(@info{@v1_tag_names}))
		{$_ = defined() ? $_ : ''}

	($ref) = (overload::StrVal($title) =~ /^(?:.*\=)?([^=]*)\((?:[^\(]*)\)$/)
		if ref $title;
	# populate data to hashref if hashref is not passed
	if (!$ref) {
		(@info{@v1_tag_names}) =
			($title, $artist, $album, $year, $comment, $tracknum, $genre);

	# put data from hashref into hashref if hashref is passed
	} elsif ($ref eq 'HASH') {
		%info = %$title;

	# return otherwise
	} else {
		carp(<<'EOT');
Usage: set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM])
       set_mp3tag (FILE, $HASHREF)
EOT
		return undef;
	}

	if (not (defined $file && $file ne '')) {
		$@ = "No file specified";
		return undef;
	}

	if (not -s $file) {
		$@ = "File is empty";
		return undef;
	}

	# comment field length 28 if ID3v1.1
	$v1_tag_fields{COMMENT} = 28 if $info{TRACKNUM};


	# only if -w is on
	if ($^W) {
		# warn if fields too long
		foreach my $field (keys %v1_tag_fields) {
			$info{$field} = '' unless defined $info{$field};
			if (length($info{$field}) > $v1_tag_fields{$field}) {
				carp "Data too long for field $field: truncated to " .
					 "$v1_tag_fields{$field}";
			}
		}

		if ($info{GENRE}) {
			carp "Genre `$info{GENRE}' does not exist\n"
				unless exists $mp3_genres{$info{GENRE}};
		}
	}

	if ($info{TRACKNUM}) {
		$info{TRACKNUM} =~ s/^(\d+)\/(\d+)$/$1/;
		unless ($info{TRACKNUM} =~ /^\d+$/ &&
			$info{TRACKNUM} > 0 && $info{TRACKNUM} < 256) {
			carp "Tracknum `$info{TRACKNUM}' must be an integer " .
				"from 1 and 255\n" if $^W;
			$info{TRACKNUM} = '';
		}
	}

	if (ref $file) { # filehandle passed
		$fh = $file;
	} else {
		if (not open $fh, '+<', $file) {
			$@ = "Can't open $file: $!";
			return undef;
		}
	}

	binmode $fh;
	$oldfh = select $fh;
	seek $fh, -128, 2;
	# go to end of file if no tag, beginning of file if tag
	seek $fh, (<$fh> =~ /^TAG/ ? -128 : 0), 2;

	# get genre value
	$info{GENRE} = $info{GENRE} && exists $mp3_genres{$info{GENRE}} ?
		$mp3_genres{$info{GENRE}} : 255;  # some default genre

	local $\;
	# print TAG to file
	if ($info{TRACKNUM}) {
		print pack 'a3a30a30a30a4a28xCC', 'TAG', @info{@v1_tag_names};
	} else {
		print pack 'a3a30a30a30a4a30C', 'TAG', @info{@v1_tag_names[0..4, 6]};
	}

	select $oldfh;

	_close($file, $fh);

	return 1;
}

=pod

=item get_mp3tag (FILE [, VERSION, RAW_V2])

Returns hash reference containing tag information in MP3 file.  The keys
returned are the same as those supplied for C<set_mp3tag>, except in the
case of RAW_V2 being set.

If VERSION is C<1>, the information is taken from the ID3v1 tag (if present).
If VERSION is C<2>, the information is taken from the ID3v2 tag (if present).
If VERSION is not supplied, or is false, the ID3v1 tag is read if present, and
then, if present, the ID3v2 tag information will override any existing ID3v1
tag info.

If RAW_V2 is C<1>, the raw ID3v2 tag data is returned, without any manipulation
of text encoding.  The key name is the same as the frame ID (ID to name mappings
are in the global %v2_tag_names).

If RAW_V2 is C<2>, the ID3v2 tag data is returned, manipulating for Unicode if
necessary, etc.  It also takes multiple values for a given key (such as comments)
and puts them in an arrayref.

If the ID3v2 version is older than ID3v2.2.0 or newer than ID3v2.4.0, it will
not be read.

Strings returned will be in Latin-1, unless UTF-8 is specified (L<use_mp3_utf8>),
(unless RAW_V2 is C<1>).

Also returns a TAGVERSION key, containing the ID3 version used for the returned
data (if TAGVERSION argument is C<0>, may contain two versions).

=cut

sub get_mp3tag {
	my ($file, $ver, $raw_v2, $find_ape) = @_;
	my ($tag, $v2h, $fh);

	my $v1    = {};
	my $v2    = {};
	my $ape   = {};
	my %info  = ();
	my @array = ();

	$raw_v2 ||= 0;
	$ver = !$ver ? 0 : ($ver == 2 || $ver == 1) ? $ver : 0;

	if (not (defined $file && $file ne '')) {
		$@ = "No file specified";
		return undef;
	}

	my $filesize = -s $file;

	if (!$filesize) {
		$@ = "File is empty";
		return undef;
	}

	if (ref $file) { # filehandle passed
		$fh = $file;
	} else {
		if (not open $fh, '<', $file) {
			$@ = "Can't open $file: $!";
			return undef;
		}
	}

	binmode $fh;

	# Try and find an APE Tag - this is where FooBar2k & others
	# store ReplayGain information
	if ($find_ape) {

		$ape = _parse_ape_tag($fh, $filesize, \%info);
	}

	if ($ver < 2) {

		$v1 = _get_v1tag($fh, \%info);

		if ($ver == 1 && !$v1) {
			_close($file, $fh);
			$@ = "No ID3v1 tag found";
			return undef;
		}
	}

	if ($ver == 2 || $ver == 0) {
		($v2, $v2h) = _get_v2tag($fh);
	}

	if (!$v1 && !$v2 && !$ape) {
		_close($file, $fh);
		$@ = "No ID3 tag found";
		return undef;
	}

	if (($ver == 0 || $ver == 2) && $v2) {

		if ($raw_v2 == 1 && $ver == 2) {

			%info = %$v2;

			$info{'TAGVERSION'} = $v2h->{'version'};

		} else {

			_parse_v2tag($raw_v2, $v2, \%info);

			if ($ver == 0 && $info{'TAGVERSION'}) {
				$info{'TAGVERSION'} .= ' / ' . $v2h->{'version'};
			} else {
				$info{'TAGVERSION'} = $v2h->{'version'};
			}
		}
	}

	unless ($raw_v2 && $ver == 2) {
		foreach my $key (keys %info) {
			if (defined $info{$key}) {
				$info{$key} =~ s/\000+.*//g;
				$info{$key} =~ s/\s+$//;
			}
		}

		for (@v1_tag_names) {
			$info{$_} = '' unless defined $info{$_};
		}
	}

	if (keys %info && exists $info{'GENRE'} && ! defined $info{'GENRE'}) {
		$info{'GENRE'} = '';
	}

	_close($file, $fh);

	return keys %info ? {%info} : undef;
}

sub _get_v1tag {
	my ($fh, $info) = @_;

	seek $fh, -128, 2;
	read($fh, my $tag, 128);

	if (!defined($tag) || $tag !~ /^TAG/) {

		return 0;
	}

	if (substr($tag, -3, 2) =~ /\000[^\000]/) {

		(undef, @{$info}{@v1_tag_names}) =
			(unpack('a3a30a30a30a4a28', $tag),
			ord(substr($tag, -2, 1)),
			$mp3_genres[ord(substr $tag, -1)]);

		$info->{'TAGVERSION'} = 'ID3v1.1';

	} else {

		(undef, @{$info}{@v1_tag_names[0..4, 6]}) =
			(unpack('a3a30a30a30a4a30', $tag),
			$mp3_genres[ord(substr $tag, -1)]);

		$info->{'TAGVERSION'} = 'ID3v1';
	}

	if ($UNICODE) {

		# Save off the old suspects list, since we add
		# iso-8859-1 below, but don't want that there
		# for possible ID3 v2.x parsing below.
		my $oldSuspects = $Encode::Encoding{'Guess'}->{'Suspects'};

		for my $key (keys %{$info}) {

			next unless $info->{$key};

			# Try and guess the encoding.
			my $value = $info->{$key};
			my $icode = Encode::Guess->guess($value);

			unless (ref($icode)) {

				# Often Latin1 bytes are
				# stuffed into a 1.1 tag.
				Encode::Guess->add_suspects('iso-8859-1');

				while (length($value)) {

					$icode = Encode::Guess->guess($value);

					last if ref($icode);

					# Remove garbage and retry
					# (string is truncated in the
					# middle of a multibyte char?)
					$value =~ s/(.)$//;
				}
			}

			$info->{$key} = Encode::decode(ref($icode) ? $icode->name : 'iso-8859-1', $info->{$key});
		}

		Encode::Guess->set_suspects(keys %{$oldSuspects});
	}

	return 1;
}

sub _parse_v2tag {
	my ($raw_v2, $v2, $info) = @_;

	# Make sure any existing TXXX flags are an array.
	# As we might need to append comments to it below.
	if ($v2->{'TXXX'} && ref($v2->{'TXXX'}) ne 'ARRAY') {

		$v2->{'TXXX'} = [ $v2->{'TXXX'} ];
	}

	# J.River Media Center sticks RG tags in comments.
	# Ugh. Make them look like TXXX tags, which is really what they are.
	if (ref($v2->{'COMM'}) eq 'ARRAY' && grep { /Media Jukebox/ } @{$v2->{'COMM'}}) {

		for my $comment (@{$v2->{'COMM'}}) {

			if ($comment =~ /Media Jukebox/) {

				# we only want one null to lead.
				$comment =~ s/^\000+//g;

				push @{$v2->{'TXXX'}}, "\000$comment";
			}
		}
	}

	my $hash = $raw_v2 == 2 ? { map { ($_, $_) } keys %v2_tag_names } : \%v2_to_v1_names;

	for my $id (keys %$hash) {

		next if !exists $v2->{$id};

		if ($id =~ /^UFID?$/) {

			my @ufid_list = split(/\0/, $v2->{$id});

			$info->{$hash->{$id}} = $ufid_list[1] if ($#ufid_list > 0);

		} elsif ($id =~ /^RVA[D2]?$/) {

			# Expand these binary fields. See the ID3 spec for Relative Volume Adjustment.
			if ($id eq 'RVA2') {

				# ID is a text string
				($info->{$hash->{$id}}->{'ID'}, my $rvad) = split /\0/, $v2->{$id};

				my $channel = $rva2_channel_types{ ord(substr($rvad, 0, 1, '')) };

				$info->{$hash->{$id}}->{$channel}->{'REPLAYGAIN_TRACK_GAIN'} = 
					sprintf('%f', _grab_int_16(\$rvad) / 512);

				my $peakBytes = ord(substr($rvad, 0, 1, ''));

				if (int($peakBytes / 8)) {

					$info->{$hash->{$id}}->{$channel}->{'REPLAYGAIN_TRACK_PEAK'} = 
						sprintf('%f', _grab_int_16(\$rvad) / 512);
				}

			} elsif ($id eq 'RVAD' || $id eq 'RVA') {

				my $rvad  = $v2->{$id};
				my $flags = ord(substr($rvad, 0, 1, ''));
				my $desc  = ord(substr($rvad, 0, 1, ''));

				# iTunes appears to be the only program that actually writes
				# out a RVA/RVAD tag. Everyone else punts.
				for my $type (qw(REPLAYGAIN_TRACK_GAIN REPLAYGAIN_TRACK_PEAK)) {

					for my $channel (qw(RIGHT LEFT)) {

						my $val = _grab_uint_16(\$rvad) / 256;

						# iTunes uses a range of -255 to 255
						# to be -100% (silent) to 100% (+6dB)
						if ($val == -255) {
							$val = -96.0;
						} else {
							$val = 20.0 * log(($val+255)/255)/log(10);
						}

						$info->{$hash->{$id}}->{$channel}->{$type} = $flags & 0x01 ? $val : -$val;
					}
				}
			}

		} elsif ($id =~ /^A?PIC$/) {

			my $pic = $v2->{$id};

			# if there is more than one picture, just grab the first one.
			if (ref($pic) eq 'ARRAY') {
				$pic = (@$pic)[0];
			}

			use bytes;

			my $valid_pic  = 0;
			my $pic_len    = 0;
			my $pic_format = '';

			# look for ID3 v2.2 picture
			if ($pic && $id eq 'PIC') {

				# look for ID3 v2.2 picture
				my ($encoding, $format, $picture_type, $description) = unpack 'Ca3CZ*', $pic;
				$pic_len = length($description) + 1 + 5;

				# skip extra terminating null if unicode
				if ($encoding) { $pic_len++; }

				if ($pic_len < length($pic)) {
					$valid_pic  = 1;
					$pic_format = $format;
				}

			} elsif ($pic && $id eq 'APIC') {

				# look for ID3 v2.3 picture
				my ($encoding, $format) = unpack 'C Z*', $pic;

				$pic_len = length($format) + 2;

				if ($pic_len < length($pic)) {

					my ($picture_type, $description) = unpack "x$pic_len C Z*", $pic;

					$pic_len += 1 + length($description) + 1;

					# skip extra terminating null if unicode
					if ($encoding) { $pic_len++; }

					$valid_pic  = 1;
					$pic_format = $format;
				}
			}

			# Proceed if we have a valid picture.
			if ($valid_pic && $pic_format) {

				my ($data) = unpack("x$pic_len A*", $pic);

				if (length($data) && $pic_format) {

					$info->{$hash->{$id}} = {
						'DATA'   => $data,
						'FORMAT' => $pic_format,
					}
				}
			}

		} else {
			my $data1 = $v2->{$id};

			# this is tricky ... if this is an arrayref,
			# we want to only return one, so we pick the
			# first one.  but if it is a comment, we pick
			# the first one where the first charcter after
			# the language is NULL and not an additional
			# sub-comment, because that is most likely to be
			# the user-supplied comment
			if (ref $data1 && !$raw_v2) {
				if ($id =~ /^COMM?$/) {
					my($newdata) = grep /^(....\000)/, @{$data1};
					$data1 = $newdata || $data1->[0];
				} elsif ($id !~ /^(?:TXXX?|PRIV)$/) {
					# We can get multiple User Defined Text frames in a mp3 file
					$data1 = $data1->[0];
				}
			}

			$data1 = [ $data1 ] if ! ref $data1;

			for my $data (@$data1) {
				# TODO : this should only be done for certain frames;
				# using RAW still gives you access, but we should be smarter
				# about how individual frame types are handled.  it's not
				# like the list is infinitely long.
				$data =~ s/^(.)//; # strip first char (text encoding)
				my $encoding = $1;
				my $desc;

				# Comments & Unsyncronized Lyrics have the same format.
				if ($id =~ /^(COM[M ]?|USLT)$/) { # space for iTunes brokenness

					$data =~ s/^(?:...)//;		# strip language
				}

				if ($UNICODE) {

					if ($encoding eq "\001" || $encoding eq "\002") {  # UTF-16, UTF-16BE
						# text fields can be null-separated lists;
						# UTF-16 therefore needs special care
						#
						# foobar2000 encodes tags in UTF-16LE
						# (which is apparently illegal)
						# Encode dies on a bad BOM, so it is
						# probably wise to wrap it in an eval
						# anyway
						$data = eval { Encode::decode('utf16', $data) } || Encode::decode('utf16le', $data);

					} elsif ($encoding eq "\003") { # UTF-8

						# make sure string is UTF8, and set flag appropriately
						$data = Encode::decode('utf8', $data);

					} elsif ($encoding eq "\000") {

						# Only guess if it's not ascii.
						if ($data && $data !~ /^[\x00-\x7F]+$/) {

							# Try and guess the encoding, otherwise just use latin1
							my $dec = Encode::Guess->guess($data);

							if (ref $dec) {
								$data = $dec->decode($data);
							} else {
								# Best try
								$data = Encode::decode('iso-8859-1', $data);
							}
						}
					}

				} else {

					# If the string starts with an
					# UTF-16 little endian BOM, use a hack to
					# convert to ASCII per best-effort
					my $pat;
					if ($data =~ s/^\xFF\xFE//) {
						$pat = 'v';
					} elsif ($data =~ s/^\xFE\xFF//) {
						$pat = 'n';
					}

					if ($pat) {
						$data = pack 'C*', map {
							(chr =~ /[[:ascii:]]/ && chr =~ /[[:print:]]/)
								? $_
								: ord('?')
						} unpack "$pat*", $data;
					}
				}

				# We do this after decoding so we could be certain we're dealing
				# with 8-bit text.
				if ($id =~ /^(COM[M ]?|USLT)$/) { # space for iTunes brokenness

					$data =~ s/^(.*?)\000//;	# strip up to first NULL(s),
									# for sub-comments (TODO:
									# handle all comment data)
					$desc = $1;

				} elsif ($id =~ /^TCON?$/) {

					my ($index, $name);

					# Turn multiple nulls into a single.
					$data =~ s/\000+/\000/g;

					# Handle the ID3v2.x spec - 
					#
					# just an index number, possibly
					# paren enclosed - referer to the v1 genres.
					if ($data =~ /^ \(? (\d+) \)?\000?$/sx) {

						$index = $1;

					# Paren enclosed index with refinement.
					# (4)Eurodisco
					} elsif ($data =~ /^ \( (\d+) \)\000? ([^\(].+)$/x) {

						($index, $name) = ($1, $2);

					# List of indexes: (37)(38)
					} elsif ($data =~ /^ \( (\d+) \)\000?/x) {

						my @genres = ();

						while ($data =~ s/^ \( (\d+) \)\000?//x) {

							push @genres, $mp3_genres[$1];
						}

						$data = \@genres;
					}

					# Text based genres will fall through.
					if ($name && $name ne "\000") {
						$data = $name;
					} elsif (defined $index) {
						$data = $mp3_genres[$index];
					}
				}

				if ($raw_v2 == 2 && $desc) {
					$data = { $desc => $data };
				}

				if ($raw_v2 == 2 && exists $info->{$hash->{$id}}) {

					if (ref $info->{$hash->{$id}} eq 'ARRAY') {
						push @{$info->{$hash->{$id}}}, $data;
					} else {
						$info->{$hash->{$id}} = [ $info->{$hash->{$id}}, $data ];
					}

				} else {

					# User defined frame
					if ($id eq 'TXXX') {

						my ($key, $val) = split(/\0/, $data);
						$info->{uc($key)} = $val;

					} elsif ($id eq 'PRIV') {

						my ($key, $val) = split(/\0/, $data);
						$info->{uc($key)} = unpack('v', $val);

					} else {

						$info->{$hash->{$id}} = $data;
					}
				}
			}
		}
	}
}

sub _get_v2tag {
	my($fh) = @_;
	my($off, $end, $myseek, $v2, $v2h, $hlen, $num, $wholetag);

	$v2 = {};
	$v2h = _get_v2head($fh) or return;

	if ($v2h->{major_version} < 2) {
		carp "This is $v2h->{version}; " .
		     "ID3v2 versions older than ID3v2.2.0 not supported\n"
		     if $^W;
		return;
	}

	# use syncsafe bytes if using version 2.4
	# my $bytesize = ($v2h->{major_version} > 3) ? 128 : 256;

	# alas, that's what the spec says, but iTunes and others don't syncsafe
	# the length, which breaks MP3 files with v2.4 tags longer than 128 bytes,
	# like every image file.
	my $bytesize = 256;

	if ($v2h->{major_version} == 2) {
		$hlen = 6;
		$num = 3;
	} else {
		$hlen = 10;
		$num = 4;
	}

	$off = $v2h->{ext_header_size} + 10;
	$end = $v2h->{tag_size} + 10; # should we read in the footer too?

	seek $fh, $v2h->{offset}, 0;
	read $fh, $wholetag, $end;

	$wholetag =~ s/\xFF\x00/\xFF/gs if $v2h->{unsync};

	$myseek = sub {
		my $bytes = substr($wholetag, $off, $hlen);
		return unless $bytes =~ /^([A-Z0-9]{$num})/
			|| ($num == 4 && $bytes =~ /^(COM )/);  # stupid iTunes
		my($id, $size) = ($1, $hlen);
		my @bytes = reverse unpack "C$num", substr($bytes, $num, $num);

		for my $i (0 .. ($num - 1)) {
			$size += $bytes[$i] * $bytesize ** $i;
		}

		my $flags = {};
		if ($v2h->{major_version} > 3) {
			my @bits = split //, unpack 'B16', substr($bytes, 8, 2);
			$flags->{frame_unsync}       = $bits[14];
			$flags->{data_len_indicator} = $bits[15];
		}

		return($id, $size, $flags);
	};

	while ($off < $end) {
		my($id, $size, $flags) = &$myseek or last;

		my $bytes = substr($wholetag, $off+$hlen, $size-$hlen);

		my $data_len;
		if ($flags->{data_len_indicator}) {
			$data_len = 0;
			my @data_len_bytes = reverse unpack 'C4', substr($bytes, 0, 4);
			$bytes = substr($bytes, 4);
		        for my $i (0..3) {
				$data_len += $data_len_bytes[$i] * 128 ** $i;
		        }
		}

		# perform frame-level unsync if needed (skip if already done for whole tag)
		$bytes =~ s/\xFF\x00/\xFF/gs if $flags->{frame_unsync} && !$v2h->{unsync};

		# if we know the data length, sanity check it now.
		if ($flags->{data_len_indicator} && defined $data_len) {
		        carp "Size mismatch on $id\n" unless $data_len == length($bytes);
		}

		if (exists $v2->{$id}) {
			if (ref $v2->{$id} eq 'ARRAY') {
				push @{$v2->{$id}}, $bytes;
			} else {
				$v2->{$id} = [$v2->{$id}, $bytes];
			}
		} else {
			$v2->{$id} = $bytes;
		}
		$off += $size;
	}

	return($v2, $v2h);
}


=pod

=item get_mp3info (FILE)

Returns hash reference containing file information for MP3 file.
This data cannot be changed.  Returned data:

	VERSION		MPEG audio version (1, 2, 2.5)
	LAYER		MPEG layer description (1, 2, 3)
	STEREO		boolean for audio is in stereo

	VBR		boolean for variable bitrate
	BITRATE		bitrate in kbps (average for VBR files)
	FREQUENCY	frequency in kHz
	SIZE		bytes in audio stream
	OFFSET		bytes offset that stream begins

	SECS		total seconds
	MM		minutes
	SS		leftover seconds
	MS		leftover milliseconds
	TIME		time in MM:SS

	COPYRIGHT	boolean for audio is copyrighted
	PADDING		boolean for MP3 frames are padded
	MODE		channel mode (0 = stereo, 1 = joint stereo,
			2 = dual channel, 3 = single channel)
	FRAMES		approximate number of frames
	FRAME_LENGTH	approximate length of a frame
	VBR_SCALE	VBR scale from VBR header

On error, returns nothing and sets C<$@>.

=cut

sub get_mp3info {
	my($file) = @_;
	my($off, $byte, $eof, $h, $tot, $fh);

	if (not (defined $file && $file ne '')) {
		$@ = "No file specified";
		return undef;
	}

	if (not -s $file) {
		$@ = "File is empty";
		return undef;
	}

	if (ref $file) { # filehandle passed
		$fh = $file;
	} else {
		if (not open $fh, '<', $file) {
			$@ = "Can't open $file: $!";
			return undef;
		}
	}

	$off = 0;
	$tot = 8192;

	# Let the caller change how far we seek in looking for a header.
	if ($try_harder) {
		$tot *= $try_harder;
	}

	binmode $fh;
	seek $fh, $off, 0;
	read $fh, $byte, 4;

	if ($off == 0) {
		if (my $v2h = _get_v2head($fh)) {
			$tot += $off += $v2h->{tag_size};
			seek $fh, $off, 0;
			read $fh, $byte, 4;
		}
	}

	$h = _get_head($byte);
	my $is_mp3 = _is_mp3($h); 

	# the head wasn't where we were expecting it.. dig deeper.
	unless ($is_mp3) {

		# do only one read - it's _much_ faster
		$off++;
		seek $fh, $off, 0;
		read $fh, $byte, $tot;
		 
		my $i;
		 
		# now walk the bytes looking for the head
		for ($i = 0; $i < $tot; $i++) {

			last if ($tot - $i) < 4;
		 
			my $head = substr($byte, $i, 4) || last;
			 
			next if (ord($head) != 0xff);
			 
			$h = _get_head($head);
			$is_mp3 = _is_mp3($h);
			last if $is_mp3;
		}
		 
		# adjust where we are for _get_vbr()
		$off += $i;

		if ($off > $tot && !$try_harder) {
			_close($file, $fh);
			$@ = "Couldn't find MP3 header (perhaps set " .
			     '$MP3::Info::try_harder and retry)';
			return undef;
		}
	}

	my $vbr = _get_vbr($fh, $h, \$off);

	seek $fh, 0, 2;
	$eof = tell $fh;
	seek $fh, -128, 2;
	$eof -= 128 if <$fh> =~ /^TAG/ ? 1 : 0;

	_close($file, $fh);

	$h->{size} = $eof - $off;
	$h->{offset} = $off;

	return _get_info($h, $vbr);
}

sub _get_info {
	my($h, $vbr) = @_;
	my $i;

	# No bitrate or sample rate? Something's wrong.
	unless ($h->{bitrate} && $h->{fs}) {
		return {};
	}

	$i->{VERSION}	= $h->{IDR} == 2 ? 2 : $h->{IDR} == 3 ? 1 :
				$h->{IDR} == 0 ? 2.5 : 0;
	$i->{LAYER}	= 4 - $h->{layer};
	$i->{VBR}	= defined $vbr ? 1 : 0;

	$i->{COPYRIGHT}	= $h->{copyright} ? 1 : 0;
	$i->{PADDING}	= $h->{padding_bit} ? 1 : 0;
	$i->{STEREO}	= $h->{mode} == 3 ? 0 : 1;
	$i->{MODE}	= $h->{mode};

	$i->{SIZE}	= $vbr && $vbr->{bytes} ? $vbr->{bytes} : $h->{size};
	$i->{OFFSET}	= $h->{offset};

	my $mfs		= $h->{fs} / ($h->{ID} ? 144000 : 72000);
	$i->{FRAMES}	= int($vbr && $vbr->{frames}
				? $vbr->{frames}
				: $i->{SIZE} / ($h->{bitrate} / $mfs)
			  );

	if ($vbr) {
		$i->{VBR_SCALE}	= $vbr->{scale} if $vbr->{scale};
		$h->{bitrate}	= $i->{SIZE} / $i->{FRAMES} * $mfs;
		if (not $h->{bitrate}) {
			$@ = "Couldn't determine VBR bitrate";
			return undef;
		}
	}

	$h->{'length'}	= ($i->{SIZE} * 8) / $h->{bitrate} / 10;
	$i->{SECS}	= $h->{'length'} / 100;
	$i->{MM}	= int $i->{SECS} / 60;
	$i->{SS}	= int $i->{SECS} % 60;
	$i->{MS}	= (($i->{SECS} - ($i->{MM} * 60) - $i->{SS}) * 1000);
#	$i->{LF}	= ($i->{MS} / 1000) * ($i->{FRAMES} / $i->{SECS});
#	int($i->{MS} / 100 * 75);  # is this right?
	$i->{TIME}	= sprintf "%.2d:%.2d", @{$i}{'MM', 'SS'};

	$i->{BITRATE}		= int $h->{bitrate};
	# should we just return if ! FRAMES?
	$i->{FRAME_LENGTH}	= int($h->{size} / $i->{FRAMES}) if $i->{FRAMES};
	$i->{FREQUENCY}		= $frequency_tbl[3 * $h->{IDR} + $h->{sampling_freq}];

	return $i;
}

sub _get_head {
	my($byte) = @_;
	my($bytes, $h);

	$bytes = _unpack_head($byte);
	@$h{qw(IDR ID layer protection_bit
		bitrate_index sampling_freq padding_bit private_bit
		mode mode_extension copyright original
		emphasis version_index bytes)} = (
		($bytes>>19)&3, ($bytes>>19)&1, ($bytes>>17)&3, ($bytes>>16)&1,
		($bytes>>12)&15, ($bytes>>10)&3, ($bytes>>9)&1, ($bytes>>8)&1,
		($bytes>>6)&3, ($bytes>>4)&3, ($bytes>>3)&1, ($bytes>>2)&1,
		$bytes&3, ($bytes>>19)&3, $bytes
	);

	$h->{bitrate} = $t_bitrate[$h->{ID}][3 - $h->{layer}][$h->{bitrate_index}];
	$h->{fs} = $t_sampling_freq[$h->{IDR}][$h->{sampling_freq}];

	return $h;
}

sub _is_mp3 {
	my $h = $_[0] or return undef;
	return ! (	# all below must be false
		 $h->{bitrate_index} == 0
			||
		 $h->{version_index} == 1
			||
		($h->{bytes} & 0xFFE00000) != 0xFFE00000
			||
		!$h->{fs}
			||
		!$h->{bitrate}
			||
		 $h->{bitrate_index} == 15
			||
		!$h->{layer}
			||
		 $h->{sampling_freq} == 3
			||
		 $h->{emphasis} == 2
			||
		!$h->{bitrate_index}
			||
		($h->{bytes} & 0xFFFF0000) == 0xFFFE0000
			||
		($h->{ID} == 1 && $h->{layer} == 3 && $h->{protection_bit} == 1)
		# mode extension should only be applicable when mode = 1
		# however, failing just becuase mode extension is used when unneeded is a bit strict
		#	||
		#($h->{mode_extension} != 0 && $h->{mode} != 1)
	);
}

sub _vbr_seek {
	my $fh    = shift;
	my $off   = shift;
	my $bytes = shift;
	my $n     = shift || 4;

	seek $fh, $$off, 0;
	read $fh, $$bytes, $n;

	$$off += $n;
}

sub _get_vbr {
	my($fh, $h, $roff) = @_;
	my($off, $bytes, @bytes, %vbr);

	$off = $$roff;

	$off += 4;

	if ($h->{ID}) {	# MPEG1
		$off += $h->{mode} == 3 ? 17 : 32;
	} else {	# MPEG2
		$off += $h->{mode} == 3 ? 9 : 17;
	}

	_vbr_seek($fh, \$off, \$bytes);
	return unless $bytes eq 'Xing';

	_vbr_seek($fh, \$off, \$bytes);
	$vbr{flags} = _unpack_head($bytes);

	if ($vbr{flags} & 1) {
		_vbr_seek($fh, \$off, \$bytes);
		$vbr{frames} = _unpack_head($bytes);
	}

	if ($vbr{flags} & 2) {
		_vbr_seek($fh, \$off, \$bytes);
		$vbr{bytes} = _unpack_head($bytes);
	}

	if ($vbr{flags} & 4) {
		_vbr_seek($fh, \$off, \$bytes, 100);
# Not used right now ...
#		$vbr{toc} = _unpack_head($bytes);
	}

	if ($vbr{flags} & 8) { # (quality ind., 0=best 100=worst)
		_vbr_seek($fh, \$off, \$bytes);
		$vbr{scale} = _unpack_head($bytes);
	} else {
		$vbr{scale} = -1;
	}

	$$roff = $off;
	return \%vbr;
}

sub _get_v2head {
	my $fh = $_[0] or return;
	my($v2h, $bytes, @bytes);
	$v2h->{offset} = 0;

	# check first three bytes for 'ID3'
	seek $fh, 0, 0;
	read $fh, $bytes, 3;

	# TODO: add support for tags at the end of the file
	if ($bytes eq 'RIF' || $bytes eq 'FOR') {
		_find_id3_chunk($fh, $bytes) or return;
		$v2h->{offset} = tell $fh;
		read $fh, $bytes, 3;
	}

	return unless $bytes eq 'ID3';

	# get version
	read $fh, $bytes, 2;
	$v2h->{version} = sprintf "ID3v2.%d.%d",
		@$v2h{qw[major_version minor_version]} =
			unpack 'c2', $bytes;

	# get flags
	read $fh, $bytes, 1;
	my @bits = split //, unpack 'b8', $bytes;
	if ($v2h->{major_version} == 2) {
		$v2h->{unsync}       = $bits[7];
		$v2h->{compression}  = $bits[8];
		$v2h->{ext_header}   = 0;
		$v2h->{experimental} = 0;
	} else {
		$v2h->{unsync}       = $bits[7];
		$v2h->{ext_header}   = $bits[6];
		$v2h->{experimental} = $bits[5];
		$v2h->{footer}       = $bits[4] if $v2h->{major_version} == 4;
	}

	# get ID3v2 tag length from bytes 7-10
	$v2h->{tag_size} = 10;	# include ID3v2 header size
	$v2h->{tag_size} += 10 if $v2h->{footer};
	read $fh, $bytes, 4;
	@bytes = reverse unpack 'C4', $bytes;
	foreach my $i (0 .. 3) {
		# whoaaaaaa nellllllyyyyyy!
		$v2h->{tag_size} += $bytes[$i] * 128 ** $i;
	}

	# get extended header size
	$v2h->{ext_header_size} = 0;
	if ($v2h->{ext_header}) {
		read $fh, $bytes, 4;
		@bytes = reverse unpack 'C4', $bytes;

		# use syncsafe bytes if using version 2.4
		my $bytesize = ($v2h->{major_version} > 3) ? 128 : 256;
		for my $i (0..3) {
			$v2h->{ext_header_size} += $bytes[$i] * $bytesize ** $i;
		}
	}

	return $v2h;
}

sub _find_id3_chunk {
	my($fh, $filetype) = @_;
	my($bytes, $size, $tag, $pat, $mat);

	read $fh, $bytes, 1;
	if ($filetype eq 'RIF') {  # WAV
		return 0 if $bytes ne 'F';
		$pat = 'a4V';
		$mat = 'id3 ';
	} elsif ($filetype eq 'FOR') { # AIFF
		return 0 if $bytes ne 'M';
		$pat = 'a4N';
		$mat = 'ID3 ';
	}
	seek $fh, 12, 0;  # skip to the first chunk

	while ((read $fh, $bytes, 8) == 8) {
		($tag, $size)  = unpack $pat, $bytes;
		return 1 if $tag eq $mat;
		seek $fh, $size, 1;
	}

	return 0;
}

sub _unpack_head {
	unpack('l', pack('L', unpack('N', $_[0])));
}

sub _grab_int_16 {
        my $data  = shift;
        my $value = unpack('s',substr($$data,0,2));
        $$data    = substr($$data,2);
        return $value;
}

sub _grab_uint_16 {
        my $data  = shift;
        my $value = unpack('S',substr($$data,0,2));
        $$data    = substr($$data,2);
        return $value;
}

sub _grab_int_32 {
        my $data  = shift;
        my $value = unpack('V',substr($$data,0,4));
        $$data    = substr($$data,4);
        return $value;
}

sub _parse_ape_tag {
	my ($fh, $filesize, $info) = @_;

	my $ape_tag_id = 'APETAGEX';

	seek $fh, -256, 2;
	read($fh, my $tag, 256);
	my $pre_tag = substr($tag, 0, 128, '');

	# Try and bail early if there's no ape tag.
	if (substr($pre_tag, 96, 8) ne $ape_tag_id && substr($tag, 96, 8) ne $ape_tag_id) {

		seek($fh, 0, 0);
		return 0;
	}

	my $id3v1_tag_size      = 128;
	my $ape_tag_header_size = 32;
	my $lyrics3_tag_size    = 10;
	my $tag_offset_start    = 0;
	my $tag_offset_end      = 0;

	seek($fh, (0 - $id3v1_tag_size - $ape_tag_header_size - $lyrics3_tag_size), 2);

	read($fh, my $ape_footer_id3v1, $id3v1_tag_size + $ape_tag_header_size + $lyrics3_tag_size);

	if (substr($ape_footer_id3v1, (length($ape_footer_id3v1) - $id3v1_tag_size - $ape_tag_header_size), 8) eq $ape_tag_id) {

		$tag_offset_end = $filesize - $id3v1_tag_size;

	} elsif (substr($ape_footer_id3v1, (length($ape_footer_id3v1) - $ape_tag_header_size), 8) eq $ape_tag_id) {

		$tag_offset_end = $filesize;
	}

	seek($fh, $tag_offset_end - $ape_tag_header_size, 0);

	read($fh, my $ape_footer_data, 32);

	my $ape_footer = _parse_ape_header_or_footer($ape_footer_data);

	if (keys %{$ape_footer}) {

		my $ape_tag_data = '';

		if ($ape_footer->{'flags'}->{'header'}) {

			seek($fh, ($tag_offset_end - $ape_footer->{'tag_size'} - $ape_tag_header_size), 0);

			$tag_offset_start = tell($fh);

			read($fh, $ape_tag_data, $ape_footer->{'tag_size'} + $ape_tag_header_size);

		} else {

			$tag_offset_start = $tag_offset_end - $ape_footer->{'tag_size'};

			seek($fh, $tag_offset_start, 0);

			read($fh, $ape_tag_data, $ape_footer->{'tag_size'});
		}

		my $ape_header_data = substr($ape_tag_data, 0, $ape_tag_header_size, '');
		my $ape_header      = _parse_ape_header_or_footer($ape_header_data);

		for (my $c = 0; $c < $ape_header->{'tag_items'}; $c++) {
		
			# Loop through the tag items
			my $tag_len   = _grab_int_32(\$ape_tag_data);
			my $tag_flags = _grab_int_32(\$ape_tag_data);

			$ape_tag_data =~ s/^(.*?)\0//;

			my $tag_item_key = uc($1 || 'UNKNOWN');

			$info->{$tag_item_key} = substr($ape_tag_data, 0, $tag_len, '');
		}
	}

	seek($fh, 0, 0);

	return 1;
}

sub _parse_ape_header_or_footer {
	my $bytes = shift;
	my %data = ();

	if (substr($bytes, 0, 8, '') eq 'APETAGEX') {

		$data{'version'}      = _grab_int_32(\$bytes);
		$data{'tag_size'}     = _grab_int_32(\$bytes);
		$data{'tag_items'}    = _grab_int_32(\$bytes);
		$data{'global_flags'} = _grab_int_32(\$bytes);

		# trim the reseved bytes
		_grab_int_32(\$bytes);
		_grab_int_32(\$bytes);

		$data{'flags'}->{'header'}    = ($data{'global_flags'} & 0x80000000) ? 1 : 0;
		$data{'flags'}->{'footer'}    = ($data{'global_flags'} & 0x40000000) ? 1 : 0;
		$data{'flags'}->{'is_header'} = ($data{'global_flags'} & 0x20000000) ? 1 : 0;
	}

	return \%data;
}

sub _close {
	my($file, $fh) = @_;
	unless (ref $file) { # filehandle not passed
		close $fh or carp "Problem closing '$file': $!";
	}
}

BEGIN {
	@mp3_genres = (
		'Blues',
		'Classic Rock',
		'Country',
		'Dance',
		'Disco',
		'Funk',
		'Grunge',
		'Hip-Hop',
		'Jazz',
		'Metal',
		'New Age',
		'Oldies',
		'Other',
		'Pop',
		'R&B',
		'Rap',
		'Reggae',
		'Rock',
		'Techno',
		'Industrial',
		'Alternative',
		'Ska',
		'Death Metal',
		'Pranks',
		'Soundtrack',
		'Euro-Techno',
		'Ambient',
		'Trip-Hop',
		'Vocal',
		'Jazz+Funk',
		'Fusion',
		'Trance',
		'Classical',
		'Instrumental',
		'Acid',
		'House',
		'Game',
		'Sound Clip',
		'Gospel',
		'Noise',
		'AlternRock',
		'Bass',
		'Soul',
		'Punk',
		'Space',
		'Meditative',
		'Instrumental Pop',
		'Instrumental Rock',
		'Ethnic',
		'Gothic',
		'Darkwave',
		'Techno-Industrial',
		'Electronic',
		'Pop-Folk',
		'Eurodance',
		'Dream',
		'Southern Rock',
		'Comedy',
		'Cult',
		'Gangsta',
		'Top 40',
		'Christian Rap',
		'Pop/Funk',
		'Jungle',
		'Native American',
		'Cabaret',
		'New Wave',
		'Psychadelic',
		'Rave',
		'Showtunes',
		'Trailer',
		'Lo-Fi',
		'Tribal',
		'Acid Punk',
		'Acid Jazz',
		'Polka',
		'Retro',
		'Musical',
		'Rock & Roll',
		'Hard Rock',
	);

	@winamp_genres = (
		@mp3_genres,
		'Folk',
		'Folk-Rock',
		'National Folk',
		'Swing',
		'Fast Fusion',
		'Bebop',
		'Latin',
		'Revival',
		'Celtic',
		'Bluegrass',
		'Avantgarde',
		'Gothic Rock',
		'Progressive Rock',
		'Psychedelic Rock',
		'Symphonic Rock',
		'Slow Rock',
		'Big Band',
		'Chorus',
		'Easy Listening',
		'Acoustic',
		'Humour',
		'Speech',
		'Chanson',
		'Opera',
		'Chamber Music',
		'Sonata',
		'Symphony',
		'Booty Bass',
		'Primus',
		'Porn Groove',
		'Satire',
		'Slow Jam',
		'Club',
		'Tango',
		'Samba',
		'Folklore',
		'Ballad',
		'Power Ballad',
		'Rhythmic Soul',
		'Freestyle',
		'Duet',
		'Punk Rock',
		'Drum Solo',
		'Acapella',
		'Euro-House',
		'Dance Hall',
		'Goa',
		'Drum & Bass',
		'Club-House',
		'Hardcore',
		'Terror',
		'Indie',
		'BritPop',
		'Negerpunk',
		'Polsk Punk',
		'Beat',
		'Christian Gangsta Rap',
		'Heavy Metal',
		'Black Metal',
		'Crossover',
		'Contemporary Christian',
		'Christian Rock',
		'Merengue',
		'Salsa',
		'Thrash Metal',
		'Anime',
		'JPop',
		'Synthpop',
	);

	@t_bitrate = ([
		[0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256],
		[0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160],
		[0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160]
	],[
		[0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448],
		[0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384],
		[0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320]
	]);

	@t_sampling_freq = (
		[11025, 12000,  8000],
		[undef, undef, undef],	# reserved
		[22050, 24000, 16000],
		[44100, 48000, 32000]
	);

	@frequency_tbl = map { $_ ? eval "${_}e-3" : 0 }
		map { @$_ } @t_sampling_freq;

	@mp3_info_fields = qw(
		VERSION
		LAYER
		STEREO
		VBR
		BITRATE
		FREQUENCY
		SIZE
		OFFSET
		SECS
		MM
		SS
		MS
		TIME
		COPYRIGHT
		PADDING
		MODE
		FRAMES
		FRAME_LENGTH
		VBR_SCALE
	);

	%rva2_channel_types = (
		0x00 => 'OTHER',
		0x01 => 'MASTER',
		0x02 => 'FRONT_RIGHT',
		0x03 => 'FRONT_LEFT',
		0x04 => 'BACK_RIGHT',
		0x05 => 'BACK_LEFT',
		0x06 => 'FRONT_CENTER',
		0x07 => 'BACK_CENTER',
		0x08 => 'SUBWOOFER',
	);

	%v1_tag_fields =
		(TITLE => 30, ARTIST => 30, ALBUM => 30, COMMENT => 30, YEAR => 4);

	@v1_tag_names = qw(TITLE ARTIST ALBUM YEAR COMMENT TRACKNUM GENRE);

	%v2_to_v1_names = (
		# v2.2 tags
		'TT2' => 'TITLE',
		'TP1' => 'ARTIST',
		'TAL' => 'ALBUM',
		'TYE' => 'YEAR',
		'COM' => 'COMMENT',
		'TRK' => 'TRACKNUM',
		'TCO' => 'GENRE', # not clean mapping, but ...
		# v2.3 tags
		'TIT2' => 'TITLE',
		'TPE1' => 'ARTIST',
		'TALB' => 'ALBUM',
		'TYER' => 'YEAR',
		'COMM' => 'COMMENT',
		'TRCK' => 'TRACKNUM',
		'TCON' => 'GENRE',
		# v2.3 tags - needed for MusicBrainz
		'UFID' => 'Unique file identifier',
		'TXXX' => 'User defined text information frame',
	);

	%v2_tag_names = (
		# v2.2 tags
		'BUF' => 'Recommended buffer size',
		'CNT' => 'Play counter',
		'COM' => 'Comments',
		'CRA' => 'Audio encryption',
		'CRM' => 'Encrypted meta frame',
		'ETC' => 'Event timing codes',
		'EQU' => 'Equalization',
		'GEO' => 'General encapsulated object',
		'IPL' => 'Involved people list',
		'LNK' => 'Linked information',
		'MCI' => 'Music CD Identifier',
		'MLL' => 'MPEG location lookup table',
		'PIC' => 'Attached picture',
		'POP' => 'Popularimeter',
		'REV' => 'Reverb',
		'RVA' => 'Relative volume adjustment',
		'SLT' => 'Synchronized lyric/text',
		'STC' => 'Synced tempo codes',
		'TAL' => 'Album/Movie/Show title',
		'TBP' => 'BPM (Beats Per Minute)',
		'TCM' => 'Composer',
		'TCO' => 'Content type',
		'TCR' => 'Copyright message',
		'TDA' => 'Date',
		'TDY' => 'Playlist delay',
		'TEN' => 'Encoded by',
		'TFT' => 'File type',
		'TIM' => 'Time',
		'TKE' => 'Initial key',
		'TLA' => 'Language(s)',
		'TLE' => 'Length',
		'TMT' => 'Media type',
		'TOA' => 'Original artist(s)/performer(s)',
		'TOF' => 'Original filename',
		'TOL' => 'Original Lyricist(s)/text writer(s)',
		'TOR' => 'Original release year',
		'TOT' => 'Original album/Movie/Show title',
		'TP1' => 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group',
		'TP2' => 'Band/Orchestra/Accompaniment',
		'TP3' => 'Conductor/Performer refinement',
		'TP4' => 'Interpreted, remixed, or otherwise modified by',
		'TPA' => 'Part of a set',
		'TPB' => 'Publisher',
		'TRC' => 'ISRC (International Standard Recording Code)',
		'TRD' => 'Recording dates',
		'TRK' => 'Track number/Position in set',
		'TSI' => 'Size',
		'TSS' => 'Software/hardware and settings used for encoding',
		'TT1' => 'Content group description',
		'TT2' => 'Title/Songname/Content description',
		'TT3' => 'Subtitle/Description refinement',
		'TXT' => 'Lyricist/text writer',
		'TXX' => 'User defined text information frame',
		'TYE' => 'Year',
		'UFI' => 'Unique file identifier',
		'ULT' => 'Unsychronized lyric/text transcription',
		'WAF' => 'Official audio file webpage',
		'WAR' => 'Official artist/performer webpage',
		'WAS' => 'Official audio source webpage',
		'WCM' => 'Commercial information',
		'WCP' => 'Copyright/Legal information',
		'WPB' => 'Publishers official webpage',
		'WXX' => 'User defined URL link frame',

		# v2.3 tags
		'AENC' => 'Audio encryption',
		'APIC' => 'Attached picture',
		'COMM' => 'Comments',
		'COMR' => 'Commercial frame',
		'ENCR' => 'Encryption method registration',
		'EQUA' => 'Equalization',
		'ETCO' => 'Event timing codes',
		'GEOB' => 'General encapsulated object',
		'GRID' => 'Group identification registration',
		'IPLS' => 'Involved people list',
		'LINK' => 'Linked information',
		'MCDI' => 'Music CD identifier',
		'MLLT' => 'MPEG location lookup table',
		'OWNE' => 'Ownership frame',
		'PCNT' => 'Play counter',
		'POPM' => 'Popularimeter',
		'POSS' => 'Position synchronisation frame',
		'PRIV' => 'Private frame',
		'RBUF' => 'Recommended buffer size',
		'RVAD' => 'Relative volume adjustment',
		'RVRB' => 'Reverb',
		'SYLT' => 'Synchronized lyric/text',
		'SYTC' => 'Synchronized tempo codes',
		'TALB' => 'Album/Movie/Show title',
		'TBPM' => 'BPM (beats per minute)',
		'TCOM' => 'Composer',
		'TCON' => 'Content type',
		'TCOP' => 'Copyright message',
		'TDAT' => 'Date',
		'TDLY' => 'Playlist delay',
		'TENC' => 'Encoded by',
		'TEXT' => 'Lyricist/Text writer',
		'TFLT' => 'File type',
		'TIME' => 'Time',
		'TIT1' => 'Content group description',
		'TIT2' => 'Title/songname/content description',
		'TIT3' => 'Subtitle/Description refinement',
		'TKEY' => 'Initial key',
		'TLAN' => 'Language(s)',
		'TLEN' => 'Length',
		'TMED' => 'Media type',
		'TOAL' => 'Original album/movie/show title',
		'TOFN' => 'Original filename',
		'TOLY' => 'Original lyricist(s)/text writer(s)',
		'TOPE' => 'Original artist(s)/performer(s)',
		'TORY' => 'Original release year',
		'TOWN' => 'File owner/licensee',
		'TPE1' => 'Lead performer(s)/Soloist(s)',
		'TPE2' => 'Band/orchestra/accompaniment',
		'TPE3' => 'Conductor/performer refinement',
		'TPE4' => 'Interpreted, remixed, or otherwise modified by',
		'TPOS' => 'Part of a set',
		'TPUB' => 'Publisher',
		'TRCK' => 'Track number/Position in set',
		'TRDA' => 'Recording dates',
		'TRSN' => 'Internet radio station name',
		'TRSO' => 'Internet radio station owner',
		'TSIZ' => 'Size',
		'TSRC' => 'ISRC (international standard recording code)',
		'TSSE' => 'Software/Hardware and settings used for encoding',
		'TXXX' => 'User defined text information frame',
		'TYER' => 'Year',
		'UFID' => 'Unique file identifier',
		'USER' => 'Terms of use',
		'USLT' => 'Unsychronized lyric/text transcription',
		'WCOM' => 'Commercial information',
		'WCOP' => 'Copyright/Legal information',
		'WOAF' => 'Official audio file webpage',
		'WOAR' => 'Official artist/performer webpage',
		'WOAS' => 'Official audio source webpage',
		'WORS' => 'Official internet radio station homepage',
		'WPAY' => 'Payment',
		'WPUB' => 'Publishers official webpage',
		'WXXX' => 'User defined URL link frame',

		# v2.4 additional tags
		# note that we don't restrict tags from 2.3 or 2.4,
		'ASPI' => 'Audio seek point index',
		'EQU2' => 'Equalisation (2)',
		'RVA2' => 'Relative volume adjustment (2)',
		'SEEK' => 'Seek frame',
		'SIGN' => 'Signature frame',
		'TDEN' => 'Encoding time',
		'TDOR' => 'Original release time',
		'TDRC' => 'Recording time',
		'TDRL' => 'Release time',
		'TDTG' => 'Tagging time',
		'TIPL' => 'Involved people list',
		'TMCL' => 'Musician credits list',
		'TMOO' => 'Mood',
		'TPRO' => 'Produced notice',
		'TSOA' => 'Album sort order',
		'TSOP' => 'Performer sort order',
		'TSOT' => 'Title sort order',
		'TSST' => 'Set subtitle',

		# grrrrrrr
		'COM ' => 'Broken iTunes comments',
	);
}

=pod

=back

=head1 TROUBLESHOOTING

If you find a bug, please send me a patch (see the project page in L<"SEE ALSO">).
If you cannot figure out why it does not work for you, please put the MP3 file in
a place where I can get it (preferably via FTP, or HTTP, or .Mac iDisk) and send me
mail regarding where I can get the file, with a detailed description of the problem.

If I download the file, after debugging the problem I will not keep the MP3 file
if it is not legal for me to have it.  Just let me know if it is legal for me to
keep it or not.


=head1 TODO

=over 4

=item ID3v2 Support

Still need to do more for reading tags, such as using Compress::Zlib to decompress
compressed tags.  But until I see this in use more, I won't bother.  If something
does not work properly with reading, follow the instructions above for
troubleshooting.

ID3v2 I<writing> is coming soon.

=item Get data from scalar

Instead of passing a file spec or filehandle, pass the
data itself.  Would take some work, converting the seeks, etc.

=item Padding bit ?

Do something with padding bit.

=item Test suite

Test suite could use a bit of an overhaul and update.  Patches very welcome.

=over 4

=item *

Revamp getset.t.  Test all the various get_mp3tag args.

=item *

Test Unicode.

=item *

Test OOP API.

=item *

Test error handling, check more for missing files, bad MP3s, etc.

=back

=item Other VBR

Right now, only Xing VBR is supported.

=back


=head1 THANKS

Edward Allen,
Vittorio Bertola,
Michael Blakeley,
Per Bolmstedt,
Tony Bowden,
Tom Brown,
Sergio Camarena,
Chris Dawson,
Anthony DiSante,
Luke Drumm,
Kyle Farrell,
Jeffrey Friedl,
brian d foy,
Ben Gertzfield,
Brian Goodwin,
Todd Hanneken,
Todd Harris,
Woodrow Hill,
Kee Hinckley,
Roman Hodek,
Ilya Konstantinov,
Peter Kovacs,
Johann Lindvall,
Alex Marandon,
Peter Marschall,
michael,
Trond Michelsen,
Dave O'Neill,
Christoph Oberauer,
Jake Palmer,
Andrew Phillips,
David Reuteler,
John Ruttenberg,
Matthew Sachs,
scfc_de,
Hermann Schwaerzler,
Chris Sidi,
Roland Steinbach,
Brian S. Stephan,
Stuart,
Dan Sully,
Jeffery Sumler,
Predrag Supurovic,
Bogdan Surdu,
Pierre-Yves Thoulon,
tim,
Pass F. B. Travis,
Tobias Wagener,
Ronan Waide,
Andy Waite,
Ken Williams,
Ben Winslow,
Meng Weng Wong.


=head1 CURRENT AUTHOR 

Dan Sully E<lt>dan | at | slimdevices.comE<gt> & Slim Devices, Inc.

=head1 AUTHOR EMERITUS

Chris Nandor E<lt>pudge@pobox.comE<gt>, http://pudge.net/

=head1 COPYRIGHT AND LICENSE 

Copyright (c) 2006 Dan Sully & Slim Devices, Inc. All rights reserved. 

Copyright (c) 1998-2005 Chris Nandor. All rights reserved. 

This program is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=head1 SEE ALSO

=over 4

=item Slim Devices

	http://www.slimdevices.com/

=item mp3tools

	http://www.zevils.com/linux/mp3tools/

=item mpgtools

	http://www.dv.co.yu/mpgscript/mpgtools.htm
	http://www.dv.co.yu/mpgscript/mpeghdr.htm

=item mp3tool

	http://www.dtek.chalmers.se/~d2linjo/mp3/mp3tool.html

=item ID3v2

	http://www.id3.org/

=item Xing Variable Bitrate

	http://www.xingtech.com/support/partner_developer/mp3/vbr_sdk/

=item MP3Ext

	http://rupert.informatik.uni-stuttgart.de/~mutschml/MP3ext/

=item Xmms

	http://www.xmms.org/


=back

=cut




1;
} # end scope block

########################-----CDDB_get-----########################

{ # start scope block
#  (c) 2004 Armin Obersteiner <armin@xos.net>
package CDDB_get::Internal;

use Config;

use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $debug);

require Exporter;

@ISA = qw(Exporter AutoLoader);
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
@EXPORT_OK = qw(
  get_cddb
  get_discids
);
$VERSION = '2.27';

use Fcntl;
use IO::Socket;
use Data::Dumper qw(Dumper);

#$debug=1;

# setup for linux, solaris x86, solaris spark
# you freebsd guys give me input

# listed variables to be "local" to the enclosing block. See 'man perlsub'.
my ( $os, $machine, $CDROMREADTOCHDR, $CDROMREADTOCENTRY, $CDROM_MSF );
my ( $CDDB_HOST, $CDDB_PORT, $CDDB_MODE, $CD_DEVICE   );
my ( $HELLO_ID, $PROTO_VERSION, $BIG_ENDIAN, $BITS_64 );

sub set_standard_values {

   print STDERR "cddb: checking for os ... " if $debug;

   $os=`uname -s`;
   $machine=`uname -m`;
   chomp $os;
   chomp $machine;

   print STDERR "$os ($machine) " if $debug;

   # cdrom IOCTL magic (from c headers)
   # linux x86 is default

   # /usr/include/linux/cdrom.h
   $CDROMREADTOCHDR=0x5305;
   $CDROMREADTOCENTRY=0x5306;
   $CDROM_MSF=0x02;

   # default config

   $CDDB_HOST = "freedb.freedb.org";
   $CDDB_PORT = 8880;
   $CDDB_MODE = "cddb";
   $CD_DEVICE = "/dev/cdrom";

   $HELLO_ID  = "root nowhere.com fastrip 0.77";
   $PROTO_VERSION = 5;

   # endian check

   $BIG_ENDIAN = unpack("h*", pack("s", 1)) =~ /01/;

   if($BIG_ENDIAN) { 
      print STDERR "[big endian] " if $debug;
   } else {
      print STDERR "[little endian] " if $debug;
   }

   # 64bit pointer check

   $BITS_64 = $Config{ptrsize} == 8 ? 1 : 0;

   if($BITS_64) {
      print STDERR "[64 bit]\n" if $debug;
   } else {
      print STDERR "[32 bit]\n" if $debug;
   }

   if($os eq "SunOS") {
      # /usr/include/sys/cdio.h
      $CDROMREADTOCHDR=0x49b;	# 1179
      $CDROMREADTOCENTRY=0x49c;	# 1180

      if(-e "/vol/dev/aliases/cdrom0") {
         $CD_DEVICE="/vol/dev/aliases/cdrom0";
      } else {
         if($machine =~ /^sun/) {  
            # on sparc and old suns
            $CD_DEVICE="/dev/rdsk/c0t6d0s0";
         } else {
            # on intel 
            $CD_DEVICE="/dev/rdsk/c1t0d0p0";
         }
      }
   } elsif($os =~ /BSD/i) {  # works for netbsd, infos for other bsds welcome
      # /usr/include/sys/cdio.h

      $CDROMREADTOCHDR=0x40046304;
      $CDROMREADTOCENTRY=0xc0086305;

      if($BITS_64) {
         $CDROMREADTOCENTRY=0xc0106305;
      }

      $CD_DEVICE="/dev/cd0a";

      if($os eq "OpenBSD") {
         $CD_DEVICE="/dev/cd0c";
      }
   }
}

sub read_toc {
  my $device=shift;
  my $tochdr=chr(0) x 16;
  
  set_standard_values();

  sysopen (CD,$device, O_RDONLY | O_NONBLOCK) or die "cannot open cdrom [$!] [$device]";    
  #print "\n read_toc --> \$tochdr = $tochdr\n";
  #print "\n read_toc --> \$device = $device\n";
  #print "\n read_toc --> \$CDROMREADTOCHDR = $CDROMREADTOCHDR\n";  
  ioctl(CD, $CDROMREADTOCHDR, $tochdr) or die "cannot read toc [$!] [$device]";
  
  my ($start,$end);  
  if($os =~ /BSD/) {
    ($start,$end)=unpack "CC",(substr $tochdr,2,2);
  } else {
    ($start,$end)=unpack "CC",$tochdr;
  }
  print STDERR "start track: $start, end track: $end\n" if $debug;

  my @tracks=();

  for (my $i=$start; $i<=$end;$i++) {
    push @tracks,$i;
  }
  push @tracks,0xAA;

  my @r=();
  my $tocentry;
  my $toc="";
  my $size=0;
  for(@tracks) {
    $toc.="        ";
    $size+=8;
  }
 
  if($os =~ /BSD/) { 
    my $size_hi=int($size / 256);
    my $size_lo=$size & 255;      

    if($BIG_ENDIAN) {
      if($BITS_64) {
        # better but just perl >= 5.8.0
        # $tocentry=pack "CCCCx![P]P", $CDROM_MSF,0,$size_hi,$size_lo,$toc; 
        $tocentry=pack "CCCCxxxxP", $CDROM_MSF,0,$size_hi,$size_lo,$toc; 
      } else {
        $tocentry=pack "CCCCP8l", $CDROM_MSF,0,$size_hi,$size_lo,$toc; 
      }
    } else {
      if($BITS_64) {
        $tocentry=pack "CCCCxxxxP", $CDROM_MSF,0,$size_lo,$size_hi,$toc; 
      } else {
        $tocentry=pack "CCCCP8l", $CDROM_MSF,0,$size_lo,$size_hi,$toc; 
      }
    }
    ioctl(CD, $CDROMREADTOCENTRY, $tocentry) or die "cannot read track info [$!] [$device]";
  }

  my $count=0;
  foreach my $i (@tracks) {
    my ($min,$sec,$frame);
    unless($os =~ /BSD/) {
      $tocentry=pack "CCC", $i,0,$CDROM_MSF;
      $tocentry.=chr(0) x 16;
      ioctl(CD, $CDROMREADTOCENTRY, $tocentry) or die "cannot read track $i info [$!] [$device]";
      ($min,$sec,$frame)=unpack "CCCC", substr($tocentry,4,4);
    } else {
      ($min,$sec,$frame)=unpack "CCC", substr($toc,$count+5,3);
    } 
    $count+=8;

    my %cdtoc=();
 
    $cdtoc{min}=$min;
    $cdtoc{sec}=$sec;
    $cdtoc{frame}=$frame;
    $cdtoc{frames}=int($frame+$sec*75+$min*60*75);

    my $data = unpack("C",substr($tocentry,1,1)); 
    $cdtoc{data} = 0;
    if($data & 0x40) {
      $cdtoc{data} = 1;
    } 

    push @r,\%cdtoc;
  }   
  close(CD);
 
  return @r;
}                                      

sub cddb_sum {
  my $n=shift;
  my $ret=0;

  while ($n > 0) {
    $ret += ($n % 10);
    $n = int $n / 10;
  }
  return $ret;
}                       

sub cddb_discid {
  my $total=shift;
  my $toc=shift;

  my $i=0;
  my $t=0;
  my $n=0;
  
  while ($i < $total) {
    $n = $n + cddb_sum(($toc->[$i]->{min} * 60) + $toc->[$i]->{sec});
    $i++;
  }
  $t = (($toc->[$total]->{min} * 60) + $toc->[$total]->{sec}) -
      (($toc->[0]->{min} * 60) + $toc->[0]->{sec});
  return (($n % 0xff) << 24 | $t << 8 | $total);
}                                       

sub get_discids {
  my $cd=shift;
  $CD_DEVICE = $cd if (defined($cd));

  my @toc=read_toc($CD_DEVICE);
  my $total=$#toc;

  my $id=cddb_discid($total,\@toc);

  return [$id,$total,\@toc];
}

sub get_cddb {
  my $config=shift;
  my $diskid=shift;
  my $id;
  my $toc;
  my $total;
  my @r;
  
  set_standard_values();

  my $input = $config->{input};
  my $multi = $config->{multi};
  $input = 0 if $multi;

  print STDERR Dumper($config) if $debug;

  $CDDB_HOST = $config->{CDDB_HOST} if (defined($config->{CDDB_HOST}));
  $CDDB_PORT = $config->{CDDB_PORT} if (defined($config->{CDDB_PORT}));
  $CDDB_MODE = $config->{CDDB_MODE} if (defined($config->{CDDB_MODE}));
  $CD_DEVICE = $config->{CD_DEVICE} if (defined($config->{CD_DEVICE}));
  $HELLO_ID  = $config->{HELLO_ID} if (defined($config->{HELLO_ID}));
  $PROTO_VERSION  = $config->{PROTO_VERSION} if (defined($config->{PROTO_VERSION}));
  my $HTTP_PROXY = $config->{HTTP_PROXY} if (defined($config->{HTTP_PROXY}));
  my $FW=1 if (defined($config->{FW}));
 
  if(defined($diskid)) {
    $id=$diskid->[0];
    $total=$diskid->[1];
    $toc=$diskid->[2];
  } else {
    my $diskid=get_discids($CD_DEVICE);
    $id=$diskid->[0];
    $total=$diskid->[1];
    $toc=$diskid->[2];
  }

  my @list=();
  my $return;
  my $socket;

  my $id2 = sprintf "%08x", $id;
  my $query = "cddb query $id2 $total";
  for (my $i=0; $i<$total ;$i++) {
      $query.=" $toc->[$i]->{frames}";
  }

  # this was to old total calculation, does not work too well, its included if new version makes problems
  # $query.=" ". int(($toc->[$total]->{frames}-$toc->[0]->{frames})/75);

  $query.=" ". int(($toc->[$total]->{frames})/75);

  print Dumper($toc) if $debug;

  if ($CDDB_MODE eq "cddb") {
    print STDERR "cddb: connecting to $CDDB_HOST:$CDDB_PORT\n" if $debug;

    $socket=IO::Socket::INET->new(PeerAddr=>$CDDB_HOST, PeerPort=>$CDDB_PORT,
        Proto=>"tcp",Type=>SOCK_STREAM) or die "cannot connect to cddb db: $CDDB_HOST:$CDDB_PORT [$!]";

    $return=<$socket>;
    unless ($return =~ /^2\d\d\s+/) {
      die "not welcome at cddb db";
    }

    print $socket "cddb hello $HELLO_ID\n";

    $return=<$socket>;
    print STDERR "hello return: $return" if $debug;
    unless ($return =~ /^2\d\d\s+/) {
      die "handshake error at cddb db: $CDDB_HOST:$CDDB_PORT";
    }

    print $socket "proto $PROTO_VERSION\n";

    $return=<$socket>;
    print STDERR "proto return: $return" if $debug;
    unless ($return =~ /^2\d\d\s+/) {
      die "protokoll mismatch error at cddb db: $CDDB_HOST:$CDDB_PORT";
    }
 
    print STDERR "cddb: sending: $query\n" if $debug;
    print $socket "$query\n";

    $return=<$socket>;
    chomp $return;

    print STDERR "cddb: result: $return\n" if $debug;
  } elsif ($CDDB_MODE eq "http") {
    my $query2=$query;
    $query2 =~ s/ /+/g;
    my $id=$HELLO_ID;
    $id =~ s/ /+/g;

    my $url = "/~cddb/cddb.cgi?cmd=$query2&hello=$id&proto=$PROTO_VERSION";

    my $host=$CDDB_HOST;
    my $port=80;

    my ($user,$pass);

    if($HTTP_PROXY) {
      if($HTTP_PROXY =~ /^(http:\/\/|)(.+?):(.+)\@(.+?):(.+)/) {
        $user=$2;
        $pass=$3;
        $host=$4;
        $port=$5;
      } elsif($HTTP_PROXY =~ /^(http:\/\/|)(.+?):(\d+)/) {
        $host=$2;
        $port=$3;
      }
      $url="http://$CDDB_HOST".$url." HTTP/1.0";
    }

    print STDERR "cddb: connecting to $host:$port\n" if $debug;

    $socket=IO::Socket::INET->new(PeerAddr=>$host, PeerPort=>$port,
        Proto=>"tcp",Type=>SOCK_STREAM) or die "cannot connect to cddb db: $host:$port [$!]";

    print STDERR "cddb: http send: GET $url\n" if $debug;
    print $socket "GET $url\n";

    if($user) {
      my $cred = encode_base64("$user:$pass");
      print $socket "Proxy-Authorization: Basic $cred\n";
    }

    print $socket "\n";
    print $socket "\n" if $FW;

    if($HTTP_PROXY) {
      while(<$socket> =~ /^\S+/){};
    }

    $return=<$socket>;
    chomp $return;

    print STDERR "cddb: http result: $return\n" if $debug;
  } else {
    die "unkown mode: $CDDB_MODE for querying cddb";
  }

  $return =~ s/\r//g;

  my ($err) = $return =~ /^(\d\d\d)\s+/;
  unless ($err =~ /^2/) {
    die "query error at cddb db: $CDDB_HOST:$CDDB_PORT";
  }

  if($err==202) {
    return undef;
  } elsif(($err==211) || ($err==210)) {
    while(<$socket>) {
      last if(/^\./);
      push @list,$_;
      s/\r//g;
      print STDERR "unexact: $_" if $debug;
    } 
  } elsif($err==200) {
    $return =~ s/^200 //;
    push @list,$return;
  } else {
    die "cddb: unknown: $return";
  }

  my @to_get;

  unless($multi) {
    if (@list) { 
      my $index;
      if($input==1) {
        print "This CD could be:\n\n";
        my $i=1;
        for(@list) {
          my ($tit) = $_ =~ /^\S+\s+\S+\s+(.*)/;
          print "$i: $tit\n";
          $i++
        }
        print "\n0: none of the above\n\nChoose: ";
        my $n=<STDIN>;
        $index=int($n);
      } else {
        $index=1;
      } 

      if ($index == 0) {
        return undef;
      } else {
        push @to_get,$list[$index-1];
      }
    }
  } else {
    push @to_get,@list;
  }

  my $i=0;
  for my $get (@to_get) {
    #200 misc 0a01e802 Meredith Brooks / Bitch Single 
    my ($cat,$id,$at) = $get =~ /^(\S+?)\s+(\S+?)\s+(.*)/;

    my $artist;
    my $title;

    if($at =~ /\//) {
      ($artist,$title)= $at =~ /^(.*?)\s\/\s(.*)/;
    } else {
      $artist=$at;
      $title=$at;
    }

    my %cd=();
    $cd{artist}=$artist;
    chomp $title;
    $title =~ s/\r//g;
    $cd{title}=$title;
    $cd{cat}=$cat;
    $cd{id}=$id;

    my @lines;

    $query="cddb read $cat $id";

    if ($CDDB_MODE eq "cddb") {
      print STDERR "cddb: getting: $query\n" if $debug;
      print $socket "$query\n";

      while(<$socket>) {
        last if(/^\./);
        push @lines,$_;
      }
      if(@to_get-1 == $i) {
        print $socket "quit\n";
        close $socket;
      }

    } elsif ($CDDB_MODE eq "http") {
      close $socket;

      my $query2=$query;
      $query2 =~ s/ /+/g;
      my $id=$HELLO_ID;
      $id =~ s/ /+/g;

      my $url = "/~cddb/cddb.cgi?cmd=$query2&hello=$id&proto=$PROTO_VERSION";

      my $host=$CDDB_HOST;
      my $port=80;

      my ($user,$pass);

      if($HTTP_PROXY) {
        if($HTTP_PROXY =~ /^(http:\/\/|)(.+?):(.+)\@(.+?):(.+)/) {
          $user=$2;
          $pass=$3;
          $host=$4;
          $port=$5;
        } elsif($HTTP_PROXY =~ /^(http:\/\/|)(.+?):(\d+)/) {
          $host=$2;
          $port=$3;
        }
        $url="http://$CDDB_HOST".$url." HTTP/1.0";
      }

      print STDERR "cddb: connecting to $host:$port\n" if $debug;

      $socket=IO::Socket::INET->new(PeerAddr=>$host, PeerPort=>$port,
        Proto=>"tcp",Type=>SOCK_STREAM) or die "cannot connect to cddb db: $host:$port [$!]";

      print STDERR "cddb: http send: GET $url\n" if $debug;
      print $socket "GET $url\n";

      if($user) {
        my $cred = encode_base64("$user:$pass");
        print $socket "Proxy-Authorization: Basic $cred\n";
      }

      print $socket "\n";
      print $socket "\n" if $FW;

      if($HTTP_PROXY) {
        while(<$socket> =~ /^\S+/){};
      }

      while(<$socket>) {
        last if(/^\./);
        push @lines,$_;
      }
      close $socket;
    } else {
      die "unkown mode: $CDDB_MODE for querying cddb";
    }

    # xmcd
    #
    # Track frame offsets:
    #	150
    # ...
    #	210627
    #
    # Disc length: 2952 seconds
    #
    # Revision: 1
    # Submitted via: xmcd 2.0
    #

    for(@lines) {
      last if(/^\./);
      next if(/^\d\d\d/);
      push @{$cd{raw}},$_;
      #TTITLE0=Bitch (Edit) 
      if(/^TTITLE(\d+)\=\s*(.*)/) {
        my $t= $2;
        chop $t;
        $cd{frames}[$1]=$toc->[$1]->{frames};
        $cd{data}[$1]=$toc->[$1]->{data};
        unless (defined $cd{track}[$1]) {
          $cd{track}[$1]=$t;
        } else {
          $cd{track}[$1]=$cd{track}[$1].$t;
        }
      } elsif(/^DYEAR=\s*(\d+)/) {
        $cd{'year'} = $1;
      } elsif(/^DGENRE=\s*(\S+.*)/) {
        my $t = $1;
        chop $t;
        $cd{'genre'} = $t;
      } elsif(/^\#\s+Revision:\s+(\d+)/) {
        $cd{'revision'} = $1;
      }
    }

    $cd{tno}=$#{$cd{track}}+1;
    $cd{frames}[$cd{tno}]=$toc->[$cd{tno}]->{frames};
    
    return %cd unless($multi);
    push @r,\%cd;
    $i++;
  }

  return @r;
}


   1;  # don't forget to return a true value from the file
} # end scope block

