#!/usr/bin/perl                        
use Gtk2; INIT {Gtk2->init;}    # load the Gtk-Perl module - see <man Gtk2>
use Glib qw/filename_from_unicode filename_to_unicode/;
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;        # Format for Input/Output character - interfaces between Perl's strings and
                   # the rest of the system - see <man Encode>.
		   
#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 ":sys_wait_h"; # used on sub 'change_count'

set_locale Gtk2;               # internationalize
#no locale;

#require 5.004;
#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 $character = 'iso-8859-1';	# also known as Latin1

#------------------------- 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   To get audio cd informations from freedb.freedb.org,\n";
          warn  "   install the perl module \"CDDB_get-version.tar.gz\".\n"; 
   }
   return $false;
}
my $use_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   To get MP3 info, install the perl module \"MP3-Info-version.tar.gz\".\n"; }
   return $false;
}
my $use_MP3Info = modules_mp3info();
use_winamp_genres() if $use_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 "Couldnt 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; }
   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;
}
#-----------------------------------------------------------------------------#		   

# gtk+2.0 - 2.4.9 -9mdk  and  perl-Glib-1.080
# examples: perl /usr/share/doc/perl-Gtk2-1.083/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 - 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.52";
my $AUTHOR = "Claudio Fernandes de Souza Rodrigues";
my $DATE = "November 30 2006";
my $HOMEPAGE = "http://gnormalize.sourceforge.net";

#----------------------------------------------------------#
## ------- default path used by the cdrom drive --------- ##
my $audiodevice_path ="/dev/cdrom";
#----------------------------------------------------------#
#----------------------------------------------------------#
my $home = "$ENV{HOME}"; my $os;
# my $date = system("date +%Y");
my $window; my $window_width = 740; my $window_height = 560;
my $tooltips; #$tooltips->set_delay( 1000 ); # 1s of wait
my $notebook; my $button; my $spinner;my $spinner_q; my $spinner_bitrate_mp3; 
my $spinner_bitrate_ogg; my $spinner_bitrate_mp4; my $value; 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 = "Fix"; my $num_d;
my $file_dialog; my $button_clear;
my $label_type; my $label_VB; my $entry_f; my $entry_d;
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 $combo_Min; my $vb_Min=64;
my $label_Max; my $combo_Max; my $vb_Max=320;
my $combo_const_avg; my $combo_bitrate;
my $file_mp3=""; my $file_ogg=""; my $file_mpc=""; my $file_ape=""; 
my $file_flac=""; my $file_wav=""; my $file_mp4=""; my $file_wav_copy="";
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 $da;
my $symbol; my $align; my $separator; my $table;
my $orientation; my $new_val; my $ripper = 'cdparanoia';
my $entry_l; my $entry_n; my $combo_mode; my $combo_fq; 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 $file_input = 'other'; my $file_output = 'mp3';
my $file_output_copy; 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 = 100; 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_remember_mp3 = 'average'; my $encode_remember_mp4 = 'average'; 
my $encode_remember_ogg = 'average'; my $encode_remember_mpc = 'variable'; my $input = "Directory";
my $check_button_del_wav; my $check_button_cddb; my $check_button_fchooser; 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 $combo_cddb_transport; my $cddb_transport = 'cddb';
my $priority = 15; my $change_properties = $false; my $new_file_chooser = $true;
my $check_button_change; my $check_button_overwrite; my $check_button_overwrite_cddb;
my $overwrite_cddb = $false; my $entry_format_cda; my $file_format_cda_rip = "%a-%b-%n-%t";
my $overwrite = $false; my $volume_normalize = 30; my $insensibility = 0.5; my $spinner_sensi;
my $mode = 'joint stereo'; my $freq = 44100; my $comp_ape = 2000; my $comp_flac = 3;
my $spinner_lang;  my $language = 1; my $combo_rip; my $combo_char; 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 $button_file; my $button_dir; 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_length;
my $button_info_type = 1; my $notebook_page_num = 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_total_time; my $audio_cd_fileSize; my $audio_cd_channel;
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 $normalize_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 $vorbiscomment_path; my $audiocd;
my $cdcd_path = ""; my $cdplayer = "Audio::CD"; my $combo_cdplayer;
#---mp3/ogg tag
my $channel; my $mode_original; 
my $Comment; my $Genre; my $Frequency = 0; my $Time_Min_Sec; my $Title; 
my $Artist; my $Track_Number; my $Total_Track; my $Album; my $Year; 
my $Technical_Info;
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 $color_bg_cdplay = '#839975'; my $color_cdplayer_shadow = '#839975'; 
my $color_cdplayer_arrows = '#000000'; my $color_cdplayer_shadow_motion = '#FFA500';
my $color_cdplayer_arrows_motion = '#000000'; my $color_cdplayer_digit = '#000000';
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_track = 1; # default audio track
my $total_time = 0;
my @tracks_to_play = ();
my @tracks_already_played = ();
my @tracks_already_played_time = ();
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;
#---player---#
my $device_path = "/dev/audio"; my $device_type = "oss"; my $player_mp3 = "mpg321";
my $player_flac = "mplayer";  my %all_mp3_player; my %all_ogg_player; my %all_flac_player; 

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

sub read_config {
	my $config = $home."/.gnormalize_config";
	$config = encode_char("$config");
	
	if( -r "$config" ) {
	   my $file_number = 1;	
	   # read config file
	   open(CONFIG, "$config" ); 
	   while( <CONFIG> ) 
	   {   
	      if ($_ =~ /^cdrom=(.*)/){ $audiodevice_path = $1; }
	      if ($_ =~ /^input=(.*)/){ $input = $1; }
	      if ($_ =~ /^recursively=(.*)/){ $recursively = $1; } 
	      if ($_ =~ /^file_output=(.*)/){ $file_output = $1; }	      
	      if ($_ =~ /^directory_output=(.*)/){ $directory_output = $1; }
	      if ($_ =~ /^normalization_type=(.*)/){ $norm_type = $1; } 
	      if ($_ =~ /^volume_normalize=(.*)/){ $volume_normalize = $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 ($_ =~ /^file_format_cda_rip=(.*)/){ $file_format_cda_rip = $1; }
	      if ($_ =~ /^new_file_chooser=(.*)/){ $new_file_chooser = $1; } 
	      if ($_ =~ /^overwrite=(.*)/){ $overwrite = $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=(.*)/){ $character = $1; }
	      if ($_ =~ /^cdplayer=(.*)/){ $cdplayer = $1; }	      
	      if ($_ =~ /^window_font_name=(.*)/){ $window_font_name = $1; }	     	      
	      if ($_ =~ /^ripper=(.*)/){ $ripper = $1; }
	      if ($_ =~ /^language=(.*)/){ $language = $1; }	      
	      if ($_ =~ /^encode=(.*)/){ $encode = $1; }  
	      if ($_ =~ /^encode_remember_mp3=(.*)/){ $encode_remember_mp3 = $1; } 
	      if ($_ =~ /^encode_remember_mp4=(.*)/){ $encode_remember_mp4 = $1; } 
	      if ($_ =~ /^encode_remember_mpc=(.*)/){ $encode_remember_mpc = $1; } 
	      if ($_ =~ /^encode_remember_ogg=(.*)/){ $encode_remember_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=(mpg321|mpg123|madplay|mplayer)/){ $player_mp3 = $1; }	      	      
	      if ($_ =~ /^player_flac=(.*)/){ $player_flac = $1; }
	      if ($_ =~ /^device_path=(.*)/){ $device_path = $1; }
	      if ($_ =~ /^device_type=(.*)/){ $device_type = $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_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; }
	      	      	      
	      # read the music list
	      if ($_ =~ /^play=(.*)::file=(\d+)::track=(.*)::artist=(.*)::title=(.*)::album=(.*)::length=(.*)::bitrate=(\d+)::year=(.*)::frequency=(\d+)::filepath=(.*)::filename=(.*)::extension=(.*)$/){ 
                 my $filepath = $11;
		 if ( not -e encode_char($filepath) ){ next; } # next if filepath don't exist 
		 push @files_info, {   # fill the array of array references
                                       rip         => $1,
	                               file        => $file_number,
			               track       => $3,
			               artist      => $4,
			               title       => $5,
			               album       => $6,			  
			               length      => $7,
			               bitrate     => $8,
				       year        => $9,
				       frequency   => $10,
				       filepath    => $filepath,  # $11,
				       filename    => $12,		  
			               extension   => $13
                                   };
	         $file_number += 1; 		        
	      }	         	      	       
	}
	close(CONFIG);
     }
     $file_output_copy = $file_output;
     $volume_normalize = number_value($volume_normalize);
     return;
}


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

# save configurations only when quit the program
sub save_config {
	my $config = $home."/.gnormalize_config";
	if ( not -e encode_char("$config") ){ print "Save configuration file: $config\n"; }
	
	# test_expr ? if_true_expr : if_false_expr	
	open(CONFIG, ">",  encode_char("$config") ) || 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 "input=$input\n";
	  print CONFIG "recursively=",$check_button_recursively->get_active?1:0,"\n";	  
	  print CONFIG "file_output=$file_output\n";
	  print CONFIG "directory_output=$directory_output\n";	  	  
	  print CONFIG "normalization_type=$norm_type\n";
	  print CONFIG "volume_normalize=",$spinner->get_value_as_int,"\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=",$combo_cddb_transport->entry->get_text,"\n";		   
	  print CONFIG "priority=",$spinner_pri->get_value,"\n";
	  print CONFIG "change_properties=",$check_button_change->get_active?1:0,"\n";	  
	  print CONFIG "file_format_cda_rip=",$entry_format_cda->get_text,"\n"; 	  
	  print CONFIG "new_file_chooser=",$check_button_fchooser->get_active?1:0,"\n";
	  print CONFIG "overwrite=",$check_button_overwrite->get_active?1:0,"\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=",$combo_char->entry->get_text,"\n";
	  print CONFIG "cdplayer=",$combo_cdplayer->entry->get_text,"\n";	  
	  print CONFIG "window_font_name=",$button_font->get_label,"\n";	  	
	  print CONFIG "ripper=",$combo_rip->entry->get_text,"\n";  
	  print CONFIG "language=",$spinner_lang->get_value,"\n";
	  print CONFIG "encode=",$combo_const_avg->entry->get_text,"\n";
	  print CONFIG "encode_remember_mp3=$encode_remember_mp3\n";
	  print CONFIG "encode_remember_mp4=$encode_remember_mp4\n";
	  print CONFIG "encode_remember_mpc=$encode_remember_mpc\n";
	  print CONFIG "encode_remember_ogg=$encode_remember_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=",$combo_mode->entry->get_text,"\n";	  
	  print CONFIG "Min=",$combo_Min->entry->get_text,"\n";
	  print CONFIG "Max=",$combo_Max->entry->get_text,"\n";
	  print CONFIG "freq=",$combo_fq->entry->get_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_flac=$player_flac\n";
	  print CONFIG "device_path=$device_path\n";	
	  print CONFIG "device_type=$device_type\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_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 "\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} eq 'cda' or $d->{remove});
             print CONFIG "play=$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}::filepath=$d->{filepath}::".
			  "filename=$d->{filename}::extension=$d->{extension}\n";		   
          }	  	  	  	    	       
	close CONFIG;
}

read_config(); 
#save_config(); # save when quit; see 'sub Quit'
#print "file_output = $file_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 $msg; my $tips;

my $name1; my $name2; my $name3; my $name4; my $name5; my $name6; my $name7; my $name8; my $name9; my $name10;
my $name11; my $name12; my $name13; my $name14; my $name15; my $name16; my $name17; my $name18; my $name19; my $name20;
my $name21; my $name22; my $name23; my $name24; my $name25; my $name26; my $name27; my $name28; my $name29; my $name30; 
my $name31; my $name32; my $name33; my $name34; my $name35; my $name36; my $name37; my $name38; my $name39; my $name40;
my $name41; my $name42; my $name43; my $name44; my $name45; my $name46; my $name47; my $name48; my $name49; my $name50;
my $name51; my $name52; my $name53; my $name54; my $name55; my $name56; my $name57; my $name58; my $name59; my $name60;

my $tip1; my $tip2; my $tip3; my $tip4; my $tip5; my $tip6; my $tip7; my $tip8; my $tip9; my $tip10;
my $tip11; my $tip12; my $tip13; my $tip14; my $tip15; my $tip16; my $tip17; my $tip18; my $tip19; my $tip20;
my $tip21; my $tip22; my $tip23; my $tip24; my $tip25; my $tip26; my $tip27; my $tip28; my $tip29; my $tip30;
my $tip31; my $tip32; my $tip33; my $tip34; my $tip35; my $tip36; my $tip37; my $tip38; my $tip39; my $tip40;
my $tip41; my $tip42; my $tip43; my $tip44; my $tip45; my $tip46; my $tip47; my $tip48; my $tip49; my $tip50;
my $tip51; my $tip52; my $tip53; my $tip54; my $tip55;

my $msg1; my $msg2; my $msg3; my $msg4; my $msg5; my $msg6; my $msg7; my $msg8; my $msg9; my $msg10;
my $msg11; my $msg12; my $msg13; my $msg14; my $msg15; my $msg16; my $msg17; my $msg18; my $msg19; my $msg20;
my $msg21; my $msg22; my $msg23; my $msg24; my $msg25; my $msg26; my $msg27; my $msg28; my $msg29; my $msg30;
my $msg31; my $msg32; my $msg33; my $msg34; my $msg35; my $msg36; my $msg37; my $msg38; my $msg39; my $msg40;
my $msg41; my $msg42; my $msg43; my $msg44; my $msg45; my $msg46; my $msg47; my $msg48; my $msg49; my $msg50;
my $msg51; my $msg52; my $msg53; my $msg54; my $msg55; my $msg56; my $msg57; my $msg58; my $msg59; my $msg60;
my $msg61; my $msg62; my $msg63; my $msg64; my $msg65; my $msg66; my $msg67; my $msg68; my $msg69; my $msg70;
my $msg71; my $msg72; my $msg73; my $msg74; my $msg75; my $msg76; my $msg77; my $msg78; my $msg79; my $msg80;
my $msg81; my $msg82; my $msg83; my $msg84; my $msg85; my $msg86; my $msg87; my $msg88; my $msg89; my $msg90;
my $msg91; my $msg92;


if ( $language == 1 )   # 1 : english
{
   $name1 = "Normalization Type:";
   $name2 = "Insensibility:";
   $name3 = "Selected File:";
   $name4 = "Input Directory:";
   $name5 = "Input";
   $name6 = "Output";
   $name7 = "File";
   $name8 = "Recursively";
   $name9 = "delete wav files";
   $name10 = "change properties";
   $name11 = "overwrite";
   $name12 = "priority:";
   $name13 = "add command:";
   $name14 = "filename rip:";
   $name15 = "character:";
   $name16 = "idiom:";
   $name17 = "font:";
   $name18 = "Read CDDB";
   $name19 = "Overwrite CDDB";
   $name20 = "CDDB server:";
   $name21 = "Port:";
   $name22 = "Transport:";
   $name23 = "disable paranoia";
   $name24 = "disable extra paranoia";
   $name25 = "abort on skip";
   $name26 = "never skip repair";
   $name27 = "paranoia no-verify";
   $name28 = "paranoia disable";
   $name29 = "ripper:";
   $name30 = "Encode Type:";
   $name31 = "Mode:";
   $name32 = "Encode Quality:";
   $name33 = "Variable:";
   $name34 = "Title:";
   $name35 = "Artist:";
   $name36 = "Album:";
   $name37 = "Comment:";
   $name38 = "Year:";
   $name39 = "Track Number:";
   $name40 = "Genre:";
   $name41 = "Freq:";
   $name42 = "Time:";
   $name43 = "Channels:";
   $name44 = "length";
   $name45 = "track";
   $name46 = "artist";
   $name47 = "title";
   $name48 = "Size:";
   $name49 = "year";
   $name50 = "filepath";
   $name51 = "extension";
   $name52 = "Output Directory:";
   $name53 = "album";
   $name54 = "Directory";
   $name55 = "animation";
   $name56 = "filename";
   
   $tip1  = "Adjust the RMS volume to the target amplitude (must be between 1 and 99). RMS is the Root ";
   $tip1 .= "Mean Square of sound amplitude, that is, sqrt(mean(amplitude^2)).";
   $tip2  = "Insensibility of normalize. Only not re-encode if:\n";
   $tip2 .= "1) the extension of input file is the same of output file;\n";
   $tip2 .= "2) and \"$name10\" button is not active;\n";
   $tip2 .= "3) and adjust of normalize is less than insensibility value.";
   $tip3  = "Always normalize/convert only the \"$name3\" that will be saved into the \"$name52\". ";
   $tip3 .= "Press Show button to see all the files that can be normalized.";      
   $tip4  = "Normalize/Convert all supported files inside the directory (recursively or not).";
   $tip5  = "Include subdirectories: descende recursively into the directory preserving the same structure.";
   $tip6  = "After normalize, the output format will be mp3. Play it with mpg321 or madplay.";
   $tip7  = "After normalize, the output format will be mp4 (also know as m4a) or aac. Play it with xmms plugin \"faad2-xmms\" or mplayer.";
   $tip8  = "After normalize, the output format will be mpc (also know as mpp or mp+). Play it with mppdec or xmms plugin.";
   $tip9  = "After normalize, the output format will be ogg. Play it with ogg123.";
   $tip10 = "After normalize, the output format will be ape. Play it with the command:\n   mac \"song.ape\"  - -d | play -t wav - ";
   
   $tip11  = "After normalize, the output format will be flac. Play it with flac123 or xmms plugin.\nRequired flac version >= \"1.1.1\".";
   $tip11 .= "\n\nNOTE: \"Compression may be {lossless compression}, in which all of the information in the original data is preserved, ";
   $tip11 .= "and the original data may be recovered in form identical to its original form; or {lossy compression}, ";
   $tip11 .= "in which some of the information in the original data is lost, and decompression results in a data form ";
   $tip11 .= "slightly different from the original.\" [PJC - Stardict]\n";
   $tip11 .= "Lossless: Free from loss. [1913 Webster]\n";
   $tip11 .= "\nExamples of lossless compression audio: ape and flac.\n";
   $tip11 .= "Examples of lossy compression audio: mp3, mp4, mpc and ogg.\n";
   $tip11 .= "Example of audio without compression: wav.\n";
   $tip12  = "After the normalize process, the temporary wav files will be deleted.";
   $tip13  = "Use the new Gtk2::FileChooser or the old Gtk2::FileSelection when a file is selected.";
   $tip14  = "Modify scheduling priority: 0 (highest priority) to 19 (lowest)";
   $tip15  = "After normalize the files, you can change its enconde properties by determining the encode type, the bitrate of all ";
   $tip15 .= "output files, etc. Otherwise, the bitrate of each input file and others properties will be conserved.";
   $tip16  = "Output filename format used only for rip Audio CD:\n";
   $tip16 .= "   %a - artist\n";
   $tip16 .= "   %b - album\n";
   $tip16 .= "   %t - song title\n";
   $tip16 .= "   %n - track number\n";
   $tip16 .= "   %y - year\n";
   $tip16 .= "   %g - genre";
   $tip17  = "The normalized file will be saved in the same directory of input. If it already exist then overwrite the original file.";
   $tip18  = "Put here the additional command line used to encode $file_output files.";  
   $tip19  = "Choose your language (you need restart the gnormalize):\n   1 : english\n   2 : portugus (Brasil)\n";
   $tip19 .= "Escolha o seu idioma (voc precisa reiniciar o gnormalize).";
   $tip20  = "Advised font: Sans 10.";
   
   $tip21  = "Read the CDDB info for Audio CD in your drive from CDDB server \"$CDDB_server\" or from files saved into $home/.cddd/.";
   $tip22  = "Always get CDDB info from server and overwrite the CDDB file saved at $home/.cddd/";
   $tip23  = "Some servers:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880";
   $tip24  = "Choose the port number.";
   $tip25  = "Disable all data verification and correction features. Consequently the extraction/rip is more quickly. ";
   $tip25 .= "This option implies that -Y is active. See cdparanoia (option -Z).";
   $tip26  = "Do not accept any skips; retry forever if needed. See cdparanoia (option -z).";
   $tip27  = "Disables intra-read data verification; only overlap checking at read boundaries is performed. Not recommended. See cdparanoia (option -Y).";
   $tip28  = "If the read skips due to imperfect data, a scratch, whatever, abort reading this track. See cdparanoia (option -X).";
   $tip29  = "Use the paranoia library instead of cdda2wav's routines for reading. See cdda2wav (option -paranoia).";
   $tip30  = "Disables paranoia mode. Paranoia is still being used. See cdda2wav (option -paraopts=help).";
   
   $tip31  = "Switches verify off, and overlap on.";
   $tip32  = "Choose a targeted average bitrate. Sets encoding to the bitrate closest to this value (in Kb/s).";
   $tip33  = "Adjust the quality of mp3; 9 is the worst quality, 0 is the best quality with more Kb/s. See: man lame (option: -V).";
   $tip34  = "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.";
   $tip35  = "Adjust the quality of lame encoder for mp3 files: 0 is the best quality with maximum ";
   $tip35 .= "algorithms process; 9 is the worst quality but more fast. See: man lame (option: -q).";
   $tip36  = "Set default variable bitrate (VBR) quantizer quality in percent for mp4 format; 500 is the best ";
   $tip36 .= "quality with more Kb/s used; 10 is the worst quality. See: <faac --help>.";
   $tip37  =  "Adjust the quality of encode for mpc using profiles; 8 (braindead) is the best quality with more Kb/s used,";
   $tip37 .= " 2 (telephone) is the worst quality. See: mppenc --longhelp\n";
   $tip37 .= " q=2 --telephone - lowest quality,       (32... 48 kbps)\n";
   $tip37 .= " q=3 --thumb     - low quality/internet, (58... 86 kbps)\n";
   $tip37 .= " q=4 --radio     - medium (MP3) quality, (112...152 kbps)\n";
   $tip37 .= " q=5 --standard  - high quality (dflt),  (142...184 kbps)\n";
   $tip37 .= " q=6 --xtreme    - extreme high quality, (168...212 kbps)\n";
   $tip37 .= " q=7 --insane    - extreme high quality, (232...268 kbps)\n";
   $tip37 .= " q=8 --braindead - extreme high quality, (232...278 kbps)";
   $tip38  = "Compression level:\n  fast: 1000\n  normal: 2000\n  high: 3000\n  extra high: 4000\n  insane: 5000\n";
   $tip38 .= "\nMore compression level \nresults small files.\nSee the help: mac";
   $tip39  = "Compression level:\n  fast: 0\n  normal: 5\n  best: 8\nSee <man flac>.";
   $tip40  = "Track number";
   $tip41  = "Total track number";
   $tip42  = "Try /dev/cdrom, /dev/dvd, /dev/hdc or ...";
   $tip43  = "Refresh the cdrom drive and erase the playlist.";
   $tip44  = "Unselect all tracks.";
   $tip45  = "Select all tracks.";
   $tip46  = "Show the Tux and others penguins animations.";
   $tip47  = "After normalize, the output format will be wav. This is suitable to make an audio cd from wav files.";
   $tip48  = "If there is more than one artist, use:\nArtist1 & Artist2 & Artist3 & ...";
   $tip49  = "Show the progress bar.";
   $tip50  = "Hide the progress bar.";
   $tip51  = "Show the command line and others info.";
   $tip52  = "Hide the command line and others info.";
   $tip53  = "Quit.";
   $tip54  = "Clear all messages.";
   $tip55  = "Close the gnormalize player config.";
   
   $msg1  = "Supported Files into the directory (recursively):\n";
   $msg2  = "Supported Files into the directory (not recursively):\n";      
   $msg3  = " Choose a mp3/mp4/mpc/ogg/ape/flac/wav/cda file to normalize!";
   $msg4  = " Dependence not satisfied!";
   $msg5  = " Choose files with mp3, mp4, mpc, ogg, ape, flac or wav extension!";
   $msg6  = " Can't choose mp3 format! lame not found.";
   $msg7  = " Can't choose mp4 format! faad not found.";
   $msg8  = " Can't choose ogg format! oggdec not found.";
   $msg9  = " Can't choose mpc format! mppdec not found.";
   $msg10 = " Can't choose ape format! mac not found.";
   $msg11 = " Can't choose flac format! flac not found.";
   $msg12 = ": read only!";
   $msg13 = " Select at least one track to rip!";
   $msg14 = " Success! Rip finished.";
   $msg15 = " Rip stopped!";    
   $msg16 = " Success!";       
   $msg17 = " Success! File converted.";
   $msg18 = " Success! File normalized.";
   $msg19 = "stop ripping";
   $msg20 = " Get info from ";
   $msg21 = " Please, wait. cdparanoia is reading the cdrom ...";
   $msg22 = " Please, select at least one track to play.";
   $msg23 = "Can't find \"";
   $msg24 = "\" in executable path.";
   $msg25 = "The output can't be \"mp3\" format.";
   $msg26 = "The output can't be \"ogg\" format.";
   $msg27 = "The output can't be \"mpc\" format.";
   $msg28 = "The output can't be \"ape\" format.";
   $msg29 = "The output can't be \"flac\" format.";
   $msg30 = "The output can't be \"mp4\" format.";
   $msg31 = "The wav files can't be normalized.";
   $msg32 = "The input can't be \"ogg\" format.";
   $msg33 = "The input can't be \"mpc\" format.";
   $msg34 = "The input can't be \"mp4\" format.";
   $msg35 = "cdcd is a Command Driven CD player.";
   $msg36 = "\nFirst run \"cdcd\" in command line to make the config file .cdcdrc\n";
   $msg37 = "Choose \"n\" for the question:  Are you connected to a network (y/n) [y]?\n";
   $msg38 = "Can't use the perl module \"";
   $msg39 = "Can't play audio CD.";
   $msg40  = "gnormalize is a front end to normalize, a ripper, an encoder, an audio converter, a metadata (tag) editor and an audio ";
   $msg40 .= "player. It decodes the files to WAV, then normalizes the WAV and re-encodes it. gnormalize can convert";
   $msg40 .= " audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV.";
   $msg41  = "This file will not be normalized!";
   $msg42 = " according to insensibility, not normalize ";
   $msg43 = "Not normalize because adjustment ";
   $msg44 = " is less than insensibility value.\n";
   $msg45 = " not normalize ";
   $msg46 = " don't need encode ";
   $msg47 = " already normalized ";
   $msg48 = "This file is already normalized.\n";
   $msg49 = " Stop normalizing!";
   $msg50 = "Applying adjustment of ";
   $msg51 = " normalizing: adjustment of ";
   $msg52 = "Computing levels...";
   $msg53 = " normalized with adjustment of ";
   $msg54 = " ripping audio to wav";
   $msg55 = " Stop ripping!";
   $msg56 = "copy maked.";
   $msg57 = " Stop lame decoding!";
   $msg58 = " Stop lame encoding!";   
   $msg59 = "Save changes of tag.";
   $msg60 = "Save changes of tag to $home/.cddb directory.";
   $msg61 = " This informations will be saved on normalized file.";   
   $msg62 = " tag saved.";
   $msg63 = "Select a mp3/mp4/mpc/ogg/ape/flac/wav file.";
   $msg64 = "\nHomepage: $HOMEPAGE\nThis software is available under GNU General Public Licence.";
   $msg65 = " output: ";
   $msg66 = "file selected - info can be edited.";
   $msg67 = " Unable to open cdrom drive ";
   $msg68 = " Getting information from cddb ...";
   $msg69 = " none cddb information.";
   $msg70 = " Press save button on \"info\" tab to save this changes.";
   $msg71 = " Not connected, using ";
   $msg72 = " cddb: can't connect to internet!";
   $msg73 = " Can't rip audio CD! cdparanoia not found.";
   $msg74 = " Can't rip audio CD! cdda2wav not found.";
   $msg75 = "Select a mp3, mp4, mpc, ogg, ape, flac, or wav file";
   $msg76 = "Select one directory or one supported file.";
   $msg77 = "settings";
   $msg78 = "Selected file";
   $msg79 = "\nRecomended minimum version:\n";
   $msg80 = " Invalid option!";
   $msg81 = " Press the \"Refresh the cdrom\" button and type again the changes.";
   $msg82 = "\n None cddb info, install the perl module \"CDDB_get\".";
   $msg83 = "\n No mp3 info, install the perl module \"MP3::Info\".";
   $msg84  = "\ngnormalize is a front end to normalize, a ripper, an encoder, an audio converter, a metadata (tag) ";
   $msg84 .= "editor and an audio player.";
   $msg85  = "\ngnormalize decodes the files to WAV, then normalizes the WAV and re-encodes it. ";
   $msg85 .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC and WAV.";
   $msg86 = "Selected Directory (recursively)";
   $msg87 = "Select a directory containing mp3, mp4, mpc, ogg, ape, flac, or wav file.";
   $msg88 = "Selected Directory (not recursively)";
   $msg89 = "Removing temporary file:";
   $msg90 = "Can not find no supported file inside of directory!";
   $msg91 = "Choose the directory where all the files will be saved.";
   $msg92 = "remove this music from list";
}

if ( $language == 2 )   # 2 : portugus
{
   $name1 = "Normalizao:";
   $name2 = "Insensibilidade:";
   $name3 = "Arquivo Selecionado:";
   $name4 = "Diretrio de entrada:";
   $name5 = "Entrada";
   $name6 = "Sada";
   $name7 = "Arquivo";
   $name8 = "Recursivamente";
   $name9 = "remover wav";
   $name10 = "alterar propriedades";
   $name11 = "sobrescrever";
   $name12 = "prioridade:";
   $name13 = "adicionar comando:";
   $name14 = "arquivo rip:";
   $name15 = "caracteres:";
   $name16 = "idioma:";
   $name17 = "fonte:";
   $name18 = "ler CDDB";
   $name19 = "sobrescrever CDDB";
   $name20 = "CDDB servidor:";
   $name21 = "Porta:";
   $name22 = "Transporte:";
   $name23 = "desativar paranoia";
   $name24 = "desativar extra paranoia";
   $name25 = "abortar no caso de arranho";
   $name26 = "reler indefinidamente";
   $name27 = "paranoia no verificar";
   $name28 = "desativar paranoia";
   $name29 = "extrator:";
   $name30 = "Tipo de Codificao:";
   $name31 = "Modo:";
   $name32 = "Qualidade:";
   $name33 = "Varivel:";
   $name34 = "Ttulo:";
   $name35 = "Artista:";
   $name36 = "Album:";
   $name37 = "Comentrio:";
   $name38 = "Ano:";
   $name39 = "Nmero:";
   $name40 = "Gnero:";
   $name41 = "Freq:";
   $name42 = "Durao:";
   $name43 = "Canais:";
   $name44 = "durao";
   $name45 = "faixa";
   $name46 = "artista";
   $name47 = "ttulo";
   $name48 = "Tamanho:";
   $name49 = "ano";
   $name50 = "arquivo";
   $name51 = "extenso";
   $name52 = "Diretrio de sada:";
   $name53 = "album";
   $name54 = "Diretrio";
   $name55 = "animao";
   $name56 = "nome do arquivo";
   
   $tip1  = "Ajusta o volume mdio RMS a uma dada amplitude (deve estar entre 1 e 99). RMS significa Root ";
   $tip1 .= "Mean Square (Raiz Quadrada da Mdia) da amplitude do som, isto , sqrt(mean(amplitude^2)).";
   $tip2  = "Insensibilidade do normalize. Apenas no re-codifica se:\n";
   $tip2 .= "1) a extenso do arquivo de entrada for a mesma da sada;\n";
   $tip2 .= "2) e o boto \"$name10\" no estiver ativo;\n";
   $tip2 .= "3) e o ajuste do normalize for menor que o valor de insensibilidade.";
   $tip3  = "Sempre normaliza/converte apenas o \"$name3\" que ser salvo dentro do \"$name52\". ";
   $tip3 .= "Pressione o boto Show para ver todos os arquivos que podem ser normalizados.";      
   $tip4  = "Normaliza/converte todos os arquivos suportados dentro do diretrio (recursivamente ou no).";            
   $tip5  = "Inclue subdiretrios: desce recursivamente dentro do diretrio preservando a mesma estrutura.";
   $tip6  = "Depois de normalizar, o formato de sada ser mp3. Para ouvir arquivos mp3 utilize o mpg321 ou madplay.";
   $tip7  = "Depois de normalizar, o formato de sada ser mp4 (tambm conhecido como m4a) ou acc. ";
   $tip7 .= "Para ouvir arquivos mp4 utilize o plugin do xmms \"faad2-xmms\" ou mplayer.";
   $tip8  = "Depois de normalizar, o formato de sada ser mpc (tambm conhecido como mpp ou mp+). ";
   $tip8 .= "Para ouvir arquivos mpc utilize o comando mppdec ou o plugin do xmms.";          
   $tip9  = "Depois de normalizar, o formato de sada ser ogg. Para ouvir arquivos ogg utilize o ogg123.";
   $tip10 = "Depois de normalizar, o formato de sada ser ape. Para ouvir arquivos ape use o comando:\n   mac \"song.ape\"  - -d | play -t wav - ";   
   
   $tip11  = "Depois de normalizar, o formato de sada ser flac. Para ouvir arquivos flac utilize o flac123 ou o plugin do xmms.\nVerso do flac exigida >= \"1.1.1\".";
   $tip11 .= "\n\nNOTA: \"Compresso pode ser {lossless compression}, na qual toda a informao do arquivo original  preservada, ";
   $tip11 .= "e o arquivo original pode ser recuperado a partir do arquivo comprimido na forma idntica ao original; ou {lossy compression}, ";
   $tip11 .= "na qual alguma informao do arquivo original  perdida, e a descompresso resulta em um arquivo ";
   $tip11 .= "levemente differente do arquivo original.\" [PJC - Stardict]\n";
   $tip11 .= "Lossless: Livre de perdas.\n";
   $tip11 .= "\nExamplos de audio com {lossless compression}: ape e flac.\n";
   $tip11 .= "Examplos de audio com {lossy compression}: mp3, mp4, mpc e ogg.\n";
   $tip11 .= "Examplo de audio sem compresso: wav.\n";
   $tip12  = "Depois do processo de normalizao, os arquivos temporrios wav sero removidos/apagados.";
   $tip13  = "Usar o novo Gtk2::FileChooser ou o antigo Gtk2::FileSelection quando um arquivo for selecionado.";
   $tip14  = "Modificar o gerenciamento de prioridade na execuo dos comandos. Seu valor varia de 0 (maior prioridade) at 19 (menor prioridade)."; 
   $tip15  = "Depois de normalizar os arquivos, voc pode alterar suas propriedades determinando o tipo de codificao, ";
   $tip15 .= "o bitrate de todos os arquivos de sada, etc. Caso contrrio, o bitrate de cada arquivo de entrada e ";
   $tip15 .= "outras propriedades sero conservados na medida do possvel.";
   $tip16  = "Formato para o nome final do arquivo, usado apenas para ripar/extrair arquivos do CD de audio:\n";
   $tip16 .= "   %a - artista\n";
   $tip16 .= "   %b - album\n";
   $tip16 .= "   %t  - ttulo da msica\n";
   $tip16 .= "   %n - nmero da faixa\n";
   $tip16 .= "   %y - ano\n";
   $tip16 .= "   %g - gnero";
   $tip17  = "O arquivo normalizado ser salvo no mesmo diretrio da entrada e ocorrer sobrescrio (salvar por cima) se existir outro arquivo de mesmo nome."; 
   $tip18  = "Coloque aqui linha de comando adicional usada para codificar os arquivos $file_output.";  
   $tip19  = "Choose your language (you need restart the gnormalize):\n   1 : english\n   2 : portugus (Brasil)\n";
   $tip19 .= "Escolha o seu idioma (voc precisa reiniciar o gnormalize).";
   $tip20  = "Fonte aconselhada: Sans 10.";
   
   $tip21  = "Carregar informaes para o CD de audio em seu drive a partir do servidor CDDB \"$CDDB_server\" ou do arquivo copiado em $home/.cddd/.";
   $tip22  = "Sempre buscar informaes do servidor CDDB e sobrescrever o arquivo salvado/copiado em $home/.cddd/ .";
   $tip23  = "Alguns servidores:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880";
   $tip24  = "Escolha o nmero da porta.";
   $tip25  = "Desativar toda a verificao e correo de erros na leitura de dados. Consequentemente a extrao  mais rpida. ";
   $tip25 .= "Esta opo tambm implica em (opo -Y) ativa. Veja cdparanoia (opo -Z).";
   $tip26  = "No aceita nenhuma omisso na leitura dos dados; ler indefinidamente se necessrio. Veja cdparanoia (opo -z).";
   $tip27  = "Desativa a verificao interna dos dados; apenas cobre e verifica a regio das fronteiras. No  recomendado. Veja cdparanoia (opo -Y).";
   $tip28  = "Se a leitura pula/salta devido a dados imperfeitos, arranhes, etc., abandonar a leitura desta faixa do CD. Veja cdparanoia (opo -X).";
   $tip29  = "Usar, para a leitura do CD, a biblioteca do paranoia ao invs das rotinas do cdda2wav. Veja cdda2wav (opo -paranoia).";   
   $tip30  = "Desativar o modo paranoia. Mas, paranoia ainda assim ser usado. Veja cdda2wav (opo -paraopts=help).";
   
   $tip31  = "Desativa a verificao, mas habilita a leitura sobreposta da regio das fronteiras.";
   $tip32  = "Escolha o valor do bitrate mdio. Ajusta o codificador/encoder a este valor o mas prximo possvel (in Kb/s). ";
   $tip32 .= "Bitrate  a taxa de bits utilizada no arquivo por unidade de tempo.";
   $tip33  = "Ajusta a qualidade do mp3; 9  a pior qualidade, 0  a melhor qualidade com mais Kb/s usado. Veja: man lame (opo: -V).";
   $tip34  = "Ajusta a qualidade do ogg; 10  a melhor qualidade com mais Kb/s usado, -1  a pior qualidade. Veja: man oggenc.";
   $tip35  = "Ajusta a qualidade do codificador lame para os arquivos mp3: 0  a melhor qualidade com a mxima iterao no processo algortmo; ";
   $tip35 .= "9  a pior qualidade, contudo muito mais rpido. Veja: man lame (opo: -q).";
   $tip36  = "Ajusta a qualidade do varivel bitrate (VBR) em porcentagem para o formato mp4; 500  a melhor ";
   $tip36 .= "qualidade com mais Kb/s usado; 10  a pior qualidade. Veja: <faac --help>.";
   $tip37  = "Ajusta a qualidade de codificao para os arquivos mpc usando um conjunto de rotinas (profiles); ";
   $tip37 .= "8 (braindead)  a melhor qualidade com mais Kb/s usado, 2 (telephone)  a pior qualidade. Veja: <mppenc --longhelp>.\n";
   $tip37 .= " q=2 --telephone - pior qualidade,           (32... 48 kbps)\n";
   $tip37 .= " q=3 --thumb     - baixa qualidade/internet, (58... 86 kbps)\n";
   $tip37 .= " q=4 --radio     - qualidade mdia (MP3),    (112...152 kbps)\n";
   $tip37 .= " q=5 --standard  - qualidade alta (padro),  (142...184 kbps)\n";
   $tip37 .= " q=6 --xtreme    - qualidade muito alta, (168...212 kbps)\n";
   $tip37 .= " q=7 --insane    - qualidade muito alta, (232...268 kbps)\n";
   $tip37 .= " q=8 --braindead - qualidade altssima,         (232...278 kbps)";
   $tip38  = "Nvel de Compresso:\n  fast (rpida): 1000\n  normal: 2000\n  high (alta): 3000\n  extra high: 4000\n  insane: 5000\n";
   $tip38 .= "\nMaior nvel de compresso resulta \nem arquivos menores.\nVeja o comando: mac";
   $tip39  = "Nvel de Compresso:\n  fast (rpida): 0\n  normal: 5\n  best (mxima): 8\nVeja <man flac>.";
   $tip40  = "Nmero da msica.";
   $tip41  = "Nmero total de msicas.";
   $tip42  = "Tente /dev/cdrom, /dev/dvd, /dev/hdc ou ...";   
   $tip43  = "Atualiza o drive do cdrom e apaga a lista de msicas.";
   $tip44  = "Selecionar nenhuma msica.";
   $tip45  = "Selecionar todas as msicas.";
   $tip46  = "Mostrar a animao do Tux e de outros pingins.";
   $tip47  = "Depois de normalizar, o formato de sada ser wav. Esta opo  conveniente para gravar um cd de audio a partir dos arquivos wav.";
   $tip48  = "Se houver mais de um artista, use:\nArtista1 & Artista2 & Artista3 & ...";
   $tip49  = "Exibir a barra de progresso.";
   $tip50  = "Omitir a barra de progresso.";
   $tip51  = "Exibir as linhas de comando e outras informaes.";
   $tip52  = "Omitir as linhas de comando e outras informaes.";
   $tip53  = "Sair.";
   $tip54  = "Apagar todas as mensagens.";
   $tip55  = "Fechar a configurao do gnormalize player.";
   
   $msg1  = "Arquivos suportados dentro do diretrio (recursivamente):\n";
   $msg2  = "Arquivos suportados dentro do diretrio (no recursivamente):\n";   
   $msg3  = " Escolha um arquivo mp3/mp4/mpc/ogg/ape/flac/wav/cda para normalizar!";
   $msg4  = " Dependncia no satisfeita!";
   $msg5  = " Escolha arquivos com a extenso mp3, mp4, mpc, ogg, ape, flac ou wav!";
   $msg6  = " No pode escolher o formato mp3! lame no encontrado.";
   $msg7  = " No pode escolher o formato mp4! faad no encontrado.";
   $msg8  = " No pode escolher o formato ogg! oggdec no encontrado.";
   $msg9  = " No pode escolher o formato mpc! mppdec no encontrado.";
   $msg10 = " No pode escolher o formato ape! mac no encontrado.";
   $msg11 = " No pode escolher o formato flac! flac no encontrado.";
   $msg12 = ": apenas para leitura!";
   $msg13 = " Selecione ao menos uma msica para ripar/extrair!";
   $msg14 = " Sucesso! Extrao finalizada.";
   $msg15 = " Extrao interrompida!";    
   $msg16 = " Sucesso!";       
   $msg17 = " Sucesso! Arquivo convertido.";
   $msg18 = " Sucesso! Arquivo normalizado.";
   $msg19 = "Interromper a extrao";
   $msg20 = " Informao obtida de ";
   $msg21 = " Favor esperar. cdparanoia est lendo o cdrom ...";
   $msg22 = " Favor, selecione pelo menos uma msica para tocar.";
   
   $msg23 = "No encontrado \"";
   $msg24 = "\" nos diretrios executveis.";
   $msg25 = "O formato de sada no pode ser \"mp3\".";
   $msg26 = "O formato de sada no pode ser \"ogg\".";
   $msg27 = "O formato de sada no pode ser \"mpc\".";
   $msg28 = "O formato de sada no pode ser \"ape\".";
   $msg29 = "O formato de sada no pode ser \"flac\".";
   $msg30 = "O formato de sada no pode ser \"mp4\".";
   $msg31 = "O arquivo wav no pode ser normalizado.";
   $msg32 = "O formato de entrada no poder ser \"ogg\".";
   $msg33 = "O formato de entrada no poder ser \"mpc\".";
   $msg34 = "O formato de entrada no poder ser \"mp4\".";
   $msg35 = "cdcd  um tocador de CD em linha de comando.";
   $msg36 = "\nPrimeiro execute \"cdcd\" em linha de comando para gerar o arquivo de configurao .cdcdrc\n";
   $msg37 = "Escolha \"n\" para a questo:  Are you connected to a network (y/n) [y]?\n";
   $msg38 = "No pode ser usado o mdulo perl \"";
   $msg39 = "CD de audio no poder ser tocado.";
   $msg40  = "gnormalize  um utilitrio do normalize, um ripper/extrator, um codificador, um conversor de audio, um editor de ";
   $msg40 .= "metadados (tag) e um tocador de audio. Ele decodifica os arquivos para WAV, em seguida normaliza e recodifica-os. ";
   $msg40 .= "gnormalize suporta converso entre os formatos de audio MP3, MP4, MPC, OGG, APE, FLAC e WAV.";
   $msg41  = "Este arquivo no ser normalizado!";
   $msg42 = " de acordo com a insensibilidade, no normalizar ";
   $msg43 = "No normalizar pois o ajuste ";
   $msg44 = "  menor que o valor da insensibilidade.\n";
   $msg45 = " no normalizar ";
   $msg46 = " no necessita codificar/encodar ";
   $msg47 = " j normalizado ";
   $msg48 = "Este arquivo j est normalizado.\n";
   $msg49 = " Interromper a normalizao!";
   $msg50 = "Aplicando ajuste de ";
   $msg51 = " normalizando: ajuste de ";
   $msg52 = "Calculando o ajuste ...";
   $msg53 = " normalizado com ajuste de ";
   $msg54 = " extraindo audio para wav";
   $msg55 = " Interrompendo a extrao!";
   $msg56 = "cpia realizada.";
   $msg57 = " Parar decodificao lame!";
   $msg58 = " Parar codificao lame!";   
   $msg59 = "Salvar alteraes do tag.";
   $msg60 = "Salvar alteraes do tag no diretrio $home/.cddb .";
   $msg61 = " Estas informaes sero salvas no arquivo normalizado.";      
   $msg62 = " tag alterado.";
   $msg63 = "Selecione um arquivo mp3/mp4/mpc/ogg/ape/flac/wav .";
   $msg64 = "\nHomepage: $HOMEPAGE\nEste software est disponvel sob a GNU General Public Licence.";
   $msg65 = " sada: ";
   $msg66 = "selecionado - info pode ser editado.";
   $msg67 = " No foi possvel ler o cdrom no drive ";
   $msg68 = " Obtendo informao do cddb ...";
   $msg69 = " nenhuma informao do cddb.";
   $msg70 = " Pressione o boto Save (Salvar) em \"info\" para salvar as alteraes.";
   $msg71 = " No conectado, usando ";
   $msg72 = " cddb: no pode conectar  internet!";
   $msg73 = " No pode extrair CD de audio! cdparanoia no encontrado.";
   $msg74 = " No pode extrair CD de audio! cdda2wav no encontrado.";
   $msg75 = "Selecione um arquivo mp3, mp4, mpc, ogg, ape, flac, ou wav.";
   $msg76 = "Selecione um diretrio ou um arquivo suportado.";
   $msg77 = "ajustes";
   $msg78 = "Arquivo selecionado";
   $msg79 = "\nVerso mnima recomendada:\n";
   $msg80 = " Opo Invlida!";
   $msg81 = " Pressione o boto \"Atualizar o cdrom\" e digite novamente as alteraes.";
   $msg82 = "\n Nenhuma informao do cddb, instale o perl mdulo \"CDDB_get\".";  
   $msg83 = "\n Nenhuma informao dos arquivos mp3, instale o perl mdulo \"MP3::Info\".";
   $msg84  = "\ngnormalize  um utilitrio do normalize, um ripper/extrator, um codificador, um conversor de audio, ";
   $msg84 .= "um editor de metadados (tag) e um tocador de audio.";
   $msg85 = "\ngnormalize decodifica os arquivos para WAV, em seguida normaliza e recodifica-os. ";
   $msg85 .= "gnormalize suporta converso entre os formatos de audio MP3, MP4, MPC, OGG, APE, FLAC e WAV.";   
   $msg86 = "Diretrio selecionado (recursivamente)";   
   $msg87 = "Selecione um diretrio contendo arquivo mp3, mp4, mpc, ogg, ape, flac, ou wav.";
   $msg88 = "Diretrio selecionado (no recursivamente):";
   $msg89 = "Removendo arquivo temporrio";
   $msg90 = "Nenhum arquivo suportado foi encontrado dentro do diretrio!";
   $msg91 = "Escolha o diretrio onde todos os arquivos sero copiados.";
   $msg92 = "remove esta msica da lista";
}


#############----------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 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("data");
$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("config");
$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("info");
$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("rip");
$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 about notebook icon	 
my $label_about = Gtk2::Label->new("about");
$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 ( $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("normalize: 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
#nesta table1 teremos 3 notaes.
#$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($name5);
$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, 3, 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($name6);
$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, 4, 0); 
$table12->set_border_width (4);
$table12->set_row_spacings(6);
$table12->set_col_spacings(2);
$frame12->add( $table12 );
$table12->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
my $notebook2 = Gtk2::Notebook->new; 
# position = 'left', 'right','top', 'bottom'
$notebook2->set( homogeneous => $true  ); # 'tab-hborder' => 20
$notebook2->set_tab_pos( 'left' );

my $label_option1 = Gtk2::Label->new("option1");
my $label_option2 = Gtk2::Label->new("option2");
my $label_cddb = Gtk2::Label->new("cddb");
my $label_ripper = Gtk2::Label->new("ripper");
#$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 ".$msg77 );
$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("file 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;
use constant COLUMN_FILE       => 1;
use constant COLUMN_ARTIST     => 2;
use constant COLUMN_TITLE      => 3;
use constant COLUMN_ALBUM      => 4;
use constant COLUMN_TRACK      => 5; # this is the column 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_FILENAME   => 11;
use constant COLUMN_EXTENSION  => 12;
use constant COLUMN_COLOR      => 13; # 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
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
$treeview_play->get_selection->set_mode ('multiple'); # single,multiple
$treeview_play->get_selection->signal_connect (changed => \&selection_tree);
$treeview_play->signal_connect (button_press_event => \&button_press_event_treeview);
$treeview_play->set_reorderable ($false);
$treeview_play->set_search_column (COLUMN_ARTIST);
$treeview_play->set_enable_search($true);
$treeview_play->show;

$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
		});										
	 
# 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_track = 1;
	 
   # 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   => $i + 1,
	                 track  => $i + 1,
			 artist => "artist",
			 title  => "music title",			 	                 			 
			 album  => "album",
			 comment     => "comment",	  	                 
			 year        => "year",
			 total_track => "total_track",
			 genre       => "genre",
			 length      => "$array[$i]",			 
			 filepath    => "$num".".cda",
			 filename    => "$num".".cda",
			 bitrate     => "1411",
		      #  fileSize    => $audio_cd_fileSize;
			 frequency   => "44100",		 
			 extension   => "cda",
			 editable    => $true,
			 show        => $true,
			 remove      => $false, #remove from playlist
			 playing     => $false,
			 played      => $false,
      };      
   }
   my $model = create_standard_model(@files_info);
   return $model;
}

sub create_model_files_to_be_played {  # add more file to @files_info(); player mode
   
   if ( not defined $files_info[0]{artist} ){ @files_info = (); }      
   #print "--->  n = ",$#files_info + 1,"\n";
   my $music_number = $#files_info + 1;  # original size
   
   my $j = 0;      
   for (my $i = 0; $i <= $#array_of_files;$i++){  # ($#array_of_files + 1) or @array is the size	     	     
      
      determine_file_input_and_directory($array_of_files[$i]);
      
      if    ($file_input eq 'mp3'  and not $mpg123_path and not $mpg321_path and not $madplay_path and not $mplayer_path ){ next; }  # mp3 files can't be played!
      elsif ($file_input eq 'mp4'  and not $mplayer_path ){ next; }   # "MP4 files can't be played!"
      elsif ($file_input eq 'mpc'  and not $mpcdec_path  ){ next; }   # "MPC files can't be played!"
      elsif ($file_input eq 'ogg'  and not $ogg123_path  ){ next; }   # "OGG files can't be played!"
      elsif ($file_input eq 'flac' and not $mplayer_path and not $flac123_path ){ next; }   # "FLAC files can't be played!"
      elsif ($file_input eq 'wav'  and not $mplayer_path ){ next; }   # "WAV files can't be played!"      
      elsif ($file_input eq 'ape'  and not $ape_path and not $play_path ){ next; } # "APE files can't be played!"      
      else  { $j += 1; }      
               
      get_info_from_file();   # refresh mp3/mp4/mpc/... info
      (my $filename = $array_of_files[$i]) =~ s/(.*\/)//g;                # copy and remove (path)/
      
      if ( $check_button_fchooser->get_active and $button_dir->get_active ){ # use the new Gtk2::FileChooser      
         my $percentage = number_value( sprintf("%.2f", ( $i/($#array_of_files + 1) ) ) );                                   
	  
         $progbar_files_info->set_text( reduce_length_size($filename, 100) );  # Gtk2::ProgressBar to show file info
         $progbar_files_info->set_fraction ($percentage);
         #printf "Percentage = $percentage ; filename = $filename\n";
      }
      
      while (Gtk2->events_pending) {Gtk2->main_iteration};
      #print " \$array_of_files[$i] = $array_of_files[$i-1] ; Album = $Album \n";
      	         
      # making array of array references - see <man perllol> 
      push @files_info, { 
                          rip    => $true,
	                  file   => $j + $music_number,
			  track  => $Track_Number,
			  artist => $Artist,
			  title  => $Title,
			  album  => $Album,			  
			  comment      => $Comment,	  	                 
			  year         => $Year,
			  total_track  => $Total_Track,
			  genre        => $Genre,
			  length       => $Time_Min_Sec,
	                  filepath     => $array_of_files[$i],
			  filename     => $filename,
			  bitrate      => $bitrate_original,
			  fileSize     => $fileSize,
			  frequency    => $Frequency,
			  extension    => $file_input,
			  editable     => $true,
			  show         => $true,
			  remove       => $false, #remove from playlist
			  playing      => $false,
			  played       => $false,
                        };

   } # for - final     
   my $model = create_standard_model(@files_info);
   return $model;	
}

sub create_standard_model {  # add more file to @files_info(); player mode
   my @array = @_;
   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
				     'Glib::String',                 # filename
				     'Gtk2::Gdk::Color',             # to select one color
				    );
   # append more data to the list store            
   foreach my $d (@array) {          # print "\$d->{file} = $d->{file} ; \$d->{rip} = $d->{rip}\n"; 
      next if ($d->{remove});
      my $iter = $model->append;
      $model->set ($iter,
		     COLUMN_RIP,       $d->{rip},  # rip or play
		     COLUMN_FILE,      $d->{file}, # file number
                     COLUMN_TRACK,     $d->{track},
		     COLUMN_ARTIST,    $d->{artist},
	             COLUMN_TITLE,     $d->{title},
		     COLUMN_ALBUM,     $d->{album},
	             COLUMN_LENGTH,    $d->{length},		   	
		     COLUMN_BITRATE,   $d->{bitrate},		   
		     COLUMN_YEAR,      $d->{year},		   	
		     COLUMN_FREQUENCY, $d->{frequency},		   	
                     COLUMN_FILEPATH,  $d->{filepath},
		     COLUMN_FILENAME,  $d->{filename},
		     COLUMN_EXTENSION, $d->{extension},
		     COLUMN_COLOR,     $d->{playing} ? $color_row_playing : 
		                       $d->{played}  ? $color_row_already_played : undef, # undef: without color; this column is hidden
                  );
   }
   #print "-->  array num = ",$#array + 1," ; file_info num = ",$#files_info + 1,"\n"; 
   return $model;	
}

my $treeview_artist; my $column_artist_playlist; my $column_album_playlist;

###-------------- 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
#$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->set_reorderable ($false);
$treeview_album->show;	 
# add tree view to the ScrolledWindow
$scrolled_window_album->add ($treeview_album);

# album column
my $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 ($name53, $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);

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

#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
# Perls sort function is O(N*logN) efficiency order.
sub all_albuns {  # search for all differents albums "efficiently". Eficincia: uso racional do recursos, cpu, processamento.
   my @array_of_hash = @_;  # @files_info
   if ( not defined $array_of_hash[0]{album} ){ return; }
   
   my %seen = ();  # hash ; save all differents albuns indicating the total songs inside each album 	   
   my @temp = map  { album => $_ , played => $albums_already_played{uc($_)} }, # set 'played' to False if $albums_already_played{uc($_)} is undef
              sort { uc($a) cmp uc($b) }     # sort the album name; all elements are already differents
              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_albuns = ( { album => 'All' , played => 0 } );  # 'All' is Always the first element
   push @all_albuns, @temp;
   
   #foreach my $alb (@all_albuns) { print "\$alb->{album} = $alb->{album}\n";  }         
   return @all_albuns;
}

sub return_album_name{ 
   my $hash = shift;
   my $album = $hash->{album};
   if ($album eq ""){                                                      # if 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 track selected
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;  # 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{uc($album)}++;  # Set True to the album name;  See 'Programming Perl', 24.2, 3a. Ed, "Efficiency"
   }
   #foreach my $alb (keys %albums) { print "albuns = $alb\n"; }  
   my @artist_in_the_album = ();      
  
   LOOP:for (my $i = 0; $i <= $#files_info; $i++){      
      next if $files_info[$i]->{remove};            
      my $album_guess = return_album_name($files_info[$i]);    # if no album name, create a guess name from filepath

      if ( $albums{uc($album_guess)} or $albums{uc('All')} ){  # Search for all artists inside this album	 
         push @artist_in_the_album, $files_info[$i];
	 #( my $music = $files_info[$i]->{filepath} ) =~ s/(.*\/)//g; print "musics = $music\n";
	 next LOOP; 	          
      }
   }     
   return if (@artist_in_the_album <= 0);
   
   # add new files to tree model   
   $model = create_standard_model(@artist_in_the_album);    # make a new treeview_play model
   $treeview_play->set_model($model);   # add the new model
   $treeview_play->columns_autosize;
   
   make_artist_and_album_treeview_column( $true, $false, @artist_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 ( $make_artist_column, $make_album_column, @all_treeview_info ) = @_;	      
   my ( $new_title, $model );
    
   if ( $make_artist_column ){   
      my @all_dif_artist = all_artist( @all_treeview_info );  # search for all differents artists
      $model = create_standard_model( @all_dif_artist );
      $treeview_artist->set_model($model);                    # add the new model
      $new_title = @all_dif_artist > 0 ? $name46 ." ($#all_dif_artist)" : $name46 ;
      $column_artist_playlist->set_title( $new_title );       # artist (number)
   }
   if ( $make_album_column ){    
      my @all_dif_album = all_albuns( @all_treeview_info );   # search for all differents albums
      $model = create_standard_model( @all_dif_album );
      $treeview_album->set_model($model);                     # add the new model
      $new_title = @all_dif_album > 0 ? $name53 ." ($#all_dif_album)" : $name53 ;
      $column_album_playlist->set_title( $new_title );        # album (number)
   }
} 


###---------------------- 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
#$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->set_reorderable ($false);
$treeview_artist->show;	 
# add tree view to the ScrolledWindow
$scrolled_window_artist->add ($treeview_artist);

# artist column
my $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 ($name46, $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);

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

#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_artist {  # search for all differents artists
   my @array_of_hash = @_;   
   if ( not defined $array_of_hash[0]{artist} ){ return; }
     
   my %seen = ();      
   my @temp = map  { artist => $_ , played => $artists_already_played{uc($_)} },
              sort { uc($a) cmp uc($b) }      # sort the album name; all elements are already differents
              grep { not $seen{uc($_)} ++ }   # Eliminate duplicate values from a list; Perl CookBook , Chap 4.7
	      map return_artist_name($_),     # map $_->{artist},
	      @array_of_hash;
		 
   my @all_artist = ( { artist => 'All', played => 0 } );  # 'All' is Always the first element
   push @all_artist, @temp;
   	      
   #foreach my $alb (@all_artist) { print "\$alb->{artist} = $alb->{artist}\n";  }        
   return @all_artist;
}

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 & ...' on '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;
   foreach my $path (@paths){
      my $iter = $model->get_iter($path);
      next unless $iter;
      my $artist = $model->get_value($iter,COLUMN_ARTIST);
      $artists{uc($artist)}++;  # See 'Programming Perl', 24.2, 3a. Ed, "Efficiency"
   }  
   my @album_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{uc($art)} or $artists{uc('All')} ){
	    push @album_with_artist, $files_info[$i];
	    next LOOP; # to not select the same files_info, not duplicate
         }
      }
   }     
   return if (@album_with_artist <= 0);        
   
   # add new files to tree model
   $model = create_standard_model(@album_with_artist);	
   $treeview_play->set_model($model); # add the new model
   $treeview_play->columns_autosize;

   make_artist_and_album_treeview_column( $false, $true, @album_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;  
                  
   my $menu = Gtk2::Menu->new;     
   my $item = Gtk2::ImageMenuItem->new("$msg92");   # "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--------------------###
# Adicionamos este frame5 em vbox6 (vbox6 est dentro do notebook)
my $frame5 = new Gtk2::Frame();
# Set the frame's label
# Align the label at the right of the frame
$frame5->set_label_align( 1.0, 0.0 );
# Set the style of the frame
$frame5->set_shadow_type( 'etched_out' );
# $vbox->pack_start( $child, $expand, $fill, $padding ); 
$vbox6->pack_start( $frame5, $true, $true, 0 );  
#$vbox6->add($frame5);
$frame5->show();

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

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

# we put this $frame_normalize inside the vbox_up
# Adicionamos este $frame_normalize em vbox_up ;; Este frame contm o boto 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 contm 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 contm 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 - rtulo) ao lado do menu
$label = new Gtk2::Label( $name1 );
$label->set_alignment( 1.0, 0.5 );  # right   
$table1->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0);
$label->show();

#####------------Option-Menu-------------------#####

# see range at gtkperl-tutorial
# see /usr/share/doc/perl-Gtk2-1.080/gtk-demo/menu.pl

#$widget = Gtk2::ComboBox->new_text; # if Gtk2 >= 2.4.0
#$widget->append_text ("Option 1");
#$widget->append_text ("Option 2");

my $menu = Gtk2::Menu->new;
#$menu->set_size_request( -1, -1 );
$menu->show;

my $item_fix = Gtk2::MenuItem->new( "Fix" );
$item_fix->signal_connect( "activate", \&tra , "Fix" );
$item_fix->show;
$menu->append( $item_fix );

my $item_p = Gtk2::MenuItem->new( "Peak" );
$item_p->signal_connect( "activate", \&tra , "Peak" );
$item_p->show;
$menu->append( $item_p );

my $item_mix = Gtk2::MenuItem->new( "Mix" );
$item_mix->signal_connect( "activate", \&tra, "Mix" );
$item_mix->show;
$menu->append( $item_mix );

my $item_none = Gtk2::MenuItem->new( "None" );
$item_none->signal_connect( "activate", \&tra, "None" );
$item_none->show;
$menu->append( $item_none );

my $opt_menu = Gtk2::OptionMenu->new; 
$opt_menu->set_menu( $menu );
$opt_menu->show;

$table1->attach ($opt_menu,  1, 2, 0, 1, 'fill', 'shrink', 0, 0);
 
sub tra
{  my ( $item, $t_name ) = @_; 
   if ($t_name eq "Fix" ) {$norm_type="Fix";  $spinner->set_sensitive($true );} 
   if ($t_name eq "Peak") {$norm_type="Peak"; $spinner->set_sensitive($false);}
   if ($t_name eq "Mix")  {$norm_type="Mix";  $spinner->set_sensitive($false);}
   if ($t_name eq "None") {$norm_type="None"; $spinner->set_sensitive($false);}
   return $norm_type;
}

#####------------ final of option_menu ----------#####

# 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( $volume_normalize, 1.0, 99.0, 1.0, 5.0, 0.0 );
#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits );
$spinner = new Gtk2::SpinButton( $adj, 0.2, 0 );
$spinner->set_wrap( $true );
$spinner->set_editable($false);
$spinner->set_update_policy( 'if_valid' );
$tooltips = new Gtk2::Tooltips();
$tooltips->set_tip( $spinner, $tip1 );
$align->add($spinner);
$spinner->show();

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

if ($norm_type eq "Fix")  { $opt_menu->set_history (0); $spinner->set_sensitive($true );} # 0 set to "Fix"
if ($norm_type eq "Peak") { $opt_menu->set_history (1); $spinner->set_sensitive($false);} 
if ($norm_type eq "Mix")  { $opt_menu->set_history (2); $spinner->set_sensitive($false);} 
if ($norm_type eq "None") { $opt_menu->set_history (3); $spinner->set_sensitive($false);} # 3 set to "None"

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

$label = new Gtk2::Label( $name2 );
$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, $tip2 );
$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( $name3 );
$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, $msg63 );
$entry_f->select_region( 0, length( $entry_f->get_text() ) );
$table1->attach_defaults ($entry_f, 1, 6, 1, 2 );
$entry_f->set_sensitive($true);
$entry_f->set('editable' => $false );
$entry_f->show();

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

$label = new Gtk2::Label( $name4 );
$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_d = new Gtk2::Entry( );
#$entry_d->set_max_length (100);

$directory = "$ENV{'PWD'}";   # inicializao da varivel
$directory =~ s/\/{1,}$//;    # remove the '/' character from final if it exists.
$directory_base = $directory; # used to make_directory_final()
   
$entry_d->set_text( "$directory" );
$tooltips->set_tip( $entry_d, "$directory");
$entry_d->select_region( 0, length( $entry_d->get_text() ) );
$table1->attach_defaults ($entry_d, 1, 5, 2, 3 );
$entry_d->set_sensitive($false);
$entry_d->set('editable' => $false );
$entry_d->show;

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

$tooltips->set_tip( $button, $msg76 );
$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( $name52 );
$label->set_alignment( 1.0, 0.5 );  # right   
$table1->attach ($label, 0, 1, 3, 4, 'fill', 'fill', 0, 0);
$label->show();

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

$button = Gtk2::Button->new;
$button->add( DrawIcons('gtk-go-down','button') );
$tooltips->set_tip( $button, $msg91 );
$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;  
}

################------Input--------##################
#######------------radiobutton--------------#########

# veja:   man perlnumber  ou perlop ou man overload

# criar um label vazio
$label = new Gtk2::Label( "   " );
$label->set_alignment( 1.0, 0.5 );  # right 
$table11->attach ($label, 0, 1, 0, 1, 'fill', 'fill', 0, 0);
$label->show();

$button_file = new Gtk2::RadioButton(  undef , $name7 );
$tooltips->set_tip( $button_file, $tip3 );
# $button_file->set_active( $true );  #padro - ativo
$table11->attach_defaults($button_file, 1, 2, 0, 1);
$button_file->signal_connect( "toggled", \&Dir_File );
$button_file->show;

$button_dir = new Gtk2::RadioButton( $button_file, $name54 );
$tooltips->set_tip( $button_dir, $tip4 );
$table11->attach_defaults($button_dir, 1, 2, 1, 2);
$button_dir->signal_connect( "toggled", \&Dir_File );
$button_dir->show;  

sub Dir_File {
#dependendo se os botes Directory ou File estiverem ativos, teremos estas opes.
       # SWITCH: { # see  man perlsyn
            if ($button_dir->get_active) {
			  #print( "Choose: Directory\n" );
			  $entry_f->set_sensitive($false);
			  $entry_d->set_sensitive($true);
			  $check_button_recursively->set_sensitive($true);
			  $input = "Directory";
	    }
	    if ($button_file->get_active) { 
                          #print( "Choose: File\n" );
			  $entry_f->set_sensitive($true);
			  $entry_d->set_sensitive($false);
			  $check_button_recursively->set_sensitive($false);
			  $input = "File";
	    }       	  		  
}

$check_button_recursively = Gtk2::CheckButton->new ( $name8 );
$check_button_recursively->set_active($recursively);
$tooltips->set_tip( $check_button_recursively, $tip5 );
#$check_button_del_wav->set_alignment (6,0);
$table11->attach_defaults($check_button_recursively, 2, 3, 1, 2);
$check_button_recursively->show;

if ($input eq "File"){ $button_file->set_active($true);}
elsif ($input eq "Directory"){ $button_dir->set_active($true);}
Dir_File();

################-----Output--------##################
#######------------radiobutton--------------#########

# veja:   man perlnumber  ou perlop ou man overload

my $button_output_mp3 = new Gtk2::RadioButton(  undef , "mp3");
$tooltips->set_tip( $button_output_mp3, $tip6 );
$table12->attach_defaults($button_output_mp3, 0, 1, 0, 1);
$button_output_mp3->signal_connect( "clicked", \&refresh_progress_bar_names );
$button_output_mp3->show;   

my $button_output_mp4 = new Gtk2::RadioButton( $button_output_mp3, "mp4");
$tooltips->set_tip( $button_output_mp4, $tip7 );
$table12->attach_defaults($button_output_mp4, 1, 2, 0, 1);
$button_output_mp4->signal_connect( "clicked", \&refresh_progress_bar_names );
$button_output_mp4->show;

my $button_output_mpc = new Gtk2::RadioButton( $button_output_mp3, "mpc");
$tooltips->set_tip( $button_output_mpc, $tip8 );
$table12->attach_defaults($button_output_mpc, 2, 3, 0, 1);
$button_output_mpc->signal_connect( "clicked", \&refresh_progress_bar_names );
$button_output_mpc->show;

my $button_output_ogg = new Gtk2::RadioButton( $button_output_mp3, "ogg");
$tooltips->set_tip( $button_output_ogg, $tip9 );
$table12->attach_defaults($button_output_ogg, 0, 1, 1, 2);
$button_output_ogg->signal_connect( "clicked", \&refresh_progress_bar_names );
$button_output_ogg->show;    

my $button_output_ape = new Gtk2::RadioButton( $button_output_mp3, "ape");
$tooltips->set_tip( $button_output_ape, $tip10 );
$table12->attach_defaults($button_output_ape, 1, 2, 1, 2);
$button_output_ape->signal_connect( "clicked", \&refresh_progress_bar_names );
$button_output_ape->show;  

my $button_output_flac = new Gtk2::RadioButton( $button_output_mp3, "flac");
$tooltips->set_tip( $button_output_flac, $tip11 );
$table12->attach_defaults($button_output_flac, 2, 3, 1, 2);
$button_output_flac->signal_connect( "clicked", \&refresh_progress_bar_names );
$button_output_flac->show; 

my $button_output_wav = new Gtk2::RadioButton( $button_output_mp3, "wav");
$tooltips->set_tip( $button_output_wav, $tip47 );
$table12->attach_defaults($button_output_wav, 3, 4, 1, 2);
$button_output_wav->signal_connect( "clicked", \&refresh_progress_bar_names );
$button_output_wav->show; 

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

$check_button_del_wav = Gtk2::CheckButton->new ( $name9 );
$check_button_del_wav->set_active($delete_wave);
$tooltips->set_tip( $check_button_del_wav, $tip12 );
#$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_fchooser = Gtk2::CheckButton->new ("file chooser");
$check_button_fchooser->set_active($new_file_chooser);
$tooltips->set_tip( $check_button_fchooser, $tip13 );
$table2->attach($check_button_fchooser,  1, 2, 0, 1, 'fill', 'shrink', 0, 0);
$check_button_fchooser->show;

$label = new Gtk2::Label( $name12 );
$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, $tip14 );
$table2->attach($spinner_pri,  3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$spinner_pri->show();

$check_button_change = Gtk2::CheckButton->new ($name10);
$check_button_change->set_active($change_properties);
$check_button_change->signal_connect( "clicked", \&encode_choice_sensitive );
$tooltips->set_tip( $check_button_change, $tip15 );
$table2->attach($check_button_change,  0, 1, 1, 2, 'fill', 'fill', 0, 0);
$check_button_change->show;

$label = new Gtk2::Label( $name14 );
$label->set_alignment( 1.0, 0.5 ); 
$table2->attach ($label, 1, 2, 1, 2, 'fill', '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, $tip16 );
$table2->attach($entry_format_cda,  2, 4, 1, 2, ['fill','expand'], 'fill', 0, 0);
$entry_format_cda->show;

$check_button_overwrite = Gtk2::CheckButton->new ($name11);
$check_button_overwrite->set_active($overwrite);
$tooltips->set_tip( $check_button_overwrite, $tip17 );
$table2->attach($check_button_overwrite,  0, 1, 2, 3, 'fill', 'fill', 0, 0);
$check_button_overwrite->show;

$label = new Gtk2::Label( $name13 );
$label->set_alignment( 1.0, 0.5 ); 
$table2->attach ($label, 1, 2, 2, 3, '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, $tip18 );
$table2->attach($entry_command_mp3,  2, 4, 2, 3, ['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, $tip18 );
$table2->attach($entry_command_mp4,  2, 4, 2, 3, ['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, $tip18 );
$table2->attach($entry_command_mpc,  2, 4, 2, 3, ['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, $tip18 );
$table2->attach($entry_command_ogg,  2, 4, 2, 3, ['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, $tip18 );
$table2->attach($entry_command_ape,  2, 4, 2, 3, ['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, $tip18 );
$table2->attach($entry_command_flac,  2, 4, 2, 3, ['fill','expand'], 'fill', 0, 0);

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

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

# criar um label (etiqueta - rtulo) ao lado do menu
$label = new Gtk2::Label( $name15 );
$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");

$combo_char = Gtk2::Combo->new;
$combo_char->set_popdown_strings ( @all_encodings );
$combo_char->entry->set_text($character); #standard value
$combo_char->entry->set_editable ($false);
$combo_char->entry->signal_connect("changed", \&char_choice, $combo_char);
$table202->attach($combo_char,  1, 2, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$combo_char->show();

## choice of table of character
sub char_choice
{
	my ($widget,$comboCopy) = @_;
        my $entry=$comboCopy->entry->get_text();
	if ( $entry ne ""){ 
	    $character = $entry;
	    #print (" char = $character\n");
	}
}
#####-------------------final of Combo-------------#####

$check_button_animation = Gtk2::CheckButton->new ( $name55 );
$check_button_animation->set_active($show_tux_animation);
$check_button_animation->signal_connect( "clicked", \&tux_animation_textview );
$tooltips->set_tip( $check_button_animation, $tip46 );
$table202->attach($check_button_animation, 3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$check_button_animation->show;

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

$label = new Gtk2::Label( $name29 );
$label->set_alignment( 1.0, 0.5 );  
$table202->attach ($label, 0, 1, 1, 2, 'fill', 'shrink', 0, 0);
$label->show;

$combo_rip = Gtk2::Combo->new;
$combo_rip->set_popdown_strings ( "cdparanoia", "cdda2wav" );
$combo_rip->entry->set_text( "$ripper" ); #standard value
$combo_rip->entry->set_editable($false); 
$combo_rip->entry->signal_connect("changed", \&ripperChanged, $combo_rip);
$table202->attach ($combo_rip, 1, 2, 1, 2, ['fill','expand'], 'shrink', 0, 0);
$combo_rip->show();

## audio mp3 bitrate is changed
sub ripperChanged
{
	my ($widget,$comboCopy) = @_;
        my $entry=$comboCopy->entry->get_text();
	if ( $entry eq ""){ return; }
	$ripper = $entry; # copy the value of bitrate changed
	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( $name16 );
$label->set_alignment( 1.0, 0.5 );  
$table202->attach ($label, 2, 3, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$label->show;

$adj = new Gtk2::Adjustment( $language, 1, 2, 1, 0, 0 );
$spinner_lang = new Gtk2::SpinButton( $adj, 0.1, 0 );
$spinner_lang->set_editable($false);
$spinner_lang->set_size_request( 92, -1 );
$spinner_lang->set_update_policy( 'if_valid' );
$spinner_lang->set_wrap( $true );
$tooltips->set_tip( $spinner_lang, $tip19 );
$table202->attach ($spinner_lang, 3, 4, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$spinner_lang->show();

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

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

$label = new Gtk2::Label( "cd player:" );
$label->set_alignment( 1.0, 0.5 );  
$table202->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0);
$label->show;

$combo_cdplayer = Gtk2::Combo->new;
# See the cdplayer_available() subroutine to search the cdplayer
#$combo_cdplayer->set_popdown_strings ( @all_cdplayer );
#$combo_cdplayer->entry->set_text( "$cdplayer" ); #standard value
$combo_cdplayer->entry->set_editable($false); 
#$combo_cdplayer->entry->signal_connect("changed", \&cdplayerChanged, $combo_cdplayer);
$table202->attach ($combo_cdplayer, 1, 2, 2, 3, ['expand','fill'], 'shrink', 0, 0);
$combo_cdplayer->show();

sub cdplayerChanged {  ## choose cdplayer
   my ($widget,$comboCopy) = @_;
   my $entry=$comboCopy->entry->get_text;
   if ( $entry eq "" ){ return; }
   
   #$cdplayer = "gnormalize::cdplay", "Audio::CD", "cdcd", "none"
   $cdplayer = $entry;
   #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 - rtulo) ao lado do menu
$label = new Gtk2::Label( $name17 );
$label->set_alignment( 1.0, 0.5 );  
$table202->attach ($label, 2, 3, 2, 3, '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, 2, 3, ['expand','fill'], 'shrink', 0, 0);
$tooltips->set_tip( $button_font, $tip20 );
$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);  
  $renderer_artist->set ('font' => $font_name, style => 'italic', scale => '0.9');
  $renderer_title->set  ('font' => $font_name, style => 'italic', scale => '0.9');
  
  # TreeViewColumn : treeview_album
  $renderer_album_playlist->set ('font' => $font_name, style => 'italic', scale => '0.9');
  # TreeViewColumn : treeview_artist
  $renderer_artist_playlist->set ('font' => $font_name, style => 'italic', scale => '0.9');  

  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)/i ){ 
              $child->modify_font($font_desc); 
              return $false; 
   }
   return $true;
}

sub gnome_font { # not more used
   exec_cmd_system("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 ( $name18 );
$check_button_cddb->set_active($discDB);
$check_button_cddb->signal_connect( "clicked", \&cddb_sensitive );
$tooltips->set_tip( $check_button_cddb, $tip21 );
$table203->attach($check_button_cddb,  0, 1, 0, 1, 'fill', 'shrink', 0, 0);
$check_button_cddb->show;

$check_button_overwrite_cddb = Gtk2::CheckButton->new ( $name19 );
$check_button_overwrite_cddb->set_active($overwrite_cddb);
$tooltips->set_tip( $check_button_overwrite_cddb, $tip22 );
$table203->attach($check_button_overwrite_cddb,  1, 2, 0, 1, 'fill', 'shrink', 0, 0);
$check_button_overwrite_cddb->show;

$label = new Gtk2::Label( $name20 );
$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, $tip23 );
$table203->attach($entry_CDDB_server,  1, 2, 1, 2, ['fill','expand'], 'fill', 0, 0);
$entry_CDDB_server->show;

$label = new Gtk2::Label( $name21 );
$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, $tip24 );
$table203->attach($spinner_cddb_port,  3, 4, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$spinner_cddb_port->show();

$label = new Gtk2::Label( $name22 );
$label->set_alignment( 1.0, 0.5 ); 
$table203->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0);
$label->show();

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

$combo_cddb_transport = Gtk2::Combo->new;
$combo_cddb_transport->set_popdown_strings ( "http", "cddb" );
$combo_cddb_transport->entry->set_text( $cddb_transport ); #standard value
$combo_cddb_transport->entry->set_editable($false); 
$table203->attach ($combo_cddb_transport, 1, 2, 2, 3, 'fill', 'shrink', 0, 0);
$combo_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);
      $combo_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);
      $combo_cddb_transport->set_sensitive ($false); 
   }
}
cddb_sensitive();

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

$button_noia1 = Gtk2::CheckButton->new ( $name23 );
$button_noia1->set_active($disable_paranoia);
$tooltips->set_tip( $button_noia1, $tip25 );
$table204->attach($button_noia1,  0, 1, 0, 1, ['fill','expand'], 'shrink', 0, 0);
$button_noia1->show;

$button_noia2 = Gtk2::CheckButton->new ( $name26 );
$button_noia2->set_active($never_skip_repair);
$tooltips->set_tip( $button_noia2, $tip26 );
$table204->attach($button_noia2,  1, 2, 0, 1, ['fill','expand'], 'shrink', 0, 0);
$button_noia2->show;

$button_noia3 = Gtk2::CheckButton->new ( $name24 );
$button_noia3->set_active($disable_extra_paranoia);
$tooltips->set_tip( $button_noia3, $tip27 );
$table204->attach($button_noia3,  0, 1, 1, 2, ['fill','expand'], 'shrink', 0, 0);
$button_noia3->show;

$button_noia4 = Gtk2::CheckButton->new ( $name25 );
$button_noia4->set_active($abort_on_skip);
$tooltips->set_tip( $button_noia4, $tip28 );
$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, $tip29 );
$table205->attach($button_cdda1,  0, 1, 0, 1, ['fill','expand'], 'shrink', 0, 0);
$button_cdda1->show;

$button_cdda2 = Gtk2::CheckButton->new ( $name28 );
$button_cdda2->set_active($paranoia_disable);
$tooltips->set_tip( $button_cdda2, $tip30 );
$table205->attach($button_cdda2,  1, 2, 0, 1, ['fill','expand'], 'shrink', 0, 0);
$button_cdda2->show;

$button_cdda3 = Gtk2::CheckButton->new ( $name27 );
$button_cdda3->set_active($paranoia_no_verify);
$tooltips->set_tip( $button_cdda3, $tip31 );
$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 - rtulo) ao lado do menu
$label = new Gtk2::Label( $name30 );
$label->set_alignment( 1.0, 0.5 );   
$table21->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0);
$label->show();

#####--------------------Combo---------------------#####
$combo_const_avg = Gtk2::Combo->new;
$combo_const_avg->set_popdown_strings ( "average", "constant", "variable" );
$combo_const_avg->entry->set_text( $encode ); #standard value 
$combo_const_avg->set_size_request( 104, -1 );
$combo_const_avg->entry->set_editable ($false);
$combo_const_avg->entry->signal_connect("changed", \&encode_choice, $combo_const_avg);
$table21->attach($combo_const_avg,  1, 2, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$combo_const_avg->set_sensitive($change_properties);
$combo_const_avg->show();

## encode type: constant, average or variable bitrate  
## show or hide some widgets
sub encode_choice
{
	my ($self, $combo_copy) = @_; 
        my $entry=$combo_copy->entry->get_text();
		
	if ( $entry eq "" ){ return; } # return if empty

	if ( $entry ne $encode ){      # to retain the last value changed 
	  $encode = $entry;            # set the new value for $encode 
	  encode_choice_sensitive();                                        
	  $status_bar->push($context_id, $msg65."$file_output with $encode bitrate." );
   
          # set the last encode type
          if ($button_output_mp3->get_active ){$encode_remember_mp3 = $encode;}
	  if ($button_output_mp4->get_active ){$encode_remember_mp4 = $encode;}
          if ($button_output_ogg->get_active ){$encode_remember_ogg = $encode;}
          if ($button_output_mpc->get_active ){$encode_remember_mpc = $encode;}	  
	}
}

# Set widget sensitive according to encoder choice
sub encode_choice_sensitive {
   #$encode = $combo_const_avg->entry->get_text(); #refresh $encode value
   $vb_Max = $combo_Max->entry->get_text; #refresh value
   $vb_Min = $combo_Min->entry->get_text;
      
   if ($button_output_mp3->get_active ){
       if ( $check_button_change->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_button_change->get_active){
           if ( $encode eq "average" ) { encode_sensitive(1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,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,0,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_button_change->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_button_change->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_button_change->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_button_change->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_button_change->get_active){
         if ( $bitrate_average ){ $status_bar->push($context_id, $msg65."$file_output with average bitrate.");}
         else { $status_bar->push($context_id, $msg65."$file_output with constant bitrate.");}
      }
      else { $status_bar->push($context_id, $msg65."$file_output with $encode bitrate.");}	 
   } 
   if ($button_output_mp4->get_active){  
      if ( not $check_button_change->get_active){
         { $status_bar->push($context_id, $msg65."$file_output with average bitrate.");}
      }
      else { $status_bar->push($context_id, $msg65."$file_output with $encode bitrate.");}	 
   } 
   if ($button_output_ogg->get_active){  
      if ( not $check_button_change->get_active){
         { $status_bar->push($context_id, $msg65."$file_output with average bitrate.");}
      }
      else { $status_bar->push($context_id, $msg65."$file_output with $encode bitrate.");}	 
   }  
   if ($button_output_mpc->get_active){  
      $status_bar->push($context_id, $msg65."$file_output with $encode bitrate."); 
   }
   if ($button_output_ape->get_active){ 
         my $comp_ape = $spinner_compress->get_value_as_int();
         $status_bar->push($context_id, $msg65."$file_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, $msg65."$file_output with compression level = $comp_flac.");
   }
   if ($button_output_wav->get_active){ 
         $status_bar->push($context_id, $msg65."$file_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;
   $combo_const_avg->set_sensitive($opt1);
   $combo_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);
   $combo_Min->set_sensitive($opt8);
   $combo_mode->set_sensitive($opt9);
   $spinner_V->set_sensitive($opt10);
   $spinner_Vmp4->set_sensitive($opt11);
   $spinner_Vogg->set_sensitive($opt12);
   $spinner_Vmpc->set_sensitive($opt13);
   $combo_Max->set_sensitive($opt14);
   $spinner_q->set_sensitive($opt15);
   $combo_fq->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){
      $combo_bitrate->show;
      $spinner_bitrate_mp3->hide;
      $spinner_bitrate_mp4->hide;
      $spinner_bitrate_ogg->hide;
      $spinner_compress->hide;
      $spinner_compress_flac->hide;
   }
   if ($opt18 == 2){
      $combo_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
      $combo_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 
      $combo_bitrate->hide;
      $spinner_bitrate_mp3->hide;
      $spinner_bitrate_mp4->hide;
      $spinner_bitrate_ogg->show;
      $spinner_compress->hide;
      $spinner_compress_flac->hide;
   }
   if ($opt18 == 5){
      $combo_bitrate->hide;
      $spinner_bitrate_mp3->hide;
      $spinner_bitrate_mp4->hide;
      $spinner_bitrate_ogg->hide;
      $spinner_compress->show;
      $spinner_compress_flac->hide;
   } 
   if ($opt18 == 6){
      $combo_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 - rtulo) 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();

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

$combo_bitrate = Gtk2::Combo->new;
$combo_bitrate->set_popdown_strings ( "32", "40", "48", "56", "64", "80", "96", "112", "128", "160",  "192", "224", "256", "320" );
$combo_bitrate->entry->set_text( $bitrate_constant); #standard value
$combo_bitrate->entry->set_editable($false); 
$combo_bitrate->set_size_request( 72, -1 );
# I think that "changed" is the best signal to use for this choice
$combo_bitrate->entry->signal_connect("changed", \&BitrateChanged, $combo_bitrate);
$table21->attach($combo_bitrate,  5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0);
#$combo_bitrate->set_sensitive($false);
#$combo_bitrate->show();

## audio mp3 bitrate is changed
sub BitrateChanged
{
	my ($widget,$comboCopy) = @_;
        my $entry=$comboCopy->entry->get_text();
	if ( $entry ne ""){
	$bitrate_constant = $entry; # copy the value of bitrate changed
	$status_bar->push($context_id, " constant $file_output bitrate set to $bitrate_constant Kb/s");
	}
}

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

###--------------------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, $tip32 );
$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, $tip32 );
$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, $tip32 );
$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, $msg65."$file_output with compression level = $comp_ape.");
} );
$tooltips->set_tip( $spinner_compress, $tip38 );
$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, $msg65."$file_output with compression level = $comp_flac.");
} );
$tooltips->set_tip( $spinner_compress_flac, $tip39 );
$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 - rtulo) 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 - rtulo) 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();

$combo_Min = Gtk2::Combo->new;
$combo_Min->set_popdown_strings ( "32", "40", "48", "56", "64", "80", "96", "112", "128", "160",  "192", "224", "256", "320" );
$combo_Min->entry->set_text( $vb_Min); #standard value
$combo_Min->set_size_request( 72, -1 );
$combo_Min->entry->set_editable ($false);
$combo_Min->entry->signal_connect("changed", \&bit_Min, $combo_Min);
$table21->attach($combo_Min,  8, 9, 0, 1, ['expand','fill'], 'shrink', 0, 0);
$combo_Min->set_sensitive($true);
$combo_Min->show();

## Minimum Bitrate with variable encode
sub bit_Min
{
	my ($widget,$comboCopy) = @_;
        my $entry=$comboCopy->entry->get_text();
	if ( $entry ne ""){
	     $vb_Min = $entry;
	     if ( $vb_Min > $vb_Max ) { # always assert this condition
	          $vb_Min = $vb_Max;
	          $combo_Min->entry->set_text($vb_Min); 
	     }	     
	}
}
#####-------------------final of Combo-------------#####


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

# criar um label (etiqueta - rtulo) ao lado do menu
my $label_combo_mode = new Gtk2::Label( $name31 );  
$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();

$combo_mode = Gtk2::Combo->new;
$combo_mode->set_popdown_strings ( 'joint stereo', 'stereo', 'forced joint stereo', 'dual channels', 'mono' );
$combo_mode->entry->set_text( $mode ); #standard value
$combo_mode->set_size_request( 104, -1 );
$combo_mode->entry->set_editable ($false);
$table21->attach($combo_mode,  1, 2, 1, 2, ['expand','fill'], 'shrink', 0, 0);
#$combo_mode->set_sensitive($false);
$combo_mode->show();

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

# criar um label (etiqueta - rtulo) ao lado do menu
$label_VB = new Gtk2::Label( $name33 );  
$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, $tip33 );
$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, $tip34 );
$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, $tip37 );
$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, $tip36 );
$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 - rtulo) 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();

$combo_Max = Gtk2::Combo->new;
$combo_Max->set_popdown_strings ( "32", "40", "48", "56", "64", "80", "96", "112", "128", "160",  "192", "224", "256", "320" );
$combo_Max->entry->set_text($vb_Max); #standard value
$combo_Max->set_size_request( 72, -1 );
$combo_Max->entry->set_editable ($false);
$combo_Max->entry->signal_connect("changed", \&bit_Max, $combo_Max);
$table21->attach($combo_Max,  8, 9, 1, 2, ['expand','fill'], 'shrink', 0, 0);
$combo_Max->set_sensitive($true);
$combo_Max->show();

## Maximum Bitrate with variable encode
sub bit_Max
{
	my ($widget,$comboCopy) = @_;
        my $entry=$comboCopy->entry->get_text();
	if ( $entry ne ""){
	     $vb_Max = $entry;
	     if ( $vb_Max < $vb_Min ) { # always assert this condition
	          $vb_Max = $vb_Min;
	          $combo_Max->entry->set_text($vb_Max); 
	     }
	}
}
#####-------------------final of Combo-------------#####

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

# criar um label (etiqueta - rtulo) ao lado do menu
$label = new Gtk2::Label( $name32 );
$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, $tip35 );
$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 - rtulo) ao lado do menu
$label = new Gtk2::Label( "Freq:" );   
$label->set_alignment( 1, 0.5 );
$table21->attach ($label, 4, 5, 2, 3, ['expand','fill'], 'shrink', 0, 0);
$label->show();

$combo_fq = Gtk2::Combo->new;
$combo_fq->set_popdown_strings ( "8000", "11025", "12000", "16000", "22050", "24000", "32000", "44100", "48000" );
$combo_fq->entry->set_text($freq); #standard value 
$combo_fq->set_size_request( 72, -1 );
$combo_fq->entry->set_editable ($false);
$table21->attach($combo_fq, 5, 6, 2, 3, ['expand','fill'], 'shrink', 0, 0);
$combo_fq->set_sensitive($change_properties);
$combo_fq->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-------------#####


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

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

$label = new Gtk2::Label( $name34 );
$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( $name35 );
$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, $tip48);
$table3->attach_defaults ($entry_artist, 1, 6, 1, 2 );
$entry_artist->show();

$label = new Gtk2::Label( $name36 );
$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( $name37 );
$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( $name38 );
$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( $name39 );
$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, $tip40 );
$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, $tip41 );
$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 - rtulo) ao lado do menu
$label = new Gtk2::Label( $name40 );
$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};
}

my $combo_genre = Gtk2::Combo->new;
$combo_genre->set_popdown_strings ( sort @array_genre );  # sort the array
$combo_genre->entry->set_text( "" ); #standard value
$combo_genre->entry->set_editable ($true);
$combo_genre->entry->signal_connect("changed", \&change_tag);
$table3->attach($combo_genre, 1, 6, 5, 6, 'fill', 'fill', 0, 0);
$combo_genre->show();


# when whatever tag is changed, the button_save_tag is set to set_sensitive($true)
sub change_tag {
      my $title=$entry_title->get_text;
      my $artist=$entry_artist->get_text;
      my $album=$entry_album->get_text;
      my $comment=$entry_comment->get_text;
      # some verifications/validations
      my $year = "invalid";
      if ( $entry_year->get_text =~ /^(\d+)$/ ) { $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 = ""; }
         
      my $genre=$combo_genre->entry->get_text;
           
      #print "(tn,Track_Number) = ($tn,$Track_Number) ;; (tt,Total_Track) = ($tt,$Total_Track)\n";

      # always in this order - there are 08 entries at all.
      # @array_info_from_entry = ($title,$artist,$album,$comment,$year,$tn,$tt,$genre);		    
      
      # verify any change in tag: Title, Artist, ...
      if ( ($file_input =~ /(mp3|ogg|flac|mpc|ape)/) 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() ) {
	      $button_save_tag->set_sensitive($false);
	      return ($title,$artist,$album,$comment,$year,$tn,"",$genre);
	  }
          if ( $tn =~ /^(\d+)$/ and $tt =~ /^(\d+)$/ ) { 
	     if ( $tt < $tn ){ # only compare for numbers
	        $status_bar->push($context_id, $msg80 );
	        $button_save_tag->set_sensitive($false);
	        return ($title,$artist,$album,$comment,$year,$tn,"",$genre);
	     } 
	  }  
	  if ( ( $tn eq "" and $tt =~ /^(\d+)$/ ) or $tn eq "invalid" or $tt eq "invalid" or $year eq "invalid" ) {
	     $status_bar->push($context_id, $msg80 );
	     $button_save_tag->set_sensitive($false);
	     return ($title,$artist,$album,$comment,$year,$tn,"",$genre); 
	  }
          $button_save_tag->set_sensitive($true);	  
          $tooltips->set_tip( $button_save_tag, $msg59 );
	  $status_bar->push($context_id, ""); # erase status_bar
      }
      elsif ( ($file_input =~ /cda/) and ($artist ne $Artist or $album ne $Album or $year ne $Year or $genre ne $Genre) )
      {    
          $button_save_tag->set_sensitive($true);	  
	  $tooltips->set_tip( $button_save_tag, $msg60 );
	  $status_bar->push($context_id, ""); # erase status_bar        
      }		
      else { 
          $status_bar->push($context_id, "" );
          $button_save_tag->set_sensitive($false);
      }     
      
      if ( $file_input =~ /(wav|mp4)/ ){ # for wav/mp4 file
	  # get info to be saved on normalized file
          $status_bar->push($context_id, $msg61 );
      }
      return ($title,$artist,$album,$comment,$year,$tn,$tt,$genre);
}

sub return_filepath {
   my $filepath = "$directory/";
   if    ( $file_input eq 'mp3' ){  $filepath .= $file_mp3;  }
   elsif ( $file_input eq 'mp4' ){  $filepath .= $file_mp4;  }
   elsif ( $file_input eq 'mpc' ){  $filepath .= $file_mpc;  }
   elsif ( $file_input eq 'ogg' ){  $filepath .= $file_ogg;  }
   elsif ( $file_input eq 'ape' ){  $filepath .= $file_ape;  }
   elsif ( $file_input eq 'flac'){  $filepath .= $file_flac; }
   elsif ( $file_input eq 'wav' ){  $filepath .= $file_wav;  }
   return $filepath;
}

sub file_is_writable {
   # Test if the $filepath is writable.
   # -w  File is writable by effective uid/gid.
   my $filepath = return_filepath();
   if ( not -w encode_char($filepath) ) {
      $status_bar->push($context_id, " $filepath ".$msg12 );
      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( $name41 );  
$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( $name31 ); 
$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( $name42 );  
$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( $name48 );  
$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 $file_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, $tip42 );
$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, $tip43 );
$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, $tip45 );
$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, $tip44 );
$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
# 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 */
"36 46 21 1",
" 	c None",
".	c #020400",
"+	c #141513",
"x	c #222422",
"#	c #2C2E2B",
"S	c #383A38",
"%	c #464745",
"&	c #545653",
"*	c #5F615E",
"=	c #6B6D6A",
"-	c #787A77",
";	c #858784",
">	c #929491",
",	c #A0A29F",
"'	c #AAACA9",
")	c #BBBDB9",
"!	c #C8CAC7",
"~	c #D4D6D3",
"{	c #E1E3E0",
"]	c #F0F2EF",
"^	c #FDFFFB",
"                     .x##.          ",
"                   .%>,',,%.        ",
"                 .x='',''''=.       ",
"                .x=',''',',,=.      ",
"                +*,'',>>>'',,#      ",
"               .%;,,>=->;*>''>.     ",
"              .#*,',*'!!!)=;',%.    ",
"              .&-,,*'!!!!!)*>,;.    ",
"              x*;,->!!!!!!!'=,>#    ",
"             .%*>>*!!!!!!!!!-;>&.   ",
"             +&=>-,!!!!!!!!!)=,-.   ",
"            .#&-,*)!!!!!!!!!!=>-x   ",
"            +&&-;;!!!!!!!!!!!,-;S.  ",
"           +&&*;-,!!!!!!!!!!!)*>%.  ",
"     ......%;&&;=)!!!!!!!!!!!!=>*.  ",
"   .%=***S&>;&&>=!'')!!!!!!!!!;;*.  ",
"  .&,)>,>&>,-&*;-')~~!!!!!!!!!>;-+  ",
"  x>),>,*;''-**;;,)!!)!!!!!!!~'-=x  ",
" .&');,=-,,'-*=-;,))))'!!!!!!!)--#  ",
" .=));;&,,,,=*=;>>')'',!!!!!!!!--x. ",
" .-),-==,>>>=*=-;>>',,;!!!!!!!!;-#. ",
" +;);=*->>>>=*=;;;;>>;;!!!!!!!!--#. ",
" +='-**->>>;-**;-------!!!!!!!!;-#. ",
" .=>=&&-;;;;-==;-------!!!!!!!!;=#. ",
" .*;*&&=-;;--=*;======-!!!!!!!!;=#. ",
" .%=&%%*------=;-*****;!!!!!!!)>=x. ",
" .S*&SS%=-----&--*&*&*'~~~~~~~!;=#  ",
" .x%&SSS&===-;*-;&&&&*~~{~{~{{);*+  ",
"  +%&%##%&*=-;&-'>&&&!]{{{]{{{!-*+  ",
"  .x%&S##%&*=>*=,]''~{]]]]{]]])=*.  ",
"   .xSS#S+S&*>**>{]]]]]]]]]]]],*%.  ",
"    .......S&>-*-~^^^^^^^^^^^{>*S.  ",
"           .%-;*=)^^^^^^^^^^^!-*x.  ",
"            +*,&&>]^^^^^^^^^^'*&+   ",
"             +,=&=!^^^^^^^^^{;*%.   ",
"             .=>&*>]^^^^^^^^'*&#.   ",
"              x'*&=)^^^^^^^!-&&.    ",
"              .--&&;!^^^^^{>&&%.    ",
"               #,&&&;){^]!>*&&+     ",
"               .*;&&&=>>>-&&&S.     ",
"                .;=&&&&&&&&&&.      ",
"                 +;*&&&&&&&%+.      ",
"                  +&=&&&&&%+.       ",
"                   ..xSSSx.         ",
"                      ....          ",
"                                    ");

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 = 10; # (36 46) scale the pixbuf_sound button
my $sound_size_h = 12; 
$pixbuf_sound = $pixbuf_sound->scale_simple ( $sound_size_w, $sound_size_h, 'bilinear'); # hyper, bilinear

my @random = (
# /* columns rows colors chars-per-pixel */
"40 64 2 1",
" 	c None",
".	c #1E60CB",
"                                        ",
"            ...........                 ",
"        ...................             ",
"      .......................           ",
"     ..........................         ",
"    ............................        ",
"   ...........    ...............       ",
"  ...........        .............      ",
"  ...........         .............     ",
" ...........           .............    ",
" ...........            ............    ",
" ...........             ............   ",
" ..........              ............   ",
"  .........              ............   ",
"  ........                ............  ",
"    ......                ............  ",
"                          ............  ",
"                          ............  ",
"                          ............  ",
"                          ............  ",
"                          ............  ",
"                         .............  ",
"                         ............   ",
"                         ............   ",
"                        .............   ",
"                        ............    ",
"                       ............     ",
"                      .............     ",
"                     .............      ",
"                    .............       ",
"                  ..............        ",
"                 ..............         ",
"               ..............           ",
"             ...............            ",
"             .............              ",
"             ...........                ",
"             ........                   ",
"             ......                     ",
"             ......                     ",
"             ......                     ",
"             ......                     ",
"             ......                     ",
"             ......                     ",
"             ......                     ",
"             ......                     ",
"             .....                      ",
"                                        ",
"                                        ",
"                                        ",
"                                        ",
"             ......                     ",
"            ........                    ",
"           ..........                   ",
"          ............                  ",
"         ..............                 ",
"         ..............                 ",
"         ..............                 ",
"         ..............                 ",
"         ..............                 ",
"         ..............                 ",
"          ............                  ",
"           ..........                   ",
"            ........                    ",
"             .....                      ");

my $pixbuf_random = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@random);
# $pixbuf_sound->scale_simple ($dest_width, $dest_height, $interp_type)
my $random_w = 6; # (38 64) scale
my $random_h = 9; 
$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[2] = ".	c #BFBFBF"; # #A7B1BE
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 */
"50 35 2 1",
"+	c None",
".	c #1E60CB",
"++++++++++++++++++++++++++++++++++.+++++++++++++++",
"++++++++++++++++++++++++++++++++...+++++++++++++++",
"++++++++++++++++++++++++++++++.....+++++++++++++++",
"++++++++++++++++++++++++++++.......+++++++++++++++",
"++++++++++++++++++++++++++.........+++++++++++++++",
"++++++++++++++++++++++++...........+++++++++++++++",
"++++++++........++++++....................++++++++",
"++++++..........+++++........................+++++",
"++++............++++++........................++++",
"+++......+++++++++++++++...........+++++++.....+++",
"++.....++++++++++++++++++++........+++++++++....++",
"++...+++++++++++++++++++++++.......++++++++++....+",
"+....+++++++++++++++++++++++++.....+++++++++++...+",
"+...++++++++++++++++++++++++++++...+++++++++++...+",
"...+++++++++++++++++++++++++++++++.++++++++++++...",
"...++++++++++++++++++++++++++++++++++++++++++++...",
"...++++++++++++++++++++++++++++++++++++++++++++...",
"...++++++++++++++++++++++++++++++++++++++++++++...",
"...++++++++++++++++++++++++++++++++++++++++++++...",
"...+++++++++++++.++++++++++++++++++++++++++++++...",
"+...++++++++++++...+++++++++++++++++++++++++++....",
"+...++++++++++++.....+++++++++++++++++++++++++...+",
"+....+++++++++++.......++++++++++++++++++++++....+",
"++....++++++++++.........+++++++++++++++++++....++",
"+++....+++++++++...........++++++++++++++++....+++",
"++++......++++++.............++++++............+++",
"++++...........................++++..........+++++",
"++++++........................+++++........+++++++",
"+++++++++...................++++++++++++++++++++++",
"+++++++++++++++++.........++++++++++++++++++++++++",
"+++++++++++++++++.......++++++++++++++++++++++++++",
"+++++++++++++++++.....++++++++++++++++++++++++++++",
"+++++++++++++++++....+++++++++++++++++++++++++++++",
"+++++++++++++++++..+++++++++++++++++++++++++++++++",
"+++++++++++++++++.++++++++++++++++++++++++++++++++");


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 ) = ( 14, 10 ); # Scale (50, 35)
$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[2] = ".	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 ) = ( 8 , 10 ); # (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 = ( # cd player skin
# /* 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 $db = 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*$db - $corner )/11 - 1);         # min:(8,10)   max:(13,20)
   $numbers_h = int ( $height/2 - $corner - 6 );  
   if ( $numbers_w >= 12 ){ $numbers_w = 12; }  # 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 - 5 ); # (14,10)
   #print "loop_w = $loop_w ; loop_h = $loop_h\n";
   if ( $loop_w >= 16 ){ $loop_w = 16; }
   if ( $loop_h >= 12 ){ $loop_h = 12; }
   
   ( $random_w , $random_h ) = ( int($buttons_w/2) - 1, $buttons_h - 6 );  # min:(6,9)   max:(7,12)
   if ( $random_w >= 7 ){ $random_w = 7; }
   if ( $random_h >= 12 ){ $random_h = 12; }
   
   ( $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 $db     = 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 - 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 (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
      $widget->set_size_request (225, 90); # set a minimum size: (width,height) ; Skin
      
      #(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.xpm');
      ($pixmap, $pixmap_mask) = Gtk2::Gdk::Pixmap->create_from_xpm_d($widget->window, undef, @skin);
								    								               
      #my $pixmap_widget = Gtk2::Image->new_from_pixmap ($gdkpixmap, $mask);   
      if (not $window_cd_player->get_decorated){ 
         $window_cd_player->shape_combine_mask( $pixmap_mask, 0, 0 );
      }
      
      ($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 = 38;
      
      # random button; position on the $da
      $xdest_random = 150;
      $ydest_random = 38;
      
      # sound button; position on the $da
      $xdest_sound = 186;     
      $ydest_sound = 68;
      ($sound_size_w, $sound_size_h) = (10,12);              
           
      scale_pixbuf(); 
   }
   if (not defined $pixmap){ # without skin
      $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 $height_ty = 0.35*$corner; # 0.35 * $corner	
      my $width_tx  = 0.35*$corner;		   
      # $drawable->draw_polygon ($gc, $filled, $x1, $y1, ...)
      $pixmap->draw_polygon ($gc_bg, $true, # fill whith color $gc_bg 
                                      $corner, 0, $width - $corner, 0,
				      $width - $width_tx, $height_ty,
                                      $width, $corner, $width, $height - $corner,
				      $width - $width_tx, $height - $height_ty,
				      $width - $corner, $height, $corner, $height,
				      $width_tx, $height - $height_ty,
				      0, $height - $corner, 0, $corner,
				      $width_tx, $height_ty );
				      				            				      
      # draw the limite lines
      # $drawable->draw_polygon ($gc, $filled, $x1, $y1, ...)
      $pixmap->draw_polygon ($gc_green, $false, # $widget->style->black_gc,
                                      $corner, 0, $width - $corner - 1, 0,
				      $width - $width_tx, $height_ty,
                                      $width - 1, $corner, $width - 1, $height - $corner - 1,
				      $width - $width_tx, $height - $height_ty,
				      $width - $corner - 1, $height - 1, $corner, $height - 1,
				      $width_tx, $height - $height_ty,
				      0, $height - $corner -1 , 0, $corner, 
				      $width_tx, $height_ty );
      # refresh the sizes and scale      
      scale_buttons($width, $height, $corner, $delta);
      
      ($xdest, $ydest) = (int($corner + 5*($numbers_w + $db) + $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 + $db) + $numbers_w/2); 
      $ydest_posbar = int($height/2 - 4);
      $posbar_length = $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 + 6 + $loop_w ;
      $ydest_random = $height - $corner - $random_h - 1;
      
      # sound button; position on the $da
      $xdest_sound = $width/2 - $sound_size_w - 5*$buttons_w/2 - 4*$delta + $dista;     
      $ydest_sound = $height - $sound_size_h - 4;
      
      # 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;
}

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 - no 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 + $db), $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 + $db);
      $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 + $db);
      $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 + $db);
      $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 + $db);
      $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 + $db);
      $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 + $db), $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
   $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
   @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";
   
   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_track - 1;
   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/\.(.){3,4}$//i; # remove extension
         $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_track - 1;
   
   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/\.(.){3,4}$//i; # remove extension
	 ($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 ("0gX_"); # 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 $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----#
   my $notebook = Gtk2::Notebook->new;
   $notebook->set( 'homogeneous' => $true, 'scrollable' => $true );
   $notebook->append_page( $frame_cdplayer_color, "colors" ); 
   $notebook->append_page( $frame_cdplayer_players, "players" );  
   $notebook->append_page( $frame_cdplayer_columns, "columns" );
   $notebook->append_page( $frame_cdplayer_skins, "skins" ); 
   $vbox_cdplayer_color->pack_start( $notebook, $true, $true, 0 );      

   #$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 $combo1play = Gtk2::Combo->new;
   $combo1play->set_popdown_strings (keys %all_mp3_player); # "mpg321", "mpg123", "madplay", "mplayer"
   $combo1play->entry->set_text( $player_mp3 ) if $all_mp3_player{"$player_mp3"}; #standard value 
   $combo1play->set_size_request( 90, -1 );
   $combo1play->entry->set_editable ($false);
   $combo1play->entry->signal_connect("changed", \&player_choice, $combo1play);
   $table_cdplayer_players->attach ($combo1play, 1, 2, 1, 2, ['fill','expand'], 'fill', 0, 0);
   
   sub player_choice {
	my ($self, $combo_copy) = @_; 
        my $entry=$combo_copy->entry->get_text;		
	if ( $entry eq "" ){ return; } # return if empty
	$player_mp3 = $entry;
   }
   
   my $combo1type = Gtk2::Combo->new;
   $combo1type->set_popdown_strings ( "arts", "oss", "alsa", "esd", "jack", "nas", "sun" );
   $combo1type->entry->set_text( $device_type ); #standard value 
   $combo1type->set_size_request( 90, -1 );
   $combo1type->entry->set_editable ($true);
   $combo1type->entry->signal_connect("changed", \&device_type_choice, $combo1type);
   $table_cdplayer_players->attach ($combo1type, 3, 4, 1, 2, ['fill','expand'], 'fill', 0, 0);
   
   sub device_type_choice {
	my ($self, $combo_copy) = @_; 
        my $entry=$combo_copy->entry->get_text;		
	if ( $entry eq "" ){ return; } # return if empty
	$device_type = $entry;
   }
   
   my $combo1path = Gtk2::Combo->new;
   $combo1path->set_popdown_strings ( "/dev/audio", "/dev/sound/adsp", "/dev/dsp" );
   $combo1path->entry->set_text( $device_path ); #standard value 
   $combo1path->set_size_request( 140, -1 );
   $combo1path->entry->set_editable ($true);
   $combo1path->entry->signal_connect("changed", \&device_path_choice, $combo1path);
   $table_cdplayer_players->attach ($combo1path, 3, 4, 3, 4, ['fill','expand'], 'fill', 0, 0);
   
   sub device_path_choice {
	my ($self, $combo_copy) = @_; 
        my $entry=$combo_copy->entry->get_text;		
	if ( $entry eq "" ){ return; } # return if empty
	$device_path = $entry;
   }
   
   #---mp4---#   
   my $combo2play = Gtk2::Combo->new;
   $combo2play->set_popdown_strings ( "mplayer" ) if $mplayer_path;       
   $combo2play->entry->set_text( "mplayer" )      if $mplayer_path; #standard value    
   $combo2play->set_size_request( 90, -1 );
   $combo2play->entry->set_editable ($false);
   $table_cdplayer_players->attach ($combo2play, 1, 2, 2, 3, ['fill','expand'], 'fill', 0, 0);
   
   #---mpc---#   
   my $combo3play = Gtk2::Combo->new;
   $combo3play->set_popdown_strings ( "mppdec" ) if $mpcdec_path;        
   $combo3play->entry->set_text( "mppdec" )      if $mpcdec_path; #standard value     
   $combo3play->set_size_request( 90, -1 );
   $combo3play->entry->set_editable ($false);
   $table_cdplayer_players->attach ($combo3play, 1, 2, 3, 4, ['fill','expand'], 'fill', 0, 0);
   
   #---ogg---#   
   my $combo4play = Gtk2::Combo->new;
   $combo4play->set_popdown_strings ( keys %all_ogg_player );
   $combo4play->set_size_request( 90, -1 );
   $combo4play->entry->set_editable ($false);
   $table_cdplayer_players->attach ($combo4play, 1, 2, 4, 5, ['fill','expand'], 'fill', 0, 0);     
      
   #---ape---#   
   my $combo5play = Gtk2::Combo->new;
   $combo5play->set_popdown_strings ( "mac" ) if $ape_path; # use mac and play (sox)      
   $combo5play->entry->set_text( "mac" )      if $ape_path; #standard value    
   $combo5play->set_size_request( 90, -1 );
   $combo5play->entry->set_editable ($false);
   $table_cdplayer_players->attach ($combo5play, 1, 2, 5, 6, ['fill','expand'], 'fill', 0, 0);
   
   #---flac---#   
   my $combo6play = Gtk2::Combo->new;
   $combo6play->set_popdown_strings ( keys %all_flac_player );
   $combo6play->entry->set_text( $player_flac ) if $all_flac_player{"$player_flac"}; #standard value 
   $combo6play->set_size_request( 90, -1 );
   $combo6play->entry->set_editable ($false);
   $combo6play->entry->signal_connect("changed", \&player_choice6, $combo6play);
   $table_cdplayer_players->attach ($combo6play, 1, 2, 6, 7, ['fill','expand'], 'fill', 0, 0);
      
   sub player_choice6 {
	my ($self, $combo_copy) = @_; 
        my $entry=$combo_copy->entry->get_text;
	return unless $entry; # return if empty
	$player_flac = $entry;
   }
            
   #---wav---#   
   my $combo7play = Gtk2::Combo->new;
   $combo7play->set_popdown_strings ( "mplayer" ) if $mplayer_path;       
   $combo7play->entry->set_text( "mplayer" )      if $mplayer_path; #standard value   
   $combo7play->set_size_request( 90, -1 );
   $combo7play->entry->set_editable ($false);
   $table_cdplayer_players->attach ($combo7play, 1, 2, 7, 8, ['fill','expand'], 'fill', 0, 0);
   
   
   #---------------- 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);
   
   
   #---------------- 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 $combo_scrolling = Gtk2::Combo->new;
   $combo_scrolling->set_popdown_strings ( "horinzontal1", "horinzontal2", "horinzontal3", "vertical", "random" );
   $combo_scrolling->entry->set_text( $scrolling_type ) if $scrolling_type; #standard value 
   $combo_scrolling->set_size_request( 120, -1 );
   $combo_scrolling->entry->set_editable ($false);
   $combo_scrolling->entry->signal_connect("changed", \&scrolling_choice, $combo_scrolling);
   $table_cdplayer_skins->attach ($combo_scrolling, 1, 2, 1, 2, ['fill','expand'], 'fill', 0, 0);
      
   sub scrolling_choice {
	my ($self, $combo_copy) = @_; 
        my $entry=$combo_copy->entry->get_text;
	return unless $entry; # return if empty
	$scrolling_type = $entry;
	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, "Choose the interval in milliseconds that the text will be redrawed." );   
   $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, "Choose the step incremental in pixels." );   
   $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, "Scrolling text orientation: up/down or left/right." );
   $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, "Show the xTunes like skin.\nTo take effect, change the display mode." );
   $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, 
      "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode." );
   $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, $tip55 );
   $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
         $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;
   }    
   else { Quit_window_cdplayer_color(); }
}

sub Quit_window_cdplayer_color { 
      $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_track-1]{extension} 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_system($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_track-1]{extension} 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_system($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_track-1]{extension} 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_system($cmd);	   
        }
	elsif ( $cdplayer eq "gnormalize::cdplay" ){ 
	   gnormalize::cdplay::play_cdrom_msf(Track => $selected_track, 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" ){
           exec_cmd_system("$cdcd_path -d $audiodevice_path eject");
	   # system("/usr/bin/eject /dev/hdc") || die " Error: $! \n";
	   # print " here, eject\n";	   
        }
	if ( $cdplayer eq "Audio::CD" ){ $audiocd->eject; }
	exec_cmd_system("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_track-1]{extension} 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_system($cmd);	   
        }
	elsif ( $cdplayer eq "gnormalize::cdplay" ){ 
	   gnormalize::cdplay::play_cdrom_msf(Track => $selected_track, 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 @tracks_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 $db = 1;      
     if ( $x >= $xdest_numbers and $x <= (5*($numbers_w + $db) + $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_track-1]{extension} ne 'cda'){ 	
	   my $total_sec = time_to_sec( $files_info[$selected_track-1]{length} );
	   $count = sprintf ('%.0f', $pct * $total_sec );
	   play_selection( skip => $count );
	   return $true;    
        }
	
	my $track = $selected_track; 
        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_track, 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_system($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 .gnormalize_config
   if ( $audio_cd_volume > 100 or $audio_cd_volume < 0 ){ $audio_cd_volume = 100; }
   $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) : 100;
   
   my $volume = shift || $get_vol; # Valid volumes: 0 - 100
   if ( $volume > 100 or $volume < 0 ){ $volume = 100; }   
   $audio_cd_volume = $volume;                        # 0 - 100   
   $volume = sprintf ( "%.0f", $volume * (255/100) ); # 0 - 255
   
   if ($files_info[$selected_track-1]{extension} ne 'cda' and $amixer_path ne ""){ 	
       my $cmd = "$amixer_path set Master $audio_cd_volume%"; # amixer set PCM 90% / amixer set Master 60% ; Mixer_device
       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 .gnormalize_config
   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, "Add more files to play" );
$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 > 240);       
      $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 --------------------###


###---------------------- Frame 5 --------------------###
#--------------------------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;

$frame5->add($textview_about);
# my $container = $frame5->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;
my $str = "\nAuthor: $AUTHOR\nemail: claudiofsr\@yahoo.com\ndate: $DATE ; So Paulo - Brasil";

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 encode_char("$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 (15000, \&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$msg40" , "descr");
      $buffer_about->insert_with_tags_by_name ($iter_about, "\n$msg64", "descr");
      $buffer_about->insert_with_tags_by_name ($iter_about, "\n$str", "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, $msg84 , "descr");}
   if ($count_textview == 2){ $buffer_about->insert_with_tags_by_name ($iter_mark, $msg85 , "descr");}
   if ($count_textview == 3){ $buffer_about->insert_with_tags_by_name ($iter_mark, $msg64, "descr"); }
   if ($count_textview == 4){ $buffer_about->insert_with_tags_by_name ($iter_mark, $str, "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 = $msg84;}
   if ($next_string == 2){$string = $msg85;}
   if ($next_string == 3){$string = $msg64;}
   if ($next_string == 4){$string = $str;  }
   if ($next_string == 5){
      $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->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 ( $file_input eq 'other' ){
        $normalize_button->set_active($false);
	$status_bar->push($context_id, $msg3 );
	return $false;
    }
    elsif ( $file_input eq 'error' ){
        $normalize_button->set_active($false);
	$status_bar->push($context_id, $msg4 );
	return $false;
    }
    if ( $button_dir->get_active and @array_of_files <= 0 and $file_input ne 'cda' ){
        foreach my $d (@files_info) {
	   push @array_of_files, $d->{filepath} if ( -e encode_char($d->{filepath}) );
	}
    }    
    
    # Test if the $directory is writable. -w : file is writable by effective uid/gid.
    if ( ! -w encode_char($directory_output) ){ $status_bar->push($context_id, " $directory_output ".$msg12 ); return $false;}
    
    # not change the input and output frames while any encoding process
    $frame11->set_sensitive($false);  
    $frame12->set_sensitive($false);             
    
    # if the file choosed is a supported file and the normalize button is active
    # $button_dir->get_active - normalize all files in the directory
    if ($button_dir->get_active and $normalize_button->get_active and $file_input ne 'cda'){    
	for (my $i=1;$i<=@array_of_files;$i++){  # @array is it size	     
	     (my $file = $array_of_files[$i-1]) =~ s/(.*\/)//g;      #copy and remove (path)/	     	     
	     insert_msg( $msg78 , "purple");	     
             insert_msg( ": $file\n" , "small");

	     determine_file_input_and_directory($array_of_files[$i-1]);     
  
	     # decode, normalize and encode the files
	     dec_norm_enc($file_mp3,$file_mp4,$file_ogg,$file_mpc,$file_ape,$file_flac,$file_wav,$file_wav_copy); 
	     # abandon the for loop if the <stop normalize> button is pressed
	     if ( not $normalize_button->get_active) { $directory = $directory_base; last; }
	 }
    }    
    # $button_file->get_active - normalize only the selected file in the directory
    if ( $button_file->get_active and $normalize_button->get_active and $file_input ne 'cda' ){	
        dec_norm_enc($file_mp3,$file_mp4,$file_ogg,$file_mpc,$file_ape,$file_flac,$file_wav,$file_wav_copy); # decode, normalize and encode the files
    }  
    
    # start to rip an audio cd
    my $one_rip = $false;
    if ( $normalize_button->get_active and $file_input eq 'cda' ){      
        my $at_least_one_music_selected = $true;
       
        while ( $at_least_one_music_selected eq $true and $normalize_button->get_active ){
            $at_least_one_music_selected = $false;
	  
            for (my $row=0; $row <= $#files_info ; $row++){ 
               # if some track is toggled, then start to rip      
               if ($files_info[$row]{rip} eq $true ){
	          $at_least_one_music_selected = $true;
		  last; #abandon the for loop
	       }	   
            }
	    if ( $at_least_one_music_selected eq $false and @files_info >= 1 and $one_rip eq $false ){ 
	       $status_bar->push($context_id, $msg13 );
	    }
            if ( $at_least_one_music_selected eq $true ){
    	       search_track_and_rip ();
	       $one_rip = $true;
	    }
        } # final of while loop 
    } 
    # Show the final messages
    if ($file_input eq 'cda' and $one_rip eq $true){  
       if ($rip_sucess eq $true and $normalize_button->get_active){ $status_bar->push($context_id, $msg14 ); }
       else { $status_bar->push($context_id, $msg15 );}
    }
    if ($file_input ne 'cda'){
       if ($norm_type eq "None"){  $status_bar->push($context_id, $msg16 );}
       elsif ($file_input ne $file_output){ $status_bar->push($context_id, $msg17 );}
       else { $status_bar->push($context_id, $msg18 );}
    }
    # return the input and output frames to original state after processes
    $frame11->set_sensitive($true);  
    $frame12->set_sensitive($true);
    
    # After stop the process, label is changed.
    if ($file_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
{	  
   my $model = $treeview_play->get_model;
     
   $da->set_sensitive($false);
   stop_playing_music();
    	      
   for (my $row=0; $row <= $#files_info ; $row++){ 
       
      next if $files_info[$row]{extension} ne 'cda';      
      # find $iter and $path associeted to some $track
      my $track = sprintf("%02d", $row + 1 );  # 02d : leading zero
      my ($iter,$path) = search_iter_path_for_track($track);      
      $treeview_play->scroll_to_cell($path, undef, $true ,0.50, 0.50) if $path;	
          
      if ($files_info[$row]{rip} and $normalize_button->get_active){  # if the music is toggled, then rip it
             my $file_wav;
	     stop_playing_music();	       	  
	     $normalize_button->set_label( $msg19 );
	     change_font_for_all_child($window_font_name,$normalize_button);
	     # set the artist of the music; get it from info of gnormalize or cddb
	     if ( $entry_artist->get_text eq "" ){ 
	            $entry_artist->set_text($files_info[$row]{artist});}
	     elsif ( $files_info[$row]{artist} eq "artist" ){ 
	            $files_info[$row]{artist} = $entry_artist->get_text; 
	            $model->set ($iter, COLUMN_ARTIST, $files_info[$row]{artist}); }
             else { $entry_artist->set_text($files_info[$row]{artist});}
	     # set the title of the music
	     if ( $entry_title->get_text eq "" ){ 
	            $entry_title->set_text($files_info[$row]{title});}
	     elsif ( $files_info[$row]{title} eq "music title" ){ 
	            $files_info[$row]{title} = $entry_title->get_text; 
	            $model->set ($iter, COLUMN_TITLE, $files_info[$row]{title}); }
             else { $entry_title->set_text($files_info[$row]{title});}
	     
	     $Total_Track = $#files_info + 1;	     
	     $entry_tn->set_text($track);
	     $entry_tt->set_text($Total_Track);
	     	    	     
	     # Filename format for rip Audio CD
	     # %t = title of song; %a = artist; %b = album
	     # %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/$Album/ig;
	     $file_format =~ s/%n/$track/ig;
	     $file_format =~ s/%y/$Year/ig;
	     $file_format =~ s/%g/$Genre/ig;	     	     
	     $file_format =~ s/"/\'/g; # substitue the char " for '
	     $file_format =~ s/[\/;*?|><"\$!\015]/_/g;
	     
	     $file_wav = encode_char($file_format.'.wav');	# final filename format
	     #$file_wav = "$files_info[$row]{artist}-$track-$files_info[$row]{title}.wav";  #filename

	     # ripping start here  ;;  $rip_sucess get $true if the rip is completed
	     insert_msg(" --- ripping ---\n" , "small-green");
	     if ($ripper eq "cdparanoia"){ $rip_sucess = rip_audio_cdparanoia($track,$file_wav);} 
	     elsif ($ripper eq "cdda2wav"){$rip_sucess = rip_audio_cdda2wav($track,$file_wav);  }   
	   
	     if ( $normalize_button->get_active ){  # the rip was successfuly completed
                    $files_info[$row]{rip} = $false; # change the boolean value
                    $model->set ($iter, COLUMN_RIP, $files_info[$row]{rip}) if $iter; # 'untaggle' the ripped music
		      
	            ($file_mp3,$file_mp4,$file_ogg,$file_mpc,$file_ape,$file_flac,$file_wav,$file_wav_copy) = file_with_extension($file_wav);
                    #$directory = exec_cmd_system("pwd");
		    # decode, normalize and encode the files
                    dec_norm_enc($file_mp3,$file_mp4,$file_ogg,$file_mpc,$file_ape,$file_flac,$file_wav,$file_wav_copy);
                    # abandon the 'for (my $row=0; ...)' loop when the button <stop normalize> is pressed
                    if ( not $normalize_button->get_active) {last;}
	     } 
	     $entry_title->set_text(""); #erase entry
      }  
   } # final of ''for (my $row=0; $row <= $#files_info ; $row++){ ''
   
   if ( $cdcd_path ne "" 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 $file_mp3 = shift;   # in this order: $file_mp3 ; $file_mp4 ; $file_ogg ; $file_mpc ; 
       my $file_mp4 = shift;
       my $file_ogg = shift;   # $file_ape ; $file_flac ; $file_wav ; $file_wav_copy
       my $file_mpc = shift;
       my $file_ape = shift;
       my $file_flac = shift;
       my $file_wav = shift;
       my $file_wav_copy = shift;
       my $file;
       my $insensibility = $spinner_sensi->get_value;
       $priority = $spinner_pri->get_value; #priority
       
       if    ( $file_input eq 'mp3' ){ $file = $file_mp3; }
       elsif ( $file_input eq 'mp4' ){ $file = $file_mp4; }       
       elsif ( $file_input eq 'mpc' ){ $file = $file_mpc; }
       elsif ( $file_input eq 'ogg' ){ $file = $file_ogg; }
       elsif ( $file_input eq 'ape' ){ $file = $file_ape; }
       elsif ( $file_input eq 'flac'){ $file = $file_flac;}
       elsif ( $file_input eq 'wav' ){ $file = $file_wav; }
       
       if ($file_input ne 'cda'){
          insert_msg(" --- decoding ---\n" , "small-green") if $file_input ne 'wav';
          # for the case when the file is deleted or changed after pressed the normalize_button
          if ( not -e encode_char("$directory/$file")){ 
              $status_bar->push($context_id, " Can't find $file_input file to normalize!");
              return $false;}
       }
       refresh_progress_bar_names();
       refresh_input_output_arrows();
       
       if ( $file_input =~ /(mp3|mp4|mpc|ogg|ape|flac)/ ){ get_info_from_file(); }        
       if ( $file_input =~ /(wav|cda)/ ){       get_info_from_entries(); }  # get info from entry "info " of gnormalize
       
       # decode, normalize and encode the files
       # decode:
       $normalize_button->set_label("stop decoding");
       change_font_for_all_child($window_font_name,$normalize_button);              
       if    ( $file_input eq 'mp3'  and $lame_path ne ""   ){ decode_mp3_to_wav(); }
       elsif ( $file_input eq 'mp4'  and $faad_path ne ""   ){ decode_mp4_to_wav(); }
       elsif ( $file_input eq 'ogg'  and $oggdec_path ne "" ){ decode_ogg_to_wav(); } 
       elsif ( $file_input eq 'mpc'  and $mpcdec_path ne "" ){ decode_mpc_to_wav(); } 
       elsif ( $file_input eq 'ape'  and $ape_path ne ""    ){ decode_ape_to_wav(); }    
       elsif ( $file_input eq 'flac' and $flac_path ne ""  ){ decode_flac_to_wav();}
       elsif ( $file_input eq 'wav'  and $directory_output ne $directory ){      
          my $cmd = "cp -f \"$directory/$file\"  \"$directory_output\" ";
	  insert_msg("." , "small-ini");
	  insert_msg("$cmd\n" , "small"); #print on debug textview
	  exec_cmd_system($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");
	    normalize_wav();
       }             
                   
       # encode:
       # if $check_button_change not active and file is already normalized and has the same extension then make copy,
       # otherwise the file will be encoded.
       # the output can be mp3 or ogg 
       if ( $normalize_button->get_active ) {
       
         if ( $button_output_wav->get_active ) { # output: wav ; encode wav -> wav !!! 
	 
	   my $cmd = "cp -f \"$directory_output/$file_wav_copy\"  \"$directory_final/$file_wav\" ";
	   insert_msg("." , "small-ini");
	   insert_msg("$cmd\n" , "small"); #print on debug textview
	   exec_cmd_system($cmd);
	 
           finalize_process($file_wav); 
           return $true;
	 }
       
         if ( $file_input eq $file_output and ( $already_normalized or abs($adjust) <= $insensibility ) and
            $norm_type ne "None" and not $check_button_change->get_active ){
           # then make a copy, don't need to encode
	   # note that .cda never satisfy this conditons
	   if ( abs($adjust) <= $insensibility ){ same_extension_overwrite(); }
         }
         # $file_wav always satisfy this conditon
         else { 
           $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 ) {encode_wav_to_mp3();}
	   elsif ( $button_output_mp4->get_active ) {encode_wav_to_mp4();}
	   elsif ( $button_output_mpc->get_active ) {encode_wav_to_mpc();}
	   elsif ( $button_output_ogg->get_active ) {encode_wav_to_ogg();}
	   elsif ( $button_output_ape->get_active ) {encode_wav_to_ape();}
	   elsif ( $button_output_flac->get_active) {encode_wav_to_flac();}
         } 
       }
}

## 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) = @_;
   ## 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";}
           }
   }
   # In the case of stop process, always remove file_wav_copy if it exist
   if ( -e encode_char("$directory_output/$file_wav_copy") ){ 
            exec_cmd_system("rm -f \"$directory_output/$file_wav_copy\" ");
   }
   #remove wav file if button_del_wav is active and $file_wav exist
   if ($check_button_del_wav->get_active and -e encode_char("$directory_output/$file_wav") ){ 
	    exec_cmd_system("rm -f \"$directory_output/$file_wav\" "); 
   }		
   # 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 encode_char("$directory_output/_normAAAAAA") ){ 
            exec_cmd_system("rm -f \"$directory_output/_normAAAAAA\" ");
   }
   $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("ps", "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, $tip53 );
$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->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 ( $file_input eq 'other' ){ draw_input_output($da_arrow_dec,undef,"mp3","wav"); } # default
   else { draw_input_output($da_arrow_dec,undef,("$file_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 " data_0 = $data[0] ;; data_1 = $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","$file_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, $tip54 );
$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 ("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, $tip51 );
   }
   elsif ( $button_info_type == 2 ){ # $frame_debug->show;  
      $align_hold_2_buttons->add ($button_hide_info);
      $tooltips->set_tip( $button_hide_info, $tip52 );
      resize_window();
   }
   elsif ( $button_info_type == 3 ){
      $align_hold_2_buttons->add ($button_hide_info);
      $tooltips->set_tip( $button_hide_info, $tip50 );
      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, $tip49 );     
      $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 {
    my $prog = shift;            # find path of $prog
    my $comment = shift || "";   # show one message/comment ; 
                                 # show no message
    my $path = "";
    my $fullpath;
    @_ = split(/:/, $ENV{PATH});
    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;                   # abandon the 'for' loop
	}
    }
    if ( $comment eq "NO_COMMENT" ) { return $path; }
    if ($path eq "") {
       insert_msg( $msg23, "black");
       insert_msg("$prog" , "red");
       insert_msg( $msg24." $comment\n" , "black");
    }
    return $path;
} 

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

    # see <man Gtk2::version>
    # the GtkFileChooser, new in gtk+ 2.4.0 and first supported in
    # Gtk2-Perl at 1.040, is available.
    my $Gtk2_version_boolean = Gtk2->CHECK_VERSION (2, 4, 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.040 or not $Gtk2_version_boolean ) {
       insert_msg( "Found Gtk2 (version = $Gtk2_version) and Gtk2_Perl (version = $Gtk2_Perl_version).", "black");
       insert_msg( $msg79 , "red");
       insert_msg( "   Gtk2 version >= 2.4.0 ; Gtk2_Perl version >= 1.040\n\n", "red");
    }

    $lame_path = find_prog("lame", $msg25 );
    #print " lame_path = $lame_path \n";
    if ($lame_path eq "") { $button_output_mp3->set_sensitive($false); }
    
    $oggenc_path = find_prog("oggenc", $msg26 );
    #print " oggenc_path = $oggenc_path \n";
    if ($oggenc_path eq "") { $button_output_ogg->set_sensitive($false); }
    
    $mpcenc_path = find_prog("mppenc", $msg27 );
    if ($mpcenc_path eq "") { $button_output_mpc->set_sensitive($false);}
    
    $ape_path = find_prog("mac", $msg28 );
    if ($ape_path eq "") { $button_output_ape->set_sensitive($false);  }
    
    $flac_path = find_prog("flac", $msg29 );
    if ($flac_path eq "") { $button_output_flac->set_sensitive($false);}
    
    $faac_path = find_prog("faac", $msg30 );
    if ($faac_path eq "") { $button_output_mp4->set_sensitive($false);}
    
    if ($lame_path ne "")      {$button_output_mp3->set_active($true); }
    elsif ($oggenc_path ne "") {$button_output_ogg->set_active($true); }
    elsif ($mpcenc_path ne "") {$button_output_mpc->set_active($true); }
    elsif ($ape_path ne ""   ) {$button_output_ape->set_active($true); }
    elsif ($flac_path ne ""  ) {$button_output_flac->set_active($true);}
    elsif ($faac_path ne "")   {$button_output_mp4->set_active($true); }
    else {$normalize_button->set_sensitive($false);} # do nothing!!
    
    $metaflac_path = find_prog("metaflac");
    
    $normalize_path = find_prog("normalize", $msg31 );
    if ($normalize_path eq "") {
       $norm_type = "None";
       $opt_menu->set_history (3); # 3 set to "None"
       $opt_menu->set_sensitive($false);
       $spinner->set_sensitive($false);
    }
    
    $oggdec_path = find_prog("oggdec", $msg32 );
    
    $mpcdec_path = find_prog("mppdec", $msg33 );
    
    $faad_path = find_prog("faad", $msg34 );
    
    $cdparanoia_path = find_prog("cdparanoia");
    if ($cdparanoia_path eq "") {
	$combo_rip->entry->set_text("cdda2wav"); 
	$combo_rip->set_sensitive($false);
	$ripper = "cdda2wav";
    } 
    $cdda2wav_path = find_prog("cdda2wav", "NO_COMMENT" );
    if ($cdda2wav_path eq "") {
	$combo_rip->entry->set_text("cdparanoia"); 
	$combo_rip->set_sensitive($false);
	$ripper = "cdparanoia";
    }  
    
    $vorbiscomment_path = find_prog("vorbiscomment");
    
    if (not $use_cddbget){ insert_msg( $msg82, "black"); } 
    if (not $use_MP3Info){ insert_msg( $msg83, "black"); }
    
    #---- flac players ----# ; mppdec too
    $mplayer_path = find_prog("mplayer", "Can not find mplayer to play MP3/MP4/WAV/FLAC!" );
    $flac123_path = find_prog("flac123", "NO_COMMENT" );
    
    $all_flac_player{"mplayer"} = $mplayer_path if $mplayer_path;
    $all_flac_player{"flac123"} = $flac123_path if $flac123_path;
       
    foreach my $key (reverse keys %all_flac_player) {
       $player_flac = $key if ( not $all_flac_player{"$player_flac"} ); 
    }
    
    if ( $flac123_path eq "" and $mplayer_path eq ""){
       $flac123_path = find_prog("flac123", "FLAC files can't be played!" );  
    } 
    
    #---- mp3 players ----# ; mppdec too
    $mpg123_path  = find_prog("mpg123", "NO_COMMENT" ); 
    $mpg321_path  = find_prog("mpg321", "NO_COMMENT" );
    $madplay_path = find_prog("madplay", "NO_COMMENT" );
    
    $all_mp3_player{"mpg321"}  = $mpg321_path  if $mpg321_path;
    $all_mp3_player{"mpg123"}  = $mpg123_path  if $mpg123_path;
    $all_mp3_player{"madplay"} = $madplay_path if $madplay_path;
    $all_mp3_player{"mplayer"} = $mplayer_path if $mplayer_path;
        
    foreach my $key (reverse 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("mpg123", "MP3 files can't be played!" );
       find_prog("mpg321", "MP3 files can't be played!" );
       find_prog("madplay", "MP3 files can't be played!" ); 
    }
    #---- ogg players ----# ;
    $ogg123_path  = find_prog("ogg123", "OGG files can't be played!" );
    $all_ogg_player{"ogg123"} = $ogg123_path if $ogg123_path;
    
    $play_path = find_prog("play", "APE files can't be played!" );
    
    $amixer_path = find_prog("amixer", "Can not set volume level!" );
}

 # Audio CD player uses gnormalize::cdplay or Audio::CD or cdcd.
sub cdplayer_available {
   my @all_cdplayer = ();
   $cdcd_path = find_prog("cdcd", "NO_COMMENT" );
   
   if ( $cdcd_path ne "" and not -e encode_char("$home/.cdcdrc") ){ 	
      insert_msg( $msg36 , "black");
      insert_msg( $msg37 , "black");     
   }
   if ( $use_audiocd eq $false and $cdcd_path eq "" and $os !~ /Linux/i ){
      insert_msg( $msg38 , "black");
      insert_msg("Audio::CD" , "red");
      insert_msg("\".\n" , "black");
      $cdcd_path = find_prog("cdcd", $msg35 ); 
   }
   
   #$cdplayer eq "Audio::CD", "cdcd", "gnormalize::cdplay", "none"   
   if ($os =~ /Linux/i       ) { push @all_cdplayer, "gnormalize::cdplay";}
   if ($use_audiocd eq $true ) { push @all_cdplayer, "Audio::CD";  }
   if ($cdcd_path ne ""      ) { push @all_cdplayer, "cdcd";       }
   
   $combo_cdplayer->set_popdown_strings ( @all_cdplayer );
   
   # Set value
   if ( @all_cdplayer >= 1 ){
      if    ( $cdcd_path ne ""      and $cdplayer eq "cdcd"       ){ }
      elsif ( $use_audiocd eq $true and $cdplayer eq "Audio::CD"  ){ }
      elsif ( $os =~ /Linux/i      ){$cdplayer = "gnormalize::cdplay";}  # gnormalize::cdplay have preference, if the others is not choose  
      elsif ( $use_audiocd eq $true){$cdplayer = "Audio::CD" ;        } 
      elsif ( $cdcd_path ne ""     ){$cdplayer = "cdcd" ;             }
      
      $combo_cdplayer->entry->set_text( $cdplayer );
   }
   else{ $combo_cdplayer->entry->set_text( "none" ); }

   $combo_cdplayer->entry->signal_connect("changed", \&cdplayerChanged, $combo_cdplayer);
}

verify_all_paths();
cdplayer_available();

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

sub dir_selection_output {
   my $gtk2_version = Gtk2->CHECK_VERSION (2, 4, 0); # boolean
   my $gtk2_Perl_version = $Gtk2::VERSION;   
   if ( $gtk2_Perl_version < 1.040 or not $gtk2_version ) {
      dir_selection_old();
      return $true;    
   }   
   if ( $check_button_fchooser->get_active ){ dir_output_new(); }
   else { dir_output_old(); }      
   return $true;
}

my $file_dialog_output;
sub dir_output_new {
   # 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');
					     
   # "you first need to convert filename from the local encoding to unicode." (see <man Glib>)					     					        
   $file_dialog_output->set_current_folder( filename_from_unicode $directory_output ); #abrir no lacal especfico       
   # Gtk2::FileChooserAction : 'select-folder', 'open', 
   $file_dialog_output->set_action ('select-folder'); # directory selection only                   
   if ('ok' eq $file_dialog_output->run) {      
      #my $selected_dir =  filename_to_unicode $file_dialog_output->get_filename;     
      my $selected_dir = $file_dialog_output->get_filename;
      $directory_output = encode("utf8",$selected_dir);
      $entry_d2->set_text( $directory_output );
      $tooltips->set_tip( $entry_d2, $directory_output );
      verify_writable_dir( $directory_output );      
   };
   $file_dialog_output->destroy;
}

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

   $file_dialog_output = new Gtk2::FileSelection( "Choose the Output Directory" );
   $file_dialog_output->set('show-fileops' => $true, 'select-multiple' => $false);
   #abrir no lacal especfico
   $file_dialog_output->set_filename( $directory_output );
   $file_dialog_output->file_list->set_sensitive($false); 
   if ('ok' eq $file_dialog_output->run) { 
      $directory_output = $file_dialog_output->get_filename;
      $entry_d2->set_text( $directory_output ); 
      $tooltips->set_tip( $entry_d2, $directory_output );
      verify_writable_dir( $directory_output );      
   };           
   $file_dialog_output->destroy;
}

sub verify_writable_dir {
   my $dir = shift;   
   if ( not -w encode_char($dir) ){ 
         $status_bar->push($context_id, " $dir ".$msg12 );
	 $directory_output = $home;
	 $entry_d2->set_text( $directory_output );
         $tooltips->set_tip( $entry_d2, $directory_output );
   }
   else{ $status_bar->push($context_id, " " ); }
}

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


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

sub dir_selection {
   
   # see <man Gtk2::version>
   # the GtkFileChooser, new in gtk+ 2.4.0 and first supported in
   # Gtk2-Perl at 1.040, is available
   my $gtk2_version = Gtk2->CHECK_VERSION (2, 4, 0); # boolean
   my $gtk2_Perl_version = $Gtk2::VERSION;
   #print "gtk2_version = $gtk2_version ;;  gtk2_Perl_version = $gtk2_Perl_version \n";
   
   if ( $gtk2_Perl_version < 1.040 or not $gtk2_version ) {
      dir_selection_old();
      return $true;    
   }
   
   if ( $check_button_fchooser->get_active ){ dir_selection_new(); }
   else { dir_selection_old(); }   
   
   return $true;
}


sub dir_selection_new {

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

   # 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 -----------------------###
   
   # "you first need to convert filename from the local encoding to unicode." (see <man Glib>)
   $file_dialog->set_current_folder( filename_from_unicode "$directory_base/" ); #abrir no lacal especfico
   # $file_dialog->set('use-preview-label' => $true );   
   
   if ($button_file->get_active) {  # file selection
      # Gtk2::FileChooserAction : 'select-folder', 'open', 
      $file_dialog->set_action ('open');          # file selection is possible
      if ('ok' eq $file_dialog->run) { file_selected(); };
   }   
   if ($button_dir->get_active ) {  # dir selection
      # Gtk2::FileChooserAction : 'select-folder', 'open', 
      $file_dialog->set_action ('select-folder'); # directory selection only             
      
      # Create the Gtk2::ProgressBar to read file info
      $progbar_files_info = Gtk2::ProgressBar->new; 
      $progbar_files_info->set_text( $directory );
      $progbar_files_info->set_orientation('left_to_right');
      $progbar_files_info->show;      
      $file_dialog->set_extra_widget ($progbar_files_info);
      
      $file_dialog->signal_connect( "selection-changed", sub {
         my $current_folder = $file_dialog->get_current_folder;
	 #my $selected_dir =  filename_to_unicode $file_dialog->get_filename;      
	 my $selected_dir = $file_dialog->get_filename;
	 $selected_dir = encode("utf8",$selected_dir);
	 
	 $progbar_files_info->set_text( $selected_dir );
	 $entry_d->set_text($selected_dir);
	 $tooltips->set_tip( $entry_d, $selected_dir);	 
	 #print "current_folder = $current_folder ; selected_dir = $selected_dir\n"; 
      });      
      if ('ok' eq $file_dialog->run) { directory_selected(); }; 
   }   

   $file_dialog->destroy;
}

sub dir_selection_old {

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

   $file_dialog = new Gtk2::FileSelection( $fd_msg );
   $file_dialog->set('show-fileops' => $true, 'select-multiple' => $false);
   $file_dialog->set_filename("$directory_base/"); # abrir no lacal especfico
   
   # $file_dialog->dir_list and $file_dialog->file_list are widget = Gtk2::TreeView
   
   if ($button_file->get_active) {  # file selection
      if ('ok' eq $file_dialog->run) { file_selected(); };
   }       
   if ($button_dir->get_active ) {  # dir selection
      $file_dialog->file_list->set_sensitive($false); 
      if ('ok' eq $file_dialog->run) { directory_selected(); }; 
      # $file_dialog->ok_button->signal_connect( "clicked", \&directory_selected );        
   }   
   $file_dialog->destroy;
}

sub file_selected {
   my $filename = $file_dialog->get_filename;  # file path or directory path   
   $filename = encode("utf8",$filename) if ($check_button_fchooser->get_active);   
   
   (my $file = $filename) =~ s/(.*\/)//g;      # copy and remove (path)/
   insert_msg( "\n$msg78: $file\n\n" , "small");
   
   ($directory = $filename) =~ s/(.*)\/.*/$1/g;
   #$directory = encode_char("$directory/");
   
   #print "directory = $directory ; file = $file ; filename = $filename \n";
   fill_with_all_informations($directory,$file);    
}   
   
sub directory_selected {
   $directory = $file_dialog->get_filename;    
   $directory = encode("utf8",$directory) if ($check_button_fchooser->get_active);
   
   my $msg_dir = ($check_button_recursively->get_active) ? $msg86: $msg88;
   insert_msg( "\n$msg_dir: $directory\n\n" , "small");      
   
   fill_with_all_informations($directory,''); 
}

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

# get all file extensions from original filename
sub file_with_extension {
   my $file = shift;  # example: $file = 'Music.MP3'

   ($file_mp3 = $file) =~ s/\.(.){3,4}$/.mp3/i; # to obtain the filename with appropriate extension
   ($file_mp4 = $file) =~ s/\.(.){3,4}$/.mp4/i;
   ($file_ogg = $file) =~ s/\.(.){3,4}$/.ogg/i;
   ($file_mpc = $file) =~ s/\.(.){3,4}$/.mpc/i;
   ($file_ape = $file) =~ s/\.(.){3,4}$/.ape/i;
   ($file_flac = $file) =~ s/\.(.){3,4}$/.flac/i;
   ($file_wav = $file) =~ s/\.(.){3,4}$/.wav/i;
   ($file_wav_copy = $file) =~ s/\.(.){3,4}$/-normalized.wav/i; #change file extension to .wav
		  
   # return to the real extension name; for that cases *.mP3, Mp3, ...		  
   if    ( $file_input eq 'mp3'){ $file_mp3 = $file; } 
   elsif ( $file_input eq 'mp4'){ $file_mp4 = $file; } 
   elsif ( $file_input eq 'ogg'){ $file_ogg = $file; } # return to original extension  
   elsif ( $file_input eq 'mpc'){ $file_mpc = $file; }
   elsif ( $file_input eq 'ape'){ $file_ape = $file; }
   elsif ( $file_input eq 'flac'){ $file_flac = $file; }
   elsif ( $file_input eq 'wav'){ $file_wav = $file; }
		  
   $entry_f->set_text( "$file" ); # refresh file to normalize
   $tooltips->set_tip( $entry_f, "$file");
   $entry_d->set_text( "$directory" );
   $tooltips->set_tip( $entry_d, "$directory");
   	     
   return ($file_mp3,$file_mp4,$file_ogg,$file_mpc,$file_ape,$file_flac,$file_wav,$file_wav_copy)
}

sub determine_file_input_and_directory {
   
   my $filepath = shift;  # full file path name
   #print " filepath = $filepath \n";
   
   # determine the directory
  
   (my $file = $filepath) =~ s/(.*\/)//g;        # copy and remove (path)/	     	     
   ($directory = $filepath) =~ s/(.*)\/.*/$1/g;  # $directory is a global variable
   $directory =~ s/\/{1,}$//; #remove the '/' character from final if it exists.

   # determine the input/extension 
    
   if ( $file =~ /\.mp3$/i ){       # verify if file extension is .mp3 
          $file_input = 'mp3';
	  $file_mp3 = $file; }      # for files like: music.Mp3, music.MP3  or music.mP3 
   elsif ( $file =~ /\.(mp4|m4a|aac)$/i ){ 
          $file_input = 'mp4';
	  $file_mp4 = $file; } 
   elsif ( $file =~ /\.(mpc|mpp|mp\+)$/i ){  # for files like: music.mpc, .mpp, MPC, MPp ...
          $file_input = 'mpc';
	  $file_mpc = $file; }	  	  
   elsif ( $file =~ /\.ogg$/i ){    # for files like: music.OGG, music.OgG  or music.oGG or ... 
          $file_input = 'ogg';
	  $file_ogg = $file; }       
   elsif ( $file =~ /\.ape$/i ){ 
          $file_input = 'ape';
	  $file_ape = $file; } 
   elsif ( $file =~ /\.flac$/i ){ 
          $file_input = 'flac';
	  $file_flac = $file; } 	  	   
   elsif ( $file =~ /\.wav$/i ){ 
          $file_input = 'wav'; 
	  $file_wav = $file; } 	  
   else{  $file_input = 'other'; }
   
   ($file_mp3,$file_mp4,$file_ogg,$file_mpc,$file_ape,$file_flac,$file_wav,$file_wav_copy) = file_with_extension($file);  
}
   
sub satisfy_the_dependencies {   
   
   # dependencies:
   
   if ($file_input eq 'other'){
        $status_bar->push($context_id, $msg5 );
        pbar_erase_name();  # erase progress bar names
        return $false;
   }   	
   if ($file_input eq 'mp3' and ($lame_path eq "" or not $use_MP3Info) ) {
       $status_bar->push($context_id, $msg6 );
       pbar_erase_name();  # erase progress bar names
       $file_input = 'error';
       return $false;
   }
   if ($file_input eq 'mp4' and $faad_path eq "") {
       $status_bar->push($context_id, $msg7 );
       pbar_erase_name();  # erase progress bar names
       $file_input = 'error';
       return $false;
   }
   if ($file_input eq 'ogg' and $oggdec_path eq "") {
       $status_bar->push($context_id, $msg8 );
       pbar_erase_name();  # erase progress bar names
       $file_input = 'error';
       return $false;
   }
   if ($file_input eq 'mpc' and $mpcdec_path eq "") {
       $status_bar->push($context_id, $msg9 );
       pbar_erase_name();  # erase progress bar names
       $file_input = 'error';
       return $false;
   }
   if ($file_input eq 'ape' and $ape_path eq "") {
       $status_bar->push($context_id, $msg10 );
       pbar_erase_name();  # erase progress bar names
       $file_input = 'error';
       return $false;
   }
   if ($file_input eq 'flac' and $flac_path eq "") {
       $status_bar->push($context_id, $msg11 );
       pbar_erase_name();  # erase progress bar names
       $file_input = 'error';
       return $false;
   }            
   return $true;
}


sub fill_with_all_informations {
   $directory = shift;
   my $file = shift;  
   
   $directory =~ s/\/{1,}$//;    # remove the '/' character from final if it exists.   
   $directory_base = $directory; # used to make_directory_final()
   my $full_path_filename = $directory."/".$file;    
   
   # show the info of selected_file
   determine_file_input_and_directory($full_path_filename);
          
   get_info_from_file();   # refresh mp3/mp4/mpc/... info   
   
   return if (not satisfy_the_dependencies() and $button_file->get_active);
   
   refresh_progress_bar_names();   
   refresh_input_output_arrows();                     
   
   make_array_of_files();  # make an array of files with only supported extensions: *.mp3 , *.mp4*, *.mpc, *.ogg ...      
   if (@array_of_files <= 0){ 
      $tooltips->set_tip( $entry_f, $msg63 ); # entry at beginning
      return;
   }
   fill_treeview_files_to_be_played();
   
   if ($button_dir->get_active){ $full_path_filename = $array_of_files[0]; } # select the first file
   determine_file_input_and_directory($full_path_filename);               
   get_info_from_file();   # refresh mp3/mp4/mpc/... info  
   
   $normalize_button->set_label("normalize");
   change_font_for_all_child($window_font_name,$normalize_button);
}

sub refresh_input_output_arrows {  # draw arrows

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


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

sub refresh_progress_bar_names {
   my $spinner_V_msg;
   my $output_copy = $file_output;  # save the old value
  
   if ($button_output_mp3->get_active) { $file_output = 'mp3'; }
   if ($button_output_mp4->get_active) { $file_output = 'mp4'; }
   if ($button_output_mpc->get_active) { $file_output = 'mpc'; }
   if ($button_output_ogg->get_active) { $file_output = 'ogg'; }
   if ($button_output_ape->get_active) { $file_output = 'ape'; }
   if ($button_output_flac->get_active){ $file_output = 'flac';}
   if ($button_output_wav->get_active) { $file_output = 'wav'; }
    
   if ( $file_output ne $output_copy ){ return; } # to retain the last values only   
   #print "file_output = $file_output ;; output_copy = $output_copy\n";
   
   # get the last encode type from encode_choice()
   if ($button_output_mp3->get_active){$encode = $encode_remember_mp3; $combo_const_avg->entry->set_text($encode);}
   if ($button_output_mp4->get_active){$encode = $encode_remember_mp4; $combo_const_avg->entry->set_text($encode);}
   if ($button_output_ogg->get_active){$encode = $encode_remember_ogg; $combo_const_avg->entry->set_text($encode);}
   if ($button_output_mpc->get_active){$encode = $encode_remember_mpc; $combo_const_avg->entry->set_text($encode);}
   
   if   ( $file_input eq 'wav'){ $pbar->set_text(" "); $pbar->set_fraction(0) ; }
   elsif( $file_input ne 'cda'){ $pbar->set_text(reduce_length_size($file_wav)); $pbar->set_fraction(0) ; }
   
   $pbar_n->set_text(reduce_length_size($file_wav)); 
   $pbar_n->set_fraction(0);
   
   if ($button_output_ogg->get_active) { 
       draw_input_output($da_arrow_enc,undef,("wav","ogg"));
       $frame21->set_label("oggenc ".$msg77);
       my $encode_copy = $combo_const_avg->entry->get_text(); # copy $encode value 
       if ( $encode_copy eq "constant" ){ $encode_copy = 'average'; }
       $combo_const_avg->set_popdown_strings( "average", "variable" );
       $combo_const_avg->entry->set_text($encode_copy); # necessary for not change the $encode value
       #print ("ogg: encode = $encode; encode_copy = $encode_copy ;; encode_remember_ogg = $encode_remember_ogg\n");
       $pbar_encode->set_text(reduce_length_size($file_ogg)); $pbar_encode->set_fraction(0) ;
   }
   if ($button_output_mpc->get_active) { 
       draw_input_output($da_arrow_enc,undef,("wav","mpc"));
       $frame21->set_label("mppenc ".$msg77);
       $combo_const_avg->set_popdown_strings( "variable" );
       $encode = $combo_const_avg->entry->get_text; 
       $pbar_encode->set_text(reduce_length_size($file_mpc)); $pbar_encode->set_fraction(0);
   }
   if ($button_output_mp3->get_active) { 
       draw_input_output($da_arrow_enc,undef,("wav","mp3"));  #default
       $frame21->set_label("lame ".$msg77);
       my $encode_copy = $combo_const_avg->entry->get_text(); # copy $encode value 
       $combo_const_avg->set_popdown_strings( "average", "constant", "variable" );
       $combo_const_avg->entry->set_text($encode_copy); # necessary for not change the $encode value
       $pbar_encode->set_text(reduce_length_size($file_mp3)); $pbar_encode->set_fraction(0);
   }
   if ($button_output_mp4->get_active) { 
       draw_input_output($da_arrow_enc,undef,("wav","mp4"));
       $frame21->set_label("faac ".$msg77);       
       my $encode_copy = $combo_const_avg->entry->get_text(); # copy $encode value 
       if ( $encode_copy eq "constant" ){ $encode_copy = 'average';}
       $combo_const_avg->set_popdown_strings( "average", "variable" );
       $combo_const_avg->entry->set_text($encode_copy); # necessary for not change the $encode value
       $pbar_encode->set_text(reduce_length_size($file_mp4)); $pbar_encode->set_fraction(0);
   }   
   if ($button_output_ape->get_active) { 
       draw_input_output($da_arrow_enc,undef,("wav","ape"));
       $frame21->set_label("ape ".$msg77);
       $pbar_encode->set_text(reduce_length_size($file_ape)); $pbar_encode->set_fraction(0);
   }
   if ($button_output_flac->get_active) { 
       draw_input_output($da_arrow_enc,undef,("wav","flac"));
       $frame21->set_label("flac ".$msg77);
       $pbar_encode->set_text(reduce_length_size($file_flac)); $pbar_encode->set_fraction(0);
   }   
   if ($button_output_wav->get_active) { 
       draw_input_output($da_arrow_enc,undef,("wav","wav"));
       $frame21->set_label("wav ".$msg77);
       $pbar_encode->set_text(" "); $pbar_encode->set_fraction(0);
   }         
   
   $status_bar->push($context_id, " ");
   
   if ( $language == 1 ){$tip18  = "Put here the additional command line used to encode $file_output files.";}
   if ( $language == 2 ){$tip18  = "Coloque aqui linha de comando adicional usada para codificar os arquivos $file_output.";}
   
   # additional command line
   $tooltips->set_tip( $entry_command_mp3, $tip18 );
   $tooltips->set_tip( $entry_command_mp4, $tip18 );
   $tooltips->set_tip( $entry_command_mpc, $tip18 );
   $tooltips->set_tip( $entry_command_ogg, $tip18 );
   $tooltips->set_tip( $entry_command_ape, $tip18 );
   $tooltips->set_tip( $entry_command_flac, $tip18 );
 
   encode_choice_sensitive(); 
}

sub pbar_erase_name{
   $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);
}

#####------------------------------------------#####
# calcule the space to be reduced to obtain a standard stringsize
# 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 -----#####

# Find recursively all files. See <man perlfunc> and Recipe 9.7 from Perl Cookbook, 2nd Edition.
sub make_array_of_files {
    # no warnings; 
    my @all_filename = ();
    $directory =~ s/\/{1,}$//; #remove the '/' character from final if it exists.
    my $directories = encode_char("$directory"); # $directories could be an array @directories

    # 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
       wanted   => sub {
          my $filename = $File::Find::name;
	  
	  if ( $File::Find::dir ne $directory and ( not $check_button_recursively->get_active or 
	       $input eq "File") ){ return; } # not find recursively
	  
          if ( not -r $filename ){ return; }  # -r : File is readable by effective uid/gid.
	  if ( -d $filename ){ return; }      # -d : File is a directory      
          push @all_filename, $filename;
       } 
    } => $directories;
    
    # Directory Selection with some Filter
    my $filter;    
    eval { $filter = $file_dialog->get_filter->get_name; };    
    if (defined $filter){
       #print "filter = $filter\n";
       $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_filename ; $i++){
       #print "filename[$i] = $all_filename[$i] \n";
       my $file = $all_filename[$i];
       
       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( "$msg90\n", "small-red");
       $status_bar->push($context_id, $msg90 );
       return $false;   
    }           
       
    if ( $check_button_recursively->get_active and  $input eq "Directory" ){
           insert_msg( $msg1 , "small-black");}
    else { insert_msg( $msg2 , "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
   $treeview_play->set_model($model);              # add the new model
   add_columns( show_play => $true);               # add columns to the treeview_play   
   
   make_artist_and_album_treeview_column( $true, $true, @files_info );
   
   $button_unselec->set_sensitive($true);
   $button_selec->set_sensitive($true); 
   $da->set_sensitive($true);
   @tracks_already_played = ();
   @tracks_already_played_time = ();    
   
   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 $file_path = shift ; # full path name

   #my $fh = encode("utf8",$file_mp3);
   #print ("fh = $fh\n");
   #my $fh2 = decode("utf8",$fh);
   #print ("fh2 = $fh2\n");
   
   # erase the global strings tags of files
   $Title=""; $Artist=""; $Album=""; $Year=""; $fileSize = 0;
   $Comment=""; $Track_Number=""; $Genre=""; $Frequency = 0;
   $mode_original = ""; $Time_Min_Sec = ""; $Technical_Info = "MPEG";
   $bitrate_average = $true; $Total_Track = "";
   %metadata = (); # clear all hashvariables
   $bitrate_original = 160; # standard value if "change properties" is not active 
   #$encode = $combo_const_avg->entry->get_text(); #refresh $encode value
   
   #------------------------mp3--------------------------#
   # Only show the mp3 info for a file whose extension is .mp3
   if ( $file_input eq 'mp3' ){
      $frame31->set_label ("MP3 info");
      # get_mp3_info_from_file(); 
      #read_ID3v1_mp3_tag($file_mp3);      
      #$bitrate_average = read_Xing_mp3_tag($file_mp3);
      read_mp3_info_tag($file_mp3);
      # show_mp3_info2($file_mp3);
      $label_mode->set_label ($name31." $mode_original");
   }    
   #------------------------mp4--------------------------#
   # Only show the ogg info for a file whose extension is .mp4
   elsif ( $file_input eq 'mp4' ){
      $frame31->set_label ("MP4 info");	
      get_mp4_info_from_file($file_mp4);  
      $label_kbps->set_label ("Bitrate: $bitrate_original Kb/s"); 
      $label_mode->set_label ($channel);
   }      
   #------------------------mpc--------------------------#
   # Only show the ogg info for a file whose extension is .mpc
   elsif ( $file_input eq 'mpc' ){
      $frame31->set_label ("MPC info");
      show_APE_tag($file_mpc);   
      show_mpc_info($file_mpc);
      $encode = 'average';
      $bitrate_average = $true;
      $label_kbps->set_label ("Bitrate: $bitrate_original Kb/s"); 
      $label_mode->set_label ($name43." 2");
   }   
   #------------------------ogg--------------------------#
   # Only show the ogg info for a file whose extension is .ogg
   elsif ( $file_input eq 'ogg' ){
      $frame31->set_label ("OGG info");
      show_ogg_tag($file_ogg);
      show_ogg_info($file_ogg);
      #get_ogg_info_from_file();
      $label_mode->set_label ($channel);
      $label_kbps->set_label ("Bitrate: $bitrate_original Kb/s\nNominal : $bitrate_nominal Kb/s");
   } 
   #------------------------ape--------------------------#
   # Only show the ogg info for a file whose extension is .ape
   elsif ( $file_input eq 'ape' ){ 
      $frame31->set_label ("APE info");    
      show_APE_tag($file_ape); 
      show_ape_info($file_ape);      
      $encode = 'average';
      $bitrate_average = $true;
      $label_kbps->set_label ("Bitrate: $bitrate_original Kb/s"); 
      $label_mode->set_label ($channel);
   }  
   #------------------------flac-------------------------#
   # Only show the meta info for a file whose extension is .flac
   elsif ( $file_input eq 'flac' ){ 
      $frame31->set_label ("FLAC info");   
      show_flac_info($file_flac); 
      $encode = 'average';
      $bitrate_average = $true;
      $label_kbps->set_label ("Bitrate: $bitrate_original Kb/s"); 
      $label_mode->set_label ($channel); 
   } 
   #------------------------cda--------------------------#
   elsif ( $file_input eq 'cda' ){
      show_cda_tag();
      $frame31->set_label ("CD info");   
      $Technical_Info = "Audio CD";
      $Frequency = 44100;
      # decompressed audio has 1411.2 Kb/s, for CD audio 
      $Time_Min_Sec = $audio_cd_total_time;
      $fileSize = $audio_cd_fileSize;
      $channel  = $audio_cd_channel;
      $label_kbps->set_label ("Bitrate: 1411 Kb/s");
      $label_mode->set_label ($channel);      
   } 
   #------------------------wav--------------------------#
   elsif ( $file_input eq 'wav' ){
      $frame31->set_label ("WAV info");
      show_wav_info($file_wav); 
      $Technical_Info = "WAV";
      $label_kbps->set_label ("Bitrate: $bitrate_original Kb/s"); 
      $label_mode->set_label ($channel);
   }
   #------------------------other------------------------#
   elsif ( $file_input eq 'other' ){
      $frame31->set_label ("file info");
      $label_mode->set_label ($name31." $mode_original");
      $label_kbps->set_label ("Bitrate:");      
   }

   #------------- remove special characters -------------#
   
   $Title   = remove_special_chars($Title);     $Artist = remove_special_chars($Artist);
   $Album   = remove_special_chars($Album);     $Genre  = remove_special_chars($Genre);
   $Comment = remove_special_chars($Comment);    $Year  = remove_special_chars($Year);
   $Track_Number = remove_special_chars($Track_Number);
   $Total_Track  = remove_special_chars($Total_Track);
   
   $Track_Number = sprintf("%02d", $Track_Number ) if ( $Track_Number =~ /(\d+)/ ); # leading zero    
   $Total_Track  = sprintf("%02d", $Total_Track  ) if ( $Total_Track  =~ /(\d+)/ );
   
   #-------------- set the tag info on the tab entries --------------#
    
   $entry_title->set_text( "$Title" );
   $entry_artist->set_text( "$Artist" );
   $entry_album->set_text( "$Album" ); 
   $entry_year->set_text( "$Year" );  
   $entry_tn->set_text( "$Track_Number" );
   $entry_tt->set_text( "$Total_Track" );   
   $entry_comment->set_text( "$Comment" );  
   $combo_genre->entry->set_text( "$Genre" );
   $label_mpeg->set_label ("$Technical_Info");
   
   if (number_value($fileSize)>0){ $label_size->set_label ( $name48." $fileSize MB"); }
   else { $label_size->set_label ( $name48); }
   
   if ($Frequency <= 0){ $label_freq->set_label ( $name41 );}
   else { $label_freq->set_label ( $name41." $Frequency Hz");}
   $label_time->set_label ($name42." $Time_Min_Sec"); 

   # remove the decimals numbers: 146.5  --> 146
   $bitrate_original = sprintf("%.0f", number_value($bitrate_original) ); #Kbitrate
     
   $button_save_tag->set_sensitive($false); # always when a new file is loaded.
}

#  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    {TSSE      LAME v3.96COMM 
	#   !   XXXID3v1 Comment Created by GripTIT2    
	#   Vinheta do CapetaTPE1      Almir SaterTALB  
	#  
   InstrumentalCOMM      XXX Created by 
	# GripTYER      1885TRCK      3TCON 
	#      (0)

sub show_cda_tag{   
   my $model = $treeview_play->get_model;    
   my @paths = $treeview_play->get_selection->get_selected_rows; # sel = Gtk2::TreePath  
   my $path = $paths[0]; #get only the first selected path
   return unless $path;
   $iter = $model->get_iter($path);
   return unless $iter;                     
  
   my $selected = $model->get_value($iter,COLUMN_FILE); # track number
   my $row = $selected - 1;  # $track-1;      

   $Title   = $files_info[$row]{title};
   $Artist  = $files_info[$row]{artist};
   $Comment = $files_info[$row]{comment};
   $Album   = $files_info[$row]{album};
   $Genre   = $files_info[$row]{genre};
   $Year    = $files_info[$row]{year};
   $Track_Number = $files_info[$row]{track};
   $Total_Track  = $files_info[$row]{total_track};      
}


sub show_mpc_info {
    my $fname = shift;
    my $header;
    my $file_path = $directory."/".$fname; 
    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);

    if ($file_path !~ /\.(mpc|mpp|mp\+)$/i) { return $false;}
    
    open(IN, encode_char("$file_path") ) || die "Can't read $file_path: $!, stopped";
    
    binmode IN;
    $fileSize   = -s encode_char("$file_path");
    
    # 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);     
    
    # 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 $fname = shift;
    my $header;
    my $file_path = $directory."/".$fname; 
    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' );

    if ($file_path !~ /\.ape$/i) { return $false;}
    
    open(IN, encode_char("$file_path") ) || die "Can't read $file_path: $!, stopped";
    
    binmode IN;
    $fileSize   = -s encode_char("$file_path");
    #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 );
    $Technical_Info = "MAC version: $version\nComp: ".$CompLevel[$CompressionLevel/1000];  
    $channel = $name43." $Channels";
    $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ;
    $bitrate_original = $bitrate;
    $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes
    
    #----------------------------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 $fname = shift;
    my $header;
    my $file_path = $directory."/".$fname; 
    my $buffer;
    
    use constant FLACHEADERFLAG => 'fLaC'; # FLAC__STREAM_SYNC_STRING
    
    my @block_type = ( 'STREAMINFO', 'PADDING', 'APPLICATION', 'SEEKTABLE', 
                       'VORBIS_COMMENT', 'CUESHEET', 'reserved' );	       

    if ($file_path !~ /\.flac$/i) { return $false;}
    
    open(IN, encode_char("$file_path") ) || die "Can't read $file_path: $!, stopped";
    
    binmode IN;
    $fileSize = -s encode_char("$file_path");
    
    # 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);  
       }
       $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("%.1f",$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%";  
    $channel = $name43." $Channels";
    $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ;
    $bitrate_original = $bitrate;
    $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes

# 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 = shift;

   # 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"

   
   # 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';  }
   else { $vendor =""; }
   if ( $file_input eq 'ogg' ) { $Technical_Info = "OGG Vorbis $vendor"; }
  
   # 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}; }
    

# 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 $fname = shift;
    my $header;
    my $file_path = $directory."/".$fname; 
    my $buffer;
    
    use constant OGGHEADERFLAG => 'OggS';
    
    my @block_type = ( 'STREAMINFO', 'PADDING', 'APPLICATION', 'SEEKTABLE', 
                       'VORBIS_COMMENT', 'CUESHEET', 'reserved' );	       

    if ($file_path !~ /\.ogg$/i) { return $false;}
    
    open(OGG, encode_char("$file_path") ) || die "Can't read $file_path: $!, stopped";
    
    binmode OGG;
    $fileSize = -s encode_char("$file_path");
    
    # 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;
	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;
	   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;
	   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 );   
    $channel = $name43." $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";

    #$Technical_Info = "OGG Vorbis";
    $bitrate_average = $true;
       
    close(OGG);
    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 $fname = shift;
    my $file_path = $directory."/".$fname; 	       

    if ($file_path !~ /\.ogg$/i) { return $false;}
    
    open(VORBIS, encode_char("$file_path") ) || die "Can't read $file_path: $!, 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;
	   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);
    #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 $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, encode("$character","$cmd 2>&1 |") )  or die;
   
   ## 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 ){ $channel = $name43." $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 $fname = shift;
    my $header;
    my $file_path = $directory."/".$fname; 
    my $buffer;
    
    use constant WAVHEADERFLAG => 'RIFF';       

    if ($file_path !~ /\.wav$/i) { return $false;}
    
    open(WAV, encode_char("$file_path") ) || die "Can't read $file_path: $!, stopped";
    
    binmode WAV;

    $fileSize = -s encode_char("$file_path");  # $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("%.0f", ($BytesPerSecond * 8)/1000 ); #Kbitrate
    
    read (WAV, my $BlockAlignment, 2); # read 2 byte = 16 bits
    
    read (WAV, my $SampleDepth, 2); # read 2 byte = 16 bits
    $SampleDepth = unpack "S",$SampleDepth; # Sample Size
    $channel = $name43." $Channels\n($SampleDepth 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) ;  
    #$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);
    $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ;
    $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes ; 2**10 = 1024

# 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
#   int16_t	DataFormat;     // Compression Code: (1) for PCM/uncompressed raw sample values ;; (2) for Microsoft ADPCM ; ...
#   int16_t	NumChannels;
#   int32_t	SampleRate;
#   int32_t	BytesPerSecond; // BytesPerSecond = SampleRate * BlockAlignment
#   int16_t	BlockAlignment; // BlockAlignment = SampleDepth / 8 * NumChannels
#   int16_t	SampleDepth;    // Significant Bits Per Sample: This value specifies the number of bits used to define each sample.
#   char	DataTag[4];	// 'data'
#   int32_t	DataLength;
#} 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 $file_path = $directory."/".$fname; 
    my $buffer;
    
    my ($title, $artist, $album, $year, $comment, $tracknum, $genre);    

    if ($file_path !~ /\.mp3$/i) { return $false;}
    
    open(IN, encode_char("$file_path") ) || die "Can't read $file_path: $!, stopped";
    
    binmode IN;
    $fileSize   = -s encode_char("$file_path");    
    
    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 ( $file, $title, $artist, $album, $year, $comment, $tracknum, $genre) = @_;        
    my $buffer; my $ID3v1 = "";
    
    $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;}
    
    open(IN, "+<", encode_char("$file") ) || die "Can't open $file: $!, stopped";    
    
    binmode IN;        
    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    
    if ( $preamble ne 'TAG' ){ seek(IN, 0, 2); } # go to the end of file
    else{ seek(IN,-128, 2);} #overwrite, clobber
    
    # save TAG to file, 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 {
    my $fname = shift;
    my $file_path = $directory."/".$fname;  
    my $buffer;
    my $off = -1; my $byte = "" ; my $try_harder = 4096;
    my $frames = 0;  $fileSize = 0; 

    if ($file_path !~ /\.mp3$/i) { return $false;}
    
    open(IN, encode_char("$file_path") ) || die "Can't read $file_path: $!, 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 $fname = shift;
    my $file_path = $directory."/".$fname;  

    if ($file_path !~ /\.mp3$/i) { return $false;}
    
    my $file = encode_char("$file_path");
    
    ## MP3::Info - Copyright (c) 1998-2005 Chris Nandor.
    my $mp3 = MP3::Info->new($file) if $use_MP3Info;
    get_mp3tag($file)               if $use_MP3Info;
    get_mp3info ($file)             if $use_MP3Info;
    use_mp3_utf8($false)            if $use_MP3Info;
    
    # eval : see <man perlfunc>
    eval { $mp3->title;   }; if ($@){warn "\n$file_path: $@";} 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($file, 2, 2) if $use_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'});

        
    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 );
    
    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_original = $@ ? "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);}         
    
    if ($bitrate_average){
          $label_kbps->set_label ("Variable\nBitrate: $bitrate_original Kb/s");}
    else{ $label_kbps->set_label ("Constant\nBitrate: $bitrate_original Kb/s");}  
    
    $fileSize = -s $file;
    $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);}
    
    $Technical_Info = "MPEG$version/layer$layer";     
}


# only obtain info from ogg files
sub get_mp4_info_from_file {
   my $fname = shift;

   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;

   my $file_path = $directory."/".$fname;
   if ($file_path !~ /\.(mp4|m4a|aac)$/i) { return $false;}
   
   $file_path = encode_char("$file_path");    
   $fileSize  = -s $file_path;
   
   my $cmd; # command
   $cmd = "$faad_path -i \"$file_path\" ";
	    
   my $res = open (INFO, encode("$character","$cmd 2>&1 |") )  or die;
  
   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
            #title: Prelude (Suite n.1)  testo
            #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   	       
	       $channel = $name43." $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; 	       
	       $channel = $name43." 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" ;  
}


sub save_ID3v2_mp3_tag { 
    my ( $file, $title, $artist, $album, $year, $comment, $track, $TotalTrack, $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
    $file = encode_char("$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 ( $TotalTrack ne "" and $TotalTrack =~ /\d+/ and $TotalTrack >= $track ){ $track = $track."/".$TotalTrack; }
    my $sz_tra = length($track);
    my $sz_yea = length($year); # size in byte
    
    my $genre_number = get_genre_number($genre);	
    $genre .= " [$genre_number]" if (defined $genre_number);
    my $sz_gen = length(encode_char($genre));
     
    my $sz_tit = length(encode_char($title)); # ISO-8859-1 or utf8: encode("utf8",$title);
    my $sz_art = length(encode_char($artist));
    my $sz_alb = length(encode_char($album));
    my $sz_com = length(encode_char($comment));
    my $sz_enc = length($metadata{'Encoded by'})            if ($metadata{'Encoded by'});        
    my $sz_lyr = length(encode_char($metadata{'Lyrics'}))   if ($metadata{'Lyrics'});
    my $sz_cps = length(encode_char($metadata{'Composer'})) if ($metadata{'Composer'});   
    my $sz_len = length($metadata{'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, "+<", encode_char("$file") ) || die "Can't open $file: $!, 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 ? 256 : 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 256
       $need_rewrite_file = $true;
       $min_size   = int($tagSize/256) * 256 + 256;   #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 * 256 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, ,encode_char($title)   if ($title ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_art}", 'TPE1', $sz_art_pack, $tagFlagsFrame, ,encode_char($artist)  if ($artist ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_alb}", 'TALB', $sz_alb_pack, $tagFlagsFrame, ,encode_char($album)   if ($album ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_gen}", 'TCON', $sz_gen_pack, $tagFlagsFrame, ,encode_char($genre)   if ($genre ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_yea}", 'TYER', $sz_yea_pack, $tagFlagsFrame, ,$year                 if ($year ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_tra}", 'TRCK', $sz_tra_pack, $tagFlagsFrame, ,$track                if ($track ne "");
       $ID3v2 .= pack "a4a4a2x1a${sz_enc}", 'TENC', $sz_enc_pack, $tagFlagsFrame, ,encode_char($metadata{'Encoded by'})         if ($metadata{'Encoded by'});
       $ID3v2 .= pack "a4a4a2x1a${sz_cps}", 'TCOM', $sz_cps_pack, $tagFlagsFrame, ,encode_char($metadata{'Composer'})           if ($metadata{'Composer'});
       $ID3v2 .= pack "a4a4a2x1a${sz_len}", 'TLEN', $sz_len_pack, $tagFlagsFrame, ,$metadata{'Length'}                          if ($metadata{'Length'});
       $ID3v2 .= pack "a4a4a2x1a3x1a${sz_com}", 'COMM', $sz_com_pack, $tagFlagsFrame, ,'XXX', ,encode_char($comment)            if ($comment ne "");
       $ID3v2 .= pack "a4a4a2x1a3x1a${sz_lyr}", 'USLT', $sz_lyr_pack, $tagFlagsFrame, ,'XXX', ,encode_char($metadata{'Lyrics'}) if ($metadata{'Lyrics'});
    $ID3v2 .= pack "x${padding}";
    #$ID3v2 .= pack "a3a2a1a4", '3DI', $tagVersion, $tagFlags, $tagSize_pack;  #Footer is optional
    
    # ID3    6TIT2      Prelude (Suite n.1)TPE1 ...     
    
    if ( $need_rewrite_file eq $true ){            
       my $n = $$;
       while (1) { # make one temp file
          $tmpfile = "$directory_output/gnormalize-".$n.".temp";	 
          if ( open(TEMP, encode_char(">$tmpfile") ) ) { last; }
	  if ( not -w encode_char("$tmpfile") ){ $status_bar->push($context_id, " $tmpfile ".$msg12 ); die " $tmpfile ".$msg12; }
          $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 ( "$file" ) or die "Can't delete $file: $!\n";
       # don't use rename, see man perlfunc.
       # rename($tmpfile, $file) || die "Can't rename temp file, leaving in $tmpfile, stopped"; 
       my $cmd = "mv -f \"$tmpfile\" \"$file\" "; # move (overwrite) the file
       exec_cmd_system($cmd);
       #print "use the temp file ; total size = $total_size ; original_sz = $original_sz\n"; 
    }
    else{ 
       seek(FILE, 0 , 0);                       # go to begining of file
       syswrite ( FILE, $ID3v2, $total_size );  # syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET
       close(FILE);  
       #print "total size = $total_size\n"; 
    }
                     
}

# 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 $fname = shift;
    my $file_path = $directory."/".$fname; 
    
    my $APEtag; my $APEtag_footer; my $Preample;
    my $version; my $tag_size; my $item_count;
    my $tag_flags;

    if ($file_path !~ /\.(mpc|mpp|mp\+|ape)$/i) {return;}
    
    open(IN, encode_char("$file_path") ) || die "Can't read $file_path: $!, 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( $Track_Number =~ /(\d+)\/(\d+)/ ){ $Track_Number = $1 ; $Total_Track = $2 ; }
    #print ("--> track = $Track_Number ;; Total_Track = $Total_Track \n");
    if ( defined($taghash{'encoded by'}) ){ $metadata{'Encoded by'} = $taghash{'encoded by'}; }
}


sub remove_apetag {
	    my $fname = shift;
	    my $tag_size; my $tag_flags;
	    my $APEfooter; my $preamble;

	    if (not -s encode_char("$fname")) { $@ = "File is empty"; return undef; }
	    
	    # see <man perlopentut>
	    open(APE, encode_char("+< $fname\0") ) || die "Can't read $fname: $!, stopped";
	    
	    my $fh = \*APE; # fh: FileHandle passed
	    
	    binmode $fh;
	    
	    seek($fh,-32, 2);  # Set FileHandle 32 byte from the end of file
	    read($fh, $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 ($fh, -$tag_size, 2);
	    my $file_size = tell $fh;  # file_size - APEtag_size : get the current position
	    
	    #read($fh, $APEfooter, $tag_size, 0);
	    #print "tell = $file_size  ;; APEtag = $APEfooter\n";
	    
            truncate $fh, $file_size or warn "Can't truncate '$fname': $!";
	    
	    # 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	    
	    	    
	    close($fh);			
}


sub write_apetag {
	    my $fname = shift;
	    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)

            # convert to utf8
            $Album = encode("utf8",$Album);
            $Artist = encode("utf8",$Artist);
            $Title = encode("utf8",$Title);
            $Comment = encode("utf8",$Comment);
            $Genre = encode("utf8",$Genre);
            if ( $Total_Track ne "" ){ $Track_Number = $Track_Number."/".$Total_Track; }
	    
	    if (not -s encode_char("$fname") ) { print "File <$fname> is empty: $@"; return undef; }
	    
	    open(APETAG, encode_char(">>$fname") ) || die "Can't read $fname: $!, stopped";	    
	    binmode APETAG; 

	    seek APETAG, 0, 2; # go to end of file : 2 to set it to EOF (End Of File)
	    
	    my $sz_yea = length($Year); # size in byte
	    my $sz_tra = length($Track_Number);
	    my $sz_gen = length($Genre);
	    my $sz_art = length($Artist);
	    my $sz_alb = length($Album);
	    my $sz_tit = length($Title);
	    my $sz_com = length($Comment);
	    
	    ## $metadata{'Encoded by'} = "MAC with gnormalize (http://gnormalize.sourceforge.net)";
	    $metadata{'Encoded by'} = encode("utf8",$metadata{'Encoded by'}) if ($metadata{'Encoded by'});       	    
	    my $sz_enc = length($metadata{'Encoded by'})                     if ($metadata{'Encoded by'});     
	    
	    my $tagTotalSize = 32;  # + 32 bytes (Footer)
	    my $items = 0;	    
	    do { 
	       use bytes; 
	       if ($Year             ne ""){ $items ++; $tagTotalSize += 8 + length('Year') + 1 + $sz_yea;   }
	       if ($Track_Number     ne ""){ $items ++; $tagTotalSize += length('Track') + $sz_tra + 9;      }
	       if ($Genre            ne ""){ $items ++; $tagTotalSize += length('Genre') + $sz_gen + 9;      }
	       if ($Artist           ne ""){ $items ++; $tagTotalSize += length('Artist') + $sz_art + 9;     }
	       if ($Album            ne ""){ $items ++; $tagTotalSize += length('Album') + $sz_alb + 9;      }
	       if ($Title            ne ""){ $items ++; $tagTotalSize += length('Title') + $sz_tit + 9;      }
	       if ($Comment          ne ""){ $items ++; $tagTotalSize += length('Comment') + $sz_com + 9;    }
	       if ($metadata{'Encoded by'}){ $items ++; $tagTotalSize += length('Encoded by') + $sz_enc + 9; }
	    };
	    
            # L: An unsigned long value. --- see <man perlfunc>
	    my $tagVersion      = pack('L', 2000 ); # 2000 =   
	    $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                          Year 1975
	    	    
	    print APETAG pack "a8a4a4a4a4x8", 'APETAGEX', $tagVersion, $tagTotalSize, $tagTotalItems, $tagGlobalFlags;
	    if ($Year             ne ""){ print APETAG pack "a8a5a${sz_yea}", pack('L', $sz_yea ), 'Year', $Year;          }
	    if ($Track_Number     ne ""){ print APETAG pack "a8a6a${sz_tra}", pack('L', $sz_tra ), 'Track', $Track_Number; }
	    if ($Genre            ne ""){ print APETAG pack "a8a6a${sz_gen}", pack('L', $sz_gen ), 'Genre', $Genre;        }
	    if ($Artist           ne ""){ print APETAG pack "a8a7a${sz_art}", pack('L', $sz_art ), 'Artist', $Artist;      }
	    if ($Album            ne ""){ print APETAG pack "a8a6a${sz_alb}", pack('L', $sz_alb ), 'Album', $Album;        }
	    if ($Title            ne ""){ print APETAG pack "a8a6a${sz_tit}", pack('L', $sz_tit ), 'Title', $Title;        }
	    if ($Comment          ne ""){ print APETAG pack "a8a8a${sz_com}", pack('L', $sz_com ), 'Comment', $Comment;    }
	    if ($metadata{'Encoded by'}){ print APETAG pack "a8a11a${sz_enc}",pack('L', $sz_enc ), 'Encoded by', $metadata{'Encoded by'};}	    
	    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";	    
}
	

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 $file_input = $files_info[$row]{extension};
     my $title = $files_info[$row]{title};
     print "\$filepath = $filepath ; \$file_input = $file_input ; \$title = $title\n";
  } 
}

# save_tag button of table31
sub save_tag {
    my $cmd;
    my $filepath;
    
    # get all current 8 entries:
    ($Title,$Artist,$Album,$Comment,$Year,$Track_Number,$Total_Track,$Genre) = array_of_tag_entry();    
    # ppaths();

    #verify if the choosed file is valid
    if ( $file_input eq 'mp3' ){
        $filepath = $directory."/".$file_mp3;	
	
	my $genre_number = get_genre_number($Genre) || '12'; # 12 Other : default	
        #print "genre_number = $genre_number ;; Genre = $Genre\n";
       
        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_number );	             
    }      
    if ( $file_input eq 'ogg' ){
       if ($vorbiscomment_path eq "") {
          $status_bar->push($context_id, " vorbiscomment can't be found!");
          return $false;
       }
       $filepath = $directory."/".$file_ogg;
                
       $cmd  = "$vorbiscomment_path -w \"$filepath\" -t \"description=$Comment\"  ";
       $cmd .= " -t \"title=$Title\" -t \"artist=$Artist\"  -t \"genre=$Genre\" ";
       $cmd .= " -t \"date=$Year\" -t \"album=$Album\" ";
       if ( $Total_Track ne "" and $Total_Track >= $Track_Number ) {
              $cmd .= " -t \"tracknumber=$Track_Number/$Total_Track\"  ";}
       else { $cmd .= " -t \"tracknumber=$Track_Number\"  ";}   
       exec_cmd_system($cmd);
    }    
    if ( $file_input eq 'flac' ){
       if ($metaflac_path eq "") {
          $status_bar->push($context_id, " metaflac can't be found!");
          return $false;
       }
       $filepath = $directory."/".$file_flac;         
       exec_cmd_system("$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  --set-tag=Title=\"$Title\" --set-tag=Artist=\"$Artist\"";
       $cmd .= " --set-tag=Album=\"$Album\" --set-tag=Date=\"$Year\" --set-tag=Description=\"$Comment\"";
       # put the Total_Track in file_mp3
       if ($Total_Track ne "" and $Total_Track >= $Track_Number){$cmd .= " --set-tag=Tracknumber=\"$Track_Number/$Total_Track\"";}
       else {$cmd .= " --set-tag=Tracknumber=\"$Track_Number\"";}
       $cmd .= " --set-tag=Genre=\"$Genre\"  \"$filepath\"";	
	
       exec_cmd_system($cmd);	
    }
    if ( $file_input eq 'mpc' ){
       $filepath = $directory."/".$file_mpc;	    
       remove_apetag ("$filepath");   	    
       write_apetag ("$filepath");
    }   
    if ( $file_input eq 'ape' ){
       $filepath = $directory."/".$file_ape;	    
       remove_apetag ("$filepath");   	    
       write_apetag ("$filepath");	    
    }
    
    my $info_cddb = "";
    if ( $file_input eq 'cda' ){                
       $info_cddb = save_cddb_info_to_home(); # save info to "$home/.cddb/ ($dir/) $cddbid"
       $status_bar->push($context_id, " Saved tag to $info_cddb");	    
    }
    else{ $status_bar->push($context_id, " $file_input".$msg62 ); }
    
    $button_save_tag->set_sensitive($false); 
    get_info_from_entries(); # refresh Artist, Title, Album ...
    
    Set_this_changes_on_Table($filepath) if $file_input ne 'cda';
}

sub Set_this_changes_on_Table {
   my $filepath = shift;  
   my $tree_selection = $treeview_play->get_selection;
   my $model = $treeview_play->get_model;
   
   my @rows = ();
   for (my $row = 0; $row <= $#files_info; $row++){  
       if ($filepath eq $files_info[$row]->{filepath}){
          push @rows, $row;
       }
   } # print "\@rows = @rows ; \$filepath = $filepath\n";
   
   foreach my $row (@rows){ 
      my $track = $row + 1;
      my ($iter,$path) = search_iter_path_for_track($track);
    
      $files_info[$row]{artist}   = $Artist;     # change this value
      $files_info[$row]{title}    = $Title;
      $files_info[$row]{album}    = $Album;
      $files_info[$row]{comment}  = $Comment;
      $files_info[$row]{year}     = $Year;
      $files_info[$row]{track}    = $Track_Number;
      $files_info[$row]{total_track}    = $Total_Track;
      $files_info[$row]{genre}    = $Genre;
   
      $model->set ($iter, COLUMN_ARTIST, $Artist, # set value on model
                          COLUMN_TITLE,  $Title,
		          COLUMN_ALBUM,  $Album,
		          COLUMN_TRACK,  $Track_Number,
		          COLUMN_YEAR,   $Year
	          ) if $iter;
   }		   
}      

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

# get_info_from_entries from entry "tag" of gnormalize for wave files
sub get_info_from_entries {
    # 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 = $combo_genre->entry->get_text; 
}

# Set values from entries to keys: $Title,$Artist,...
sub array_of_tag_entry {
   # tag array
   my @array_info_from_entry = change_tag();

   # always in this order - there are 08 entries at all.
   # @array_info_from_entry = ($title,$artist,$album,$comment,$year,$tn,$Total_Track,$genre);
			    
   for (my $i = 0; $i <= $#array_info_from_entry; $i++){ 
      $array_info_from_entry[$i] = remove_special_chars( $array_info_from_entry[$i] );	
      #print("array_info_from_entry($i) = $array_info_from_entry[$i] \n");
   }	
   $Title = $array_info_from_entry[0];         $Artist  = $array_info_from_entry[1];
   $Album = $array_info_from_entry[2];         $Comment = $array_info_from_entry[3];
   $Year  = $array_info_from_entry[4];    $Track_Number = $array_info_from_entry[5];
   $Total_Track = $array_info_from_entry[6];     $Genre = $array_info_from_entry[7];	
   
   return ($Title,$Artist,$Album,$Comment,$Year,$Track_Number,$Total_Track,$Genre);	
   #-----------------------------------------------#
}

sub remove_special_chars {
   my $text = shift;
   if ( not defined($text) ){ return; }
   $text =~ s/[;*?|><"\$!\015]//g;    # remove special characters	
   $text =~ s/"/''/g;                 # substitute the char " for ''
   $text =~ s/`/'/g;
   return $text;
}

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

##--------------------- Character ---------------------##

# substitute the command <system()> by this sub routine <exec_cmd_system()>
# this occur because of error on loading character such that , , , ...
# in the filename and dirname. This is character encoding routine on
# input/output via a filehandle <open()>.
# see man Encode. utf8, PerlIO, perlrun, ...
sub exec_cmd_system {
   my ($cmd) = @_;  # $cmd is a string
   my $value;
   # "to convert a string from Perl's internal format to iso-8859-1 (also known as Latin1)
   #  use:   <$octets = encode("iso-8859-1", $string);>  "
   #  in my case:  $character = 'iso-8859-1'
   # open filehandle, filename
   open (CM, encode("$character","$cmd 2>&1 |") ) or die "couldn't execute \"$cmd\": $!";
   #print "-->\"$cmd\": $! \n";
   $/="\r"; ## start of loop
   while(<CM>){ $value=$_; } #$_ is the output of command
   $/="\n"; ## final of loop 
   close(CM);
   return $value; 
}

# change the character
sub encode_char {
   my ($cmd) = @_;    
   # iso-8859-1 is also known as Latin1
   encode("$character","$cmd") if defined $cmd;
}

# change, for exemple, 0,49 to 0.49
sub number_value{
    my $nvalue = shift;
    $nvalue =~ s/,/./g;
    return $nvalue;
}

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

sub minimum {
  my $v1 = shift;
  my $v2 = shift;
  my $min;
  if ( $v1 < $v2 ) { $min = $v1; }
  else { $min = $v2; }
  return $min;
}

sub maximum {
  my $v1 = shift;
  my $v2 = shift;
  my $max = $v1 < $v2 ? $v2 : $v1;
  return $max;
}


# if  ( the file_input have the same extension of output and $check_button_change is not active
# and $check_button_overwrite is not active then make copy. 
sub same_extension_overwrite {
    my $cmd;
    if ( $file_input eq $file_output and not $check_button_change->get_active){ # wav not satisfy this condition
         # always remove file_wav_copy if it exist and don't need to encode
         if ( -e encode_char("$directory_output/$file_wav_copy") ){ 
	      exec_cmd_system("rm -f \"$directory_output/$file_wav_copy\" "); 
         }
	 #remove wav file if button_del_wav is active and $file_wav exist
	 if ($check_button_del_wav->get_active and -e encode_char("$directory_output/$file_wav") ){ 
	      exec_cmd_system("rm -f \"$directory_output/$file_wav\" "); 
         }
         # if overwrite is active, don't need copy file
	 if ( not $check_button_overwrite->get_active){
	      # copy the mp3/ogg file (that don't need to normalize) to $directory_final
	      if ($file_input eq 'mp3'){ $cmd = "cp -f \"$directory/$file_mp3\"  \"$directory_final\" ";}
	      if ($file_input eq 'mp4'){ $cmd = "cp -f \"$directory/$file_mp4\"  \"$directory_final\" ";}
              if ($file_input eq 'ogg'){ $cmd = "cp -f \"$directory/$file_ogg\"  \"$directory_final\" ";}
	      if ($file_input eq 'mpc'){ $cmd = "cp -f \"$directory/$file_mpc\"  \"$directory_final\" ";}
	      if ($file_input eq 'ape'){ $cmd = "cp -f \"$directory/$file_ape\"  \"$directory_final\" ";}
	      if ($file_input eq 'flac'){ $cmd = "cp -f \"$directory/$file_flac\"  \"$directory_final\" ";}
	      insert_msg("$cmd\n" , "small"); #print on debug textview
	      insert_msg( $msg56 , "small-red"); 
	      insert_msg("\n" , "small");
	      exec_cmd_system($cmd);
	 }
         if ( not $already_normalized ) {
	     $pbar_n->set_fraction(0) ; 
	     my $sb = $spinner_sensi->get_value;
	     if ( abs($adjust) <= $sb ){
	         $pbar_n->set_text( $msg42 );
		 insert_msg( $msg43 , "small"); 
		 insert_msg("|$adjust| <= $sb" , "small-red");
		 insert_msg( $msg44 , "small"); 
		 insert_msg("-----*****-----\n" , "small-black");
             }
	     else { $pbar_n->set_text( $msg45 );} # for type = None
         }	
         $pbar_encode->set_fraction(0) ;  
         $pbar_encode->set_text( $msg46 );
         $status_bar->push($context_id, " ");
    }
}

sub finalize_process {        
        my $file = shift;
	my $cmd;        
	  
	# At final of encode, always remove file_wav_copy if it exist
	if ( -e encode_char("$directory_output/$file_wav_copy") ){  # if the file exists
	     $cmd = "rm -f \"$directory_output/$file_wav_copy\" ";
	     insert_msg( "\n$msg89" , "small-red"); # "Removing temporary file:"
             insert_msg("\n$cmd\n" , "small");
             exec_cmd_system($cmd);
	}
	
	#remove wav file if button_del_wav is active and $file_wav exist and ...
	if ( $check_button_del_wav->get_active and -e encode_char("$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("$cmd\n" , "small");
	     exec_cmd_system($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 
	    -e encode_char("$directory_final/$file") and -w encode_char("$directory/$file") and $directory_final ne $directory ){
	     $cmd = "mv -f \"$directory_final/$file\"  \"$directory/$file\"  ";
	     exec_cmd_system($cmd); # overwrite
	     insert_msg("\nOverwrite file:" , "small-red");
	     insert_msg("\n$cmd\n" , "small");
	     exec_cmd_system("rmdir \"$directory_final\"  "); # remove the directory if empty
	}	
	## 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 encode_char("$directory_final/$file") ) { # if the file exists
	     #remove normalized file not finished
	     exec_cmd_system("rm -f \"$directory_final/$file\" ");
	}	
}


# determine the values of 7 encode variables: $encode, $mode,
# $vb_Min, $vb_Max, $bitrate, $V, $freq
# don't need to determine $quality

sub encode_settings { 
	my $encode;
	my $mode;
	my $vb_Min;
	my $vb_Max;
	my $bitrate; 
	my $freq;
	
	# button "change properties" active
	if ( $check_button_change->get_active ){ 
	       $mode = $combo_mode->entry->get_text;
	       $encode = $combo_const_avg->entry->get_text();   # refresh value
	       if ( $file_output eq 'mp3' ) { $bitrate = $spinner_bitrate_mp3->get_value_as_int(); }# for $encode = "average"
	       elsif ( $file_output eq 'mp4' ) { $bitrate = $spinner_bitrate_mp4->get_value_as_int(); }# for $encode = "average"
	       elsif ( $file_output eq 'ogg' ) { $bitrate = $spinner_bitrate_ogg->get_value_as_int(); }# for $encode = "average"
	       $freq = number_value($combo_fq->entry->get_text);
	       # for mp3 constant $bitrate is obtainned from $combo_bitrate
	       if ( $encode eq "constant" and $file_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;  
	       # only this two possibility when button "change properties" is not active
               if ( $bitrate_average ){ $encode = "average"; } 
	       else { $encode = "constant";}
	       
	       if ( $file_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 ( $file_input =~ /(wav|cda|ape|flac)/ ){ 
	            $bitrate = 160; 
		    $freq = 44100;
		    $Vogg = $V = 4.0;
		    $Vmpc = 5.0;
		    $Vmp4 = 200;
		    $encode = "average";
	       }
	       if ( $file_input eq 'mp3' and $mode_original ne "" ){ $mode = $mode_original;}
	       else {$mode = 'joint stereo';}
	}
        $Vogg = sprintf("%0.1f", $Vogg ); $Vogg = number_value($Vogg); # only one digit
	$Vmpc = sprintf("%0.1f", $Vmpc ); $Vmpc = number_value($Vmpc);
	
	$vb_Max = $combo_Max->entry->get_text; #refresh value
        $vb_Min = $combo_Min->entry->get_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 $file_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 {
	
        my %config;
	my $CDDB_server = $entry_CDDB_server->get_text;
	my $cddb_port = $spinner_cddb_port->get_value;
	my $cddb_transport = $combo_cddb_transport->entry->get_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 = get_discids($audiodevice_path)->[0];
        $cddbid = sprintf("%08x", $cddbid);
	#print "cddbid = $cddbid ;; CDDB_server = $CDDB_server:$cddb_port ;; cddb_transport = $cddb_transport\n";

        # user interaction welcome?
        $config{input}=0;   # 1: ask user if more than one possibility
                            # 0: no user interaction		    	    
        
	my $info_cddb = "";
	$info_cddb = get_cddb_info_from_home(); # return the cddb filename
	if ( $info_cddb ne "" and not $check_button_overwrite_cddb->get_active ){	
           $status_bar->push($context_id, $msg20.$info_cddb );
	   return; #not overwrite
	}
	else{
	   eval {%cd = get_cddb(\%config);};  # get info from internet
	   if($@) { 
	      if ( $info_cddb ne "" ) { $status_bar->push($context_id, $msg71."$info_cddb."); }
	      else{ $status_bar->push($context_id, $msg72 );} # " cddb: can't connect to internet!";
	      return;
	   }
	}
	$Artist = $cd{artist};    $Artist  = remove_special_chars($Artist);
	$Album  = $cd{title};      $Album  = remove_special_chars($Album);
	$Genre  = $cd{genre};      $Genre  = remove_special_chars($Genre);
	$Year   = $cd{year};       $Year   = remove_special_chars($Year);
        $Total_Track = $cd{tno};   $Total_Track  = remove_special_chars($Total_Track);	
	
	if ($Genre eq ""){ $Genre = 'Other';} # default
	$entry_album->set_text($Album);
	$combo_genre->entry->set_text($Genre);
	$entry_year->set_text($Year);
	$entry_tt->set_text($Total_Track);
		
	my $model = $treeview_play->get_model;
		
	my $row = 0;
        foreach my $titulo ( @{$cd{track}} ) {
	  my $iter = $model->get_iter_from_string ("$row");
	  
	  $titulo = remove_special_chars($titulo);	  
	  $files_info[$row]{title} = $titulo;
	  $model->set ($iter, COLUMN_TITLE, $files_info[$row]{title});
	  
	  $files_info[$row]{artist} = $Artist;
	  $model->set ($iter, COLUMN_ARTIST, $files_info[$row]{artist});
	  
	  $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});
	  
	  $files_info[$row]{comment} = "";
	  $files_info[$row]{genre}   = $Genre;
	  $files_info[$row]{total_track}    = $Total_Track;
	  	  	  
          $row++;
        }
	save_cddb_info_to_home(); # save info to "$home/.cddb/ ($dir/) $cddbid"
			      
}

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

sub save_cddb_info_to_home {	

        my $model = $treeview_play->get_model;
	my $info_cddb = ""; #filename of $info_cddb saved at $home
	
	# Get ID number of CD.
	my $cddbid = get_discids($audiodevice_path)->[0];
	$cddbid = sprintf("%08x", $cddbid);
	
	# ($Title,$Artist,$Album,$Comment,$Year,$Track_Number,$Total_Track,$Genre) are Global variables
	
	opendir(DIR, encode_char("$home/.cddb") ) ;  #search for $home/.cddb/$Genre/ directory
	while (my $direct = readdir(DIR)) {
		next if $direct eq ".";
		next if $direct eq "..";
		if ( -e encode_char("$home/.cddb/$direct/$cddbid") ){
		   $info_cddb = "$home/.cddb/$direct/$cddbid";
		   last;
		}
	}
	closedir(DIR);
	$Genre = $combo_genre->entry->get_text;
	if ($Genre eq ""){ $Genre = 'Other';} # default
	
	# make a 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"
	# -d : if file is a directory
	if ( $info_cddb eq "" ){
	      if ( not -d encode_char("$home/.cddb/$Genre") ){
	         my $cmd = "mkdir -p \"$home/.cddb/$Genre\" "; # create the directory .cddb/$Genre
                 exec_cmd_system($cmd);
	      }
	      $info_cddb = "$home/.cddb/$Genre/$cddbid";
	}	
        
	if ($Artist eq ""){
	   my $iter  = $model->get_iter_from_string ("0");   # first row
	   $Artist = $model->get_value($iter,COLUMN_ARTIST); # get artist
	}
	my $multi_artist = $false;
	my $default_artist;
	for (my $row=0; $row <= $#files_info ; $row++){ # determine if the CD is multi artist
           my $iter  = $model->get_iter_from_string ("$row");
	   my $artist = $model->get_value($iter,COLUMN_ARTIST); # get artist
	   if ($row == 0){$default_artist = $artist;} 
	   if ($default_artist ne $artist){$multi_artist = $true; last;}  
        }
	
	$Album = "album" if $Album eq "";
		
	open( CDDB, ">", encode_char("$info_cddb") ) || 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=$Artist / $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} ne 'cda'){last;}
	   
           my $iter  = $model->get_iter_from_string ("$row");
	   
           my $title = $model->get_value($iter,COLUMN_TITLE);   # get title
	   $title = remove_special_chars($title);
	   print CDDB "TTITLE$row=$title\n";
	   
	   my $artist = $model->get_value($iter,COLUMN_ARTIST); # get artist
	   $artist = remove_special_chars($artist);
	   if ($multi_artist eq $false){
	      $files_info[$row]{artist} = $Artist;
	      $model->set($iter, COLUMN_ARTIST, $files_info[$row]{artist});
	   }
	   else{ print CDDB "TARTIST$row=$artist\n"; }
	   
	   $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});
	   
	   $files_info[$row]{total_track} = $#files_info + 1; #$Total_Track;
	   $files_info[$row]{comment} = $Comment;
	   $files_info[$row]{genre}   = $Genre;
        }
	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( encode_char("$info_cddb"),encode_char("$home/.cddb/$cddbid") ); 1 };
	if ( $symlink_exists != 1 ){ link encode_char("$info_cddb"),encode_char("$home/.cddb/$cddbid"); }
	
	show_scrolling_text(); # Display the "Artist - Title - Album ..."	
	
	make_artist_and_album_treeview_column( $true, $true, @files_info ); 	
	
	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 = get_discids($audiodevice_path)->[0];
	$cddbid = sprintf("%08x", $cddbid);
	my $tracks = get_discids($audiodevice_path)->[1];
	#print "cddbid = $cddbid ;; tracks = $tracks \n";
	
	opendir(DIR, encode_char("$home/.cddb") ) ;  #search for $genre/$cddbid file
	while (my $dir = readdir(DIR)) {
		next if $dir eq ".";
		next if $dir eq "..";
		if ( -e encode_char("$home/.cddb/$dir/$cddbid") ){
		   $info_cddb = "$home/.cddb/$dir/$cddbid";
		   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 encode_char("$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=Joo
	
	# read from file
	open( INFOCDDA, "<", encode_char("$info_cddb") ) ;
	$Artist = "artist";   # initial value
	$Album = "album";
	$Genre = "Other";
	
	# TITLES of the songs
	while( <INFOCDDA> )
	{   
	     if ($_ =~ /DTITLE=(.*)\s\/\s(.*)\n/i){ 
	        $Artist = $1;
		$Album = $2; 
	     }
	     if ($_ =~ /DYEAR=(.*)\n/i){ $Year = $1; }
	     if ($_ =~ /DGENRE=(.*)\n/i){ $Genre = $1; }
             if ($_ =~ /TITLE(\d+)=(.*)\n/i){ 
		my $row = $1;
		my $iter  = $model->get_iter_from_string ("$row");
		if ( $2 ne "" ){
		   $files_info[$row]{title} = $2;
		   $model->set ($iter, COLUMN_TITLE, $files_info[$row]{title});
		   
		   $files_info[$row]{artist} = $Artist;
		   $model->set ($iter, COLUMN_ARTIST, $files_info[$row]{artist});
		   
		   $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});
		}
	     }
	     if ($_ =~ /ARTIST(\d+)=(.*)\n/i){ #multi artist
		my $row = $1;
                my $iter  = $model->get_iter_from_string ("$row");
		if ( $2 ne "" ){
		   $files_info[$row]{artist} = $2;
		   $model->set ($iter, COLUMN_ARTIST, $files_info[$row]{artist});
		}
	     }
	}
	close(INFOCDDA);
	for (my $row=0; $row<=$#files_info;$row++){	   	   
	   $files_info[$row]{comment} = "";
	   $files_info[$row]{genre}   = $Genre;
	   $files_info[$row]{total_track} = $#files_info + 1; #$Total_Track;	   	   
	}
	$entry_artist->set_text($Artist);
	$entry_album->set_text($Album);
	$combo_genre->entry->set_text($Genre);
        $entry_year->set_text($Year);
	$entry_tt->set_text($#files_info + 1); # Total_Track
	return $info_cddb;	
}

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

#  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 $total_frames = length_music_sector();
	
	# 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;

	# 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);	
   
        # add columns to the tree view
        add_columns( show_file => $false, show_play => $false);
	
	if ( @files_info >= 1 ){ # exist, at least, one 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 ( $cdcd_path ne "" or $use_audiocd eq $true or $os =~ /Linux/i ){	   
	      $da->set_sensitive($true);
	      @tracks_already_played = ();
              @tracks_already_played_time = ();
	      $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);
	   pbar_erase_name();  # erase progress bar names
	   $file_input = 'cda';
	   get_info_from_file(); # refresh the informations to 'cda' extension
	   refresh_input_output_arrows();
	   my $file = " ";
	   ($file_mp3,$file_mp4,$file_ogg,$file_mpc,$file_ape,$file_flac,$file_wav,$file_wav_copy) = file_with_extension($file);
           $tooltips->set_tip( $entry_f, $msg63 ); # entry at beginning
	   
	   $button_save_tag->set_sensitive($false); 
           get_info_from_entries(); # refresh Artist, Title, Album ...
	   print_cdparanoia_output($total_frames);  
	   
	   if ($check_button_cddb->get_active and $use_cddbget eq $true){ 
	      $status_bar->push($context_id, $msg68 ); # " Getting information from cddb ...";
	      while (Gtk2->events_pending()) { Gtk2->main_iteration()};
	      get_cddb_info_from_internet();
	   }
	   elsif ($check_button_cddb->get_active and $use_cddbget eq $false){ 
	      $status_bar->push($context_id, $msg82 );
	   }
	   else { $status_bar->push($context_id, $msg69 );}	   	   
	   
	   show_scrolling_text(); # Display the "Artist - Title - Album ..."	   			   	   
	}
	
	make_artist_and_album_treeview_column( $true, $true, @files_info );
	
	# verify if some ripper is available.
	if ( $ripper eq "cdparanoia" and $cdparanoia_path eq "" ){
           $status_bar->push($context_id, $msg73 );
           $file_input = 'error';
           return $false;
        }
	elsif ( $ripper eq "cdda2wav" and $cdda2wav_path eq "" ){
           $status_bar->push($context_id, $msg74 );
           $file_input = 'error';
           return $false;
        }		
}

sub entry_cda_change {
   $button_selec->set_sensitive($false);
   $button_unselec->set_sensitive($false);
   $da->set_sensitive($false);
   $file_input = 'error'; # rip audio cd is not possible   
   stop_playing_music();
   #if ( defined($timer) ){ Glib::Source->remove($timer);} # quit loop, see <man Glib::MainLoop>
   
   # clear the old model - see <man Gtk2::ListStore>
   $treeview_play->get_model->clear;
   $treeview_album->get_model->clear;
   $treeview_artist->get_model->clear;

   @files_info = ();    # reset array
   @length = ();       # array of music length
   @music_sector = (); # array of relative frames
   @start_sector = (); # absolute frames - 150 (offset)
   $selected_track = 1;
}

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;
   
   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);
	   $status_bar->push($context_id, $msg67."$audiodevice_path.");
	   return $false;
	}	   
        my $total_track = $toc_audiocd->[0]->{total_track};
	$channel = $name43." 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 ( $cdparanoia_path ne "" ){ # 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, $msg21 );	
	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 -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);
	   $status_bar->push($context_id, $msg67."$audiodevice_path.");
	   return $false;
	}
	#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 = $name43." $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;
}

$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 = $Artist eq "" ? "Artist" : $Artist ;
   my $alb = $Album  eq "" ? "Album"  : $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 @cols = $treeview->get_columns; # Retuns an array of columns.
  foreach my $col (@cols){ $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);
  # 'clickable' : Whether the header can be clicked
  $column_rip->set (alignment => 0.5, 'clickable' => $true);
  $column_rip->signal_connect ( clicked => \&unselect_cda);
  $treeview->insert_column ($column_rip, COLUMN_RIP);         

  $column_rip->set_title("play") if ( $args{show_play} );
    
  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 ("file", $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);
  }  

  # 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);
  
  if ( $args{show_track} ){  
     my $column_track = Gtk2::TreeViewColumn->new_with_attributes ($name45, $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);
  } 
  
  # 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');
  
  if ( $args{show_artist} ){        
     my $column_artist = Gtk2::TreeViewColumn->new_with_attributes ($name46, $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 (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 ($name47, $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_sort_column_id (COLUMN_TITLE);
  $treeview->insert_column ($column_title, COLUMN_TITLE);    
     
  if ( $args{show_album} ){
     # album column
     my $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 ($name53, $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);
  }    
  
  # 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 ($name44, $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_resizable ($true);
     $column_bitrate->set_min_width (50);
     $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 ($name49, $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 ("freq", $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 ($name50, $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 ($true);  # 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 ($name56, $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 ($true);  # 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 ($name51, $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 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 {
  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 encode_char($filepath) and $files_info[$row]->{extension} ne 'cda' ){ 
     $status_bar->push($context_id, " $filepath ".$msg12 );
     return;
  }  
  if ($column == COLUMN_ARTIST) {
     $files_info[$row]{artist} = $new_text;
     $model->set ($iter, $column, $files_info[$row]{artist});
     $entry_artist->set_text( $new_text );	
  }
  if ($column == COLUMN_TITLE) {
     $files_info[$row]{title} = $new_text;
     $model->set ($iter, $column, $files_info[$row]{title});
     $entry_title->set_text( $new_text );
     #print ("--> title = ",$files_info[$row]{title},";;  rip = ",$files_info[$row]{rip}," track = $track\n");
  }  
  $button_save_tag->set_sensitive($true); 
  $status_bar->push($context_id, $msg70 );
}

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 and return the track selected
sub selection_tree {
  my $tree_selection = $treeview_play->get_selection;
  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
  return unless $path;
  $iter = $model->get_iter($path);
  return unless $iter;
  
  my $selected = $model->get_value($iter,COLUMN_FILE); # track number
  my $row = $selected - 1;  # $track-1;
  my $filepath = $files_info[$row]{filepath};    
  $file_input = $files_info[$row]{extension}; 
  if ( $file_input ne 'cda' ){    
     determine_file_input_and_directory($filepath);     	
  }
  else {
     pbar_erase_name();  # erase progress bar names
     my $file = " ";
     ($file_mp3,$file_mp4,$file_ogg,$file_mpc,$file_ape,$file_flac,$file_wav,$file_wav_copy) = file_with_extension($file);
     $tooltips->set_tip( $entry_f, $msg63 ); # entry at beginning
  }            
  get_info_from_file();   # get mp3/mp4/mpc/... info   
  refresh_progress_bar_names();   
  refresh_input_output_arrows();  
      
  #print "selected = $selected ; filepath = $filepath ; file_input = $file_input\n";
}

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} = $false;
      $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); 
      undef( $artists_already_played{uc($artist)} );     # 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); 
      undef( $albums_already_played{uc($album)} );       # 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',
                scroll         => $true,
		color_artist   => $true,
		color_album    => $true,
		set_rip        => $true,  
		track          => $selected_track-1,	
                @_,            # 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 $first_artist_scrolled = $false;
      foreach my $artist ( return_artist_name($files_info[$args{track}]) ){ # 'art1 & art2' return (art1,art2)

         if ( $args{select_color} eq 'no_color' ){    # color = undef
            $artists_already_played{uc($artist)} = undef;  # Set False(undef) if the artist is not played
	    $color = undef;
         }
         elsif ( $args{select_color} eq 'playing' ){  # color = $color_row_playing
            $color = $color_row_playing;
         }
         elsif ( $args{select_color} eq 'played' ){   # color = $color_row_already_played
            $artists_already_played{uc($artist)}++;        # Set True to the artist already played
	    $color = $color_row_already_played;
         } 
   
         ($iter,$path) = search_iter_path_for_some_element($artist,$treeview_artist,COLUMN_ARTIST);
         $model->set ( $iter, COLUMN_COLOR, $color ) if $iter;       # to color the selected artist line         
      
         next if ($first_artist_scrolled);
         # now, only scroll to the first selected artist. 
         $treeview_artist->scroll_to_cell($path, undef, $true ,0.50, 0.50) if ($path and $args{scroll}); 
         $first_artist_scrolled = $true;        
      }
   }
   
   if ( $args{color_album} ){ 
      $model = $treeview_album->get_model;
      my $album = return_album_name( $files_info[$args{track}] );  # if no album name, create a guess name from filepath  
   
      if ( $args{select_color} eq 'no_color' ){
         $albums_already_played{uc($album)} = undef;  # Set False(undef) if the album is not played
	 $color = undef;
      }
      elsif ( $args{select_color} eq 'playing' ){
         $color = $color_row_playing;
      }
      elsif ( $args{select_color} eq 'played' ){
         $albums_already_played{uc($album)}++;        # Set True to the album already played
	 $color = $color_row_already_played;
      }
      	 
      # Now, scroll to the selected album: 
      ($iter,$path) = search_iter_path_for_some_element($album,$treeview_album,COLUMN_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) = search_iter_path_for_track( $args{track}+1 );    # find $iter and $path associeted to some $track
   $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{track}]{rip} = $true if $args{set_rip};     # change the boolean value
      $files_info[$args{track}]{played} = $false;
      $files_info[$args{track}]{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{track}]{rip} = $true;
      $files_info[$args{track}]{played} = $false;
      $files_info[$args{track}]{playing} = $true;
      $color = $color_row_playing;
   }
   elsif ( $args{select_color} eq 'played' ){
      $files_info[$args{track}]{rip} = $false;
      $files_info[$args{track}]{played} = $true;
      $files_info[$args{track}]{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{track}]{rip},  #'untaggle' the played music
                       COLUMN_COLOR, $color) if $iter;              # color the $selected_track
   #print "file = ",$args{track}+1," ; select_color = $args{select_color} ; scroll = $args{scroll} \n";		          
}

sub search_iter_path_for_some_element { # See man Gtk2::ListStore, Gtk2::TreeModel
   my ($artist,$treeview,$column) = @_;
   my $iter; my $path;
   my $model = $treeview->get_model;
   
   my $row = 0;
   $model->foreach( sub{  # model is a $ListStore
      my($ListStore,$path2,$iter2) = @_;      
      my $artist_f = $ListStore->get_value($iter2,$column); 
      if ( uc($artist) eq uc($artist_f) ){  # if the artists are equals, the $iter is right
         $path = Gtk2::TreePath->new ($row);
         $iter = $model->get_iter($path); 	 
	 return $true; # abandon the loop 'foreach'
      }
      #print "row = $row ; artist_f = $artist_f\n";
      $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_track_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_track-1]{extension};      
  stop_playing_music();
  $status_bar->push($context_id, ""); 
  
  if ( not defined $args{skip} ) {  
     # when go_back, the selected_track is already known from @tracks_already_played
     if ( not $args{go_back} ){ 
        ($selected_track, $total_time) = track_to_play(); 
     }
     # $selected_track == -1 when there is none selected track to play
     if ( $selected_track == -1){
        if ($loop_tracks eq $false){
	    $status_bar->push($context_id, $msg22 );  
            $go_forward = $false;
	    show_time();	    		    	     	
        }
        else {
            $force_unselect_all_tracks = $false; # to select all tracks
            unselect_cda();  # subroutine that select all tracks
            ($selected_track, $total_time) = track_to_play();
            @tracks_already_played = (); 
            @tracks_already_played_time = ();
	    $selected_track_last_value = -10;
        }
	set_no_color_for_all();	
     }
  }
  if ( $selected_track == -1 ){ return $false; } # If there is no selected track  
    
  # when cda is playing and the next selected_track is not cda
  if ( $extension_last_value eq 'cda' and $files_info[$selected_track-1]{extension} ne 'cda' ){
     stop_cda(); # don't stop if the next track have cda extension      
  }
  
  # lame --quiet --decode FILENAME.mp3 - | play -t wav -  # play mp3 with lame
  #my $cmd = "$cdda2wav_path -D $audiodevice_path -q -e -t $selected_track -d0 -N ";
  #my $pid = open( PLAY, encode_char("nice -n $priority $cmd ") ) ;
  #close(PLAY);
  #$pid = fork;	  
  # 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 ($iter,$path,$model) = search_iter_path_for_track($selected_track);
  #my $music = $model->get_value($iter,COLUMN_FILEPATH); #print "music = $music\n";     
  my $music = $files_info[$selected_track-1]{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_track-1]{frequency}; }  
  if ( not -e encode_char($music) and $files_info[$selected_track-1]{extension} ne 'cda'  ){
     $files_info[$selected_track-1]{remove} = $true;
     go_forward();
     return; 
  }  
  if ( defined $args{skip} ) { $count = $args{skip}; } # determine the start time to be played
       
  if ($files_info[$selected_track-1]{extension} eq 'mp3' and ($mpg123_path or $mpg321_path or $madplay_path or $mplayer_path) ){
        
	my $frame=sprintf ('%.0f', $count * ($Frequency/1152) );  # $totalSeconds = $Total_samples/$Frequency;
	
        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, encode("$character",$music);      
  }
  elsif ( ($files_info[$selected_track-1]{extension} eq 'mp4' or $files_info[$selected_track-1]{extension} eq 'wav') and $mplayer_path ){
        
	@exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 
	              '-really-quiet', '-slave', '-noconsolecontrols', '-nojoystick','-ss', $count, encode("$character",$music) );	
  }
  elsif ($files_info[$selected_track-1]{extension} eq 'mpc' and $mpcdec_path){  
        @exec_argv = ($mpcdec_path, '--silent', '--start', $count, encode("$character",$music), $device_path ); 	   	        
  }
  elsif ($files_info[$selected_track-1]{extension} eq 'ogg' and $ogg123_path){  
        @exec_argv = ($ogg123_path, '-d', $device_type, '-b', $buffer, '-q', '-k', $count, encode("$character",$music) );	   	        
  }
  elsif ($files_info[$selected_track-1]{extension} eq 'ape' and $ape_path and $play_path){
        # mac "zzz.ape"  - -d | play -t wav -d /dev/audio -
        #@exec_argv = ($ape_path, encode("$character","$music"), '-', '-d', '|', '/usr/bin/play', '-t', 'wav', '-');
	my $cmd = "$ape_path \"$music\" - -d | $play_path -t wav -d $device_path - ";
	@exec_argv = ( encode("$character","$cmd") );
  } 
  elsif ($files_info[$selected_track-1]{extension} 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, encode("$character",$music) );     
     } 
     elsif ($flac123_path and $player_flac eq "flac123" ){   
        $count = 0;
        @exec_argv = ($flac123_path, '-d', $device_type, '-q', encode("$character",$music));   
     }
  }
  # @exec_argv = ( $play_path, '-d', $device_path, encode("$character",$music) ); # WAV files	   
   	          
  if ($files_info[$selected_track-1]{extension} 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_track-1]{extension} 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_track $selected_track ";
           exec_cmd_system($cmd);	   
        }
        elsif ( $cdplayer eq "gnormalize::cdplay" ){
	   gnormalize::cdplay::play_cdrom_msf(Track => $selected_track);
        }
        elsif ( $cdplayer eq "Audio::CD" ){ # libcdaudio  ;; Audio::CD ;; see <man Audio::CD>
	   $audiocd = Audio::CD->init("$audiodevice_path");
           $audiocd->play_track($selected_track, $selected_track);
        }
	#print "using command to play cdrom: cmd = $cmd\n";
  }	   
  # draw scrolling text     
  if ($selected_track != $selected_track_last_value){ show_scrolling_text(); }
  $selected_track_last_value = $selected_track;  
     
  $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' );   

  # 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

# find $iter and $path associeted to some file
# this is necessary when the column Track or Length is reordenable or altered
sub search_iter_path_for_track { # See man Gtk2::ListStore, Gtk2::TreeModel
   my $track = shift;
   my $iter; my $path;
   my $model = $treeview_play->get_model;
   
   $model->foreach( sub{  # model is a $ListStore
      my($ListStore,$path2,$iter2) = @_;      
      my $track_f = $ListStore->get_value($iter2,COLUMN_FILE); 
      if ($track == $track_f){  # if the tracks are equals, the $iter is the right
	 my $row = ($path2->get_indices)[0];
         $path = Gtk2::TreePath->new($row);
         $iter = $model->get_iter($path);
	 #print "row = $row ; track_f = $track_f\n";	 
	 return $true; # abandon the loop 'foreach'
      }
      return $false; # to don't abandon the loop	      
   } );
   
   return ($iter,$path);
}

# Make array with all selected tracks that will be played
# It return the selected_track number and its time length.
sub track_to_play {
       my $time = 0;  
       my $random_element = -1; # $selected_track
       @tracks_to_play = ();
           
       my $model = $treeview_play->get_model;   
     
       $model->foreach( sub{  # model is a $ListStore
          my($ListStore,$path,$iter,$val) = @_;
          my $track = $ListStore->get_value($iter,COLUMN_FILE);
	  my $row = $track - 1;
          if ($files_info[$row]{rip} eq $true ){  # if the track is toggled, then push it into array
	     push @tracks_to_play, $track;
          }
	  return $false; # to don't abandon the loop	  
       });
       # remove one element from front of @array -- see perlfunc : splice
       if ( @tracks_to_play >= 1 ){  # exist at least one element
	   if ( $play_random eq $true ){ 
	      my $rand = int( rand(@tracks_to_play) ); # pick one random element: 0<= rand < @tracks_to_play number
	      #print " rand[1---N] = $rand ;; tracks = @tracks_to_play\n";
	      $random_element = splice(@tracks_to_play, int( $rand ), 1); # pull one random element of @array
	   }
	   else { $random_element = splice(@tracks_to_play, 0, 1);} # pull the first element of @array
       }
       else{ return ( $random_element, $time ); 
       }
       $time = $files_info[$random_element-1]{length}; # 2:56:34   02:32
       $time = time_to_sec($time);	
	
       #print " random_element = $random_element ;; time = $time ;; tracks_to_play = @tracks_to_play\n";
       return ( $random_element, $time );
}

# 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_track-1]{extension} eq 'cda') {
     go_forward();
  }
  elsif ( defined $pid_player and $playing_music and $files_info[$selected_track-1]{extension} ne 'cda') {
     if ( waitpid($pid_player, WNOHANG) < 0 or $go_forward eq $true ){ go_forward(); }
  } 
  if ( $go_back eq $true and @tracks_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_track-1]{extension} 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 $track_played = $selected_track; # save this value
     
     # if the track was played completely, pass it to @track_already_played       
     push @tracks_already_played, $selected_track; 
     push @tracks_already_played_time, $total_time; 
     #print "--> tracks_already_played = @tracks_already_played  \n";

     # To color the selected artist:
     color_the_selected_tracks_and_scroll( select_color => 'played', scroll => $false, track => $track_played-1 );
			 
     play_selection(go_forward => $true);   # stop and play 
     #print "go forward ; selected_track = $selected_track ; iter = $iter\n";                  
     $go_forward = $false;
}

sub go_back {
     $go_back = $true;   
     my $row = $selected_track -1;
         
     #print "antes -- tracks_already_played = @tracks_already_played  \n";
     $selected_track = splice(@tracks_already_played, -1);      # remove the last element of @array
     $total_time     = splice(@tracks_already_played_time, -1);
     #print "depois -- tracks_already_played = @tracks_already_played ;; selected_track = $selected_track\n";
     
     # To color the selected artist:
     color_the_selected_tracks_and_scroll( select_color => 'no_color', scroll => $false, track => $row );     
     
     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_track-1] + 150;  # absolute start frame, 150 is the offset (gap) of first frame.
  my $abs_final_frame  = $start_sector[$selected_track] + 150;    # absolute final frame for the selected track
  if ( $selected_track == -1 ){ return $true; } # If there is no selected track
   
  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_track=$selected_track;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_track ) { $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_track; } 
    
  if ( $current_track != $selected_track ){ # If another program changes the selected track.
     # find $iter and $path associeted to some $track 
     my ($iter,$path) = search_iter_path_for_track($current_track);   
     $treeview_play->scroll_to_cell($path, undef, $true ,0.50, 0.50) if $path;
     $count = 0;
  }    
  $selected_track = $current_track 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_track-1]{length} if $selected_track != -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_track != $selected_track_last_value){ show_scrolling_text(); }
  $selected_track_last_value = $selected_track;
  
  stop_playing_music() if (not defined $pid_player and $files_info[$selected_track-1]{extension} ne 'cda');  	  
  
  if ( $show_time_abs and $cdplayer eq "gnormalize::cdplay" and $files_info[$selected_track-1]{extension} 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_track-1]{extension} 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

   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 (@tracks_already_played > 0 and 1==2){ #debug
      print "extension_last_value = $extension_last_value ; extesion = $files_info[$selected_track-1]{extension}\n";
   }
}

sub stop_playing_music{
   my $cmd;   
   # update the 'cdrom:' entry only if audio cd is not playing
   if ( $playing_music eq $false ){ 
      $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>
   
   if (not defined $files_info[$selected_track-1]{extension}){ return; }     
     
   if ( $playing_music and not ($go_back or $go_forward) and $files_info[$selected_track-1]{extension} eq 'cda' ){
      stop_cda();  # don't stop if the next track have cda extension       
   }   

   if ($files_info[$selected_track-1]{extension} 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 ($go_forward eq $false and $go_back eq $false){ # 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 );
   }
}

# 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 = "$cdparanoia_path -d $audiodevice_path -e -w $opt  $track \"$directory_output/$file_wav\" ";

	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview 
	insert_msg("\n" , "small");

	my $pid = open( NOIA, encode_char("nice -n $priority $cmd  2>&1 |") ) ;
	if( !defined($pid) )
	{
		$status_bar->push($context_id, " Could not rip!");
		print ( "Could not rip!  ");
		return $false;
	}
	$pid_rip_cda = $pid;
	
	$status_bar->push($context_id, $msg54 );
	$pbar->set_text((reduce_length_size("$track-$files_info[$track-1]{title}")));
	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, $msg54." - $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, $msg55 );
		    # remove wav file
		    exec_cmd_system("rm -f \"$directory_output/$file_wav\" ");
		    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 = "$cdda2wav_path dev=$audiodevice_path -x -g -no-infofile $opt -t $track \"$directory_output/$file_wav\" ";
	
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview 
	insert_msg("\n" , "small");
	
	## $pid = pid of rip
	my $pid = open( CDRIP, encode_char("nice -n $priority $cmd 2>&1 |") );
	#$pid = fork; # man perlipc
	if( !defined($pid) )
	{
		$status_bar->push($context_id, " Could not rip!");
		print ( "Could not rip!  ");
		return $false;
	}	
	
	## set rip pid, pid > 0
	$pid_rip_cda = $pid;
	
	$status_bar->push($context_id, " ripping audio to wav");
	$pbar->set_text((reduce_length_size("$track-$files_info[$row]{title}")));
	
	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!");
		    # remove wav file
		    exec_cmd_system("rm -f \"$directory_output/$file_wav\" ");
		    $/="\n";  # abandon loop
		    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 $flac_path = $entry_ape->get_text();
	
	my $cmd = "$flac_path -d \"$directory/$file_flac\" -f -o \"$directory_output/$file_wav\" ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	my $pid = open( FLACDEC, encode_char("nice -n $priority $cmd 2>&1 |") );
	if( !defined($pid) )
	{
		$status_bar->push($context_id, " Could not decode!");
		print ( "Could not decode!  ");
		return $false;
	}

	## set flac pid, pid > 0
	$pid_flac_decode = $pid;
	
	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!");
		    # remove wav file
		    exec_cmd_system("rm -f \"$directory_output/$file_wav\" ");
		    $/="\n";  # abandon loop
		    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 $cmd = "$faad_path \"$directory/$file_mp4\" -f 1 -o \"$directory_output/$file_wav\" ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	my $pid = open( FAADDEC, encode_char("nice -n $priority $cmd 2>&1 |") );
	if( !defined($pid) )
	{
		$status_bar->push($context_id, " Could not decode!");
		print ( "Could not decode!  ");
		return $false;
	}

	## set flac pid, pid > 0
	my $pid_faad_decode = $pid;
	
	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!");
		    # remove wav file
		    exec_cmd_system("rm -f \"$directory_output/$file_wav\" ");
		    $/="\n";  # abandon loop
		    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 $ape_path = $entry_ape->get_text();
	my $cmd = "$ape_path  \"$directory/$file_ape\" \"$directory_output/$file_wav\" -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, encode_char("nice -n $priority $cmd 3>&1 1>&2 2>&3 3>&- |") );
	if( !defined($pid) )
	{
		$status_bar->push($context_id, " Could not decode!");
		print ( "Could not decode!  ");
		return $false;
	}

	## set ape pid, pid > 0
	$pid_ape = $pid;
	
	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!");
		    # remove wav file
		    exec_cmd_system("rm -f \"$directory_output/$file_wav\" ");
		    $/="\n";  # abandon loop
		    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 $cmd = "$mpcdec_path  \"$directory/$file_mpc\" --wav \"$directory_output/$file_wav\" ";

	#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, encode_char("nice -n $priority $cmd 2>&1 |") );
	if( !defined($res) )
	{
		$status_bar->push($context_id, " Could not decode!");
		print ( "Could not decode!  ");
		return $false;
	}

	## set ogg pid, pid > 0
	$pid_mpc_decode = $res;
	
	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!"); 
	            if ( -e encode_char("$directory_output/$file_wav") ){exec_cmd_system("rm -f \"$directory_output/$file_wav\" ");}
		    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 $cmd = "$oggdec_path  \"$directory/$file_ogg\" -o \"$directory_output/$file_wav\" ";

	#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( OGGDEC, encode_char("nice -n $priority $cmd 2>&1 |") );
	if( !defined($res) )
	{
		$status_bar->push($context_id, " Could not decode!");
		print ( "Could not decode!  ");
		return $false;
	}

	## set ogg pid, pid > 0
	$pid_ogg_decode = $res;
	
	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 "lixo-o tes'a.ogg" to "lixo-o tes'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!"); 
	            if ( -e encode_char("$directory_output/$file_wav") ){exec_cmd_system("rm -f \"$directory_output/$file_wav\" ");}
		    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 $cmd = "$lame_path --verbose --decode \"$directory/$file_mp3\" \"$directory_output/$file_wav\" ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
 
	my $pid = open( LAME, encode_char("nice -n $priority $cmd 2>&1 |") );
	
	## set lame pid, pid > 0  see <man perlipc>
	$pid_lame_decode = $pid;
	
	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, $msg57 ); 
		    # In the case of stop decode process, always remove file_wav if it exist
	            # because the file_wav is not complete/entire
	            if ( -e encode_char("$directory_output/$file_wav") ){exec_cmd_system("rm -f \"$directory_output/$file_wav\" ");}
		    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 make_directory_final{ # when normalizing recursively or not.
   # if "$directory_base/$directory_remain",  ( $directory_remain" can be equal "" )
   # make: "$directory_base/normalized/$directory_remain"
   # for example: /tmp/teste1/teste2 ;; /tmp/teste1 ;;
   # suppose that $directory_base = '/tmp/teste1', then $directory_remain = '/teste2' or ''
   
   # Caution with metacharacters: {}[]()^$.|*+?\ 
   # To match this metacharacters use the escape sequence "\Q"..."\E" (see man perlretut)
   	     
   (my $directory_remain = $directory ) =~ s/^\Q$directory_base\E//;   
   $directory_remain = "" if ($file_input eq 'cda');
   
   $directory_final = "$directory_output/$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 encode_char("$directory_final") ){
         my $cmd = "mkdir -p \"$directory_final\" ";
	 insert_msg("\n$cmd\n" , "small"); #print on debug textview
         exec_cmd_system($cmd); 
   }  
   #print "directory = $directory \ndirectory_base = $directory_base\n";
   #print "directory_remain = $directory_remain \ndirectory_final = $directory_final\n\n";  
} 

## normalize wave files

sub normalize_wav
{       my $cmd;	
        $already_normalized = $false;
	# my $threshold = $spinner_sensi->get_value;
	my $n_type; # normalization type
	
	if ( not -e encode_char("$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 a copy of wav file to normalize or encode
	$cmd = "cp -f \"$directory_output/$file_wav\"  \"$directory_output/$file_wav_copy\" ";
	insert_msg("\n$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	exec_cmd_system($cmd);
	
	make_directory_final();
	
	# get the wave total miliseconds ;; 
	# 2352 = bytes per frame, "raw" mode ;; 1 sec have 75 frames = 75 * 2352 bytes = 176400 bytes
	my $fileSize = -s encode_char("$directory_output/$file_wav_copy");    # $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";
	
	if    ( $norm_type eq "Peak"  ) { $n_type = "--peak" ; }
	elsif ( $norm_type eq "Mix"   ) { $n_type = "-m" ;     }
	elsif ( $norm_type eq "None" ){  #------------------------------------------#
	    $pbar_n->set_text( $msg45 );                                       #
	    insert_msg( $msg41 , "small-red");                                 # 
	    insert_msg("\n" , "small");                                        #
	    $pid_normalize = -1;                                               #
            return;                                                            #
	}#---------------------------------------------------------------------#
	else{ # for $norm_type = "Fix"	
            $value = $spinner->get_value_as_int; # print ("normalization value = $value\n"); 
	    my $n_value = sprintf("%0.2f", $value/100 );
	    $n_type = "-a $n_value" ; 
	}
	
	my $threshold = sprintf("%0.1f", 2/10 ); # equal to '0.2' or '0,2'
	
	# normalize the $file_wav_copy    
	$cmd = "$normalize_path $n_type -v -T $threshold \"$directory_output/$file_wav_copy\" ";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");

	## start normalization
	my $pid = open( NORMALIZE, encode_char("nice -n $priority $cmd 2>&1 |") ) or die "couldn't execute \"$cmd\": $!\n";
        
	## set normalize pid
	$pid_normalize = $pid;	
	
	my $saved_value = 0;
	my $div = 0;
	my $sinal = "";
	$adjust = 0;

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	while( <NORMALIZE> )
	{       
		#Computing levels...
                #almir_sater-instr  90% done, ETA 00:00:00 (batch  90% done, ETA 00:00:00) 
                #Level for almir_sater-instrumental-01_corumba.wav: -14.2786dBFS (0.0000dBFS peak)
                #Applying adjustment of 3.82dB to almir_sater-instrumental-01_corumba.wav...
		#Applying adjustment of -9.49dB to almir_sater-instrumental-03_vinheta_do_capeta.wav...
                #almir_sater-instr  36% done, ETA 00:00:02 (batch  36% done, ETA 00:00:02) 
		#almir_sater-instrumental-01_corumba.wav already normalized, not adjusting...
		
		if ( $_ =~ /.*adjustment\s*of\s(-?\d+.\d+)dB.*/ ){ 
		    $adjust = number_value($1);
		    # put a positive sinal if $1 > 0
		    if ( not $1 =~ /-/ ) {$sinal="+";} 
		} 
		
		if ( $_ =~ /.*batch\s*(\d+)\%\s*done,\s*ETA.*/ )
		{
		   $saved_value = $saved_value +1;
		   #print ( "div = $1  ; saved_value = $saved_value; adjust = $adjust ; a_n = $already_normalized\n");
		   $div = number_value(sprintf("%0.2f", $1/100 ));

		   if ( $pbar_n->get_fraction() <=1 and $saved_value <= 100 ){ 
		      $pbar_n->set_fraction( $div ) ; 
		      #print ( "div = $div \n");
		      $pbar_n->set_text( $msg52 );
		      $pbar_n->set_orientation('right_to_left');
		   }
		   if ( $pbar_n->get_fraction() <=1 and $saved_value > 100 ){ 
		      $pbar_n->set_fraction( $div ) ;  
		      $pbar_n->set_text( $msg50."${sinal}${adjust}dB...");
		      $status_bar->push($context_id, $msg51."${sinal}${adjust}dB");
		      $pbar_n->set_orientation('left_to_right');
		   }
		}
		if ( $_ =~ /.*\s*already\s*normalized.*/ ){		  
		   $already_normalized = 1;
		   $pbar_n->set_fraction( 1 ) ; 
		   $pbar_n->set_text( $msg47 );	      
		   insert_msg( $msg48 , "small-red");
		}
		while (Gtk2->events_pending()) { Gtk2->main_iteration()};
		if ( not $normalize_button->get_active and $pid_normalize >= 0 ) { 
		    $pid_normalize = StopProcessing($pid_normalize, $msg49 );
		    $/="\n";  # abandon loop
		}
	}
	$/="\n"; ## final of loop
	close( NORMALIZE );
    
	if ($normalize_button->get_active) {  # if normalize button is active
	    if ( not $already_normalized ){
	       insert_msg( $msg53."${sinal}${adjust}dB." , "black");
	       insert_msg("\n" , "small");
	    }
	    $pid_normalize = -1;         # reset normalize pid on the final of process
	    return $true;
	}
	else {return $false;}   	
}

# wav --> ogg
sub encode_wav_to_ogg
{      
	my $comment;
	my $cmd; # command	
	my $bitrate;
	my $mode;
	my $freq;
	
        ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings();   
	
	# tag comment
	if ( $norm_type eq "Fix" ){
	       $comment = "gnormalize $norm_type value=$value";}
	else { $comment = "gnormalize $norm_type ";}
	
	#$comment .= $ogg_comment; # add to comment  ---  tag commands for normalized ogg file
	my $cmd_tag = " -t \"$Title\" -a \"$Artist\"  -l \"$Album\" ";
	$cmd_tag .= " -d \"$Year\" -c \"comment=$comment\" -G \"$Genre\" ";
	
	if ( $Total_Track ne "" and $Total_Track >= $Track_Number ){ $cmd_tag .= " -N \"$Track_Number/$Total_Track\" "; }	
	else { $cmd_tag .= " -N \"$Track_Number\" "; }
	
	# 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.
	
	# 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 = "$oggenc_path -q $Vogg ";
        }
	else{  # for ABR (average bitrate)
	   $cmd = "$oggenc_path -b $bitrate -m $vb_Min -M $vb_Max "; 
	} 
	$additional_command_ogg = $entry_command_ogg->get_text;
	  
	# common commands of oggenc for all options of encode
	$cmd .= " $cmd_tag --resample \"$freq\" ";
	$cmd .= " $additional_command_ogg \"$directory_output/$file_wav_copy\" -o \"$directory_final/$file_ogg\" ";
	
	#print "$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	## start encoding
	my $res = open( OGGENC, encode_char("nice -n $priority $cmd 2>&1 |") ) or die "couldn't execute \"$cmd\": $!\n";
        ## pid process of oggenc 
	if( !defined($res) )
	{
		$status_bar->push($context_id, " Could not encode!");
		return $false;
	}      
	
	## set ogg encode pid
	$pid_ogg_encode = $res;
	
	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!");
		    $/="\n";  # abandon loop
		}
	}
	$/="\n"; ## final of loop
	close(OGGENC);
	
	finalize_process($file_ogg); 
	
	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 $comment;
	my $cmd; # command
	my $bitrate;
	my $mode;
	my $freq;
	
        ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings();
	
	# tag comment
	if ( $norm_type eq "Fix" ){
	       $comment = "gnormalize $norm_type value=$value";}
	else { $comment = "gnormalize $norm_type ";}	
	
	# ----------- tag of mpc file ------------- #

	# BUG of xmms and BMP plugin for mpc files: the tag must have at 
	# least a empty space, example: --artist " "
	# send a mail to beepmp-devel@lists.sourceforge.net
	if ($Artist eq ""){$Artist = " ";}
	if ($Album eq "" ){$Album = " "; }
	if ($Year eq ""  ){$Year = "0";  }
	if ($Genre eq "" ){$Genre = " "; }
	if ($Track_Number eq ""){$Track_Number = "0";}
		
	
	if ($Title eq ""   ){ ($Title = $file_mpc) =~ s/\.(.){3}$//;     }
	my $cmd_tag = " --tag \"Title=$Title\" ";
        if ($Artist ne ""  ){ $cmd_tag .= " --artist \"$Artist\" ";      }
        if ($Album  ne ""  ){ $cmd_tag .= " --album \"$Album\" ";        }
	if ($Year ne ""    ){ $cmd_tag .= " --tag \"Year=$Year\" ";      }
        if ($comment ne "" ){ $cmd_tag .= " --tag \"Comment=$comment\" ";}
        if ($Genre ne ""   ){ $cmd_tag .= " --tag \"Genre=$Genre\" ";    }
	$cmd_tag .= " --tag \"Encoded by=MPPENC with gnormalize (http://gnormalize.sourceforge.net)\" ";
	
	if ($Track_Number != 0){ # $Track_Number ne ""
	   if ( $Total_Track eq "" ){ $cmd_tag .= " --tag \"Track=$Track_Number\" ";}
	   elsif ( $Total_Track >= $Track_Number ){ $cmd_tag .= " --tag \"Track=$Track_Number/$Total_Track\" ";}
	}
	# ----------- tag of mpc file ------------- #	
	
	# --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;
	
	$cmd = "$mpcenc_path --overwrite $profile $additional_command_mpc ";
		
	# common commands of mpcenc for all options of encode
	$cmd .= " $cmd_tag ";
	$cmd .= " \"$directory_output/$file_wav_copy\"  \"$directory_final/$file_mpc\" ";
	
	#print "$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview 
	insert_msg("\n" , "small");
	
	## start encoding
	my $res = open( MPCENC, encode_char("nice -n $priority $cmd 2>&1 |") ) or die "couldn't execute \"$cmd\": $!\n";
        ## pid process of mpcenc 
	if( !defined($res) ) {
           $status_bar->push($context_id, " Could not encode!");
           return $false;
	}      
	
	## set ogg encode pid
	$pid_mpc_encode = $res;
	
	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
		
		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!");
		    $/="\n";  # abandon loop
		}
	}
	$/="\n"; ## final of loop
	close(MPCENC);
	
	finalize_process($file_mpc); 
	
	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 $compress = $spinner_compress->get_value_as_int();

	# tag comment
	if ( $norm_type eq "Fix" ){
	       $Comment = "gnormalize $norm_type value=$value";}
	else { $Comment = "gnormalize $norm_type ";}	
	
	$additional_command_ape = $entry_command_ape->get_text;
	
	my $cmd = "$ape_path $additional_command_ape \"$directory_output/$file_wav_copy\"  \"$directory_final/$file_ape\"  -c$compress ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	# To exchange a command's STDOUT and STDERR in order to capture the STDERR 
	my $pid = open( APEENC, encode_char("nice -n $priority $cmd 3>&1 1>&2 2>&3  |") );
	if( !defined($pid) )
	{
		$status_bar->push($context_id, " Could not decode!");
		print ( "Could not decode!  ");
		return $false;
	}

	## set ape pid, pid > 0
	$pid_ape = $pid;
	
	my $div = 0; # initial value
	my $saved_value = 0;

	## loop for output - initial
	$/="\r"; ## from http://acidrip.thirtythreeandathird.net/
	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!");
		    $/="\n";  # abandon loop
		}		
	}
	$/="\n"; ## final of loop
	close( APEENC );
	
	remove_apetag ("$directory_final/$file_ape");
	$metadata{'Encoded by'} = "MAC with gnormalize (http://gnormalize.sourceforge.net)";	    
	write_apetag ("$directory_final/$file_ape");
	
	finalize_process($file_ape); 
	
	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 $comment;
	my $cmd; # command
	my $bitrate;
	my $mode;
	my $freq;
	my $compress = $spinner_compress_flac->get_value();
	
	# tag comment
	if ( $norm_type eq "Fix" ){
	       $comment = "gnormalize $norm_type value=$value";}
	else { $comment = "gnormalize $norm_type ";}	
	
        ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings();
	
	$additional_command_flac = $entry_command_flac->get_text;	

	$cmd = "$flac_path -$compress -f $additional_command_flac \"$directory_output/$file_wav_copy\" -o \"$directory_final/$file_flac\" ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	my $pid = open( FLAC, encode_char("nice -n $priority $cmd 2>&1 |") );
	if( !defined($pid) )
	{
		$status_bar->push($context_id, " Could not encode!");
		print ( "Could not encode!  ");
		return $false;
	}

	## set flac pid, pid > 0
	$pid_flac_decode = $pid;
	
	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!");
		    $/="\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 --set-tag=Title=\"$Title\" --set-tag=Artist=\"$Artist\"";
	$cmd_tag .= " --set-tag=Album=\"$Album\" --set-tag=Date=\"$Year\"";
	# put the Total_Track in file_mp3
	if ($Total_Track ne "" and $Total_Track >= $Track_Number){$cmd_tag .= " --set-tag=Tracknumber=\"$Track_Number/$Total_Track\"";}
	else {$cmd_tag .= " --set-tag=Tracknumber=\"$Track_Number\"";}
	$cmd_tag .= " --set-tag=Genre=\"$Genre\" --set-tag=Description=\"$comment\" \"$directory_final/$file_flac\"";
		
	if ( $metaflac_path ne "" and $normalize_button->get_active ){
	   insert_msg("." , "small-ini");
	   insert_msg( $cmd_tag , "small"); #print on debug textview
	   insert_msg("\n" , "small");
	   exec_cmd_system($cmd_tag);	
	}
	
	finalize_process($file_flac); 
	 
	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 $comment;
	my $cmd; # command
	my $bitrate;
	my $mode;
	my $freq;
	my $compress = $spinner_compress_flac->get_value();
	
	# tag comment
	if ( $norm_type eq "Fix" ){
	       $Comment = "gnormalize $norm_type value=$value";}
	else { $Comment = "gnormalize $norm_type ";}
	
	$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();
	
	$cmd = "$faac_path -c 44100 ";
	# use --no-tns and --no-midslide to play correctly in the Quicktime player
	if ( $encode eq "variable" and $check_button_change->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 \"$directory_output/$file_wav_copy\" -o \"$directory_final/$file_mp4\" ";

	#print "\n$cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview
	insert_msg("\n" , "small");
	
	my $pid = open( AAC, encode_char("nice -n $priority $cmd 2>&1 |") );
	if( !defined($pid) )
	{
		$status_bar->push($context_id, " Could not decode!");
		print ( "Could not decode!  ");
		return $false;
	}

	## set flac pid, pid > 0
	my $pid_faac_encode = $pid;
	
	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!");
		    $/="\n";  # abandon loop
		}		
	}
	$/="\n"; ## final of loop
	close(AAC);		
	
	finalize_process($file_mp4); 
	 
	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 --> mp3 : encode with lame
sub encode_wav_to_mp3
{      
	my $cmd; # command
	my $bitrate;
	my $mode;
	my $freq;
	
        ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings();
	
	# tag comment
	if ( $norm_type eq "Fix" ){
	       $Comment = "gnormalize $norm_type value=$value";}
	else { $Comment = "gnormalize $norm_type ";}	
	
	# tag commands for normalized mp3 file 
	my $cmd_tag = " --noreplaygain --ignore-tag-errors --add-id3v2 --pad-id3v2 --tt \"$Title\" ";
	$cmd_tag .= " --ta \"$Artist\" --tl \"$Album\" --ty \"$Year\" ";
	$cmd_tag .= " --tc \"$Comment\" --tg \"$Genre\" ";	
	if ( $Total_Track ne "" and $Total_Track >= $Track_Number ){ $cmd_tag .= " --tn \"$Track_Number/$Total_Track\" "; }	
	else { $cmd_tag .= " --tn \"$Track_Number\" "; }	
	
	# lame commands
	if ( $encode eq "constant" ){ # CBR (constant bitrate)
	   $cmd = "$lame_path -q $quality -c -b $bitrate ";
        }
	if ( $encode eq "average" ){ # ABR (average bitrate)
	   $cmd = "$lame_path -q $quality -c --abr $bitrate -b $vb_Min -B $vb_Max --nohist ";
        }
	if ( $encode eq "variable" and $check_button_change->get_active ){ # VBR (variable bitrate)
	   # b - minimum allowed bitrate - see  <man lame>
	   # B - maximum allowed bitrate
	   # V - Variable  BitRate -  0 <= quality <= 9
	   $cmd = "$lame_path -q $quality -c --vbr-new -V $V -b $vb_Min -B $vb_Max --nohist ";
        }	
	$additional_command_mp3 = $entry_command_mp3->get_text;
	# common commands of lame for all options of encode
	$cmd .= " -m \"$mode\" --resample \"$freq\" $additional_command_mp3 ";
	$cmd .= " $cmd_tag \"$directory_output/$file_wav_copy\" \"$directory_final/$file_mp3\" ";
	
	#print "cdm = $cmd\n";
	insert_msg("." , "small-ini");
	insert_msg("$cmd" , "small"); #print on debug textview 
	insert_msg("\n" , "small");
	
	## start encoding
	my $pid = open( LAME, encode_char("nice -n $priority $cmd 2>&1 |") ) or die "couldn't execute \"$cmd\": $!\n";     
	
	## set lame encode pid
	$pid_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 
		
		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, $msg58 );
		    $/="\n";  # abandon loop
		}		
	}
	$/="\n"; ## final of loop
	close( LAME );
	
	if ($normalize_button->get_active) {
	   # save the Total_Track in file_mp3 --- lame can not save the tag: 'track/Total_Track' 
	   my $filename = $directory_final."/".$file_mp3;
	   $metadata{'Encoded by'} = "LAME with gnormalize (http://gnormalize.sourceforge.net)";
	   # to save ID3v2 tag 
	   save_ID3v2_mp3_tag($filename, $Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Total_Track, $Genre);
	}	 		    
	finalize_process($file_mp3); 
	 
	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);
$file_output = $file_output_copy;

# Get values from config file ~/.gnormalize_config
if    ($file_output eq 'mp3'  and $lame_path ne ""  ) {$button_output_mp3->set_active( $true ); }  #padro - ativo
elsif ($file_output eq 'mpc'  and $mpcenc_path ne "") {$button_output_mpc->set_active( $true ); }
elsif ($file_output eq 'mp4'  and $faac_path ne ""  ) {$button_output_mp4->set_active( $true ); }
elsif ($file_output eq 'ogg'  and $oggenc_path ne "") {$button_output_ogg->set_active( $true ); }
elsif ($file_output eq 'ape'  and $ape_path ne ""   ) {$button_output_ape->set_active( $true ); }
elsif ($file_output eq 'flac' and $flac_path ne ""  ) {$button_output_flac->set_active( $true );}
elsif ($file_output eq 'wav') {$button_output_wav->set_active( $true );}
encode_choice_sensitive();
$notebook->set_current_page ($notebook_page_num);

####-----------------------ARGV-----------------------####

sub arguments {

 # Get the parameters from the command line.
 if (@ARGV == 1){      #number of arguments
    my $file = $ARGV[0];
       
    if ( ! -e encode_char("$file") ){ # if the file not exist
       print "This file not exist: $file\n";
       return; 
    }    
    $file =~ s/(.*\/)//g;      #copy and remove (path)/
    insert_msg( $msg78.": $file\n\n" , "small");   
    ($directory = $ARGV[0]) =~ s/(.*)\/.*/$1\//g;
       
    if ( $directory !~ /\// ){      # for the case of none directory: 'gnormalize music.mp3'
       $directory = "$ENV{'PWD'}"; # $directory = `pwd` 
    }    
    elsif ( $directory !~ /^\// ){  # for the case of directory like that: 'gnormalize some/place/music.mp3'
       $directory = "$ENV{'PWD'}/".$directory;
    }     
    #print "file = $file ;; directory = $directory \n";
    $button_file->set_active($true); # dir or file
    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; # necessrio 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 ------------------# 

{ # 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_track, 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);
#      }
#   "
#}   	      

