1#!/usr/local/bin/perl 2require 5.008; # require minimum Perl version 5.8 - support for Unicode. 3use Gtk2 -init; # load the Gtk-Perl module - see <man Gtk2> 4use Glib qw(filename_from_unicode filename_to_unicode filename_display_name); 5use Gtk2::Pango; # to change fonts 6use strict; # a good idea for all non-trivial Perl programs 7use warnings; # force print warnings 8use File::Find; # similar to the Unix find command, see <man File::Find> 9 10use Encode qw(encode decode is_utf8 _utf8_on _utf8_off); # see <man Encode>. 11use Unicode::Normalize qw(NFKD); # combining accent 12 13# use Fcntl; # for gnormalize::cdplay 14 15# See <man waitpid>, perlipc and Programming Perl, 3a Ed., Chap.16 16# waitpid Child_PID,FLAGS : "Waits for a particular child process to terminate and returns 17# the pid of the deceased process, or "-1" if there is no such child process." 18# waitpid(-1, WNOHANG) < 0 ; -1 : meaning wait for any child process. WNOHANG : return immediately if no child has exited. 19use POSIX qw(:sys_wait_h fmod floor ceil); # ':sys_wait_h' is used on sub 'change_count' 20 21# set_locale Gtk2; # internationalize 22 23# use POSIX qw(locale_h); # internationalize: see <man setlocale> POSIX, perlunicode and perllocale 24# Usage: POSIX::setlocale(category, locale = 0) 25# setlocale( LC_CTYPE, 'C'); # for regular expression matching, character classification, conversion, 26 # case-sensitive comparison, and wide character functions 27# setlocale( LC_NUMERIC, 'C'); # for number formatting (such as the decimal point and the thousands separator). 28# setlocale( LC_ALL, 'iso-8859-1'); 29 30$SIG{CHLD} = "IGNORE"; # kill zombies ; see man perlfunc and perlfork 31 32$|++; # Disable buffering by setting the perl-filehandle variable $| to a true value 33 34my $false = 0; my $true = 1; # convenience variables for true and false 35my $id3tag_character = 'iso-8859-1'; # Latin1 for id3tag mp3 files. 36 37# use open IO => ":encoding(iso-8859-1)"; # set PerlIO layers for Input and Output. See 'man PerlIO' 38# BEGIN { $ENV{LC_ALL} = $ENV{LANG} = 'pt_BR' } # man perluniintro 39# use open OUT => ':locale'; 40 41#------------------------- perl module: CDDB_get -----------------------------# 42# To get informations from audio cds - See <man CDDB_get> 43sub modules_cddb_get { 44 if (eval "use CDDB_get qw(get_cddb get_discids); 1;"){ return $true;} 45 else { warn "\n\n Not found CDDB_get perl module in your system.\n gnormalize will uses internal CDDB_get (version 2.27).\n"; } 46 return $false; 47} 48my $use_external_cddbget = modules_cddb_get(); 49 50#------------------------- perl module: MP3::Info ----------------------------# 51sub modules_mp3info { # Suggestions from Perl Cookbook, 2nd Edition, chapter 12.2 . 52 if (eval "use MP3::Info qw(:all); 1;"){ return $true;} 53 else { warn "\n\n Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20).\n"; } 54 return $false; 55} 56my $use_external_MP3Info = modules_mp3info(); 57use_winamp_genres() if $use_external_MP3Info; 58 59#------------------------- perl module: Audio::CD ----------------------------# 60# Imports "Audio::CD" into current package if it exist 61my $use_audiocd = $false; 62sub modules_audio_cd { # suggestions from Perl Cookbook. 63 if (eval "use Audio::CD; 1;"){ $use_audiocd = $true;} 64 # else{ warn "Could not use Audio::CD \n $@"; } 65 return $use_audiocd; 66} 67modules_audio_cd(); 68 69sub audio_cd_have_current_track { # return true if Audio::CD have current_track and $frames 70 my $audiodevice = shift; 71 if ( $use_audiocd eq $false ){ return $false; } 72 73 # umount the audio cd drive if possible. This is need to play EXTRA CD. 74 75 exec_cmd_system2('umount', "$audiodevice"); 76 77 my $audiocd = Audio::CD->init("$audiodevice"); 78 my $info = $audiocd->stat; 79 80 # See eval in perlfunc. 81 eval { $info->current_track; }; 82 if ($@) { 83 warn "\n Can't find the function \"current_track\".". 84 "\n You must install the perl module \"Audio-CD-0.04-changed.tar.gz\".\n"; 85 return $false; 86 } 87 my ($minutes, $seconds, $frames) = $info->time; 88 if (not defined($frames)){ 89 warn "\n Can't find the function \"my (\$minutes, \$seconds, \$frames) = \$info->time\".". 90 "\n You must install the perl module \"Audio-CD-0.04-changed.tar.gz\".\n"; 91 return $false; 92 } 93 return $true; 94} 95 96sub check_minimum_version { 97 my $gtk2_version = Gtk2->CHECK_VERSION (2, 6, 0); # boolean 98 my $gtk2_Perl_version = $Gtk2::VERSION; 99 if ( $gtk2_Perl_version < 1.100 or not $gtk2_version ) { 100 print "\n\$gtk2_Perl_version = $gtk2_Perl_version \n"; 101 print "\nYou need a gtk2_Perl_version more recent!\n"; 102 return $true; 103 } 104} 105check_minimum_version(); 106 107#-----------------------------------------------------------------------------# 108 109# gtk+2.0 - 2.4.9 -9mdk and perl-Glib-1.080 110# examples: perl /usr/share/doc/perl-Gtk2-doc/gtk-demo/main.pl & 111# See: man perl, perlfunc, perlintro, Gtk2, Gtk2::Window, Gtk2::index, ... 112 113# This program is free software; you can redistribute it and/or modify 114# it under the terms of the GNU General Public License as published by 115# the Free Software Foundation; either version 2, or (at your option) 116# any later version. 117 118# "Free Software, since you might like to learn a bit in the 119# process by looking at the code (or teach the author of the program how 120# to write better programs...)." 121 122# Copyright 2005/2008 - Claudio Fernandes de Souza Rodrigues 123# email: claudiofsr@yahoo.com 124 125# DISCLAIMER 126# The author assumes no responsibility for correct function, appropriate use, or misuse 127# of this program, and any damage its function, use or misuse may cause. 128 129# Pensamento filos�fico: 130# "A calcinha pode n�o ser a melhor coisa do mundo, mas est� bem perto!" 131 132##########------------Global-Variables------------########## 133###------------------------------------------------------### 134 135my $VERSION = "0.63"; 136my $AUTHOR = "Claudio Fernandes de Souza Rodrigues"; 137my $EMAIL = "claudiofsr\@yahoo.com"; 138my $DATE = "Jul 10 2008"; 139my $HOMEPAGE = "http://gnormalize.sourceforge.net"; 140 141#----------------------------------------------------------# 142## ------- default path used by the cdrom drive --------- ## 143my $audiodevice_path ="/dev/cdrom"; 144#----------------------------------------------------------# 145#----------------------------------------------------------# 146my $home = filename_to_unicode "$ENV{HOME}"; my $os; 147#my $datey = system("date +%Y"); 148my $window; my $window_width = 860; my $window_height = 580; 149my $tooltips = Gtk2::Tooltips->new; #$tooltips->set_delay( 1000 ); # wait for 1s 150my $check_button_tooltips; my $show_all_tooltips = $true; 151my $notebook; my $notebook2; my $button; my $spinner;my $spinner_q; my $spinner_bitrate_mp3; 152my $spinner_bitrate_ogg; my $spinner_bitrate_mp4; my $spinner_Vmp4; 153my $vbox_up; my $vbox1; my $vbox2; my $button_save_tag; 154my $frame1; my $frame_prog_bar; my $have_current_track = $false; 155my $table1; my $table_down; 156my $norm_type = "Track"; my $num_d; 157my $file_dialog; my $button_clear; 158my $label_type; my $label_VB; my $entry_f; my $entry_dir_input; 159my $spinner_V; my $spinner_Vogg; my $spinner_Vmpc; 160my $label_mp3b; my $combo; my $show_tux_animation = $true; my $check_button_animation; 161my $label_Min; my $ComboBox_Min; my $vb_Min=64; 162my $label_Max; my $ComboBox_Max; my $vb_Max=320; 163my $ComboBox_rip; my $ComboBox_char; 164my $ComboBox_encode_type; my $ComboBox_const_bitrate; 165my $file_mp3=""; my $file_ogg=""; my $file_mpc=""; my $file_ape=""; 166my $file_flac=""; my $file_cda=""; my $file_wav=""; my $file_mp4=""; 167my $spinner_compress; my $label_comp; my $button_quit; 168my $spinner_compress_flac; my $fileSize = 0; my $directory; 169my $directory_final; my $directory_output = $home; my $directory_base; 170my $recursively = $true; my $check_button_recursively; my $check; my $label; 171my $pbar; my $pbar_n; my $pbar_encode; my $progbar_files_info; my $label_pct; my $da; 172my $symbol; my $align; my $separator; my $table; 173my $orientation; my $new_val; my $ripper = 'cdparanoia'; 174my $entry_l; my $entry_n; my $ComboBox_mode; my $ComboBox_freq; my $entry; 175my $status_bar; my $context_id = 0; my $adjust; 176my @files_info = (); my @music_sector; my @length = (); # array with music length of audio cd 177my %albums_already_played; # hash whose key is only the played album name 178my %artists_already_played; # hash whose key is only the played artist name 179my $already_normalized; my $extension_input = 'other'; my $extension_output = 'mp3'; 180my $bitrate_nominal; # for ogg 181my $bitrate_constant = 160; my $bitrate_avr_mp3 = 160; my $bitrate_avr_mp4 = 160; 182my $quality = 3; # encoder algorithms process for lame. 183my $bitrate_avr_ogg = 160; my $bitrate_original; my $bitrate_average = $true; 184my $pid_lame_decode = -1; my $pid_lame_encode = -1; my $pid_rip_cda = -1; 185my $pid_mpc_decode = -1; my $pid_mpc_encode = -1; my $pid_cdpar_rip = -1; 186my $pid_normalize = -1; my $pid_ogg_decode = -1; my $pid_ogg_encode = -1; 187my $pid_ape = -1; my $pid_flac_decode = -1; my $pid_player; 188my $audio_cd_volume = 80; my $button_volume; 189my $V = 4; my $Vogg = 4; my $Vmpc = 5; my $Vmp4 = 200; my $encode="average";# constant, average or variable 190my @array_wav; my @array_ogg; my @array_of_files; #array of mp3/ogg/wav 191my $textview; my $scrolled; my $buffer; my $iter; my $track; 192my $vbox_text; my $hbox_text; my $frame_debug; 193my $count = 0; my $timer; my $window_font_name = 'Sans 10'; my $button_font; 194my %encode_type; $encode_type{'mp3'} = 'average'; $encode_type{'mp4'} = 'average'; 195$encode_type{'mpc'} = 'variable'; $encode_type{'ogg'} = 'average'; 196 197my %options = ( mp3 => { encode_type => 'average', # not used yet! 198 player => 'mpg321', 199 }, 200 mp4 => { encode_type => 'average', 201 player => 'mplayer', 202 }, 203 mpc => { encode_type => 'variable', 204 player => 'mpg321', 205 }, 206 ogg => { encode_type => 'average', 207 player => 'mplayer', 208 }, 209 ape => { encode_type => 'average', 210 player => 'mplayer', 211 }, 212 flac => { encode_type => 'variable', 213 player => 'mpg321', 214 }, 215 wav => { encode_type => 'average', 216 player => 'mplayer', 217 }, 218 tag => { artist => '', 219 album => '', 220 } 221 ); 222 223my $check_button_del_wav; my $check_button_cddb; my $spinner_pri; 224my $go_back = $false; my $go_forward = $false; my $delete_wave = $true; 225my $discDB = $true; my $entry_CDDB_server; my $CDDB_server = 'freedb.freedb.org'; 226my $spinner_cddb_port; my $cddb_port = 8880; my $cddb_transport = 'cddb'; 227my $priority = 15; my $change_properties = $false; 228my $check_change_properties; my $check_button_overwrite; my $check_button_overwrite_cddb; 229my $overwrite_cddb = $false; my $entry_format_cda; my $file_format_cda_rip = "%b/%n-%a-%t"; 230my $overwrite = $false; my $entry_def_comment; my $comment_tag = "gnormalize - gain=%gain"; 231my $gain = 0.00; my $insensibility = 0.3; my $spinner_sensi; 232my $mode = 'joint stereo'; my $freq = 44100; my $comp_ape = 2000; my $comp_flac = 3; 233my $entry_cda; my $button_cdda1; my $button_cdda2; my $button_cdda3; 234my $paranoia = $true; my $paranoia_disable = $false; my $paranoia_no_verify = $false; 235my $change_fonte = $true; my $change_fonte_norm = $true; 236my $change_font_layout = $true; my $change_font_rand = $true; 237my $additional_command_mp3 = ""; my $additional_command_mp4 = ""; my $additional_command_mpc = ""; 238my $additional_command_ogg = ""; my $additional_command_ape = ""; my $additional_command_flac = ""; 239my $entry_command_mp3; my $entry_command_mp4; my $entry_command_mpc; 240my $entry_command_ogg; my $entry_command_ape; my $entry_command_flac; 241my $renderer_track; my $renderer_artist; my $renderer_title; my $renderer_album; my $renderer_length; 242my $button_info_type = 1; my $notebook_page_num = 0; my $notebook_page_num2 = 0; 243my $scrolling_text_speed = 45; # 45 milliseconds 244my $scrolling_text_incremental = 1; # 1 pixel 245my $scrolling_type = "random"; my $scrolling_text_orientation = 1; 246#---cdparanoia options 247my $disable_paranoia = $false; my $disable_extra_paranoia = $false; 248my $abort_on_skip = $false; my $never_skip_repair = $false; 249my $audio_cd_channel; my $audio_cd_total_time; my $audio_cd_fileSize; 250my $button_noia1; my $button_noia2; my $button_noia3; my $button_noia4; 251# The paths are automatically found. 252my $lame_path; my $oggenc_path; my $mpcenc_path; my $ape_path; my $flac_path; 253my $metaflac_path; my $wavegain_path; my $oggdec_path; my $mpcdec_path; 254my $cdparanoia_path; my $cdda2wav_path; my $faac_path; my $faad_path; 255my $mpg123_path; my $mpg321_path; my $ogg123_path; my $flac123_path; 256my $mplayer_path; my $madplay_path; my $amixer_path; my $play_path; 257my $aplay_path; my $vorbiscomment_path; my $nice_path; my $audiocd; 258my $cdcd_path; my $cdplayer = "Audio::CD"; 259#---mp3/ogg tag 260my $mode_channel; my $Frequency = 0; my $Time_Min_Sec; my $Technical_Info; 261my $Title; my $Comment; my $Genre; my $Artist; my $Track_Number; my $Total_Track; my $Album; my $Year; 262my %metadata = (); # hash with metadata (tag) and technical information 263# ---- More global variables ---- cdrom player # 264my $window_cd_player; my $window_cd_player_width = 252; my $window_cd_player_height = 56; 265my $notebook_cd_player_num = 0; 266my $color_bg_cdplay = '#839975'; my $color_cdplayer_shadow = '#839975'; 267my $color_cdplayer_arrows = '#651DB6'; my $color_cdplayer_shadow_motion = '#651DB6'; 268my $color_cdplayer_arrows_motion = '#839975'; my $color_cdplayer_digit = '#651DB6'; 269my $color_cdplayer_digit_remaining = '#FFA500'; 270my $force_unselect_all_tracks = $false; 271my $show_cdplayer_skin = $false; my $show_cdplayer_border = $true; my $show_cdplayer_keep_above = $true; 272my $show_time_remaining = $false; my $show_time_abs = $false; 273my $playing_music = $false; 274my $selected_row = 0; # default audio track 275my $total_time = 0; 276my @rows_already_played = (); 277my $play_random = $false; my $loop_tracks = $false; 278my @start_sector; my $pause = $false; my $toc_audiocd; 279my $column_show_extension = $false; my $column_show_filepath = $false; my $column_show_filename = $false; 280my $column_show_frequency = $false; my $column_show_bitrate = $true; my $column_show_year = $false; 281my $column_show_artist = $true; my $column_show_album = $false; my $column_show_track = $true; 282my $column_show_file = $true; my $column_show_play_count = $true; 283 284my $use_filter = $false; my $ComboBox_player_with_filter; 285 286#---player---# 287my $device_path = "/dev/audio"; my $device_type = "alsa"; 288my $player_mp3 = "mpg321"; my %all_mp3_player; 289my $player_mp4 = "mplayer"; my %all_mp4_player; 290my $player_mpc = "mplayer"; my %all_mpc_player; 291my $player_ogg = "mplayer"; my %all_ogg_player; 292my $player_ape = "mplayer"; my %all_ape_player; 293my $player_flac = "mplayer"; my %all_flac_player; 294my $player_wav = "mplayer"; my %all_wav_player; 295#--languages--# 296my $language = 'English'; my $ComboBox_Lang_5a; my %all_language; # Hash of all the different languages 297my $ComboBox_Names; my $Names_Active_Num = 0; 298 299#-----------------------------------------------------# 300 301my $setting_file = "$home/.config/gnormalize/config"; 302my $lang_dir = "$home/.config/gnormalize/language"; 303my %settings; # Hash of all the different options that can be saved 304 305if ( not -d filename_from_unicode $lang_dir ){ 306 my @cmd = ( 'mkdir', '-p', $lang_dir ); # create the directory 307 exec_cmd_system2(@cmd); 308} 309 310sub read_settings { # not yet used 311 my $file = shift; 312 if ( !-e filename_from_unicode $file ) { return; } 313 open( INPUT, '<:utf8', filename_from_unicode $file ) or die "Can't open <$file>: $!, stopped"; 314 while (my $line = <INPUT>) { 315 chomp($line); 316 next if ( $line !~ /=/ ); 317 (my $key, my $value) = split(/=/, $line); 318 $settings{$key} = $value; 319 } 320 close( INPUT ); 321 #foreach my $key ( sort keys %settings ) { print $key, '=', $settings{$key}, "\n"; } 322} 323# read_settings($setting_file); 324 325sub save_settings { # not yet used 326 #$lang_dir/language.txt 327 $settings{'cdrom'} = $entry_cda->get_text; 328 329 my $key; 330 open( OUTPUT, '>:utf8', $setting_file ) or die "Couldn't open $setting_file for writing: $!\n"; 331 foreach $key ( sort keys %settings ) { print OUTPUT $key, '=', $settings{$key}, "\n"; } 332 close( OUTPUT ); 333} 334 335#######------------- Read the config file -----------####### 336 337sub read_config { 338 my $config = filename_to_unicode $setting_file; 339 340 if( -r filename_from_unicode $config ) { 341 my $file_number = 1; 342 # read config file 343 open(CONFIG, '<:utf8', $config ); 344 while( <CONFIG> ) 345 { 346 if ($_ =~ /^cdrom=(.*)/){ $audiodevice_path = $1; } 347 if ($_ =~ /^recursively=(.*)/){ $recursively = $1; } 348 if ($_ =~ /^extension_output=(.*)/){ $extension_output = $1; } 349 if ($_ =~ /^directory_output=(.*)/){ $directory_output = $1; } 350 if ($_ =~ /^normalization_type=(Track|Album|None)$/){ $norm_type = $1; } 351 if ($_ =~ /^gain=(.*)/){ $gain = $1; } 352 if ($_ =~ /^insensibility=(.*)/){ $insensibility = $1; } 353 if ($_ =~ /^delete_wave=(.*)/){ $delete_wave = $1; } 354 if ($_ =~ /^discDB=(.*)/){ $discDB = $1; } 355 if ($_ =~ /^overwrite_cddb=(.*)/){ $overwrite_cddb = $1; } 356 if ($_ =~ /^CDDB_server=(.*)/){ $CDDB_server = $1; } 357 if ($_ =~ /^cddb_port=(\d+)/){ $cddb_port = $1; } 358 if ($_ =~ /^cddb_transport=(.*)/){ $cddb_transport = $1; } 359 if ($_ =~ /^priority=(.*)/){ $priority = $1; } 360 if ($_ =~ /^change_properties=(.*)/){ $change_properties = $1; } 361 if ($_ =~ /^show_all_tooltips=([01])/){ $show_all_tooltips = $1; } 362 if ($_ =~ /^file_format_cda_rip=(.*)/){ $file_format_cda_rip = $1; } 363 if ($_ =~ /^overwrite=(.*)/){ $overwrite = $1; } 364 if ($_ =~ /^comment_tag=(.*)/){ $comment_tag = $1; } 365 if ($_ =~ /^additional_command_mp3=(.*)/){ $additional_command_mp3 = $1; } 366 if ($_ =~ /^additional_command_mp4=(.*)/){ $additional_command_mp4 = $1; } 367 if ($_ =~ /^additional_command_mpc=(.*)/){ $additional_command_mpc = $1; } 368 if ($_ =~ /^additional_command_ogg=(.*)/){ $additional_command_ogg = $1; } 369 if ($_ =~ /^additional_command_ape=(.*)/){ $additional_command_ape = $1; } 370 if ($_ =~ /^additional_command_flac=(.*)/){ $additional_command_flac = $1; } 371 if ($_ =~ /^character=(.*)/){ $id3tag_character = $1; } 372 if ($_ =~ /^cdplayer=(.*)/){ $cdplayer = $1; } 373 if ($_ =~ /^window_font_name=(.*)/){ $window_font_name = $1; } 374 if ($_ =~ /^ripper=(.*)/){ $ripper = $1; } 375 if ($_ =~ /^language=(.*)/){ $language = $1; } 376 if ($_ =~ /^Names_Active_Num=(\d+)/){ $Names_Active_Num = $1; } 377 if ($_ =~ /^encode=(.*)/){ $encode = $1; } 378 if ($_ =~ /^encode_remember_mp3=(.*)/){ $encode_type{mp3} = $1; } 379 if ($_ =~ /^encode_remember_mp4=(.*)/){ $encode_type{mp4} = $1; } 380 if ($_ =~ /^encode_remember_mpc=(.*)/){ $encode_type{mpc} = $1; } 381 if ($_ =~ /^encode_remember_ogg=(.*)/){ $encode_type{ogg} = $1; } 382 if ($_ =~ /^bitrate=(.*)/){ $bitrate_constant = $1; } 383 if ($_ =~ /^bitrate_avr_mp3=(.*)/){ $bitrate_avr_mp3 = $1; } 384 if ($_ =~ /^bitrate_avr_mp4=(.*)/){ $bitrate_avr_mp4 = $1; } 385 if ($_ =~ /^bitrate_avr_ogg=(.*)/){ $bitrate_avr_ogg = $1; } 386 if ($_ =~ /^bitrate_vrb_mp3=(.*)/){ $V = $1; } 387 if ($_ =~ /^bitrate_vrb_mp4=(.*)/){ $Vmp4 = $1; } 388 if ($_ =~ /^bitrate_vrb_ogg=(.*)/){ $Vogg = $1; } 389 if ($_ =~ /^bitrate_vrb_mpc=(.*)/){ $Vmpc = $1; } 390 if ($_ =~ /^comp_ape=(.*)/){ $comp_ape = $1; } 391 if ($_ =~ /^comp_flac=(.*)/){ $comp_flac = $1; } 392 if ($_ =~ /^mode=(.*)/){ $mode = $1; } 393 if ($_ =~ /^Min=(.*)/){ $vb_Min = $1; } 394 if ($_ =~ /^Max=(.*)/){ $vb_Max = $1; } 395 if ($_ =~ /^freq=(8000|11025|12000|16000|22050|24000|32000|44100|48000)$/){ $freq = $1; } 396 if ($_ =~ /^quality=(.*)/){ $quality = $1; } 397 if ($_ =~ /^disable_paranoia=(.*)/){ $disable_paranoia = $1; } 398 if ($_ =~ /^never_skip_repair=(.*)/){ $never_skip_repair = $1; } 399 if ($_ =~ /^disable_extra_paranoia=(.*)/){ $disable_extra_paranoia = $1; } 400 if ($_ =~ /^abort_on_skip=(.*)/){ $abort_on_skip = $1; } 401 if ($_ =~ /^paranoia=(.*)/){ $paranoia = $1; } 402 if ($_ =~ /^paranoia_disable=(.*)/){ $paranoia_disable = $1; } 403 if ($_ =~ /^paranoia_no_verify=(.*)/){ $paranoia_no_verify = $1; } 404 if ($_ =~ /^play_random=(.*)/){ $play_random = $1; } 405 if ($_ =~ /^loop_tracks=(.*)/){ $loop_tracks = $1; } 406 if ($_ =~ /^audio_cd_volume=(\d*)/){ $audio_cd_volume = $1; } 407 if ($_ =~ /^window_width=(\d+)/){ $window_width = $1; } 408 if ($_ =~ /^window_height=(\d+)/){ $window_height = $1; } 409 if ($_ =~ /^window_cd_player_width=(\d+)/){ $window_cd_player_width = $1; } 410 if ($_ =~ /^window_cd_player_height=(\d+)/){ $window_cd_player_height = $1; } 411 if ($_ =~ /^show_tux_animation=([01])/){ $show_tux_animation = $1; } 412 if ($_ =~ /^color_bg_cdplay=(#[ABCDEFabcdef\d]{6})/){ $color_bg_cdplay = $1; } 413 if ($_ =~ /^color_cdplayer_shadow=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_shadow = $1; } 414 if ($_ =~ /^color_cdplayer_arrows=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_arrows = $1; } 415 if ($_ =~ /^color_cdplayer_shadow_motion=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_shadow_motion = $1; } 416 if ($_ =~ /^color_cdplayer_arrows_motion=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_arrows_motion = $1; } 417 if ($_ =~ /^color_cdplayer_digit=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_digit = $1; } 418 if ($_ =~ /^color_cdplayer_digit_remaining=(#[ABCDEFabcdef\d]{6})/){ $color_cdplayer_digit_remaining = $1; } 419 if ($_ =~ /^scrolling_text_speed=(\d+)/){ $scrolling_text_speed = $1 if ($1>=10); } 420 if ($_ =~ /^scrolling_text_incremental=(\d+)/){ $scrolling_text_incremental = $1; } 421 if ($_ =~ /^scrolling_type=(.*)/){ $scrolling_type = $1; } 422 if ($_ =~ /^scrolling_text_orientation=((-1|1))/){ $scrolling_text_orientation = $1; } 423 if ($_ =~ /^show_cdplayer_skin=([01])/){ $show_cdplayer_skin = $1; } 424 if ($_ =~ /^show_cdplayer_border=([01])/){ $show_cdplayer_border = $1; } 425 if ($_ =~ /^show_cdplayer_keep_above=([01])/){ $show_cdplayer_keep_above = $1; } 426 if ($_ =~ /^player_mp3=(madplay|mpg123|mpg321|mplayer)$/){ $player_mp3 = $1; } 427 if ($_ =~ /^player_mp4=(mplayer)$/){ $player_mp4 = $1; } 428 if ($_ =~ /^player_mpc=(mpcdec|mplayer)$/){ $player_mpc = $1; } 429 if ($_ =~ /^player_ogg=(ogg123|mplayer)$/){ $player_ogg = $1; } 430 if ($_ =~ /^player_ape=(mac|mplayer|aplay)$/){ $player_ape = $1; } 431 if ($_ =~ /^player_flac=(flac123|mplayer)$/){ $player_flac = $1; } 432 if ($_ =~ /^player_wav=(mplayer|aplay|play)$/){ $player_wav = $1; } 433 if ($_ =~ /^device_path=(.*)/){ $device_path = $1; } 434 if ($_ =~ /^device_type=(.*)/){ $device_type = $1; } 435 if ($_ =~ /^use_filter=(\d+)/){ $use_filter = $1; } 436 if ($_ =~ /^column_show_file=(0|1)/){ $column_show_file = $1; } 437 if ($_ =~ /^column_show_artist=(0|1)/){ $column_show_artist = $1; } 438 if ($_ =~ /^column_show_album=(0|1)/){ $column_show_album = $1; } 439 if ($_ =~ /^column_show_track=(0|1)/){ $column_show_track = $1; } 440 if ($_ =~ /^column_show_extension=(0|1)/){ $column_show_extension = $1; } 441 if ($_ =~ /^column_show_play_count=(0|1)/){ $column_show_play_count = $1; } 442 if ($_ =~ /^column_show_filepath=(0|1)/){ $column_show_filepath = $1; } 443 if ($_ =~ /^column_show_filename=(0|1)/){ $column_show_filename = $1; } 444 if ($_ =~ /^column_show_frequency=(0|1)/){ $column_show_frequency = $1; } 445 if ($_ =~ /^column_show_bitrate=(0|1)/){ $column_show_bitrate = $1; } 446 if ($_ =~ /^column_show_year=(0|1)/){ $column_show_year = $1; } 447 if ($_ =~ /^button_info_type=(\d)/){ $button_info_type = $1; } 448 if ($_ =~ /^notebook_page_num=(\d+)/){ $notebook_page_num = $1; } 449 if ($_ =~ /^notebook_page_num2=(\d+)/){ $notebook_page_num2 = $1; } 450 if ($_ =~ /^notebook_cd_player_num=(\d+)/){ $notebook_cd_player_num = $1; } 451 452 # read the music list 453 if ($_ =~ /^checked=(0|1):::file=(\d+):::track=(.*):::artist=(.*):::title=(.*):::album=(.*):::length=(.*):::bitrate=(\d+):::year=(.*):::frequency=(\d+):::genre=(.*):::filepath=(.*):::directory_remain=(.*):::filename=(.*):::extension_input=(.*)$/){ 454 my $filepath = $12; # print "\$filepath = $filepath\n"; 455 456 eval { if (not -e filename_from_unicode $filepath){warn filename_from_unicode "\nCould not find <$filepath>: $!"; next;} }; 457 458 push @files_info, { # fill the array of array references 459 rip => $1, 460 file => $file_number, # file_number = row - 1 461 track => $3, 462 artist => $4, 463 title => $5, 464 album => $6, 465 length => $7, 466 bitrate => $8, 467 year => $9, 468 frequency => $10, 469 genre => $11, 470 471 filepath => $filepath, # $12, 472 directory_remain => $13, 473 filename => $14, 474 extension_input => $15, 475 }; 476 $file_number += 1; 477 } 478 } 479 close(CONFIG); 480 $extension_input = $files_info[0]{extension_input} if ( defined $files_info[0]{extension_input} ); 481 } 482 $gain = number_value($gain); 483 return; 484} 485 486#######------------- Save the config file -----------####### 487 488# save configurations only when quit the program 489sub save_config { 490 my $config = $setting_file; 491 if ( not -e filename_from_unicode $config ){ print "Save configuration file: $config\n"; } 492 493 # test_expr ? if_true_expr : if_false_expr 494 open(CONFIG, '>:utf8', filename_from_unicode $config ) or die "Can not write to <$config>: $!"; 495 print CONFIG " gnormalize - $VERSION\n"; 496 print CONFIG "author: $AUTHOR\n"; 497 print CONFIG "homepage: $HOMEPAGE\n\n"; 498 print CONFIG "cdrom=",$entry_cda->get_text,"\n"; 499 print CONFIG "recursively=$recursively\n"; 500 print CONFIG "extension_output=$extension_output\n"; 501 print CONFIG "directory_output=$directory_output\n"; 502 print CONFIG "normalization_type=$norm_type\n"; 503 print CONFIG "gain=",$spinner->get_value,"\n"; 504 print CONFIG "insensibility=",$spinner_sensi->get_value,"\n"; 505 print CONFIG "delete_wave=",$check_button_del_wav->get_active?1:0,"\n"; 506 print CONFIG "discDB=",$check_button_cddb->get_active?1:0,"\n"; 507 print CONFIG "overwrite_cddb=",$check_button_overwrite_cddb->get_active?1:0,"\n"; 508 print CONFIG "CDDB_server=",$entry_CDDB_server->get_text,"\n"; 509 print CONFIG "cddb_port=",$spinner_cddb_port->get_value,"\n"; 510 print CONFIG "cddb_transport=$cddb_transport\n"; 511 print CONFIG "priority=",$spinner_pri->get_value,"\n"; 512 print CONFIG "change_properties=",$check_change_properties->get_active?1:0,"\n"; 513 print CONFIG "show_all_tooltips=",$check_button_tooltips->get_active?1:0,"\n"; 514 print CONFIG "file_format_cda_rip=",$entry_format_cda->get_text,"\n"; 515 print CONFIG "overwrite=",$check_button_overwrite->get_active?1:0,"\n"; 516 print CONFIG "comment_tag=",$entry_def_comment->get_text,"\n"; 517 print CONFIG "additional_command_mp3=",$entry_command_mp3->get_text,"\n"; 518 print CONFIG "additional_command_mp4=",$entry_command_mp4->get_text,"\n"; 519 print CONFIG "additional_command_mpc=",$entry_command_mpc->get_text,"\n"; 520 print CONFIG "additional_command_ogg=",$entry_command_ogg->get_text,"\n"; 521 print CONFIG "additional_command_ape=",$entry_command_ape->get_text,"\n"; 522 print CONFIG "additional_command_flac=",$entry_command_flac->get_text,"\n"; 523 print CONFIG "character=",$id3tag_character,"\n"; 524 print CONFIG "cdplayer=",$cdplayer,"\n"; 525 print CONFIG "window_font_name=",$button_font->get_label,"\n"; 526 print CONFIG "ripper=",$ripper,"\n"; 527 print CONFIG "language=",$ComboBox_Lang_5a->get_active_text,"\n"; 528 print CONFIG "Names_Active_Num=",$ComboBox_Names->get_active,"\n"; 529 print CONFIG "encode=",$ComboBox_encode_type->get_active_text,"\n"; 530 print CONFIG "encode_remember_mp3=$encode_type{mp3}\n"; 531 print CONFIG "encode_remember_mp4=$encode_type{mp4}\n"; 532 print CONFIG "encode_remember_mpc=$encode_type{mpc}\n"; 533 print CONFIG "encode_remember_ogg=$encode_type{ogg}\n"; 534 print CONFIG "bitrate=$bitrate_constant\n"; 535 print CONFIG "bitrate_avr_mp3=$bitrate_avr_mp3\n"; 536 print CONFIG "bitrate_avr_mp4=$bitrate_avr_mp4\n"; 537 print CONFIG "bitrate_avr_ogg=$bitrate_avr_ogg\n"; 538 print CONFIG "bitrate_vrb_mp3=",$spinner_V->get_value,"\n"; 539 print CONFIG "bitrate_vrb_mp4=",$spinner_Vmp4->get_value,"\n"; 540 print CONFIG "bitrate_vrb_ogg=", number_value(sprintf("%.1f", $spinner_Vogg->get_value)) ,"\n"; 541 print CONFIG "bitrate_vrb_mpc=",$spinner_Vmpc->get_value,"\n"; 542 print CONFIG "comp_ape=",$spinner_compress->get_value,"\n"; 543 print CONFIG "comp_flac=",$spinner_compress_flac->get_value,"\n"; 544 print CONFIG "mode=",$ComboBox_mode->get_active_text,"\n"; 545 print CONFIG "Min=",$ComboBox_Min->get_active_text,"\n"; 546 print CONFIG "Max=",$ComboBox_Max->get_active_text,"\n"; 547 print CONFIG "freq=",$ComboBox_freq->get_active_text,"\n"; 548 print CONFIG "quality=$quality\n"; 549 print CONFIG "\n---cdparanoia options:\n"; 550 print CONFIG "disable_paranoia=",$button_noia1->get_active?1:0,"\n"; 551 print CONFIG "never_skip_repair=",$button_noia2->get_active?1:0,"\n"; 552 print CONFIG "disable_extra_paranoia=",$button_noia3->get_active?1:0,"\n"; 553 print CONFIG "abort_on_skip=",$button_noia4->get_active?1:0,"\n"; 554 print CONFIG "\n---cdda2wav options:\n"; 555 print CONFIG "paranoia=",$button_cdda1->get_active?1:0,"\n"; 556 print CONFIG "paranoia_disable=",$button_cdda2->get_active?1:0,"\n"; 557 print CONFIG "paranoia_no_verify=",$button_cdda3->get_active?1:0,"\n\n"; 558 print CONFIG "play_random=$play_random\n"; 559 print CONFIG "loop_tracks=$loop_tracks\n"; 560 print CONFIG "audio_cd_volume=$audio_cd_volume\n"; 561 print CONFIG "\n---window size:\n"; 562 # see resize_window() subroutine 563 print CONFIG "window_width=",int($window->allocation->width),"\n"; 564 print CONFIG "window_height=",$button_info_type != 2 ? 565 int($window->allocation->height) : int($window->allocation->height - $frame_debug->allocation->height) ,"\n"; 566 print CONFIG "window_cd_player_width=$window_cd_player_width\n"; 567 print CONFIG "window_cd_player_height=$window_cd_player_height\n"; 568 print CONFIG "show_tux_animation=",$check_button_animation->get_active?1:0,"\n"; 569 print CONFIG "\n---cd player color:\n"; 570 print CONFIG "color_bg_cdplay=$color_bg_cdplay\n"; 571 print CONFIG "color_cdplayer_shadow=$color_cdplayer_shadow\n"; 572 print CONFIG "color_cdplayer_arrows=$color_cdplayer_arrows\n"; 573 print CONFIG "color_cdplayer_shadow_motion=$color_cdplayer_shadow_motion\n"; 574 print CONFIG "color_cdplayer_arrows_motion=$color_cdplayer_arrows_motion\n"; 575 print CONFIG "color_cdplayer_digit=$color_cdplayer_digit\n"; 576 print CONFIG "color_cdplayer_digit_remaining=$color_cdplayer_digit_remaining\n"; 577 print CONFIG "scrolling_text_speed=$scrolling_text_speed\n"; 578 print CONFIG "scrolling_text_incremental=$scrolling_text_incremental\n"; 579 print CONFIG "scrolling_type=$scrolling_type\n"; 580 print CONFIG "scrolling_text_orientation=$scrolling_text_orientation\n"; 581 print CONFIG "show_cdplayer_skin=",$show_cdplayer_skin?1:0,"\n"; 582 print CONFIG "show_cdplayer_border=",$show_cdplayer_border?1:0,"\n"; 583 print CONFIG "show_cdplayer_keep_above=",$show_cdplayer_keep_above?1:0,"\n"; 584 print CONFIG "\n---players:\n"; 585 print CONFIG "player_mp3=$player_mp3\n"; 586 print CONFIG "player_mp4=$player_mp4\n"; 587 print CONFIG "player_mpc=$player_mpc\n"; 588 print CONFIG "player_ogg=$player_ogg\n"; 589 print CONFIG "player_ape=$player_ape\n"; 590 print CONFIG "player_flac=$player_flac\n"; 591 print CONFIG "player_wav=$player_wav\n"; 592 print CONFIG "device_path=$device_path\n"; 593 print CONFIG "device_type=$device_type\n"; 594 print CONFIG "use_filter=$use_filter\n"; 595 print CONFIG "\n---columns:\n"; 596 print CONFIG "column_show_file=",$column_show_file?1:0,"\n"; 597 print CONFIG "column_show_artist=",$column_show_artist?1:0,"\n"; 598 print CONFIG "column_show_album=",$column_show_album?1:0,"\n"; 599 print CONFIG "column_show_track=",$column_show_track?1:0,"\n"; 600 print CONFIG "column_show_extension=",$column_show_extension?1:0,"\n"; 601 print CONFIG "column_show_play_count=",$column_show_play_count?1:0,"\n"; 602 print CONFIG "column_show_filepath=",$column_show_filepath?1:0,"\n"; 603 print CONFIG "column_show_filename=",$column_show_filename?1:0,"\n"; 604 print CONFIG "column_show_frequency=",$column_show_frequency?1:0,"\n"; 605 print CONFIG "column_show_bitrate=",$column_show_bitrate?1:0,"\n"; 606 print CONFIG "column_show_year=",$column_show_year?1:0,"\n"; 607 print CONFIG "button_info_type=",$button_info_type,"\n"; 608 print CONFIG "notebook_page_num=",$notebook->get_current_page,"\n"; 609 print CONFIG "notebook_page_num2=",$notebook2->get_current_page,"\n"; 610 print CONFIG "notebook_cd_player_num=$notebook_cd_player_num\n"; 611 612 print CONFIG "\n---music list:\n"; 613 614 # save list store 615 foreach my $d (@files_info) { # print "\$d->{file} = $d->{file} ; n = ",$#files_info+1,"\n"; 616 return if not defined $files_info[0]{artist}; 617 next if ($d->{extension_input} eq 'cda' or $d->{remove}); 618 print CONFIG "checked=$d->{rip}:::file=$d->{file}:::track=$d->{track}:::artist=$d->{artist}:::". 619 "title=$d->{title}:::album=$d->{album}:::length=$d->{length}:::bitrate=$d->{bitrate}:::". 620 "year=$d->{year}:::frequency=$d->{frequency}:::genre=$d->{genre}:::filepath=$d->{filepath}:::". 621 "directory_remain=$d->{directory_remain}:::filename=$d->{filename}:::extension_input=$d->{extension_input}\n"; 622 } 623 close CONFIG; 624} 625 626read_config(); 627#save_config(); # save when quit; see 'sub Quit' 628#print "extension_output = $extension_output \n"; 629 630#######------------------- Icon --------------------######## 631 632# from /usr/share/doc/perl-Gtk2-1.054/gtk-demo/main.pl 633sub set_icon { 634 my $icon_path = shift || "/usr/share/icons/gnormalize.png"; 635 my $pixbuf; 636 eval { $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file($icon_path); }; 637 #eval { $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file("/usr/share/icons/wolf.png"); }; 638 # "/usr/share/icons/sound_section.png" 639 if ($pixbuf) { 640 # The icon has a white background, make it transparent 641 my $transparent = $pixbuf->add_alpha ($true, 0xff, 0xff, 0xff); 642 643 # only one item on the parameter list, but the parameter list is a list 644 Gtk2::Window->set_default_icon_list ($transparent); 645 #Gtk2::Window->set_default_icon_list ($pixbuf); 646 } 647} 648 649set_icon (); 650 651#######---------------- Tranlation -----------------######## 652 653my %langs; # Hash of all names, tabs, tips and messages 654 655# All defined language - hash of all the different languages 656$all_language{'English'} = $true; 657$all_language{'Portugu�s'} = $true; 658$all_language{'Fran�ais'} = $true; 659$all_language{'Nederlands'} = $true; 660$all_language{'Espag�ol'} = $true; 661$all_language{'Deutsch'} = $true; 662#$all_language{'new_language'} = $true; # <-- add a new language here 663 664read_new_langs(); 665 666$language = 'English' if not defined $all_language{"$language"}; # standard language 667 668sub set_language { 669 670 if ( $language eq 'English' ) 671 { 672 $langs{all_tab01} = "Data"; 673 $langs{all_tab02} = "Configuration"; 674 $langs{all_tab03} = "Information"; 675 $langs{all_tab04} = "Rip/Play"; 676 $langs{all_tab05} = "Translations"; 677 $langs{all_tab06} = "About"; 678 $langs{all_tab07} = "Option1"; 679 $langs{all_tab08} = "Option2"; 680 $langs{all_tab09} = "CDDB"; 681 $langs{all_tab10} = "Ripper"; 682 $langs{all_tab11} = "Colors"; 683 $langs{all_tab12} = "Players"; 684 $langs{all_tab13} = "Columns"; 685 $langs{all_tab14} = "Skins"; 686 687 $langs{name001} = "Normalization Type"; 688 $langs{name002} = "Insensibility"; 689 $langs{name003} = "Selected File"; 690 $langs{name004} = "Input Directory"; 691 $langs{name005} = "Output: Lossy Compression"; 692 $langs{name006} = "Output: Lossless Compression"; 693 $langs{name106} = "Output: Uncompressed"; 694 695 $langs{name007} = "File"; 696 $langs{name008} = "Recursively"; 697 $langs{name009} = "Delete Wav Files"; 698 $langs{name010} = "Change Properties"; 699 $langs{name011} = "Overwrite"; 700 $langs{name012} = "Priority"; 701 $langs{name013} = "Add Command"; 702 $langs{name014} = "Filename Rip"; 703 $langs{name015} = "Character"; 704 $langs{name016} = "Language"; 705 $langs{name017} = "Font"; 706 $langs{name018} = "Read CDDB"; 707 $langs{name019} = "Overwrite CDDB"; 708 $langs{name020} = "CDDB Server"; 709 $langs{name021} = "Port"; 710 $langs{name022} = "Transport"; 711 $langs{name023} = "Disable Paranoia"; 712 $langs{name024} = "Disable Extra Paranoia"; 713 $langs{name025} = "Abort on Skip"; 714 $langs{name026} = "Never Skip Repair"; 715 $langs{name027} = "Paranoia No-Verify"; 716 $langs{name028} = "Paranoia Disable"; 717 $langs{name029} = "Ripper"; 718 $langs{name030} = "Encode Type"; 719 $langs{name031} = "Mode"; 720 $langs{name032} = "Encode Quality"; 721 $langs{name033} = "Variable"; 722 $langs{name034} = "Title"; 723 $langs{name035} = "Artist"; 724 $langs{name036} = "Album"; ## <<<----- 725 $langs{name037} = "Comment"; 726 $langs{name038} = "Year"; 727 $langs{name039} = "Track Number"; 728 $langs{name040} = "Genre"; 729 $langs{name041} = "Frequency"; 730 $langs{name042} = "Time"; 731 $langs{name043} = "Channels"; 732 $langs{name044} = "Length"; 733 $langs{name045} = "Track"; 734 $langs{name046} = "Artist"; 735 $langs{name047} = "Title"; 736 $langs{name048} = "Size"; 737 $langs{name049} = "Year"; 738 $langs{name050} = "Filepath"; 739 $langs{name051} = "Extension"; 740 $langs{name052} = "Output Directory"; 741 $langs{name053} = "Album"; ## <<<----- 742 $langs{name054} = "Play Count"; 743 $langs{name055} = "Animation"; 744 $langs{name056} = "Filename"; 745 $langs{name057} = "Show Tooltips"; 746 $langs{name058} = "Guidance Language"; 747 $langs{name059} = "Current Translation"; 748 $langs{name060} = "Improve The Currente Language Translation"; 749 $langs{name061} = "Add New Language"; 750 $langs{name062} = "Add new language here and then press save buton."; 751 $langs{name063} = "Normalize"; 752 $langs{name064} = "CD Player"; 753 $langs{name065} = "Play"; 754 755 $langs{name429} = 'Play Tracks Without Any Filters'; 756 $langs{name430} = 'Play Tracks From Different Albums'; 757 $langs{name431} = 'Play Tracks From Different Artists'; 758 $langs{name432} = 'Play Tracks From Different Genres'; 759 $langs{name433} = 'Play Tracks From Different Years'; 760 761 $langs{tip101} = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n"; 762 $langs{tip101} .= "None: no normalization is done.\n"; 763 $langs{tip101} .= "---*---\n"; 764 $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n"; 765 $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files."; 766 $langs{tip102} = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. "; 767 $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n"; 768 $langs{tip102} .= "---*---\n"; 769 $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n"; 770 $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n"; 771 $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 772 $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n"; 773 $langs{tip102} .= "---*---\n"; 774 $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n"; 775 $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude."; 776 $langs{tip103} = "Insensibility of normalize. Only not re-encode if:\n"; 777 $langs{tip103} .= "1) the extension of input file is the same of output file;\n"; 778 $langs{tip103} .= "2) and \"$langs{name010}\" button is not active;\n"; 779 $langs{tip103} .= "3) and adjust of normalize is less than insensibility value."; 780 $langs{tip104} = "Select one directory with supported file."; 781 $langs{tip105} = "Choose the directory where all the files will be saved."; 782 $langs{tip106} = "Normalize/Convert all supported files inside the directory (recursively or not).\n"; 783 $langs{tip107} = "Select a directory including subdirectories: descende recursively into the directory preserving the same structure."; 784 $langs{tip108} = "After normalize, the output format will be mp3. \nPlay it with mpg123, mpg321 or madplay."; 785 $langs{tip109} = "After normalize, the output format will be mp4 (also know as m4a) or aac. \nPlay it with mplayer."; 786 $langs{tip110} = "After normalize, the output format will be mpc (also know as mpp or mp+). \nPlay it with mppdec or mplayer."; 787 $langs{tip111} = "After normalize, the output format will be ogg. \nPlay it with ogg123."; 788 $langs{tip112} = "After normalize, the output format will be ape. \nPlay it with the command:\n mac \"song.ape\" - -d | play -t wav - "; 789 $langs{tip113} = "After normalize, the output format will be flac. \nPlay it with flac123 or mplayer.\nRequired flac version >= \"1.1.1\"."; 790 $langs{tip114} = "This is suitable to make an audio cd.\nWav is an uncompressed audio format."; 791 $langs{tip115} = "NOTE:\n"; 792 $langs{tip115} .= "This compression technique is known as 'Lossy Compression' whereby during the compression data can be lost. "; 793 $langs{tip115} .= "The degree of loss varies upon settings. Although data loss does occur, it is minimal and certainly not noticable "; 794 $langs{tip115} .= "when using good settings.\nExamples of Lossy compression audio: Mp3, Mp4, Mpc and Ogg."; 795 $langs{tip116} = "NOTE:\n"; 796 $langs{tip116} .= "This compression technique is known as 'Lossless Compression' in which all of the information in the original "; 797 $langs{tip116} .= "data is preserved, and the original data may be recovered in form identical to its original form.\n"; 798 $langs{tip116} .= "Examples of Lossless compression audio: Ape and Flac."; 799 $langs{tip117} = "Show the progress bar."; 800 $langs{tip118} = "Hide the progress bar."; 801 $langs{tip119} = "Show the command line and others info."; 802 $langs{tip120} = "Hide the command line and others info."; 803 $langs{tip121} = "Quit."; 804 $langs{tip122} = "Clear all messages."; 805 806 $langs{tip201} = "After the normalize process, the temporary wav files will be deleted."; 807 $langs{tip202} = "After normalize the files, you can change its encode properties by determining the encode type, the bitrate of all "; 808 $langs{tip202} .= "output files, etc. Otherwise, the bitrate of each input file and others properties will be conserved."; 809 $langs{tip203} = "The normalized file will be saved in the same directory of input. If it already exist then overwrite the original file."; 810 $langs{tip204} = "Show the hints and informations."; 811 $langs{tip205} = "Show the Tux and others penguins animations."; 812 $langs{tip206} = "Modify scheduling priority: 0 (highest priority) to 19 (lowest)"; 813 $langs{tip207} = "Output filename format used only for rip Audio CD:\n"; 814 $langs{tip207} .= " %a - artist\n"; 815 $langs{tip207} .= " %b - album\n"; 816 $langs{tip207} .= " %t - song title\n"; 817 $langs{tip207} .= " %n - track number\n"; 818 $langs{tip207} .= " %y - year\n"; 819 $langs{tip207} .= " %g - genre"; 820 $langs{tip208} = "Advised font: Sans 10."; 821 $langs{tip209} = "Read the CDDB info for Audio CD in your drive from CDDB server \"$CDDB_server\" or from files saved into $home/.cddd/."; 822 $langs{tip210} = "Always get CDDB info from server and overwrite the CDDB file saved at $home/.cddd/"; 823 $langs{tip211} = "Some servers:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880"; 824 $langs{tip212} = "Choose the port number."; 825 $langs{tip213} = "Disable all data verification and correction features. Consequently the extraction/rip is more fast. "; 826 $langs{tip213} .= "This option implies that -Y is active. See cdparanoia (option -Z)."; 827 $langs{tip214} = "Do not accept any skips; retry forever if needed. See cdparanoia (option -z)."; 828 $langs{tip215} = "Disables intra-read data verification; only overlap checking at read boundaries is performed. Not recommended. See cdparanoia (option -Y).\n"; 829 $langs{tip215} .= "Boundaries are spaces/limit inter tracks of an audio cd. cdparanoia reads this boundaries carefully when rip on track."; 830 $langs{tip216} = "If the read skips due to imperfect data, a scratch, whatever, abort reading this track. See cdparanoia (option -X)."; 831 $langs{tip217} = "Use the paranoia library instead of cdda2wav's routines for reading. See cdda2wav (option -paranoia)."; 832 $langs{tip218} = "Disables paranoia mode. Paranoia is still being used. See cdda2wav (option -paraopts=help)."; 833 $langs{tip219} = "Switches verify off, and overlap on."; 834 $langs{tip220} = "Choose a targeted average bitrate. Sets encoding to the bitrate closest to this value (in Kb/s)."; 835 $langs{tip221} = "Adjust the quality of mp3; 9 is the worst quality, 0 is the best quality with more Kb/s. See: man lame (option: -V)."; 836 $langs{tip222} = "Adjust the quality of encode for ogg; 10 is the best quality with more Kb/s used, -1 is the worst quality. See: man oggenc."; 837 $langs{tip223} = "Adjust the quality of lame encoder for mp3 files: 0 is the best quality with maximum "; 838 $langs{tip223} .= "algorithms process; 9 is the worst quality but more fast. See: man lame (option: -q)."; 839 $langs{tip224} = "Set default variable bitrate (VBR) quantizer quality in percent for mp4 format; 500 is the best "; 840 $langs{tip224} .= "quality with more Kb/s used; 10 is the worst quality. See: <faac --help>."; 841 $langs{tip225} = "Adjust the quality of encode for mpc using profiles; 8 (braindead) is the best quality with more Kb/s used,"; 842 $langs{tip225} .= " 2 (telephone) is the worst quality. See: mppenc --longhelp\n"; 843 $langs{tip225} .= " q=2 --telephone - lowest quality, (32... 48 kbps)\n"; 844 $langs{tip225} .= " q=3 --thumb - low quality/internet, (58... 86 kbps)\n"; 845 $langs{tip225} .= " q=4 --radio - medium (MP3) quality, (112...152 kbps)\n"; 846 $langs{tip225} .= " q=5 --standard - high quality (dflt), (142...184 kbps)\n"; 847 $langs{tip225} .= " q=6 --xtreme - extreme high quality, (168...212 kbps)\n"; 848 $langs{tip225} .= " q=7 --insane - extreme high quality, (232...268 kbps)\n"; 849 $langs{tip225} .= " q=8 --braindead - extreme high quality, (232...278 kbps)"; 850 $langs{tip226} = "Compression level:\n fast: 1000\n normal: 2000\n high: 3000\n extra high: 4000\n insane: 5000\n"; 851 $langs{tip226} .= "\nMore compression level \nresults small files.\nSee the help: mac"; 852 $langs{tip227} = "Compression level:\n fast: 0\n normal: 5\n best: 8\nSee <man flac>."; 853 $langs{tip228} = "Put here the additional command line used to encode this files."; 854 $langs{tip229} = "Used to encode ID3v2.3.0 Tag for MP3 files."; 855 $langs{tip250} = "If this entry is empty, the original comment tag will be preserved. "; 856 $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value."; 857 858 859 $langs{tip301} = "If there is more than one artist, use:\nArtist1 & Artist2 & Artist3 & ..."; 860 $langs{tip302} = "Track number"; 861 $langs{tip303} = "Total track number"; 862 $langs{tip304} = "Save changes of tag."; 863 $langs{tip305} = "Save changes of tag to $home/.cddb directory."; 864 865 $langs{tip401} = "Try /dev/cdrom, /dev/dvd, /dev/hdc or ...\nSee \"/etc/fstab\" file."; 866 $langs{tip402} = "Refresh the cdrom drive and erase the playlist."; 867 $langs{tip403} = "Unselect all tracks."; 868 $langs{tip404} = "Select all tracks."; 869 $langs{tip405} = "Add more files to play."; 870 $langs{tip406} = "Close the gnormalize player config."; 871 $langs{tip407} = "Choose the interval in milliseconds that the text will be redrawed."; 872 $langs{tip408} = "Choose the step incremental in pixels."; 873 $langs{tip409} = "Scrolling text orientation: up/down or left/right."; 874 $langs{tip410} = "Show the xTunes like skin.\nTo take effect, change the display mode."; 875 $langs{tip411} = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode."; 876 $langs{tip429} = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. "; 877 $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'."; 878 $langs{tip429} .= "\n---***---\n"; 879 $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. "; 880 $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. "; 881 $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice."; 882 $langs{tip429} .= "\n---***---\n"; 883 $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. "; 884 885 $langs{tip501} = "All tabs, messages, names and tips used by gnormalize."; 886 $langs{tip502} = "You need to restart the Gnormalize to make the changes."; 887 $langs{tip503} = "Guidance Language only used to help the translations.\nRead Only."; 888 $langs{tip504} = "Save the translations and new languages inside the directory: $lang_dir."; 889 $langs{tip505} = "Improve this translation or use it as base for a new Language."; 890 891 892 $langs{msg001} = "Supported Files into the directory (recursively):"; 893 $langs{msg002} = "Supported Files into the directory (not recursively):"; 894 $langs{msg003} = " Choose a mp3/mp4/mpc/ogg/ape/flac/wav/cda file to normalize!"; 895 $langs{msg004} = " Dependence not satisfied!"; 896 $langs{msg005} = "If Same Extension, Overwrite file"; 897 $langs{msg006} = "Analyzing with ReplayGain normalization algorithms ..."; 898 899 $langs{msg012} = ": read only!"; 900 $langs{msg013} = " Select at least one track to rip!"; 901 $langs{msg014} = " Success! Rip finished."; 902 $langs{msg015} = " Rip stopped!"; 903 $langs{msg016} = " Success!"; 904 $langs{msg017} = " Success! File converted."; 905 $langs{msg018} = " Success! File normalized."; 906 $langs{msg019} = "stop ripping"; 907 $langs{msg020} = " Get info from "; 908 $langs{msg021} = " Please, wait. cdparanoia is reading the cdrom ..."; 909 $langs{msg022} = " Please, select at least one track to play."; 910 $langs{msg023} = "Can't find \""; 911 $langs{msg024} = "\" in executable path."; 912 $langs{msg025} = "The output can't be \"mp3\" format."; 913 $langs{msg026} = "The output can't be \"ogg\" format."; 914 $langs{msg027} = "The output can't be \"mpc\" format."; 915 $langs{msg028} = "The output can't be \"ape\" format."; 916 $langs{msg029} = "The output can't be \"flac\" format."; 917 $langs{msg030} = "The output can't be \"mp4\" format."; 918 $langs{msg031} = "The wav files can't be normalized."; 919 $langs{msg032} = "The input can't be \"ogg\" format."; 920 $langs{msg033} = "The input can't be \"mpc\" format."; 921 $langs{msg034} = "The input can't be \"mp4\" format."; 922 $langs{msg035} = "cdcd is a Command Driven CD player."; 923 $langs{msg036} = "First run \"cdcd\" in command line to make the config file .cdcdrc"; 924 $langs{msg037} = "Choose \"n\" for the question: Are you connected to a network (y/n) [y]?"; 925 $langs{msg038} = "Can't use the perl module \""; 926 $langs{msg039} = "Can't play audio CD."; 927 $langs{msg040} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 928 $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 929 $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert "; 930 $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 931 $langs{msg041} = "This file will not be normalized!"; 932 $langs{msg042} = "According to insensibility, not normalize"; 933 $langs{msg043} = "Not normalize because adjustment "; 934 $langs{msg044} = " is less than insensibility value."; 935 $langs{msg045} = " not normalize "; 936 $langs{msg046} = "Don't need encode"; 937 $langs{msg047} = " already normalized "; 938 $langs{msg048} = "This file is already normalized."; 939 $langs{msg049} = " Stop normalizing!"; 940 $langs{msg050} = "Applying adjustment of "; 941 $langs{msg051} = " normalizing: adjustment of "; 942 $langs{msg052} = "Computing levels..."; 943 $langs{msg053} = " normalized with adjustment of "; 944 $langs{msg054} = " ripping audio to wav"; 945 $langs{msg055} = " Stop ripping!"; 946 $langs{msg056} = "copy maked."; 947 $langs{msg057} = " Stop lame decoding!"; 948 $langs{msg058} = " Stop lame encoding!"; 949 $langs{msg061} = " This informations will be saved on normalized file."; 950 $langs{msg062} = " tag saved."; 951 $langs{msg063} = "Select a mp3/mp4/mpc/ogg/ape/flac/wav file."; 952 $langs{msg064} = "Homepage: $HOMEPAGE\nThis software is available under GNU General Public Licence."; 953 $langs{msg065} = " output: "; 954 $langs{msg066} = "file selected - $langs{all_tab03} can be edited."; 955 $langs{msg067} = " Unable to open cdrom drive "; 956 $langs{msg068} = " Getting information from cddb ..."; 957 $langs{msg069} = " none cddb information."; 958 $langs{msg070} = " Press save button on \"$langs{all_tab03}\" tab to save this changes."; 959 $langs{msg071} = " Not connected, using "; 960 $langs{msg072} = " cddb: can't connect to internet!"; 961 $langs{msg073} = " Can't rip audio CD! cdparanoia not found."; 962 $langs{msg074} = " Can't rip audio CD! cdda2wav not found."; 963 $langs{msg075} = "Select a mp3, mp4, mpc, ogg, ape, flac, or wav file"; 964 $langs{msg077} = "settings"; 965 $langs{msg078} = "Selected file"; 966 $langs{msg079} = "Recomended minimum version:"; 967 $langs{msg080} = " Invalid option!"; 968 $langs{msg081} = " Press the \"Refresh the cdrom\" button and type again the changes."; 969 $langs{msg082} = "Not found CDDB_get perl module in your system.\n gnormalize will uses internal CDDB_get (version 2.27)."; 970 $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20)."; 971 $langs{msg084} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 972 $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 973 $langs{msg085} = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. "; 974 $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 975 $langs{msg086} = "Selected Directory (recursively)"; 976 $langs{msg087} = "Select a directory containing mp3, mp4, mpc, ogg, ape, flac, or wav file."; 977 $langs{msg088} = "Selected Directory (not recursively)"; 978 $langs{msg089} = "Removing temporary file:"; 979 $langs{msg090} = "Can not find no supported file inside of directory!"; 980 $langs{msg092} = "remove this music from list"; 981 $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; S�o Paulo - Brasil"; 982 $langs{msg094} = "Translation to English: Claudio Fernandes de Souza Rodrigues."; 983 $langs{msg095} = "You must add new language name to translate!"; 984 } 985 986 if ( $language eq 'Portugu�s' ) 987 { 988 $langs{all_tab01} = "Arquivos"; 989 $langs{all_tab02} = "Configura��o"; 990 $langs{all_tab03} = "Informa��o"; 991 $langs{all_tab04} = "Rip/Play"; 992 $langs{all_tab05} = "Tradu��es"; 993 $langs{all_tab06} = "Sobre"; 994 $langs{all_tab07} = "Op��o1"; 995 $langs{all_tab08} = "Op��o2"; 996 $langs{all_tab09} = "CDDB"; 997 $langs{all_tab10} = "Ripper"; 998 $langs{all_tab11} = "Cores"; 999 $langs{all_tab12} = "Tocadores"; 1000 $langs{all_tab13} = "Colunas"; 1001 $langs{all_tab14} = "Visual"; 1002 1003 $langs{name001} = "Tipo de Normaliza��o"; 1004 $langs{name002} = "Insensibilidade"; 1005 $langs{name003} = "Arquivo Selecionado"; 1006 $langs{name004} = "Diret�rio de Entrada"; 1007 $langs{name005} = "Sa�da: Compress�o Com Perdas"; 1008 $langs{name006} = "Sa�da: Compress�o Sem Perdas"; 1009 $langs{name106} = "Sa�da: Sem Compress�o"; 1010 1011 $langs{name007} = "Arquivo"; 1012 $langs{name008} = "Recursivamente"; 1013 $langs{name009} = "Remover Wav"; 1014 $langs{name010} = "Alterar Propriedades"; 1015 $langs{name011} = "Sobrescrever"; 1016 $langs{name012} = "Prioridade"; 1017 $langs{name013} = "Adicionar Comando"; 1018 $langs{name014} = "Arquivo Rip"; 1019 $langs{name015} = "Caracteres"; 1020 $langs{name016} = "Idioma"; 1021 $langs{name017} = "Fonte"; 1022 $langs{name018} = "Ler CDDB"; 1023 $langs{name019} = "Sobrescrever CDDB"; 1024 $langs{name020} = "CDDB Servidor"; 1025 $langs{name021} = "Porta"; 1026 $langs{name022} = "Transporte"; 1027 $langs{name023} = "Desativar Paranoia"; 1028 $langs{name024} = "Desativar Extra Paranoia"; 1029 $langs{name025} = "Abortar no Caso de Arranh�o"; 1030 $langs{name026} = "Reler Indefinidamente"; 1031 $langs{name027} = "Paranoia n�o Verificar"; 1032 $langs{name028} = "Desativar Paranoia"; 1033 $langs{name029} = "Extrator"; 1034 $langs{name030} = "Tipo de Codifica��o"; 1035 $langs{name031} = "Modo"; 1036 $langs{name032} = "Qualidade"; 1037 $langs{name033} = "Vari�vel"; 1038 $langs{name034} = "T�tulo"; 1039 $langs{name035} = "Artista"; 1040 $langs{name036} = "�lbum"; 1041 $langs{name037} = "Coment�rio"; 1042 $langs{name038} = "Ano"; 1043 $langs{name039} = "N�mero"; 1044 $langs{name040} = "G�nero"; 1045 $langs{name041} = "Freq��ncia"; 1046 $langs{name042} = "Dura��o"; 1047 $langs{name043} = "Canais"; 1048 $langs{name044} = "Dura��o"; 1049 $langs{name045} = "Faixa"; 1050 $langs{name046} = "Artista"; 1051 $langs{name047} = "T�tulo"; 1052 $langs{name048} = "Tamanho"; 1053 $langs{name049} = "Ano"; 1054 $langs{name050} = "Arquivo"; 1055 $langs{name051} = "Extens�o"; 1056 $langs{name052} = "Diret�rio de Sa�da"; 1057 $langs{name053} = "�lbum"; 1058 $langs{name054} = "Play Count"; 1059 $langs{name055} = "Anima��o"; 1060 $langs{name056} = "Nome do Arquivo"; 1061 $langs{name057} = "Exibir Lembretes"; 1062 $langs{name058} = "Idioma Usado como Par�metro"; 1063 $langs{name059} = "Atual Tradu��o"; 1064 $langs{name060} = "Melhorar a Atual Tradu��o"; 1065 $langs{name061} = "Adicionar Novo Idioma"; 1066 $langs{name062} = "Adicione Aqui Novo Idioma e Pressione o Bot�o para Salvar."; 1067 $langs{name063} = "Normaliza��o"; 1068 $langs{name064} = "CD Player"; 1069 $langs{name065} = "Tocar"; 1070 1071 $langs{name429} = 'Tocar Arquivos Sem Qualquer Filtro'; 1072 $langs{name430} = 'Tocar Arquivos De Diferentes �lbuns'; 1073 $langs{name431} = 'Tocar Arquivos De Diferentes Artistas'; 1074 $langs{name432} = 'Tocar Arquivos De Diferentes G�neros'; 1075 $langs{name433} = 'Tocar Arquivos De Diferentes Anos'; 1076 1077 $langs{tip101} = "Track: usa o ajuste ReplayGain considerando uma �nica Faixa.\nAlbum: ainda n�o implementado!\n"; 1078 $langs{tip101} .= "None: nenhuma normaliza��o � realizada.\n"; 1079 $langs{tip101} .= "---*---\n"; 1080 $langs{tip101} .= "gnormalize utiliza o wavegain para normalizar os arquivos wave.\n"; 1081 $langs{tip101} .= "wavegain � um programa que aplica o algor�timo ReplayGain de normaliza��o diretamente aos arquivos wave."; 1082 $langs{tip102} = "Aplica ganhos adicionais ao audio em decib�is entre -12.0 e +12.0. "; 1083 $langs{tip102} .= "Gain = 0.00dB corresponde ao valor de refer�ncia de 89dB.\n"; 1084 $langs{tip102} .= "---*---\n"; 1085 $langs{tip102} .= "Id�ias b�sicas do algor�tmo de normaliza��o ReplayGain:\n"; 1086 $langs{tip102} .= "1. Calcular a Raiz da M�dia do Quadrados da amplitude RMS(A) a cada intervalo de 50ms;\n"; 1087 $langs{tip102} .= "2. Ordenar em ordem crescente os valores RMS(A) e escolher aquele que representa 95% dos volumes percebidos;\n"; 1088 $langs{tip102} .= "3. Ajustar a energia do sinal digital ao valor de refer�ncia de 89dB.\n"; 1089 $langs{tip102} .= "---*---\n"; 1090 $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) corresponde a Raiz da M�dia dos Quadrados da amplitude sonora A.\n"; 1091 $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), tal que A � a amplitude medida e A0 � a amplitude de refer�ncia."; 1092 $langs{tip103} = "Insensibilidade do normalize. Apenas n�o re-codifica se:\n"; 1093 $langs{tip103} .= "1) a extens�o do arquivo de entrada for a mesma da sa�da;\n"; 1094 $langs{tip103} .= "2) e o bot�o \"$langs{name010}\" n�o estiver ativo;\n"; 1095 $langs{tip103} .= "3) e o ajuste do normalize for menor que o valor de insensibilidade."; 1096 $langs{tip104} = "Selecione um diret�rio com arquivo suportado."; 1097 $langs{tip105} = "Escolha o diret�rio onde todos os arquivos ser�o copiados."; 1098 $langs{tip106} = "Normaliza/converte todos os arquivos suportados dentro do diret�rio (recursivamente ou n�o)."; 1099 $langs{tip107} = "Selecione um diret�rio incluindo subdiret�rios: desce recursivamente dentro do diret�rio preservando a mesma estrutura."; 1100 $langs{tip108} = "Depois de normalizar, o formato de sa�da ser� mp3. \nPara ouvir arquivos mp3 utilize o mpg123, mpg321 ou madplay."; 1101 $langs{tip109} = "Depois de normalizar, o formato de sa�da ser� mp4 (tamb�m conhecido como m4a) ou acc. \n"; 1102 $langs{tip109} .= "Para ouvir arquivos mp4 utilize o mplayer."; 1103 $langs{tip110} = "Depois de normalizar, o formato de sa�da ser� mpc (tamb�m conhecido como mpp ou mp+). \n"; 1104 $langs{tip110} .= "Para ouvir arquivos mpc utilize o comando mppdec ou o mplayer."; 1105 $langs{tip111} = "Depois de normalizar, o formato de sa�da ser� ogg. \nPara ouvir arquivos ogg utilize o ogg123."; 1106 $langs{tip112} = "Depois de normalizar, o formato de sa�da ser� ape. \nPara ouvir arquivos ape use o comando:\n mac \"song.ape\" - -d | play -t wav - "; 1107 $langs{tip113} = "Depois de normalizar, o formato de sa�da ser� flac. \nPara ouvir arquivos flac utilize o flac123 ou o mplayer.\nVers�o do flac exigida >= \"1.1.1\"."; 1108 $langs{tip114} = "Esta op��o � conveniente para gravar um cd de audio.\nWav � um formato de audio sem compress�o."; 1109 $langs{tip115} = "NOTE:\n"; 1110 $langs{tip115} .= "Neste procedimento, conhecido por 'Lossy Compression', dados podem ser perdidos durante a compress�o. "; 1111 $langs{tip115} .= "O grau de perda varia de acordo com os ajustes adotados e dependendo destes ajustes a perda � m�nima e n�o percept�vel "; 1112 $langs{tip115} .= "ao ouvido humano.\nExemplos de audio com Lossy Compression: Mp3, Mp4, Mpc e Ogg."; 1113 $langs{tip116} = "NOTE:\n"; 1114 $langs{tip116} .= "Este procedimento � conhecido por 'Lossless Compression' ou 'Livre de Perdas' em que toda informa��o � preservada "; 1115 $langs{tip116} .= "durante a compress�o e todos os dados podem ser recuperados de forma id�ntica aos originais.\n"; 1116 $langs{tip116} .= "Exemplos de audio com Lossless Compression: Ape e Flac."; 1117 $langs{tip117} = "Exibir a barra de progresso."; 1118 $langs{tip118} = "Omitir a barra de progresso."; 1119 $langs{tip119} = "Exibir as linhas de comando e outras informa��es."; 1120 $langs{tip120} = "Omitir as linhas de comando e outras informa��es."; 1121 $langs{tip121} = "Sair."; 1122 $langs{tip122} = "Apagar todas as mensagens."; 1123 1124 $langs{tip201} = "Depois do processo de normaliza��o, os arquivos tempor�rios wav ser�o removidos/apagados."; 1125 $langs{tip202} = "Depois de normalizar os arquivos, voc� pode alterar suas propriedades determinando o tipo de codifica��o, "; 1126 $langs{tip202} .= "o bitrate de todos os arquivos de sa�da, etc. Caso contr�rio, o bitrate de cada arquivo de entrada e "; 1127 $langs{tip202} .= "outras propriedades ser�o conservados na medida do poss�vel."; 1128 $langs{tip203} = "O arquivo normalizado ser� salvo no mesmo diret�rio da entrada e ocorrer� sobrescri��o (salvar por cima) se existir outro arquivo de mesmo nome."; 1129 $langs{tip204} = "Exibir sugest�es e informa��es."; 1130 $langs{tip205} = "Mostrar a anima��o do Tux e de outros ping�ins."; 1131 $langs{tip206} = "Modificar o gerenciamento de prioridade na execu��o dos comandos. Seu valor varia de 0 (maior prioridade) at� 19 (menor prioridade)."; 1132 $langs{tip207} = "Formato para o nome final do arquivo, usado apenas para ripar/extrair arquivos do CD de audio:\n"; 1133 $langs{tip207} .= " %a - artista\n"; 1134 $langs{tip207} .= " %b - album\n"; 1135 $langs{tip207} .= " %t - t�tulo da m�sica\n"; 1136 $langs{tip207} .= " %n - n�mero da faixa\n"; 1137 $langs{tip207} .= " %y - ano\n"; 1138 $langs{tip207} .= " %g - g�nero"; 1139 $langs{tip208} = "Fonte aconselhada: Sans 10."; 1140 $langs{tip209} = "Carregar informa��es para o CD de audio em seu drive a partir do servidor CDDB \"$CDDB_server\" ou do arquivo copiado em $home/.cddd/."; 1141 $langs{tip210} = "Sempre buscar informa��es do servidor CDDB e sobrescrever o arquivo existente em $home/.cddd/ ."; 1142 $langs{tip211} = "Alguns servidores:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880"; 1143 $langs{tip212} = "Escolha o n�mero da porta."; 1144 $langs{tip213} = "Desativar toda a verifica��o e corre��o de erros na leitura de dados. Consequentemente a extra��o � mais r�pida. "; 1145 $langs{tip213} .= "Esta op��o tamb�m implica em (op��o -Y) ativa. Veja cdparanoia (op��o -Z)."; 1146 $langs{tip214} = "N�o aceita nenhuma omiss�o na leitura dos dados; ler indefinidamente se necess�rio. Veja cdparanoia (op��o -z)."; 1147 $langs{tip215} = "Desativa a verifica��o interna dos dados; apenas cobre e verifica a regi�o das fronteiras. N�o � recomendado. Veja cdparanoia (op��o -Y)."; 1148 $langs{tip216} = "Se a leitura pula/salta devido a dados imperfeitos, arranh�es, etc., abandonar a leitura desta faixa do CD. Veja cdparanoia (op��o -X)."; 1149 $langs{tip217} = "Usar, para a leitura do CD, a biblioteca do paranoia ao inv�s das rotinas do cdda2wav. Veja cdda2wav (op��o -paranoia)."; 1150 $langs{tip218} = "Desativar o modo paranoia. Mas, paranoia ainda assim ser� usado. Veja cdda2wav (op��o -paraopts=help)."; 1151 $langs{tip219} = "Desativa a verifica��o, mas habilita a leitura sobreposta da regi�o das fronteiras."; 1152 $langs{tip220} = "Escolha o valor do bitrate m�dio. Ajusta o codificador/encoder a este valor o ma�s pr�ximo poss�vel (in Kb/s). "; 1153 $langs{tip220} .= "Bitrate � a taxa de bits utilizada no arquivo por unidade de tempo."; 1154 $langs{tip221} = "Ajusta a qualidade do mp3; 9 � a pior qualidade, 0 � a melhor qualidade com mais Kb/s usado. Veja: man lame (op��o: -V)."; 1155 $langs{tip222} = "Ajusta a qualidade do ogg; 10 � a melhor qualidade com mais Kb/s usado, -1 � a pior qualidade. Veja: man oggenc."; 1156 $langs{tip223} = "Ajusta a qualidade do codificador lame para os arquivos mp3: 0 � a melhor qualidade com a m�xima itera��o no processo algor�tmo; "; 1157 $langs{tip223} .= "9 � a pior qualidade, contudo muito mais r�pido. Veja: man lame (op��o: -q)."; 1158 $langs{tip224} = "Ajusta a qualidade do vari�vel bitrate (VBR) em porcentagem para o formato mp4; 500 � a melhor "; 1159 $langs{tip224} .= "qualidade com mais Kb/s usado; 10 � a pior qualidade. Veja: <faac --help>."; 1160 $langs{tip225} = "Ajusta a qualidade de codifica��o para os arquivos mpc usando um conjunto de rotinas (profiles); "; 1161 $langs{tip225} .= "8 (braindead) � a melhor qualidade com mais Kb/s usado, 2 (telephone) � a pior qualidade. Veja: <mppenc --longhelp>.\n"; 1162 $langs{tip225} .= " q=2 --telephone - pior qualidade, (32... 48 kbps)\n"; 1163 $langs{tip225} .= " q=3 --thumb - baixa qualidade/internet, (58... 86 kbps)\n"; 1164 $langs{tip225} .= " q=4 --radio - qualidade m�dia (MP3), (112...152 kbps)\n"; 1165 $langs{tip225} .= " q=5 --standard - qualidade alta (padr�o), (142...184 kbps)\n"; 1166 $langs{tip225} .= " q=6 --xtreme - qualidade muito alta, (168...212 kbps)\n"; 1167 $langs{tip225} .= " q=7 --insane - qualidade muito alta, (232...268 kbps)\n"; 1168 $langs{tip225} .= " q=8 --braindead - qualidade alt�ssima, (232...278 kbps)"; 1169 $langs{tip226} = "N�vel de Compress�o:\n fast (r�pida): 1000\n normal: 2000\n high (alta): 3000\n extra high: 4000\n insane: 5000\n"; 1170 $langs{tip226} .= "\nMaior n�vel de compress�o resulta \nem arquivos menores.\nVeja o comando: mac"; 1171 $langs{tip227} = "N�vel de Compress�o:\n fast (r�pida): 0\n normal: 5\n best (m�xima): 8\nVeja <man flac>."; 1172 $langs{tip228} = "Coloque aqui linha de comando adicional usada para codificar estes arquivos."; 1173 $langs{tip229} = "Usado para codificar o ID3v2.3.0 Tag em arquivos MP3."; 1174 $langs{tip250} = "Se esta entrada estiver vazia, o coment�rio original do Tag ser� preservado. "; 1175 $langs{tip250} .= "O coment�rio padr�o � \"gnormalize - gain=%gain\" com %gain substitu�do pelo seu valor."; 1176 1177 $langs{tip301} = "Se houver mais de um artista, use:\nArtista1 & Artista2 & Artista3 & ..."; 1178 $langs{tip302} = "N�mero da m�sica."; 1179 $langs{tip303} = "N�mero total de m�sicas."; 1180 $langs{tip304} = "Salvar altera��es do tag."; 1181 $langs{tip305} = "Salvar altera��es do tag no diret�rio $home/.cddb ."; 1182 1183 $langs{tip401} = "Tente /dev/cdrom, /dev/dvd, /dev/hdc ou ...\nVeja o arquivo \"/etc/fstab\"."; 1184 $langs{tip402} = "Atualiza o drive do cdrom e apaga a lista de m�sicas."; 1185 $langs{tip403} = "Selecionar nenhuma m�sica."; 1186 $langs{tip404} = "Selecionar todas as m�sicas."; 1187 $langs{tip405} = "Adicionar mais arquivos para tocar."; 1188 $langs{tip406} = "Fechar a configura��o do gnormalize player."; 1189 $langs{tip407} = "Escolha o intervalo em milisegundos que o texto ser� redesenhado."; 1190 $langs{tip408} = "Escolha o incremento no deslocamento do texto em pixels."; 1191 $langs{tip409} = "Orienta��o no deslocamento do texto: cima/baixo ou esquerda/direita."; 1192 $langs{tip410} = "Exibir um visual semelhante ao xTunes.\nPara fazer efeito, altere o modo de exibi��o."; 1193 $langs{tip411} = "Exibir Sempre: for�ar que este modo de exibi��o fique acima de outras janelas.\nPara fazer efeito, altere o modo de exibi��o."; 1194 $langs{tip429} = "Tocar arquivos que satisfazem determinados filtros pode ser mais coveniente ou agrad�vel que o m�todo aleat�rio geral. "; 1195 $langs{tip429} .= "Os filtros dispon�veis s�o 'Tocar Arquivos de Diferentes �lbuns/Artistas/G�neros/Anos'."; 1196 $langs{tip429} .= "\n---***---\n"; 1197 $langs{tip429} .= "Por exemplo, se o filtro escolhido for �lbuns, ent�o ser�o tocados arquivos entre os diferentes �lbuns. "; 1198 $langs{tip429} .= "Neste caso, todos os �lbuns ser�o tocados antes de repetir algum outro �lbum. "; 1199 $langs{tip429} .= "Em outras palavras, at� que um arquivo tenha sido tocado de cada �lbum, um mesmo �lbum n�o ser� escolhido duas vezes."; 1200 $langs{tip429} .= "\n---***---\n"; 1201 $langs{tip429} .= "Ao tocar, os filtros podem ser usados considerando a ordem direta ou aleat�ria. "; 1202 1203 $langs{tip501} = "Todas as abas, mensagens, nomes e lembretes usados pelo gnormalize."; 1204 $langs{tip502} = "Voc� precisa reiniciar o Gnormalize para efetuar as mudan�as."; 1205 $langs{tip503} = "Idioma usado apenas como par�metro para auxiliar na tradu��o.\nApenas para leitura."; 1206 $langs{tip504} = "Salvar as altera��es e novas tradu��es dentro do diret�rio: $lang_dir."; 1207 $langs{tip505} = "Aperfei�oe esta tradu��o ou use-a como base para um novo Idioma."; 1208 1209 1210 $langs{msg001} = "Arquivos suportados dentro do diret�rio (recursivamente):"; 1211 $langs{msg002} = "Arquivos suportados dentro do diret�rio (n�o recursivamente):"; 1212 $langs{msg003} = " Escolha um arquivo mp3/mp4/mpc/ogg/ape/flac/wav/cda para normalizar!"; 1213 $langs{msg004} = " Depend�ncia n�o satisfeita!"; 1214 $langs{msg005} = "Se Mesma Extens�o, Sobrescrever Arquivo"; 1215 $langs{msg006} = "Analisando com o algoritmo ReplayGain de normaliza��o ..."; 1216 1217 $langs{msg012} = ": apenas para leitura!"; 1218 $langs{msg013} = " Selecione ao menos uma m�sica para ripar/extrair!"; 1219 $langs{msg014} = " Sucesso! Extra��o finalizada."; 1220 $langs{msg015} = " Extra��o interrompida!"; 1221 $langs{msg016} = " Sucesso!"; 1222 $langs{msg017} = " Sucesso! Arquivo convertido."; 1223 $langs{msg018} = " Sucesso! Arquivo normalizado."; 1224 $langs{msg019} = "Interromper a extra��o"; 1225 $langs{msg020} = " Informa��o obtida de "; 1226 $langs{msg021} = " Favor esperar. cdparanoia est� lendo o cdrom ..."; 1227 $langs{msg022} = " Favor, selecione pelo menos uma m�sica para tocar."; 1228 1229 $langs{msg023} = "N�o encontrado \""; 1230 $langs{msg024} = "\" nos diret�rios execut�veis."; 1231 $langs{msg025} = "O formato de sa�da n�o pode ser \"mp3\"."; 1232 $langs{msg026} = "O formato de sa�da n�o pode ser \"ogg\"."; 1233 $langs{msg027} = "O formato de sa�da n�o pode ser \"mpc\"."; 1234 $langs{msg028} = "O formato de sa�da n�o pode ser \"ape\"."; 1235 $langs{msg029} = "O formato de sa�da n�o pode ser \"flac\"."; 1236 $langs{msg030} = "O formato de sa�da n�o pode ser \"mp4\"."; 1237 $langs{msg031} = "O arquivo wav n�o pode ser normalizado."; 1238 $langs{msg032} = "O formato de entrada n�o poder ser \"ogg\"."; 1239 $langs{msg033} = "O formato de entrada n�o poder ser \"mpc\"."; 1240 $langs{msg034} = "O formato de entrada n�o poder ser \"mp4\"."; 1241 $langs{msg035} = "cdcd � um tocador de CD em linha de comando."; 1242 $langs{msg036} = "Primeiro execute \"cdcd\" em linha de comando para gerar o arquivo de configura��o .cdcdrc"; 1243 $langs{msg037} = "Escolha \"n\" para a quest�o: Are you connected to a network (y/n) [y]?"; 1244 $langs{msg038} = "N�o pode ser usado o m�dulo perl \""; 1245 $langs{msg039} = "CD de audio n�o poder ser tocado."; 1246 $langs{msg040} = "gnormalize � um conversor e extractor de CDs de Audio com aplica��o do algor�timo ReplayGain de normaliza��o, um tocador de audio e um "; 1247 $langs{msg040} .= "editor de metadata (tag). gnormalize utiliza o 'wavegain' para normalizar arquivos WAV com a acur�cia do c�digo gain_analysis.c do ReplayGain. "; 1248 $langs{msg040} .= "gnormalize decodifica os arquivos para o formato WAV, normaliza os arquivos WAV e re-codifica-os. gnormalize suporta convers�o "; 1249 $langs{msg040} .= "entre os formatos de audio MP3, MP4, MPC, OGG, APE, FLAC e WAV."; 1250 $langs{msg041} = "Este arquivo n�o ser� normalizado!"; 1251 $langs{msg042} = "De acordo com a insensibilidade, n�o normalizar"; 1252 $langs{msg043} = "N�o normalizar pois o ajuste "; 1253 $langs{msg044} = " � menor que o valor da insensibilidade."; 1254 $langs{msg045} = " n�o normalizar "; 1255 $langs{msg046} = "N�o necessita codificar/encodar"; 1256 $langs{msg047} = " j� normalizado "; 1257 $langs{msg048} = "Este arquivo j� est� normalizado."; 1258 $langs{msg049} = " Interromper a normaliza��o!"; 1259 $langs{msg050} = "Aplicando ajuste de "; 1260 $langs{msg051} = " normalizando: ajuste de "; 1261 $langs{msg052} = "Calculando o ajuste ..."; 1262 $langs{msg053} = " normalizado com ajuste de "; 1263 $langs{msg054} = " extraindo audio para wav"; 1264 $langs{msg055} = " Interrompendo a extra��o!"; 1265 $langs{msg056} = "c�pia realizada."; 1266 $langs{msg057} = " Parar decodifica��o lame!"; 1267 $langs{msg058} = " Parar codifica��o lame!"; 1268 $langs{msg061} = " Estas informa��es ser�o salvas no arquivo normalizado."; 1269 $langs{msg062} = " tag alterado."; 1270 $langs{msg063} = "Selecione um arquivo mp3/mp4/mpc/ogg/ape/flac/wav ."; 1271 $langs{msg064} = "Homepage: $HOMEPAGE\nEste software est� dispon�vel sob a GNU General Public Licence."; 1272 $langs{msg065} = " sa�da: "; 1273 $langs{msg066} = "selecionado - $langs{all_tab03} pode ser editado."; 1274 $langs{msg067} = " N�o foi poss�vel ler o cdrom no drive "; 1275 $langs{msg068} = " Obtendo informa��o do cddb ..."; 1276 $langs{msg069} = " nenhuma informa��o do cddb."; 1277 $langs{msg070} = " Pressione o bot�o Save (Salvar) em \"$langs{all_tab03}\" para salvar as altera��es."; 1278 $langs{msg071} = " N�o conectado, usando "; 1279 $langs{msg072} = " cddb: falha ao conectar-se � internet!"; 1280 $langs{msg073} = " N�o pode extrair CD de audio! cdparanoia n�o encontrado."; 1281 $langs{msg074} = " N�o pode extrair CD de audio! cdda2wav n�o encontrado."; 1282 $langs{msg075} = "Selecione um arquivo mp3, mp4, mpc, ogg, ape, flac, ou wav."; 1283 $langs{msg077} = "ajustes"; 1284 $langs{msg078} = "Arquivo selecionado"; 1285 $langs{msg079} = "Vers�o m�nima recomendada:"; 1286 $langs{msg080} = " Op��o Inv�lida!"; 1287 $langs{msg081} = " Pressione o bot�o \"Atualizar o cdrom\" e digite novamente as altera��es."; 1288 $langs{msg082} = "O perl m�dulo CDDB_get n�o foi encontrado no seu sistema.\n gnormalize ir� usar o CDDB_get (vers�o 2.27) interno."; 1289 $langs{msg083} = "O perl m�dulo MP3::Info n�o foi encontrado no seu sistema.\n gnormalize ir� usar o MP3::Info (vers�o 1.20) interno."; 1290 $langs{msg084} = "gnormalize � um conversor e extractor de CDs de Audio com aplica��o do algor�timo ReplayGain de normaliza��o, um tocador de audio e um "; 1291 $langs{msg084} .= "editor de metadata (tag). gnormalize utiliza o 'wavegain' para normalizar arquivos WAV com a acur�cia do c�digo gain_analysis.c do ReplayGain. "; 1292 $langs{msg085} = "gnormalize decodifica os arquivos para o formato WAV, normaliza os arquivos WAV e re-codifica-os. gnormalize suporta convers�o "; 1293 $langs{msg085} .= "entre os formatos de audio MP3, MP4, MPC, OGG, APE, FLAC e WAV."; 1294 $langs{msg086} = "Diret�rio selecionado (recursivamente)"; 1295 $langs{msg087} = "Selecione um diret�rio contendo arquivo mp3, mp4, mpc, ogg, ape, flac, ou wav."; 1296 $langs{msg088} = "Diret�rio selecionado (n�o recursivamente):"; 1297 $langs{msg089} = "Removendo arquivo tempor�rio"; 1298 $langs{msg090} = "Nenhum arquivo suportado foi encontrado dentro do diret�rio!"; 1299 $langs{msg092} = "remove esta m�sica da lista"; 1300 $langs{msg093} = "Autor: $AUTHOR\nEmail: $EMAIL\nData: $DATE ; S�o Paulo - Brasil"; 1301 $langs{msg094} = "Tradu��o para o Portugu�s: Claudio Fernandes de Souza Rodrigues."; 1302 $langs{msg095} = "Voc� deve adicionar o nome do novo Idioma para traduzir."; 1303 } 1304 1305 if ( $language eq 'Fran�ais' ) 1306 { 1307 $langs{all_tab01} = "Fichiers"; 1308 $langs{all_tab02} = "Configuration"; 1309 $langs{all_tab03} = "Information"; 1310 $langs{all_tab04} = "Rip/Play"; 1311 $langs{all_tab05} = "Translations"; 1312 $langs{all_tab06} = "De"; 1313 $langs{all_tab07} = "Option1"; 1314 $langs{all_tab08} = "Option2"; 1315 $langs{all_tab09} = "CDDB"; 1316 $langs{all_tab10} = "Ripper"; 1317 $langs{all_tab11} = "Colors"; 1318 $langs{all_tab12} = "Players"; 1319 $langs{all_tab13} = "Columns"; 1320 $langs{all_tab14} = "Skins"; 1321 1322 $langs{name001} = "Type de Normalisation"; 1323 $langs{name002} = "Insensibilit�"; 1324 $langs{name003} = "Fichier choisi"; 1325 $langs{name004} = "R�pertoire de d�part"; 1326 $langs{name005} = "Output: Lossy Compression"; 1327 $langs{name006} = "Output: Lossless Compression"; 1328 $langs{name106} = "Output: Uncompressed"; 1329 1330 $langs{name007} = "Fichier"; 1331 $langs{name008} = "R�cursivement"; 1332 $langs{name009} = "Effacer les .wav"; 1333 $langs{name010} = "Changer les Propri�t�s"; 1334 $langs{name011} = "Remplacer"; 1335 $langs{name012} = "Propri�t�"; 1336 $langs{name013} = "Ajoute la Commande"; 1337 $langs{name014} = "Nom du Fichier Ripp�"; 1338 $langs{name015} = "Caract�re"; 1339 $langs{name016} = "Idiom"; 1340 $langs{name017} = "Police"; 1341 $langs{name018} = "Lire CDDB"; 1342 $langs{name019} = "Remplacer CDDB"; 1343 $langs{name020} = "Serveur CDDB"; 1344 $langs{name021} = "Port"; 1345 $langs{name022} = "Transport"; 1346 $langs{name023} = "D�sactiver Paranoia"; 1347 $langs{name024} = "D�sactiver Extra Paranoia"; 1348 $langs{name025} = "Annuler si Saut�"; 1349 $langs{name026} = "Never Skip Repair"; 1350 $langs{name027} = "Paranoia No-Verify"; 1351 $langs{name028} = "Paranoia D�sativ�e"; 1352 $langs{name029} = "Ripper"; 1353 $langs{name030} = "Type d\'encodage"; 1354 $langs{name031} = "Mode"; 1355 $langs{name032} = "Qualit� d\'encodage"; 1356 $langs{name033} = "Variable"; 1357 $langs{name034} = "Titre"; 1358 $langs{name035} = "Artiste"; 1359 $langs{name036} = "Album"; 1360 $langs{name037} = "Commentaire"; 1361 $langs{name038} = "Ann�e"; 1362 $langs{name039} = "Num. Piste"; 1363 $langs{name040} = "Genre"; 1364 $langs{name041} = "Frequency"; 1365 $langs{name042} = "Temps"; 1366 $langs{name043} = "Canaux"; 1367 $langs{name044} = "Length"; 1368 $langs{name045} = "Piste"; 1369 $langs{name046} = "Artiste"; 1370 $langs{name047} = "Titre"; 1371 $langs{name048} = "Taille"; 1372 $langs{name049} = "Ann�e"; 1373 $langs{name050} = "Chemin"; 1374 $langs{name051} = "Extension"; 1375 $langs{name052} = "R�pertoire de Sortie"; 1376 $langs{name053} = "Album"; 1377 $langs{name054} = "Play Count"; 1378 $langs{name055} = "Animation"; 1379 $langs{name056} = "Nom de Fichier"; 1380 $langs{name057} = "Show Tooltips"; 1381 $langs{name058} = "Guidance Language"; 1382 $langs{name059} = "Current Translation"; 1383 $langs{name060} = "Improve The Currente Language Translation"; 1384 $langs{name061} = "Add New Language"; 1385 $langs{name062} = "Add new language here and then press save buton."; 1386 $langs{name063} = "Normaliser"; 1387 $langs{name064} = "CD Player"; 1388 $langs{name065} = "Play"; 1389 1390 $langs{name429} = 'Play Tracks Without Any Filters'; 1391 $langs{name430} = 'Play Tracks From Different Albums'; 1392 $langs{name431} = 'Play Tracks From Different Artists'; 1393 $langs{name432} = 'Play Tracks From Different Genres'; 1394 $langs{name433} = 'Play Tracks From Different Years'; 1395 1396 $langs{tip101} = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n"; 1397 $langs{tip101} .= "None: no normalization is done.\n"; 1398 $langs{tip101} .= "---*---\n"; 1399 $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n"; 1400 $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files."; 1401 $langs{tip102} = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. "; 1402 $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n"; 1403 $langs{tip102} .= "---*---\n"; 1404 $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n"; 1405 $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n"; 1406 $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 1407 $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n"; 1408 $langs{tip102} .= "---*---\n"; 1409 $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n"; 1410 $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude."; 1411 $langs{tip103} = "Insensibilit� de normalisation. Ne pas re-encoder si:\n"; 1412 $langs{tip103} .= "1) l\'extension du fichier de sortie est identique � l\'entr�e;\n"; 1413 $langs{tip103} .= "2) et que le bouton \"$langs{name010}\" n\'est pas actif;\n"; 1414 $langs{tip103} .= "3) et l\'ajustement de normalisation est plus petit que la valeur d\'insensibilit�."; 1415 $langs{tip104} = "S�lectionner un r�pertoire avec fichier support�."; 1416 $langs{tip105} = "Choisir le r�pertoire o� les fichiers seront sauv�s."; 1417 $langs{tip106} = "Normaliser/Convertir tous les fichiers du r�pertoire (r�cursivement ou pas)."; 1418 $langs{tip107} = "Inclure les sous-r�pertoires: la r�cursivit� pr�serve l'arborescence."; 1419 $langs{tip108} = "Apr�s la normalisation, le format de sortie sera mp3. Ouvrez le avec mpg123, mpg321 ou le madplay."; 1420 $langs{tip109} = "Apr�s la normalisation, le format de sortie sera mp4 (aussi m4a) ou aac. Ouvrez le avec le mplayer."; 1421 $langs{tip110} = "Apr�s la normalisation, le format de sortie sera mpc (aussi mpp or mp+). Ouvrez le avec mppdec ou le mplayer."; 1422 $langs{tip111} = "Apr�s la normalisation, le format de sortie sera ogg. Ouvrez le avec ogg123."; 1423 $langs{tip112} = "Apr�s la normalisation, le format de sortie sera ape. Ouvrez le avec la commande:\n mac \"song.ape\" - -d | play -t wav - "; 1424 $langs{tip113} = "Apr�s la normalisation, le format de sortie sera flac. Ouvrez le avec flac123 ou le mplayer.\nRequiert une version flac >= \"1.1.1\"."; 1425 $langs{tip114} = "Ce qui convient pour faire un CD Audio.\nWav est un format audio non comprim�."; 1426 $langs{tip115} = "NOTE:\n"; 1427 $langs{tip115} .= "Lossy Compression, certaines informations seront perdues, le format originel ne pourra �tre retrouv� "; 1428 $langs{tip115} .= "et sera sensiblement diff�rent.\nExemples de compression audio avec perte: Mp3, Mp4, Mpc et Ogg."; 1429 $langs{tip116} = "NOTE:\n"; 1430 $langs{tip116} .= "La compression devrait �tre Lossless Compression, toutes les informations d\'origine seront pr�serv�es, "; 1431 $langs{tip116} .= "et les donn�es peuvent �tre remises en l'�tat originel.\nExemples de compression audio sans perte: Ape et Flac."; 1432 $langs{tip117} = "Montrer la progression."; 1433 $langs{tip118} = "Cacher laprogression."; 1434 $langs{tip119} = "Voir la ligne de commande et autres infos."; 1435 $langs{tip120} = "Cacher la ligne de commande et autres infos."; 1436 $langs{tip121} = "Quitter."; 1437 $langs{tip122} = "Effacer tous les messages."; 1438 1439 $langs{tip201} = "Apr�s le processus de normalisation, les fichiers wav seront effac�s."; 1440 $langs{tip202} = "Apr�s normalisation, vous pouvez changer les propri�t�s d\'encodage comme le type d\'encodage, le bitratede tous "; 1441 $langs{tip202} .= "les fichiers de sortie, etc. Autrement, les propri�t�s de d�part seront conserv�es."; 1442 $langs{tip203} = "Le fichier normalis� sera sauv� dans le m�me r�pertoire que celui de d�part. S'il existe d�j�, le remplacer."; 1443 $langs{tip204} = "Show the hints and informations."; 1444 $langs{tip205} = "Montrer les animations Tux et compagnie."; 1445 $langs{tip206} = "Modifier la priorit�: 0 (la plus forte) to 19 (la plus faible)"; 1446 $langs{tip207} = "Le formatage des noms de fichiers en sortie uniquement pour les rip de CD audio:\n"; 1447 $langs{tip207} .= " %a - artiste\n"; 1448 $langs{tip207} .= " %b - album\n"; 1449 $langs{tip207} .= " %t - titre chanson\n"; 1450 $langs{tip207} .= " %n - num�ro piste\n"; 1451 $langs{tip207} .= " %y - ann�e\n"; 1452 $langs{tip207} .= " %g - genre"; 1453 $langs{tip208} = "Police: Sans 10."; 1454 $langs{tip209} = "Lire les infos CDDB pour les CD Audio depuis le serveur CDDB \"$CDDB_server\" ou depuis un fichier sauv� dans $home/.cddd/."; 1455 $langs{tip210} = "Toujours r�cup�rer les infos CDDB depuis le serveur et remplacer les infos CDDB sauv�s dans $home/.cddd/"; 1456 $langs{tip211} = "Des serveurs:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880"; 1457 $langs{tip212} = "Choisir le num�ro de port."; 1458 $langs{tip213} = "D�sactive toute v�rification et correction de donn�es. Le rip sera plus rapide. "; 1459 $langs{tip213} .= "Cette option implique que -Y est actif. Voir cdparanoia (option -Z)."; 1460 $langs{tip214} = "Ne pas accepter de saut d\'erreurs; toujours recommencer au besoin. Voir cdparanoia (option -z)."; 1461 $langs{tip215} = "D�sactiver la v�rification interne; only overlap checking at read boundaries is performed. Non recommand�. Voir cdparanoia (option -Y)."; 1462 $langs{tip216} = "Si les sauts d\'erreur r�sultants de donn�es endommag�es ou autres, annuler la lecture de cette piste. Voir cdparanoia (option -X)."; 1463 $langs{tip217} = "Utiliser la librairie paranoia au lieu des routines cdda2wav pour lire. Voir cdda2wav (option -paranoia)."; 1464 $langs{tip218} = "D�sactiver le mode paranoia. Paranoia est encore utilis�. Voir cdda2wav (option -paraopts=help)."; 1465 $langs{tip219} = "Passer � pas de v�rification et saut d\'erreur."; 1466 $langs{tip220} = "Choisir un bitrate moyen. L\'encodage sera le plus proche possible de cette valeur (en Kb/s)."; 1467 $langs{tip221} = "Ajuster la qualit� mp3; 9 est la pire, 0 est la meilleure (en Kb/s). Voir: man lame (option: -V)."; 1468 $langs{tip222} = "Ajuster la qualit� ogg; 10 est la meilleure (en Kb/s), -1 est la pire. Voir: man oggenc."; 1469 $langs{tip223} = "Ajuster la qualit� de l\'encodage lame pour les mp3: 0 est la meilleure avec le maximum d\' "; 1470 $langs{tip223} .= "algorithmes; 9 est la pire et la plus rapide. Voir: man lame (option: -q)."; 1471 $langs{tip224} = "Choisir la qualit� du quantizer (VBR) en pourcentage pour le mp4; 500 est la meilleure "; 1472 $langs{tip224} .= "(en Kb/s utilis�s); 10 est la pire. Voir: <faac --help>."; 1473 $langs{tip225} = "Ajuster la qualit� de l\'encodage des mpc en utilisant les profiles; 8 (braindead) est la meilleure (en Kb/s),"; 1474 $langs{tip225} .= " 2 (t�l�phone) la pire qualit�. Voir: mppenc --longhelp\n"; 1475 $langs{tip225} .= " q=2 --t�l�phone - plus basse qualit�, (32... 48 kbps)\n"; 1476 $langs{tip225} .= " q=3 --thumb - basse qualit�/internet, (58... 86 kbps)\n"; 1477 $langs{tip225} .= " q=4 --radio - qualit� moyenne (MP3), (112...152 kbps)\n"; 1478 $langs{tip225} .= " q=5 --standard - haute qualit� (dflt), (142...184 kbps)\n"; 1479 $langs{tip225} .= " q=6 --xtreme - extreme haute qualit�, (168...212 kbps)\n"; 1480 $langs{tip225} .= " q=7 --insane - extreme haute qualit�, (232...268 kbps)\n"; 1481 $langs{tip225} .= " q=8 --braindead - extreme haute qualit�, (232...278 kbps)"; 1482 $langs{tip226} = "Niveau de compression:\n rapide: 1000\n normal: 2000\n �lev�: 3000\n tr�s �lev�: 4000\n le top: 5000\n"; 1483 $langs{tip226} .= "\nPlus la compression est forte \nplus les fichiers seront petits.\nVoir l'aide: mac"; 1484 $langs{tip227} = "Niveau de compression:\n rapide: 0\n normal: 5\n meilleur: 8\nVoir <man flac>."; 1485 $langs{tip228} = "Ajouter ici votre ligne de commande additionnelle pour encoder les fichiers."; 1486 $langs{tip229} = "Used to encode ID3v2.3.0 Tag for MP3 files."; 1487 $langs{tip250} = "If this entry is empty, the original comment tag will be preserved. "; 1488 $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value."; 1489 1490 $langs{tip301} = "S\'il y a plus d'un artiste (compilation), utiliser:\nArtiste1 & Artiste2 & Artiste3 & ..."; 1491 $langs{tip302} = "Num�ro piste"; 1492 $langs{tip303} = "Nombre total pistes"; 1493 $langs{tip304} = "Sauver les changements de tag."; 1494 $langs{tip305} = "Sauver les changements de tag vers $home/.cddb."; 1495 1496 $langs{tip401} = "Essayer /dev/cdrom, /dev/dvd, /dev/hdc ou ...\nVoir le fichier \"/etc/fstab\"."; 1497 $langs{tip402} = "Rafra�chir les cdrom et effacer la liste de lecture."; 1498 $langs{tip403} = "S�lectionner aucune piste."; 1499 $langs{tip404} = "S�lectionner tout."; 1500 $langs{tip405} = "Ajouter d\'autres fichiers � jouer."; 1501 $langs{tip406} = "Fermer la configuration du player."; 1502 $langs{tip407} = "Choose the interval in milliseconds that the text will be redrawed."; 1503 $langs{tip408} = "Choose the step incremental in pixels."; 1504 $langs{tip409} = "Scrolling text orientation: up/down or left/right."; 1505 $langs{tip410} = "Show the xTunes like skin.\nTo take effect, change the display mode."; 1506 $langs{tip411} = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode."; 1507 $langs{tip429} = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. "; 1508 $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'."; 1509 $langs{tip429} .= "\n---***---\n"; 1510 $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. "; 1511 $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. "; 1512 $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice."; 1513 $langs{tip429} .= "\n---***---\n"; 1514 $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. "; 1515 1516 $langs{tip501} = "All tabs, messages, names and tips used by gnormalize."; 1517 $langs{tip502} = "Vous devez de nouveau d�marrer."; 1518 $langs{tip503} = "Guidance Language only used to help the translations.\nRead Only."; 1519 $langs{tip504} = "Save the translations and new languages inside the directory: $lang_dir."; 1520 $langs{tip505} = "Improve this translation or use it as base for a new Language."; 1521 1522 1523 $langs{msg001} = "Fichiers support�s dans le r�pertoire (r�cursif):"; 1524 $langs{msg002} = "Fichiers support�s dans le r�pertoire (non r�cursif):"; 1525 $langs{msg003} = " Choisir un fichier mp3/mp4/mpc/ogg/ape/flac/wav/cda � normaliser!"; 1526 $langs{msg004} = " D�pendance non satisfaite!"; 1527 $langs{msg005} = "If Same Extension, Overwrite file"; 1528 $langs{msg006} = "Analyzing with ReplayGain normalization algorithms ..."; 1529 1530 $langs{msg012} = ": lecture seule!"; 1531 $langs{msg013} = " S�lectionner au moins une piste � ripper!"; 1532 $langs{msg014} = " Succ�s! Rip fini."; 1533 $langs{msg015} = " Rip interrompu!"; 1534 $langs{msg016} = " Succ�s!"; 1535 $langs{msg017} = " Succ�s! Fichier converti."; 1536 $langs{msg018} = " Succ�s! Fichier normalis�."; 1537 $langs{msg019} = "Arr�ter le rip"; 1538 $langs{msg020} = " R�cup�rer les infos de "; 1539 $langs{msg021} = " Attendez SVP. cdparanoia lit le cdrom ..."; 1540 $langs{msg022} = " SVP, s�lectionnez au moins une piste � jouer."; 1541 $langs{msg023} = "Ne peut trouver \""; 1542 $langs{msg024} = "\" dans le chemin d'ex�cution."; 1543 $langs{msg025} = "La sortie ne peut �tre au format \"mp3\"."; 1544 $langs{msg026} = "La sortie ne peut �tre au format \"ogg\"."; 1545 $langs{msg027} = "La sortie ne peut �tre au format \"mpc\"."; 1546 $langs{msg028} = "La sortie ne peut �tre au format \"ape\"."; 1547 $langs{msg029} = "La sortie ne peut �tre au format \"flac\"."; 1548 $langs{msg030} = "La sortie ne peut �tre au format \"mp4\"."; 1549 $langs{msg031} = "Les wav ne peuvent �tre normalis�s."; 1550 $langs{msg032} = "L\'entr�e ne peut �tre au format \"ogg\""; 1551 $langs{msg033} = "L\'entr�e ne peut �tre au format \"mpc\"."; 1552 $langs{msg034} = "L\'entr�e ne peut �tre au format \"mp4\"."; 1553 $langs{msg035} = "cdcd est un player cd � la commande."; 1554 $langs{msg036} = "Premi�rement lancer \"cdcd\" � la console pour construire le fichier de configuration .cdcdrc"; 1555 $langs{msg037} = "Choisir \"n\" � la question: Etes-vous connect� � un r�seau (y/n) [y]?"; 1556 $langs{msg038} = "Ne peut utiliser le module Perl \""; 1557 $langs{msg039} = "Ne peut lire les CD Audio."; 1558 $langs{msg040} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 1559 $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 1560 $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert "; 1561 $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 1562 $langs{msg041} = "Ce fichier ne sera pas normalis�!"; 1563 $langs{msg042} = "Non normalis� en accord avec l\'insensibilit�"; 1564 $langs{msg043} = "Non normalis� car l\'ajustement "; 1565 $langs{msg044} = " est plus petit que la valeur d\'insensibilit�."; 1566 $langs{msg045} = " ne pas normaliser "; 1567 $langs{msg046} = "Encodage non n�cessaire"; 1568 $langs{msg047} = " d�j� normalis� "; 1569 $langs{msg048} = "ce fichier est d�j� normalis�."; 1570 $langs{msg049} = " Arr�ter la normalisation!"; 1571 $langs{msg050} = "Appliquer les ajustements de "; 1572 $langs{msg051} = " normalisation: ajustement de "; 1573 $langs{msg052} = "Niveaux de calculs..."; 1574 $langs{msg053} = " normalis� avec ajustement de "; 1575 $langs{msg054} = " rip audio vers wav"; 1576 $langs{msg055} = " Arr�ter le rip!"; 1577 $langs{msg056} = "copie faite."; 1578 $langs{msg057} = " Stopper d�codage lame!"; 1579 $langs{msg058} = " Stopper encodage lame!"; 1580 $langs{msg061} = " Ces informations seront sauv�es dans le fichier normalis�."; 1581 $langs{msg062} = " tag sauv�."; 1582 $langs{msg063} = "S�lectionner un ficchier mp3/mp4/mpc/ogg/ape/flac/wav."; 1583 $langs{msg064} = "Homepage: $HOMEPAGE\nCe logiciel est disponible sous Licence Publique G�n�rale GNU."; 1584 $langs{msg065} = " sortie: "; 1585 $langs{msg066} = "fichier s�lectionn� - $langs{all_tab03} �ditable."; 1586 $langs{msg067} = " Impossible d\'ouvrir le cdrom "; 1587 $langs{msg068} = " R�cup�re l\'information de cddb ..."; 1588 $langs{msg069} = " aucune information cddb."; 1589 $langs{msg070} = " presser le bouton sauver dans l'onglet \"$langs{all_tab03}\" pour sauver ces changements."; 1590 $langs{msg071} = " Non connect�, en utilisant "; 1591 $langs{msg072} = " cddb: internet inaccessible!"; 1592 $langs{msg073} = " Ne peut ripper le CD Audio! cdparanoia introuvable."; 1593 $langs{msg074} = " Ne peut ripper le CD Audio! cdda2wav introuvable."; 1594 $langs{msg075} = "S�lectionner un fichier mp3, mp4, mpc, ogg, ape, flac, ou wav"; 1595 $langs{msg077} = "r�glages"; 1596 $langs{msg078} = "Fichier s�lectionn�"; 1597 $langs{msg079} = "Version minimum recommand�e:"; 1598 $langs{msg080} = " Option invalide!"; 1599 $langs{msg081} = " Presser le bouton \"Rafra�chir le cdrom\" et r�-entrer les changements."; 1600 $langs{msg082} = "Aucune info cddb, installer le module perl \"CDDB_get\"."; 1601 $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20)."; 1602 $langs{msg084} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 1603 $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 1604 $langs{msg085} = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. "; 1605 $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 1606 $langs{msg086} = "R�pertoire s�lectionn� (r�cursif)"; 1607 $langs{msg087} = "S�lectionner un r�pertoire contenant un fichier mp3, mp4, mpc, ogg, ape, flac, ou wav."; 1608 $langs{msg088} = "R�pertoire s�lectionn� (non r�cursif)"; 1609 $langs{msg089} = "Suppression des fichiers temporaires:"; 1610 $langs{msg090} = "Ne peut pas trouver de r�pertoire ou fichier support�!"; 1611 $langs{msg092} = "Enlever cette musique de la liste"; 1612 $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; S�o Paulo - Brasil"; 1613 $langs{msg094} = "Traduits vers fran�ais: Yaen Pujol et finis par Roger Gabriels Antwerp (Essen) Belgium\n"; 1614 $langs{msg095} = "You must add new language name to translate!"; 1615 } 1616 1617 if ( $language eq 'Nederlands' ) 1618 { 1619 $langs{all_tab01} = "Data"; 1620 $langs{all_tab02} = "Configuratie"; 1621 $langs{all_tab03} = "Information"; 1622 $langs{all_tab04} = "Rip/Play"; 1623 $langs{all_tab05} = "Translations"; 1624 $langs{all_tab06} = "Over"; 1625 $langs{all_tab07} = "Option1"; 1626 $langs{all_tab08} = "Option2"; 1627 $langs{all_tab09} = "CDDB"; 1628 $langs{all_tab10} = "Ripper"; 1629 $langs{all_tab11} = "Colors"; 1630 $langs{all_tab12} = "Players"; 1631 $langs{all_tab13} = "Columns"; 1632 $langs{all_tab14} = "Skins"; 1633 1634 $langs{name001} = "Normalizatie Type"; 1635 $langs{name002} = "Gevoeligheid"; 1636 $langs{name003} = "Geselecteerd Bestand of Map"; 1637 $langs{name004} = "Selecteer Invoer"; 1638 $langs{name005} = "Output: Lossy Compression"; 1639 $langs{name006} = "Output: Lossless Compression"; 1640 $langs{name106} = "Output: Uncompressed"; 1641 1642 $langs{name007} = "Bestand"; 1643 $langs{name008} = "Recursief"; 1644 $langs{name009} = "Delete Wav Files"; 1645 $langs{name010} = "Change Properties"; 1646 $langs{name011} = "Overwrite"; 1647 $langs{name012} = "Priority"; 1648 $langs{name013} = "Add Command"; 1649 $langs{name014} = "Filename Rip"; 1650 $langs{name015} = "Character"; 1651 $langs{name016} = "Idiom"; 1652 $langs{name017} = "Font"; 1653 $langs{name018} = "Read CDDB"; 1654 $langs{name019} = "Overwrite CDDB"; 1655 $langs{name020} = "CDDB Server"; 1656 $langs{name021} = "Port"; 1657 $langs{name022} = "Transport"; 1658 $langs{name023} = "disable paranoia"; 1659 $langs{name024} = "disable extra paranoia"; 1660 $langs{name025} = "abort on skip"; 1661 $langs{name026} = "never skip repair"; 1662 $langs{name027} = "paranoia no-verify"; 1663 $langs{name028} = "paranoia disable"; 1664 $langs{name029} = "ripper"; 1665 $langs{name030} = "Encode Type"; 1666 $langs{name031} = "Mode"; 1667 $langs{name032} = "Encode Quality"; 1668 $langs{name033} = "Variable"; 1669 $langs{name034} = "Title"; 1670 $langs{name035} = "Artist"; 1671 $langs{name036} = "Album"; 1672 $langs{name037} = "Comment"; 1673 $langs{name038} = "Year"; 1674 $langs{name039} = "Track Number"; 1675 $langs{name040} = "Genre"; 1676 $langs{name041} = "Frequency"; 1677 $langs{name042} = "Time"; 1678 $langs{name043} = "Channels"; 1679 $langs{name044} = "Length"; 1680 $langs{name045} = "Track"; 1681 $langs{name046} = "Artist"; 1682 $langs{name047} = "Title"; 1683 $langs{name048} = "Size"; 1684 $langs{name049} = "Year"; 1685 $langs{name050} = "Filepath"; 1686 $langs{name051} = "Extension"; 1687 $langs{name052} = "Selecteer Uitvoer"; 1688 $langs{name053} = "Album"; 1689 $langs{name054} = "Play Count"; 1690 $langs{name055} = "Animation"; 1691 $langs{name056} = "Filename"; 1692 $langs{name057} = "Show Tooltips"; 1693 $langs{name058} = "Guidance Language"; 1694 $langs{name059} = "Current Translation"; 1695 $langs{name060} = "Improve The Currente Language Translation"; 1696 $langs{name061} = "Add New Language"; 1697 $langs{name062} = "Add new language here and then press save buton."; 1698 $langs{name063} = "Normaliseer"; 1699 $langs{name064} = "CD Player"; 1700 $langs{name065} = "Play"; 1701 1702 $langs{name429} = 'Play Tracks Without Any Filters'; 1703 $langs{name430} = 'Play Tracks From Different Albums'; 1704 $langs{name431} = 'Play Tracks From Different Artists'; 1705 $langs{name432} = 'Play Tracks From Different Genres'; 1706 $langs{name433} = 'Play Tracks From Different Years'; 1707 1708 $langs{tip101} = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n"; 1709 $langs{tip101} .= "None: no normalization is done.\n"; 1710 $langs{tip101} .= "---*---\n"; 1711 $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n"; 1712 $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files."; 1713 $langs{tip102} = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. "; 1714 $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n"; 1715 $langs{tip102} .= "---*---\n"; 1716 $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n"; 1717 $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n"; 1718 $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 1719 $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n"; 1720 $langs{tip102} .= "---*---\n"; 1721 $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n"; 1722 $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude."; 1723 $langs{tip103} = "Insensibility of normalize. Only not re-encode if:\n"; 1724 $langs{tip103} .= "1) the extension of input file is the same of output file;\n"; 1725 $langs{tip103} .= "2) and \"$langs{name010}\" button is not active;\n"; 1726 $langs{tip103} .= "3) and adjust of normalize is less than insensibility value."; 1727 $langs{tip104} = "Select one directory with supported file."; 1728 $langs{tip105} = "Choose the directory where all the files will be saved."; 1729 $langs{tip106} = "Normalize/Convert all supported files inside the directory (recursively or not)."; 1730 $langs{tip107} = "Select a directory including subdirectories: descende recursively into the directory preserving the same structure."; 1731 $langs{tip108} = "After normalize, the output format will be mp3. Play it with mpg123, mpg321 or madplay."; 1732 $langs{tip109} = "After normalize, the output format will be mp4 (also know as m4a) or aac. Play it with mplayer."; 1733 $langs{tip110} = "After normalize, the output format will be mpc (also know as mpp or mp+). Play it with mppdec or xmms plugin."; 1734 $langs{tip111} = "After normalize, the output format will be ogg. Play it with ogg123."; 1735 $langs{tip112} = "After normalize, the output format will be ape. Play it with the command:\n mac \"song.ape\" - -d | play -t wav - "; 1736 $langs{tip113} = "After normalize, the output format will be flac. Play it with flac123 or xmms plugin.\nRequired flac version >= \"1.1.1\"."; 1737 $langs{tip114} = "This is suitable to make an audio cd.\nWav is an uncompressed audio format."; 1738 $langs{tip115} = "NOTE:\n"; 1739 $langs{tip115} .= "This compression technique is known as 'Lossy Compression' whereby during the compression data can be lost. "; 1740 $langs{tip115} .= "The degree of loss varies upon settings. Although data loss does occur, it is minimal and certainly not noticable "; 1741 $langs{tip115} .= "when using good settings.\nExamples of Lossy compression audio: Mp3, Mp4, Mpc and Ogg."; 1742 $langs{tip116} = "NOTE:\n"; 1743 $langs{tip116} .= "This compression technique is known as 'Lossless Compression' in which all of the information in the original "; 1744 $langs{tip116} .= "data is preserved, and the original data may be recovered in form identical to its original form.\n"; 1745 $langs{tip116} .= "Examples of Lossless compression audio: Ape and Flac."; 1746 $langs{tip117} = "Show the progress bar."; 1747 $langs{tip118} = "Hide the progress bar."; 1748 $langs{tip119} = "Show the command line and others info."; 1749 $langs{tip120} = "Hide the command line and others info."; 1750 $langs{tip121} = "Quit."; 1751 $langs{tip122} = "Clear all messages."; 1752 1753 $langs{tip201} = "After the normalize process, the temporary wav files will be deleted."; 1754 $langs{tip202} = "After normalize the files, you can change its encode properties by determining the encode type, the bitrate of all "; 1755 $langs{tip202} .= "output files, etc. Otherwise, the bitrate of each input file and others properties will be conserved."; 1756 $langs{tip203} = "The normalized file will be saved in the same directory of input. If it already exist then overwrite the original file."; 1757 $langs{tip204} = "Show the hints and informations."; 1758 $langs{tip205} = "Show the Tux and others penguins animations."; 1759 $langs{tip206} = "Modify scheduling priority: 0 (highest priority) to 19 (lowest)"; 1760 $langs{tip207} = "Output filename format used only for rip Audio CD:\n"; 1761 $langs{tip207} .= " %a - artist\n"; 1762 $langs{tip207} .= " %b - album\n"; 1763 $langs{tip207} .= " %t - song title\n"; 1764 $langs{tip207} .= " %n - track number\n"; 1765 $langs{tip207} .= " %y - year\n"; 1766 $langs{tip207} .= " %g - genre"; 1767 $langs{tip208} = "Advised font: Sans 10."; 1768 $langs{tip209} = "Read the CDDB info for Audio CD in your drive from CDDB server \"$CDDB_server\" or from files saved into $home/.cddd/."; 1769 $langs{tip210} = "Always get CDDB info from server and overwrite the CDDB file saved at $home/.cddd/"; 1770 $langs{tip211} = "Some servers:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880"; 1771 $langs{tip212} = "Choose the port number."; 1772 $langs{tip213} = "Disable all data verification and correction features. Consequently the extraction/rip is more fast. "; 1773 $langs{tip213} .= "This option implies that -Y is active. See cdparanoia (option -Z)."; 1774 $langs{tip214} = "Do not accept any skips; retry forever if needed. See cdparanoia (option -z)."; 1775 $langs{tip215} = "Disables intra-read data verification; only overlap checking at read boundaries is performed. Not recommended. See cdparanoia (option -Y).\n"; 1776 $langs{tip215} .= "Boundaries are spaces/limit inter tracks of an audio cd. cdparanoia reads this boundaries carefully when rip on track."; 1777 $langs{tip216} = "If the read skips due to imperfect data, a scratch, whatever, abort reading this track. See cdparanoia (option -X)."; 1778 $langs{tip217} = "Use the paranoia library instead of cdda2wav's routines for reading. See cdda2wav (option -paranoia)."; 1779 $langs{tip218} = "Disables paranoia mode. Paranoia is still being used. See cdda2wav (option -paraopts=help)."; 1780 $langs{tip219} = "Switches verify off, and overlap on."; 1781 $langs{tip220} = "Choose a targeted average bitrate. Sets encoding to the bitrate closest to this value (in Kb/s)."; 1782 $langs{tip221} = "Adjust the quality of mp3; 9 is the worst quality, 0 is the best quality with more Kb/s. See: man lame (option: -V)."; 1783 $langs{tip222} = "Adjust the quality of encode for ogg; 10 is the best quality with more Kb/s used, -1 is the worst quality. See: man oggenc."; 1784 $langs{tip223} = "Adjust the quality of lame encoder for mp3 files: 0 is the best quality with maximum "; 1785 $langs{tip223} .= "algorithms process; 9 is the worst quality but more fast. See: man lame (option: -q)."; 1786 $langs{tip224} = "Set default variable bitrate (VBR) quantizer quality in percent for mp4 format; 500 is the best "; 1787 $langs{tip224} .= "quality with more Kb/s used; 10 is the worst quality. See: <faac --help>."; 1788 $langs{tip225} = "Adjust the quality of encode for mpc using profiles; 8 (braindead) is the best quality with more Kb/s used,"; 1789 $langs{tip225} .= " 2 (telephone) is the worst quality. See: mppenc --longhelp\n"; 1790 $langs{tip225} .= " q=2 --telephone - lowest quality, (32... 48 kbps)\n"; 1791 $langs{tip225} .= " q=3 --thumb - low quality/internet, (58... 86 kbps)\n"; 1792 $langs{tip225} .= " q=4 --radio - medium (MP3) quality, (112...152 kbps)\n"; 1793 $langs{tip225} .= " q=5 --standard - high quality (dflt), (142...184 kbps)\n"; 1794 $langs{tip225} .= " q=6 --xtreme - extreme high quality, (168...212 kbps)\n"; 1795 $langs{tip225} .= " q=7 --insane - extreme high quality, (232...268 kbps)\n"; 1796 $langs{tip225} .= " q=8 --braindead - extreme high quality, (232...278 kbps)"; 1797 $langs{tip226} = "Compression level:\n fast: 1000\n normal: 2000\n high: 3000\n extra high: 4000\n insane: 5000\n"; 1798 $langs{tip226} .= "\nMore compression level \nresults small files.\nSee the help: mac"; 1799 $langs{tip227} = "Compression level:\n fast: 0\n normal: 5\n best: 8\nSee <man flac>."; 1800 $langs{tip228} = "Put here the additional command line used to encode this files."; 1801 $langs{tip229} = "Used to encode ID3v2.3.0 Tag for MP3 files."; 1802 $langs{tip250} = "If this entry is empty, the original comment tag will be preserved. "; 1803 $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value."; 1804 1805 $langs{tip301} = "If there is more than one artist, use:\nArtist1 & Artist2 & Artist3 & ..."; 1806 $langs{tip302} = "Track number"; 1807 $langs{tip303} = "Total track number"; 1808 $langs{tip304} = "Save changes of tag."; 1809 $langs{tip305} = "Save changes of tag to $home/.cddb directory."; 1810 1811 $langs{tip401} = "Try /dev/cdrom, /dev/dvd, /dev/hdc or ...\nSee \"/etc/fstab\" file."; 1812 $langs{tip402} = "Refresh the cdrom drive and erase the playlist."; 1813 $langs{tip403} = "Unselect all tracks."; 1814 $langs{tip404} = "Select all tracks."; 1815 $langs{tip405} = "Add more files to play."; 1816 $langs{tip406} = "Close the gnormalize player config."; 1817 $langs{tip407} = "Choose the interval in milliseconds that the text will be redrawed."; 1818 $langs{tip408} = "Choose the step incremental in pixels."; 1819 $langs{tip409} = "Scrolling text orientation: up/down or left/right."; 1820 $langs{tip410} = "Show the xTunes like skin.\nTo take effect, change the display mode."; 1821 $langs{tip411} = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode."; 1822 $langs{tip429} = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. "; 1823 $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'."; 1824 $langs{tip429} .= "\n---***---\n"; 1825 $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. "; 1826 $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. "; 1827 $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice."; 1828 $langs{tip429} .= "\n---***---\n"; 1829 $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. "; 1830 1831 $langs{tip501} = "All tabs, messages, names and tips used by gnormalize."; 1832 $langs{tip502} = "You need to restart the Gnormalize."; 1833 $langs{tip503} = "Guidance Language only used to help the translations.\nRead Only."; 1834 $langs{tip504} = "Save the translations and new languages inside the directory: $lang_dir."; 1835 $langs{tip505} = "Improve this translation or use it as base for a new Language."; 1836 1837 1838 $langs{msg001} = "Supported Files into the directory (recursively):"; 1839 $langs{msg002} = "Supported Files into the directory (not recursively):"; 1840 $langs{msg003} = " Choose a mp3/mp4/mpc/ogg/ape/flac/wav/cda file to normalize!"; 1841 $langs{msg004} = " Dependence not satisfied!"; 1842 $langs{msg005} = "If Same Extension, Overwrite file"; 1843 $langs{msg006} = "Analyzing with ReplayGain normalization algorithms ..."; 1844 1845 $langs{msg012} = ": read only!"; 1846 $langs{msg013} = " Select at least one track to rip!"; 1847 $langs{msg014} = " Success! Rip finished."; 1848 $langs{msg015} = " Rip stopped!"; 1849 $langs{msg016} = " Success!"; 1850 $langs{msg017} = " Success! File converted."; 1851 $langs{msg018} = " Success! File normalized."; 1852 $langs{msg019} = "stop ripping"; 1853 $langs{msg020} = " Get info from "; 1854 $langs{msg021} = " Please, wait. cdparanoia is reading the cdrom ..."; 1855 $langs{msg022} = " Please, select at least one track to play."; 1856 $langs{msg023} = "Can't find \""; 1857 $langs{msg024} = "\" in executable path."; 1858 $langs{msg025} = "The output can't be \"mp3\" format."; 1859 $langs{msg026} = "The output can't be \"ogg\" format."; 1860 $langs{msg027} = "The output can't be \"mpc\" format."; 1861 $langs{msg028} = "The output can't be \"ape\" format."; 1862 $langs{msg029} = "The output can't be \"flac\" format."; 1863 $langs{msg030} = "The output can't be \"mp4\" format."; 1864 $langs{msg031} = "The wav files can't be normalized."; 1865 $langs{msg032} = "The input can't be \"ogg\" format."; 1866 $langs{msg033} = "The input can't be \"mpc\" format."; 1867 $langs{msg034} = "The input can't be \"mp4\" format."; 1868 $langs{msg035} = "cdcd is a Command Driven CD player."; 1869 $langs{msg036} = "First run \"cdcd\" in command line to make the config file .cdcdrc"; 1870 $langs{msg037} = "Choose \"n\" for the question: Are you connected to a network (y/n) [y]?"; 1871 $langs{msg038} = "Can't use the perl module \""; 1872 $langs{msg039} = "Can't play audio CD."; 1873 $langs{msg040} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 1874 $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 1875 $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert "; 1876 $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 1877 $langs{msg041} = "This file will not be normalized!"; 1878 $langs{msg042} = "According to insensibility, not normalize"; 1879 $langs{msg043} = "Not normalize because adjustment "; 1880 $langs{msg044} = " is less than insensibility value."; 1881 $langs{msg045} = " not normalize "; 1882 $langs{msg046} = "Don't need encode"; 1883 $langs{msg047} = " already normalized "; 1884 $langs{msg048} = "This file is already normalized."; 1885 $langs{msg049} = " Stop normalizing!"; 1886 $langs{msg050} = "Applying adjustment of "; 1887 $langs{msg051} = " normalizing: adjustment of "; 1888 $langs{msg052} = "Computing levels..."; 1889 $langs{msg053} = " normalized with adjustment of "; 1890 $langs{msg054} = " ripping audio to wav"; 1891 $langs{msg055} = " Stop ripping!"; 1892 $langs{msg056} = "copy maked."; 1893 $langs{msg057} = " Stop lame decoding!"; 1894 $langs{msg058} = " Stop lame encoding!"; 1895 $langs{msg061} = " This informations will be saved on normalized file."; 1896 $langs{msg062} = " tag saved."; 1897 $langs{msg063} = "Select a mp3/mp4/mpc/ogg/ape/flac/wav file."; 1898 $langs{msg064} = "Homepage: $HOMEPAGE\nThis software is available under GNU General Public Licence."; 1899 $langs{msg065} = " output: "; 1900 $langs{msg066} = "file selected - $langs{all_tab03} can be edited."; 1901 $langs{msg067} = " Unable to open cdrom drive "; 1902 $langs{msg068} = " Getting information from cddb ..."; 1903 $langs{msg069} = " none cddb information."; 1904 $langs{msg070} = " Press save button on \"$langs{all_tab03}\" tab to save this changes."; 1905 $langs{msg071} = " Not connected, using "; 1906 $langs{msg072} = " cddb: can't connect to internet!"; 1907 $langs{msg073} = " Can't rip audio CD! cdparanoia not found."; 1908 $langs{msg074} = " Can't rip audio CD! cdda2wav not found."; 1909 $langs{msg075} = "Select a mp3, mp4, mpc, ogg, ape, flac, or wav file"; 1910 $langs{msg077} = "settings"; 1911 $langs{msg078} = "Selected file"; 1912 $langs{msg079} = "Recomended minimum version:"; 1913 $langs{msg080} = " Invalid option!"; 1914 $langs{msg081} = " Press the \"Refresh the cdrom\" button and type again the changes."; 1915 $langs{msg082} = "Not found CDDB_get perl module in your system.\n gnormalize will uses internal CDDB_get (version 2.27)."; 1916 $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20)."; 1917 $langs{msg084} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 1918 $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 1919 $langs{msg085} = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. "; 1920 $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 1921 $langs{msg086} = "Selected Directory (recursively)"; 1922 $langs{msg087} = "Select a directory containing mp3, mp4, mpc, ogg, ape, flac, or wav file."; 1923 $langs{msg088} = "Selected Directory (not recursively)"; 1924 $langs{msg089} = "Removing temporary file:"; 1925 $langs{msg090} = "Can not find no supported file inside of directory!"; 1926 $langs{msg092} = "remove this music from list"; 1927 $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; S�o Paulo - Brasil"; 1928 $langs{msg094} = "Nederlandse vertaling door Roger Gabriels Antwerp (Essen) Belgium\n"; 1929 $langs{msg094} .= "E-mail: normaliseer\@pcfreesoft.com | Homepage: htp://www.pcfreesoft.com"; 1930 $langs{msg095} = "You must add new language name to translate!"; 1931 } 1932 1933 if ( $language eq 'Espag�ol' ) 1934 { 1935 $langs{all_tab01} = "Datos"; 1936 $langs{all_tab02} = "Configuraci�n"; 1937 $langs{all_tab03} = "Information"; 1938 $langs{all_tab04} = "Rip/Play"; 1939 $langs{all_tab05} = "Translations"; 1940 $langs{all_tab06} = "Sobre"; 1941 $langs{all_tab07} = "Option1"; 1942 $langs{all_tab08} = "Option2"; 1943 $langs{all_tab09} = "CDDB"; 1944 $langs{all_tab10} = "Ripper"; 1945 $langs{all_tab11} = "Colors"; 1946 $langs{all_tab12} = "Players"; 1947 $langs{all_tab13} = "Columns"; 1948 $langs{all_tab14} = "Skins"; 1949 1950 $langs{name001} = "Tipo de Normalizaci�n"; 1951 $langs{name002} = "Insensibilidad"; 1952 $langs{name003} = "Archivo Seleccionado"; 1953 $langs{name004} = "Repertorio de Entrada"; 1954 $langs{name005} = "Output: Lossy Compression"; 1955 $langs{name006} = "Output: Lossless Compression"; 1956 $langs{name106} = "Output: Uncompressed"; 1957 1958 $langs{name007} = "Archivo"; 1959 $langs{name008} = "Recursivamente"; 1960 $langs{name009} = "Delete Wav Files"; 1961 $langs{name010} = "Change Properties"; 1962 $langs{name011} = "Overwrite"; 1963 $langs{name012} = "Priority"; 1964 $langs{name013} = "Add Command"; 1965 $langs{name014} = "Filename Rip"; 1966 $langs{name015} = "Character"; 1967 $langs{name016} = "Idiom"; 1968 $langs{name017} = "Font"; 1969 $langs{name018} = "Read CDDB"; 1970 $langs{name019} = "Overwrite CDDB"; 1971 $langs{name020} = "CDDB Server"; 1972 $langs{name021} = "Port"; 1973 $langs{name022} = "Transport"; 1974 $langs{name023} = "disable paranoia"; 1975 $langs{name024} = "disable extra paranoia"; 1976 $langs{name025} = "abort on skip"; 1977 $langs{name026} = "never skip repair"; 1978 $langs{name027} = "paranoia no-verify"; 1979 $langs{name028} = "paranoia disable"; 1980 $langs{name029} = "ripper"; 1981 $langs{name030} = "Encode Type"; 1982 $langs{name031} = "Mode"; 1983 $langs{name032} = "Encode Quality"; 1984 $langs{name033} = "Variable"; 1985 $langs{name034} = "Title"; 1986 $langs{name035} = "Artist"; 1987 $langs{name036} = "Album"; 1988 $langs{name037} = "Comment"; 1989 $langs{name038} = "Year"; 1990 $langs{name039} = "Track Number"; 1991 $langs{name040} = "Genre"; 1992 $langs{name041} = "Frequency"; 1993 $langs{name042} = "Time"; 1994 $langs{name043} = "Channels"; 1995 $langs{name044} = "Length"; 1996 $langs{name045} = "Track"; 1997 $langs{name046} = "Artist"; 1998 $langs{name047} = "Title"; 1999 $langs{name048} = "Size"; 2000 $langs{name049} = "Year"; 2001 $langs{name050} = "Filepath"; 2002 $langs{name051} = "Extension"; 2003 $langs{name052} = "Repertorio de Salida"; 2004 $langs{name053} = "Album"; 2005 $langs{name054} = "Play Count"; 2006 $langs{name055} = "Animation"; 2007 $langs{name056} = "Filename"; 2008 $langs{name057} = "Show Tooltips"; 2009 $langs{name058} = "Guidance Language"; 2010 $langs{name059} = "Current Translation"; 2011 $langs{name060} = "Improve The Currente Language Translation"; 2012 $langs{name061} = "Add New Language"; 2013 $langs{name062} = "Add new language here and then press save buton."; 2014 $langs{name063} = "Normalizaci�n"; 2015 $langs{name064} = "CD Player"; 2016 $langs{name065} = "Play"; 2017 2018 $langs{name429} = 'Play Tracks Without Any Filters'; 2019 $langs{name430} = 'Play Tracks From Different Albums'; 2020 $langs{name431} = 'Play Tracks From Different Artists'; 2021 $langs{name432} = 'Play Tracks From Different Genres'; 2022 $langs{name433} = 'Play Tracks From Different Years'; 2023 2024 $langs{tip101} = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n"; 2025 $langs{tip101} .= "None: no normalization is done.\n"; 2026 $langs{tip101} .= "---*---\n"; 2027 $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n"; 2028 $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files."; 2029 $langs{tip102} = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. "; 2030 $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n"; 2031 $langs{tip102} .= "---*---\n"; 2032 $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n"; 2033 $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n"; 2034 $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 2035 $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n"; 2036 $langs{tip102} .= "---*---\n"; 2037 $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n"; 2038 $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude."; 2039 $langs{tip103} = "Insensibility of normalize. Only not re-encode if:\n"; 2040 $langs{tip103} .= "1) the extension of input file is the same of output file;\n"; 2041 $langs{tip103} .= "2) and \"$langs{name010}\" button is not active;\n"; 2042 $langs{tip103} .= "3) and adjust of normalize is less than insensibility value."; 2043 $langs{tip104} = "Select one directory with supported file."; 2044 $langs{tip105} = "Choose the directory where all the files will be saved."; 2045 $langs{tip106} = "Normalize/Convert all supported files inside the directory (recursively or not)."; 2046 $langs{tip107} = "Select a directory including subdirectories: descende recursively into the directory preserving the same structure."; 2047 $langs{tip108} = "After normalize, the output format will be mp3. Play it with mpg123, mpg321 or madplay."; 2048 $langs{tip109} = "After normalize, the output format will be mp4 (also know as m4a) or aac. Play it with mplayer."; 2049 $langs{tip110} = "After normalize, the output format will be mpc (also know as mpp or mp+). Play it with mppdec or xmms plugin."; 2050 $langs{tip111} = "After normalize, the output format will be ogg. Play it with ogg123."; 2051 $langs{tip112} = "After normalize, the output format will be ape. Play it with the command:\n mac \"song.ape\" - -d | play -t wav - "; 2052 $langs{tip113} = "After normalize, the output format will be flac. Play it with flac123 or xmms plugin.\nRequired flac version >= \"1.1.1\"."; 2053 $langs{tip114} = "Esta opcic�n es muy corriente Para grabar un CD audio.\nWav no es un audio comprimido."; 2054 $langs{tip115} = "NOTE:\n"; 2055 $langs{tip115} .= "This compression technique is known as 'Lossy Compression' whereby during the compression data can be lost. "; 2056 $langs{tip115} .= "The degree of loss varies upon settings. Although data loss does occur, it is minimal and certainly not noticable "; 2057 $langs{tip115} .= "when using good settings.\nExamples of Lossy compression audio: Mp3, Mp4, Mpc and Ogg."; 2058 $langs{tip116} = "NOTE:\n"; 2059 $langs{tip116} .= "This compression technique is known as 'Lossless Compression' in which all of the information in the original "; 2060 $langs{tip116} .= "data is preserved, and the original data may be recovered in form identical to its original form.\n"; 2061 $langs{tip116} .= "Examples of Lossless compression audio: Ape and Flac."; 2062 $langs{tip117} = "Show the progress bar."; 2063 $langs{tip118} = "Hide the progress bar."; 2064 $langs{tip119} = "Show the command line and others info."; 2065 $langs{tip120} = "Hide the command line and others info."; 2066 $langs{tip121} = "Quit."; 2067 $langs{tip122} = "Clear all messages."; 2068 2069 $langs{tip201} = "After the normalize process, the temporary wav files will be deleted."; 2070 $langs{tip202} = "After normalize the files, you can change its encode properties by determining the encode type, the bitrate of all "; 2071 $langs{tip202} .= "output files, etc. Otherwise, the bitrate of each input file and others properties will be conserved."; 2072 $langs{tip203} = "The normalized file will be saved in the same directory of input. If it already exist then overwrite the original file."; 2073 $langs{tip204} = "Show the hints and informations."; 2074 $langs{tip205} = "Show the Tux and others penguins animations."; 2075 $langs{tip206} = "Modify scheduling priority: 0 (highest priority) to 19 (lowest)"; 2076 $langs{tip207} = "Output filename format used only for rip Audio CD:\n"; 2077 $langs{tip207} .= " %a - artist\n"; 2078 $langs{tip207} .= " %b - album\n"; 2079 $langs{tip207} .= " %t - song title\n"; 2080 $langs{tip207} .= " %n - track number\n"; 2081 $langs{tip207} .= " %y - year\n"; 2082 $langs{tip207} .= " %g - genre"; 2083 $langs{tip208} = "Advised font: Sans 10."; 2084 $langs{tip209} = "Read the CDDB info for Audio CD in your drive from CDDB server \"$CDDB_server\" or from files saved into $home/.cddd/."; 2085 $langs{tip210} = "Always get CDDB info from server and overwrite the CDDB file saved at $home/.cddd/"; 2086 $langs{tip211} = "Some servers:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880"; 2087 $langs{tip212} = "Choose the port number."; 2088 $langs{tip213} = "Disable all data verification and correction features. Consequently the extraction/rip is more fast. "; 2089 $langs{tip213} .= "This option implies that -Y is active. See cdparanoia (option -Z)."; 2090 $langs{tip214} = "Do not accept any skips; retry forever if needed. See cdparanoia (option -z)."; 2091 $langs{tip215} = "Disables intra-read data verification; only overlap checking at read boundaries is performed. Not recommended. See cdparanoia (option -Y).\n"; 2092 $langs{tip215} .= "Boundaries are spaces/limit inter tracks of an audio cd. cdparanoia reads this boundaries carefully when rip on track."; 2093 $langs{tip216} = "If the read skips due to imperfect data, a scratch, whatever, abort reading this track. See cdparanoia (option -X)."; 2094 $langs{tip217} = "Use the paranoia library instead of cdda2wav's routines for reading. See cdda2wav (option -paranoia)."; 2095 $langs{tip218} = "Disables paranoia mode. Paranoia is still being used. See cdda2wav (option -paraopts=help)."; 2096 $langs{tip219} = "Switches verify off, and overlap on."; 2097 $langs{tip220} = "Choose a targeted average bitrate. Sets encoding to the bitrate closest to this value (in Kb/s)."; 2098 $langs{tip221} = "Adjust the quality of mp3; 9 is the worst quality, 0 is the best quality with more Kb/s. See: man lame (option: -V)."; 2099 $langs{tip222} = "Adjust the quality of encode for ogg; 10 is the best quality with more Kb/s used, -1 is the worst quality. See: man oggenc."; 2100 $langs{tip223} = "Adjust the quality of lame encoder for mp3 files: 0 is the best quality with maximum "; 2101 $langs{tip223} .= "algorithms process; 9 is the worst quality but more fast. See: man lame (option: -q)."; 2102 $langs{tip224} = "Set default variable bitrate (VBR) quantizer quality in percent for mp4 format; 500 is the best "; 2103 $langs{tip224} .= "quality with more Kb/s used; 10 is the worst quality. See: <faac --help>."; 2104 $langs{tip225} = "Adjust the quality of encode for mpc using profiles; 8 (braindead) is the best quality with more Kb/s used,"; 2105 $langs{tip225} .= " 2 (telephone) is the worst quality. See: mppenc --longhelp\n"; 2106 $langs{tip225} .= " q=2 --telephone - lowest quality, (32... 48 kbps)\n"; 2107 $langs{tip225} .= " q=3 --thumb - low quality/internet, (58... 86 kbps)\n"; 2108 $langs{tip225} .= " q=4 --radio - medium (MP3) quality, (112...152 kbps)\n"; 2109 $langs{tip225} .= " q=5 --standard - high quality (dflt), (142...184 kbps)\n"; 2110 $langs{tip225} .= " q=6 --xtreme - extreme high quality, (168...212 kbps)\n"; 2111 $langs{tip225} .= " q=7 --insane - extreme high quality, (232...268 kbps)\n"; 2112 $langs{tip225} .= " q=8 --braindead - extreme high quality, (232...278 kbps)"; 2113 $langs{tip226} = "Compression level:\n fast: 1000\n normal: 2000\n high: 3000\n extra high: 4000\n insane: 5000\n"; 2114 $langs{tip226} .= "\nMore compression level \nresults small files.\nSee the help: mac"; 2115 $langs{tip227} = "Compression level:\n fast: 0\n normal: 5\n best: 8\nSee <man flac>."; 2116 $langs{tip228} = "Put here the additional command line used to encode this files."; 2117 $langs{tip229} = "Used to encode ID3v2.3.0 Tag for MP3 files."; 2118 $langs{tip250} = "If this entry is empty, the original comment tag will be preserved. "; 2119 $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value."; 2120 2121 $langs{tip301} = "If there is more than one artist, use:\nArtist1 & Artist2 & Artist3 & ..."; 2122 $langs{tip302} = "Track number"; 2123 $langs{tip303} = "Total track number"; 2124 $langs{tip304} = "Save changes of tag."; 2125 $langs{tip305} = "Save changes of tag to $home/.cddb directory."; 2126 2127 $langs{tip401} = "Try /dev/cdrom, /dev/dvd, /dev/hdc or ...\nSee \"/etc/fstab\" file."; 2128 $langs{tip402} = "Refresh the cdrom drive and erase the playlist."; 2129 $langs{tip403} = "Unselect all tracks."; 2130 $langs{tip404} = "Select all tracks."; 2131 $langs{tip405} = "Add more files to play."; 2132 $langs{tip406} = "Close the gnormalize player config."; 2133 $langs{tip407} = "Choose the interval in milliseconds that the text will be redrawed."; 2134 $langs{tip408} = "Choose the step incremental in pixels."; 2135 $langs{tip409} = "Scrolling text orientation: up/down or left/right."; 2136 $langs{tip410} = "Show the xTunes like skin.\nTo take effect, change the display mode."; 2137 $langs{tip411} = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode."; 2138 $langs{tip429} = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. "; 2139 $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'."; 2140 $langs{tip429} .= "\n---***---\n"; 2141 $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. "; 2142 $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. "; 2143 $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice."; 2144 $langs{tip429} .= "\n---***---\n"; 2145 $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. "; 2146 2147 $langs{tip501} = "All tabs, messages, names and tips used by gnormalize."; 2148 $langs{tip502} = "You need to restart the Gnormalize."; 2149 $langs{tip503} = "Guidance Language only used to help the translations.\nRead Only."; 2150 $langs{tip504} = "Save the translations and new languages inside the directory: $lang_dir."; 2151 $langs{tip505} = "Improve this translation or use it as base for a new Language."; 2152 2153 2154 $langs{msg001} = "Supported Files into the directory (recursively):"; 2155 $langs{msg002} = "Supported Files into the directory (not recursively):"; 2156 $langs{msg003} = " Choose a mp3/mp4/mpc/ogg/ape/flac/wav/cda file to normalize!"; 2157 $langs{msg004} = " Dependence not satisfied!"; 2158 $langs{msg005} = "If Same Extension, Overwrite file"; 2159 $langs{msg006} = "Analyzing with ReplayGain normalization algorithms ..."; 2160 2161 $langs{msg012} = ": read only!"; 2162 $langs{msg013} = " Select at least one track to rip!"; 2163 $langs{msg014} = " Success! Rip finished."; 2164 $langs{msg015} = " Rip stopped!"; 2165 $langs{msg016} = " Success!"; 2166 $langs{msg017} = " Success! File converted."; 2167 $langs{msg018} = " Success! File normalized."; 2168 $langs{msg019} = "stop ripping"; 2169 $langs{msg020} = " Get info from "; 2170 $langs{msg021} = " Please, wait. cdparanoia is reading the cdrom ..."; 2171 $langs{msg022} = " Please, select at least one track to play."; 2172 $langs{msg023} = "Can't find \""; 2173 $langs{msg024} = "\" in executable path."; 2174 $langs{msg025} = "The output can't be \"mp3\" format."; 2175 $langs{msg026} = "The output can't be \"ogg\" format."; 2176 $langs{msg027} = "The output can't be \"mpc\" format."; 2177 $langs{msg028} = "The output can't be \"ape\" format."; 2178 $langs{msg029} = "The output can't be \"flac\" format."; 2179 $langs{msg030} = "The output can't be \"mp4\" format."; 2180 $langs{msg031} = "The wav files can't be normalized."; 2181 $langs{msg032} = "The input can't be \"ogg\" format."; 2182 $langs{msg033} = "The input can't be \"mpc\" format."; 2183 $langs{msg034} = "The input can't be \"mp4\" format."; 2184 $langs{msg035} = "cdcd is a Command Driven CD player."; 2185 $langs{msg036} = "First run \"cdcd\" in command line to make the config file .cdcdrc"; 2186 $langs{msg037} = "Choose \"n\" for the question: Are you connected to a network (y/n) [y]?"; 2187 $langs{msg038} = "Can't use the perl module \""; 2188 $langs{msg039} = "Can't play audio CD."; 2189 $langs{msg040} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 2190 $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 2191 $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert "; 2192 $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 2193 $langs{msg041} = "This file will not be normalized!"; 2194 $langs{msg042} = "According to insensibility, not normalize"; 2195 $langs{msg043} = "Not normalize because adjustment "; 2196 $langs{msg044} = " is less than insensibility value."; 2197 $langs{msg045} = " not normalize "; 2198 $langs{msg046} = "Don't need encode"; 2199 $langs{msg047} = " already normalized "; 2200 $langs{msg048} = "This file is already normalized."; 2201 $langs{msg049} = " Stop normalizing!"; 2202 $langs{msg050} = "Applying adjustment of "; 2203 $langs{msg051} = " normalizing: adjustment of "; 2204 $langs{msg052} = "Computing levels..."; 2205 $langs{msg053} = " normalized with adjustment of "; 2206 $langs{msg054} = " ripping audio to wav"; 2207 $langs{msg055} = " Stop ripping!"; 2208 $langs{msg056} = "copy maked."; 2209 $langs{msg057} = " Stop lame decoding!"; 2210 $langs{msg058} = " Stop lame encoding!"; 2211 $langs{msg061} = " This informations will be saved on normalized file."; 2212 $langs{msg062} = " tag saved."; 2213 $langs{msg063} = "Select a mp3/mp4/mpc/ogg/ape/flac/wav file."; 2214 $langs{msg064} = "Homepage: $HOMEPAGE\nThis software is available under GNU General Public Licence."; 2215 $langs{msg065} = " output: "; 2216 $langs{msg066} = "file selected - $langs{all_tab03} can be edited."; 2217 $langs{msg067} = " Unable to open cdrom drive "; 2218 $langs{msg068} = " Getting information from cddb ..."; 2219 $langs{msg069} = " none cddb information."; 2220 $langs{msg070} = " Press save button on \"$langs{all_tab03}\" tab to save this changes."; 2221 $langs{msg071} = " Not connected, using "; 2222 $langs{msg072} = " cddb: can't connect to internet!"; 2223 $langs{msg073} = " Can't rip audio CD! cdparanoia not found."; 2224 $langs{msg074} = " Can't rip audio CD! cdda2wav not found."; 2225 $langs{msg075} = "Select a mp3, mp4, mpc, ogg, ape, flac, or wav file"; 2226 $langs{msg077} = "settings"; 2227 $langs{msg078} = "Selected file"; 2228 $langs{msg079} = "Recomended minimum version:"; 2229 $langs{msg080} = " Invalid option!"; 2230 $langs{msg081} = " Press the \"Refresh the cdrom\" button and type again the changes."; 2231 $langs{msg082} = "Not found CDDB_get perl module in your system.\n gnormalize will uses internal CDDB_get (version 2.27)."; 2232 $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20)."; 2233 $langs{msg084} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 2234 $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 2235 $langs{msg085} = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. "; 2236 $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 2237 $langs{msg086} = "Selected Directory (recursively)"; 2238 $langs{msg087} = "Select a directory containing mp3, mp4, mpc, ogg, ape, flac, or wav file."; 2239 $langs{msg088} = "Selected Directory (not recursively)"; 2240 $langs{msg089} = "Removing temporary file:"; 2241 $langs{msg090} = "Can not find no supported file inside of directory!"; 2242 $langs{msg092} = "remove this music from list"; 2243 $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; S�o Paulo - Brasil"; 2244 $langs{msg094} = "Traducci�n al Espag�ol: Victor Hugo Vidal conjuntamente con Roger Gabriels - Antwerp Belgium\n"; 2245 $langs{msg094} .= "E-mail: normaliseer\@pcfreesoft.com | Homepage: http://www.pcfreesoft.com"; 2246 $langs{msg095} = "You must add new language name to translate!"; 2247 } 2248 2249 if ( $language eq 'Deutsch' ) 2250 { 2251 $langs{all_tab01} = "Daten"; 2252 $langs{all_tab02} = "Konfiguration"; 2253 $langs{all_tab03} = "Information"; 2254 $langs{all_tab04} = "Rip/Play"; 2255 $langs{all_tab05} = "Translations"; 2256 $langs{all_tab06} = "�ber"; 2257 $langs{all_tab07} = "Option1"; 2258 $langs{all_tab08} = "Option2"; 2259 $langs{all_tab09} = "CDDB"; 2260 $langs{all_tab10} = "Ripper"; 2261 $langs{all_tab11} = "Colors"; 2262 $langs{all_tab12} = "Players"; 2263 $langs{all_tab13} = "Columns"; 2264 $langs{all_tab14} = "Skins"; 2265 2266 $langs{name001} = "Normungstyp"; 2267 $langs{name002} = "Unempf�nglichkeit"; 2268 $langs{name003} = "Selektierte Datei"; 2269 $langs{name004} = "Importieren von Verzeichnis"; 2270 $langs{name005} = "Output: Lossy Compression"; 2271 $langs{name006} = "Output: Lossless Compression"; 2272 $langs{name106} = "Output: Uncompressed"; 2273 2274 $langs{name007} = "Datei"; 2275 $langs{name008} = "Zur�ckkehrend"; 2276 $langs{name009} = "Delete Wav Files"; 2277 $langs{name010} = "Change Properties"; 2278 $langs{name011} = "Overwrite"; 2279 $langs{name012} = "Priority"; 2280 $langs{name013} = "Add Command"; 2281 $langs{name014} = "Filename Rip"; 2282 $langs{name015} = "Character"; 2283 $langs{name016} = "Idiom"; 2284 $langs{name017} = "Font"; 2285 $langs{name018} = "Read CDDB"; 2286 $langs{name019} = "Overwrite CDDB"; 2287 $langs{name020} = "CDDB Server"; 2288 $langs{name021} = "Port"; 2289 $langs{name022} = "Transport"; 2290 $langs{name023} = "disable paranoia"; 2291 $langs{name024} = "disable extra paranoia"; 2292 $langs{name025} = "abort on skip"; 2293 $langs{name026} = "never skip repair"; 2294 $langs{name027} = "paranoia no-verify"; 2295 $langs{name028} = "paranoia disable"; 2296 $langs{name029} = "ripper"; 2297 $langs{name030} = "Encode Type"; 2298 $langs{name031} = "Mode"; 2299 $langs{name032} = "Encode Quality"; 2300 $langs{name033} = "Variable"; 2301 $langs{name034} = "Title"; 2302 $langs{name035} = "Artist"; 2303 $langs{name036} = "Album"; 2304 $langs{name037} = "Comment"; 2305 $langs{name038} = "Year"; 2306 $langs{name039} = "Track Number"; 2307 $langs{name040} = "Genre"; 2308 $langs{name041} = "Frequency"; 2309 $langs{name042} = "Time"; 2310 $langs{name043} = "Channels"; 2311 $langs{name044} = "Length"; 2312 $langs{name045} = "Track"; 2313 $langs{name046} = "Artist"; 2314 $langs{name047} = "Title"; 2315 $langs{name048} = "Size"; 2316 $langs{name049} = "Year"; 2317 $langs{name050} = "Filepath"; 2318 $langs{name051} = "Extension"; 2319 $langs{name052} = "Exportieren von Verzeichnis"; 2320 $langs{name053} = "Album"; 2321 $langs{name054} = "Play Count"; 2322 $langs{name055} = "Animation"; 2323 $langs{name056} = "Filename"; 2324 $langs{name057} = "Show Tooltips"; 2325 $langs{name058} = "Guidance Language"; 2326 $langs{name059} = "Current Translation"; 2327 $langs{name060} = "Improve The Currente Language Translation"; 2328 $langs{name061} = "Add New Language"; 2329 $langs{name062} = "Add new language here and then press save buton."; 2330 $langs{name063} = "Normalisieren"; 2331 $langs{name064} = "CD Player"; 2332 $langs{name065} = "Play"; 2333 2334 $langs{name429} = 'Play Tracks Without Any Filters'; 2335 $langs{name430} = 'Play Tracks From Different Albums'; 2336 $langs{name431} = 'Play Tracks From Different Artists'; 2337 $langs{name432} = 'Play Tracks From Different Genres'; 2338 $langs{name433} = 'Play Tracks From Different Years'; 2339 2340 $langs{tip101} = "Track: use ReplayGain Single Track gain setting.\nAlbum: don't implemented yet!\n"; 2341 $langs{tip101} .= "None: no normalization is done.\n"; 2342 $langs{tip101} .= "---*---\n"; 2343 $langs{tip101} .= "gnormalize uses the wavegain to normalize wave files.\n"; 2344 $langs{tip101} .= "wavegain is a program that applies ReplayGain normalization algorithms directly to wave files."; 2345 $langs{tip102} = "Apply additional Manual Gain adjustment in decibels between -12.0 and +12.0. "; 2346 $langs{tip102} .= "Gain = 0.00dB correspond to 89dB standard or reference value.\n"; 2347 $langs{tip102} .= "---*---\n"; 2348 $langs{tip102} .= "Basic ideas of ReplayGain normalization algorithms:\n"; 2349 $langs{tip102} .= "1. Calculate the Root Mean Square (RMS) of the waveform every 50ms;\n"; 2350 $langs{tip102} .= "2. Sort the RMS values into numerical order, and choose the value 95% up the list to represent the overall perceived loudness;\n"; 2351 $langs{tip102} .= "3. Calibrate the energy of a digital signal to 89dB standard value and apply the gain adjustment.\n"; 2352 $langs{tip102} .= "---*---\n"; 2353 $langs{tip102} .= "RMS(A) = sqrt(mean(A^2)) is the Root Mean Square of sound amplitude A.\n"; 2354 $langs{tip102} .= "Gain(A) = 2*10*log(A/A0), such that A is the measured amplitude and A0 is the reference amplitude."; 2355 $langs{tip103} = "Insensibility of normalize. Only not re-encode if:\n"; 2356 $langs{tip103} .= "1) the extension of input file is the same of output file;\n"; 2357 $langs{tip103} .= "2) and \"$langs{name010}\" button is not active;\n"; 2358 $langs{tip103} .= "3) and adjust of normalize is less than insensibility value."; 2359 $langs{tip104} = "Select one directory with supported file."; 2360 $langs{tip105} = "Choose the directory where all the files will be saved."; 2361 $langs{tip106} = "Normalize/Convert all supported files inside the directory (recursively or not)."; 2362 $langs{tip107} = "Select a directory including subdirectories: descende recursively into the directory preserving the same structure."; 2363 $langs{tip108} = "After normalize, the output format will be mp3. Play it with mpg123, mpg321 or madplay."; 2364 $langs{tip109} = "After normalize, the output format will be mp4 (also know as m4a) or aac. Play it with mplayer."; 2365 $langs{tip110} = "After normalize, the output format will be mpc (also know as mpp or mp+). Play it with mppdec or xmms plugin."; 2366 $langs{tip111} = "After normalize, the output format will be ogg. Play it with ogg123."; 2367 $langs{tip112} = "After normalize, the output format will be ape. Play it with the command:\n mac \"song.ape\" - -d | play -t wav - "; 2368 $langs{tip113} = "After normalize, the output format will be flac. Play it with flac123 or xmms plugin.\nRequired flac version >= \"1.1.1\"."; 2369 $langs{tip114} = "Es ist geeignet, Audio-Cds von wav-Dateien herzustellen.\nWav ist ein unkrompimiertes Audio Format."; 2370 $langs{tip115} = "NOTE:\n"; 2371 $langs{tip115} .= "This compression technique is known as 'Lossy Compression' whereby during the compression data can be lost. "; 2372 $langs{tip115} .= "The degree of loss varies upon settings. Although data loss does occur, it is minimal and certainly not noticable "; 2373 $langs{tip115} .= "when using good settings.\nExamples of Lossy compression audio: Mp3, Mp4, Mpc and Ogg."; 2374 $langs{tip116} = "NOTE:\n"; 2375 $langs{tip116} .= "This compression technique is known as 'Lossless Compression' in which all of the information in the original "; 2376 $langs{tip116} .= "data is preserved, and the original data may be recovered in form identical to its original form.\n"; 2377 $langs{tip116} .= "Examples of Lossless compression audio: Ape and Flac."; 2378 $langs{tip117} = "Show the progress bar."; 2379 $langs{tip118} = "Hide the progress bar."; 2380 $langs{tip119} = "Show the command line and others info."; 2381 $langs{tip120} = "Hide the command line and others info."; 2382 $langs{tip121} = "Quit."; 2383 $langs{tip122} = "Clear all messages."; 2384 2385 $langs{tip201} = "After the normalize process, the temporary wav files will be deleted."; 2386 $langs{tip202} = "After normalize the files, you can change its encode properties by determining the encode type, the bitrate of all "; 2387 $langs{tip202} .= "output files, etc. Otherwise, the bitrate of each input file and others properties will be conserved."; 2388 $langs{tip203} = "The normalized file will be saved in the same directory of input. If it already exist then overwrite the original file."; 2389 $langs{tip204} = "Show the hints and informations."; 2390 $langs{tip205} = "Show the Tux and others penguins animations."; 2391 $langs{tip206} = "Modify scheduling priority: 0 (highest priority) to 19 (lowest)"; 2392 $langs{tip207} = "Output filename format used only for rip Audio CD:\n"; 2393 $langs{tip207} .= " %a - artist\n"; 2394 $langs{tip207} .= " %b - album\n"; 2395 $langs{tip207} .= " %t - song title\n"; 2396 $langs{tip207} .= " %n - track number\n"; 2397 $langs{tip207} .= " %y - year\n"; 2398 $langs{tip207} .= " %g - genre"; 2399 $langs{tip208} = "Advised font: Sans 10."; 2400 $langs{tip209} = "Read the CDDB info for Audio CD in your drive from CDDB server \"$CDDB_server\" or from files saved into $home/.cddd/."; 2401 $langs{tip210} = "Always get CDDB info from server and overwrite the CDDB file saved at $home/.cddd/"; 2402 $langs{tip211} = "Some servers:\nfreedb.freedb.org:8880\nus.freedb.org:8880\ncddb.com\nus.cddb.com:8880\nsunsite.unc.edu:8880"; 2403 $langs{tip212} = "Choose the port number."; 2404 $langs{tip213} = "Disable all data verification and correction features. Consequently the extraction/rip is more fast. "; 2405 $langs{tip213} .= "This option implies that -Y is active. See cdparanoia (option -Z)."; 2406 $langs{tip214} = "Do not accept any skips; retry forever if needed. See cdparanoia (option -z)."; 2407 $langs{tip215} = "Disables intra-read data verification; only overlap checking at read boundaries is performed. Not recommended. See cdparanoia (option -Y).\n"; 2408 $langs{tip215} .= "Boundaries are spaces/limit inter tracks of an audio cd. cdparanoia reads this boundaries carefully when rip on track."; 2409 $langs{tip216} = "If the read skips due to imperfect data, a scratch, whatever, abort reading this track. See cdparanoia (option -X)."; 2410 $langs{tip217} = "Use the paranoia library instead of cdda2wav's routines for reading. See cdda2wav (option -paranoia)."; 2411 $langs{tip218} = "Disables paranoia mode. Paranoia is still being used. See cdda2wav (option -paraopts=help)."; 2412 $langs{tip219} = "Switches verify off, and overlap on."; 2413 $langs{tip220} = "Choose a targeted average bitrate. Sets encoding to the bitrate closest to this value (in Kb/s)."; 2414 $langs{tip221} = "Adjust the quality of mp3; 9 is the worst quality, 0 is the best quality with more Kb/s. See: man lame (option: -V)."; 2415 $langs{tip222} = "Adjust the quality of encode for ogg; 10 is the best quality with more Kb/s used, -1 is the worst quality. See: man oggenc."; 2416 $langs{tip223} = "Adjust the quality of lame encoder for mp3 files: 0 is the best quality with maximum "; 2417 $langs{tip223} .= "algorithms process; 9 is the worst quality but more fast. See: man lame (option: -q)."; 2418 $langs{tip224} = "Set default variable bitrate (VBR) quantizer quality in percent for mp4 format; 500 is the best "; 2419 $langs{tip224} .= "quality with more Kb/s used; 10 is the worst quality. See: <faac --help>."; 2420 $langs{tip225} = "Adjust the quality of encode for mpc using profiles; 8 (braindead) is the best quality with more Kb/s used,"; 2421 $langs{tip225} .= " 2 (telephone) is the worst quality. See: mppenc --longhelp\n"; 2422 $langs{tip225} .= " q=2 --telephone - lowest quality, (32... 48 kbps)\n"; 2423 $langs{tip225} .= " q=3 --thumb - low quality/internet, (58... 86 kbps)\n"; 2424 $langs{tip225} .= " q=4 --radio - medium (MP3) quality, (112...152 kbps)\n"; 2425 $langs{tip225} .= " q=5 --standard - high quality (dflt), (142...184 kbps)\n"; 2426 $langs{tip225} .= " q=6 --xtreme - extreme high quality, (168...212 kbps)\n"; 2427 $langs{tip225} .= " q=7 --insane - extreme high quality, (232...268 kbps)\n"; 2428 $langs{tip225} .= " q=8 --braindead - extreme high quality, (232...278 kbps)"; 2429 $langs{tip226} = "Compression level:\n fast: 1000\n normal: 2000\n high: 3000\n extra high: 4000\n insane: 5000\n"; 2430 $langs{tip226} .= "\nMore compression level \nresults small files.\nSee the help: mac"; 2431 $langs{tip227} = "Compression level:\n fast: 0\n normal: 5\n best: 8\nSee <man flac>."; 2432 $langs{tip228} = "Put here the additional command line used to encode this files."; 2433 $langs{tip229} = "Used to encode ID3v2.3.0 Tag for MP3 files."; 2434 $langs{tip250} = "If this entry is empty, the original comment tag will be preserved. "; 2435 $langs{tip250} .= "The default comment is \"gnormalize - gain=%gain\" with %gain replaced by its value."; 2436 2437 $langs{tip301} = "If there is more than one artist, use:\nArtist1 & Artist2 & Artist3 & ..."; 2438 $langs{tip302} = "Track number"; 2439 $langs{tip303} = "Total track number"; 2440 $langs{tip304} = "Save changes of tag."; 2441 $langs{tip305} = "Save changes of tag to $home/.cddb directory."; 2442 2443 $langs{tip401} = "Try /dev/cdrom, /dev/dvd, /dev/hdc or ...\nSee \"/etc/fstab\" file."; 2444 $langs{tip402} = "Refresh the cdrom drive and erase the playlist."; 2445 $langs{tip403} = "Unselect all tracks."; 2446 $langs{tip404} = "Select all tracks."; 2447 $langs{tip405} = "Add more files to play."; 2448 $langs{tip406} = "Close the gnormalize player config."; 2449 $langs{tip407} = "Choose the interval in milliseconds that the text will be redrawed."; 2450 $langs{tip408} = "Choose the step incremental in pixels."; 2451 $langs{tip409} = "Scrolling text orientation: up/down or left/right."; 2452 $langs{tip410} = "Show the xTunes like skin.\nTo take effect, change the display mode."; 2453 $langs{tip411} = "Always On Top: keep the play mode window above the others windows.\nTo take effect, change the display mode."; 2454 $langs{tip429} = "Play tracks that satisfies established filters can be more convenient or pleasant than the general random approach. "; 2455 $langs{tip429} .= "The available filters are 'Play Tracks From Different Albums/Artists/Genres/Years'."; 2456 $langs{tip429} .= "\n---***---\n"; 2457 $langs{tip429} .= "For example, if the filter is set to Albums, then play tracks jumping between different Albums. "; 2458 $langs{tip429} .= "In this case, all Albums will be played before repeat some Album. "; 2459 $langs{tip429} .= "In others words, until one track has been played from each Album, the same Album will not be chosen twice."; 2460 $langs{tip429} .= "\n---***---\n"; 2461 $langs{tip429} .= "When playing, the filters can be used considering the straight or random order. "; 2462 2463 $langs{tip501} = "All tabs, messages, names and tips used by gnormalize."; 2464 $langs{tip502} = "Sie m�ssen den Gnormalize wiederanfangen."; 2465 $langs{tip503} = "Guidance Language only used to help the translations.\nRead Only."; 2466 $langs{tip504} = "Save the translations and new languages inside the directory: $lang_dir."; 2467 $langs{tip505} = "Improve this translation or use it as base for a new Language."; 2468 2469 2470 $langs{msg001} = "Supported Files into the directory (recursively):"; 2471 $langs{msg002} = "Supported Files into the directory (not recursively):"; 2472 $langs{msg003} = " Choose a mp3/mp4/mpc/ogg/ape/flac/wav/cda file to normalize!"; 2473 $langs{msg004} = " Dependence not satisfied!"; 2474 $langs{msg005} = "If Same Extension, Overwrite file"; 2475 $langs{msg006} = "Analyzing with ReplayGain normalization algorithms ..."; 2476 2477 $langs{msg012} = ": read only!"; 2478 $langs{msg013} = " Select at least one track to rip!"; 2479 $langs{msg014} = " Success! Rip finished."; 2480 $langs{msg015} = " Rip stopped!"; 2481 $langs{msg016} = " Success!"; 2482 $langs{msg017} = " Success! File converted."; 2483 $langs{msg018} = " Success! File normalized."; 2484 $langs{msg019} = "stop ripping"; 2485 $langs{msg020} = " Get info from "; 2486 $langs{msg021} = " Please, wait. cdparanoia is reading the cdrom ..."; 2487 $langs{msg022} = " Please, select at least one track to play."; 2488 $langs{msg023} = "Can't find \""; 2489 $langs{msg024} = "\" in executable path."; 2490 $langs{msg025} = "The output can't be \"mp3\" format."; 2491 $langs{msg026} = "The output can't be \"ogg\" format."; 2492 $langs{msg027} = "The output can't be \"mpc\" format."; 2493 $langs{msg028} = "The output can't be \"ape\" format."; 2494 $langs{msg029} = "The output can't be \"flac\" format."; 2495 $langs{msg030} = "The output can't be \"mp4\" format."; 2496 $langs{msg031} = "The wav files can't be normalized."; 2497 $langs{msg032} = "The input can't be \"ogg\" format."; 2498 $langs{msg033} = "The input can't be \"mpc\" format."; 2499 $langs{msg034} = "The input can't be \"mp4\" format."; 2500 $langs{msg035} = "cdcd is a Command Driven CD player."; 2501 $langs{msg036} = "First run \"cdcd\" in command line to make the config file .cdcdrc"; 2502 $langs{msg037} = "Choose \"n\" for the question: Are you connected to a network (y/n) [y]?"; 2503 $langs{msg038} = "Can't use the perl module \""; 2504 $langs{msg039} = "Can't play audio CD."; 2505 $langs{msg040} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 2506 $langs{msg040} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 2507 $langs{msg040} .= "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. gnormalize can convert "; 2508 $langs{msg040} .= "audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 2509 $langs{msg041} = "This file will not be normalized!"; 2510 $langs{msg042} = "According to insensibility, not normalize"; 2511 $langs{msg043} = "Not normalize because adjustment "; 2512 $langs{msg044} = " is less than insensibility value."; 2513 $langs{msg045} = " not normalize "; 2514 $langs{msg046} = "Don't need encode"; 2515 $langs{msg047} = " already normalized "; 2516 $langs{msg048} = "This file is already normalized."; 2517 $langs{msg049} = " Stop normalizing!"; 2518 $langs{msg050} = "Applying adjustment of "; 2519 $langs{msg051} = " normalizing: adjustment of "; 2520 $langs{msg052} = "Computing levels..."; 2521 $langs{msg053} = " normalized with adjustment of "; 2522 $langs{msg054} = " ripping audio to wav"; 2523 $langs{msg055} = " Stop ripping!"; 2524 $langs{msg056} = "copy maked."; 2525 $langs{msg057} = " Stop lame decoding!"; 2526 $langs{msg058} = " Stop lame encoding!"; 2527 $langs{msg061} = " This informations will be saved on normalized file."; 2528 $langs{msg062} = " tag saved."; 2529 $langs{msg063} = "Select a mp3/mp4/mpc/ogg/ape/flac/wav file."; 2530 $langs{msg064} = "Homepage: $HOMEPAGE\nThis software is available under GNU General Public Licence."; 2531 $langs{msg065} = " output: "; 2532 $langs{msg066} = "file selected - $langs{all_tab03} can be edited."; 2533 $langs{msg067} = " Unable to open cdrom drive "; 2534 $langs{msg068} = " Getting information from cddb ..."; 2535 $langs{msg069} = " none cddb information."; 2536 $langs{msg070} = " Press save button on \"$langs{all_tab03}\" tab to save this changes."; 2537 $langs{msg071} = " Not connected, using "; 2538 $langs{msg072} = " cddb: can't connect to internet!"; 2539 $langs{msg073} = " Can't rip audio CD! cdparanoia not found."; 2540 $langs{msg074} = " Can't rip audio CD! cdda2wav not found."; 2541 $langs{msg075} = "Select a mp3, mp4, mpc, ogg, ape, flac, or wav file"; 2542 $langs{msg077} = "settings"; 2543 $langs{msg078} = "Selected file"; 2544 $langs{msg079} = "Recomended minimum version:"; 2545 $langs{msg080} = " Invalid option!"; 2546 $langs{msg081} = " Press the \"Refresh the cdrom\" button and type again the changes."; 2547 $langs{msg082} = "Not found CDDB_get perl module in your system.\n gnormalize will uses internal CDDB_get (version 2.27)."; 2548 $langs{msg083} = "Not found MP3::Info perl module in your system.\n gnormalize will uses internal MP3::Info (version 1.20)."; 2549 $langs{msg084} = "gnormalize is an audio converter and CD ripper with ReplayGain normalization algorithms, an audio player and a "; 2550 $langs{msg084} .= "metadata (tag) editor. It uses 'wavegain' to normalize wave files with the accurate gain_analysis.c code from ReplayGain. "; 2551 $langs{msg085} = "gnormalize decodes the file to WAV format, then normalizes the WAV and re-encodes it. "; 2552 $langs{msg085} .= "gnormalize can convert audio format between MP3, MP4, MPC, OGG, APE, FLAC, and WAV."; 2553 $langs{msg086} = "Selected Directory (recursively)"; 2554 $langs{msg087} = "Select a directory containing mp3, mp4, mpc, ogg, ape, flac, or wav file."; 2555 $langs{msg088} = "Selected Directory (not recursively)"; 2556 $langs{msg089} = "Removing temporary file:"; 2557 $langs{msg090} = "Can not find no supported file inside of directory!"; 2558 $langs{msg092} = "remove this music from list"; 2559 $langs{msg093} = "Author: $AUTHOR\nEmail: $EMAIL\nDate: $DATE ; S�o Paulo - Brasil"; 2560 $langs{msg094} = "Deutsche �bersetzung gemacht durch Roger Gabriels Antwerp (Essen) Belgium\n"; 2561 $langs{msg094} .= "E-mail: normaliseer\@pcfreesoft.com | Homepage: htp://www.pcfreesoft.com"; 2562 $langs{msg095} = "You must add new language name to translate!"; 2563 } 2564 2565 #if ( $language eq 'new_language' ) 2566 #{ 2567 # ... 2568 # ... 2569 #} 2570 2571 read_new_langs(); 2572 foreach my $lang ( sort keys %all_language ) { read_langs("$lang_dir/${lang}.txt") if ( $language eq $lang ); } 2573 2574} # final of 'sub set_language' 2575 2576set_language(); 2577 2578sub read_new_langs { # read new language inside $lang_dir 2579 return if ( ! -d filename_from_unicode $lang_dir ); 2580 opendir(DIR, filename_from_unicode $lang_dir ) ; #search for $lang_dir directory 2581 while (my $file = readdir(DIR)) { 2582 next if $file eq "."; 2583 next if $file eq ".."; 2584 if ( -w filename_from_unicode "$lang_dir/$file" ){ # -w File is writable by effective uid/gid. 2585 ( my $lang = $file) =~ s/\.txt$//; 2586 #print "\$file = $file ; \$lang = $lang \n"; 2587 $all_language{$lang} = $true; # Set New Language 2588 } 2589 } 2590 closedir(DIR); 2591} 2592 2593sub read_langs { 2594 my $file = shift; 2595 return if ( ! -e filename_from_unicode $file ); 2596 my $last_key = 'msg001'; 2597 open( INPUT, '<:utf8', filename_from_unicode $file ) or die "Can't open <$file>: $!, stopped"; 2598 while (my $line = <INPUT>) { # regular expressions: see 'man perlre' and 'man perlretut'. 2599 chomp($line); # avoid \n on last field 2600 next if ( $line =~ /^$/ ); # remover linha vazia # ^$ matches an empty string 2601 #$line =~ s/\n/\\n/sg; print "\$line = $line\n"; 2602 my $key; my $value; 2603 2604 #if ( $line =~ /^\$langs{(.*)}\s+=\s+"(.*)";/s){ $key = $1; $value = $2 } # $langs{$key}=$value 2605 if ( $line =~ /^(.*)<===>(.*)/s){ $key = $1; $value = $2 } # $langs{$key}=$value 2606 2607 #print "\$key = $key ; \$last_key = $last_key \n"; 2608 if ( not defined $key and defined $last_key and defined $line ) { $langs{$last_key} .= "\n$line"; next; } 2609 2610 $langs{$key} = $value; 2611 $last_key = $key; 2612 } 2613 close( INPUT ); 2614 #print "333-->\$language = $language \n"; 2615} 2616 2617#############----------Main--Window----------############### 2618#####--------------------------------------------------##### 2619#######-------------------Initial-------------------######## 2620 2621# main window - tela principal 2622$window = new Gtk2::Window( "toplevel" ); # principal janela 2623$window->signal_connect( "delete_event", \&Quit ); 2624$window->set_border_width( 1 ); 2625$window->set_decorated ($true); 2626# Realization is necessary when you want a widget to use 2627# a GdkWindow to access the X server. 2628$window->realize; 2629$window->set( 'resizable' => $true, 'allow-shrink' => $false, 'allow-grow' => $true); 2630# for set_uposition see <man Gtk2::Widget> 2631#$window->set_uposition (300,200); # (x,y) - window should be placed on the screen. 2632# 'center'; 'none'; 'mouse' ; 'center-on-parent', 'center-always' ; 2633#$window->set_position ('center-always'); 2634$window->set_title( "gnormalize - $VERSION" ); 2635#Gtk2::Widget->set_size_request($widget, $width, $height); 2636#$window->set_size_request(520,450); #minimum required size, can't shrink for size less than this. 2637$window->resize($window_width, $window_height); 2638#my $color = Gtk2::Gdk::Color->parse ("#B8D3C1"); $window->modify_bg ('normal', $color); 2639$window->show; 2640 2641###------------ vbox main -----------------### 2642# "Inside the window we need a vbox to arrange the widgets vertically 2643# $vbox = new Gtk2::VBox( $homogeneous, $spacing ); 2644# $vbox->pack_start( $child, $expand, $fill, $padding ); 2645# If the $expand argument is a true value, then the widgets are laid out 2646# in the box to fill in all the extra space in the box so the box is expanded 2647# to fill the area allotted to it; otherwise the box is shrunk to just fit 2648# the widgets. Setting expand to a false value will allow you to do right 2649# and left justification of your widgets. Note that setting $homogeneous 2650# to true on the VBox is the same as setting $expand to true for each widget." 2651 2652my $vbox_main = new Gtk2::VBox( $false, 0 ); 2653$vbox_main->set_border_width( 0 ); 2654$window->add($vbox_main); 2655$vbox_main->show; 2656 2657###-----------------vpaned-----------------### 2658###-----------------init-------------------### 2659# see <man Gtk2::Paned> 2660# Inside the $vbox_main we put vpaned 2661# and inside vpaned we put vbox_up and vbox_down 2662 2663my $vpaned = Gtk2::VPaned->new; 2664$vpaned->set_border_width (0); 2665$vbox_main->pack_start( $vpaned, $true, $true, 0 ); 2666$vpaned->show; 2667 2668###--------------- vbox_up --------------------### 2669 2670$vbox_up = new Gtk2::VBox( $false, 2 ); 2671$vbox_up->set_border_width( 1 ); 2672$vpaned->add1 ($vbox_up); 2673$vbox_up->show; 2674 2675###------------ vbox_down ------------------### 2676 2677my $vbox_down = new Gtk2::VBox( $false, 2 ); 2678$vbox_down->set_border_width( 1 ); 2679$vpaned->add2 ($vbox_down); 2680$vbox_down->show; 2681 2682###-----------------------------------------### 2683 2684# "child1_resize" determines whether the first child 2685# should expand when $paned is resized. 2686$vpaned->child1_resize ($true); 2687$vpaned->child2_resize ($true); 2688 2689# "If shrink is true, then that child can be made 2690# smaller than its requisition by the user." 2691$vpaned->child1_shrink($false); 2692$vpaned->child2_shrink($false); 2693 2694###-----------------final------------------### 2695###--------------- vpaned -----------------### 2696 2697 2698#------------------ tabs for notebook ---------------# 2699 2700#criamos o vbox1 e o adicionamos dentro do notebook 2701$vbox1 = new Gtk2::VBox( $false, 2 ); 2702$vbox1->set_border_width( 4 ); 2703$vbox1->show(); 2704 2705#criamos o vbox2 e o adicionamos dentro do notebook 2706$vbox2 = new Gtk2::VBox( $false, 2 ); 2707$vbox2->set_border_width( 4 ); 2708$vbox2->show(); 2709 2710#criamos o vbox3 e o adicionamos dentro do notebook 2711my $vbox3 = new Gtk2::VBox( $false, 2 ); 2712$vbox3->set_border_width( 4 ); 2713$vbox3->show(); 2714 2715#criamos o vbox4 e o adicionamos dentro do notebook 2716my $vbox4 = new Gtk2::VBox( $false, 2 ); 2717$vbox4->set_border_width( 4 ); 2718$vbox4->show(); 2719 2720#criamos o vbox5 e o adicionamos dentro do notebook 2721my $vbox5 = new Gtk2::VBox( $false, 2 ); 2722$vbox5->set_border_width( 4 ); 2723$vbox5->show(); 2724 2725#criamos o vbox6 e o adicionamos dentro do notebook 2726my $vbox6 = new Gtk2::VBox( $false, 2 ); 2727$vbox6->set_border_width( 4 ); 2728$vbox6->show(); 2729 2730#------------------ icons for notebook ---------------# 2731 2732sub DrawIcons { # To show the icons correctely 2733 my ($stockid,$size) = @_; 2734 my $icon_image = Gtk2::Image->new_from_stock($stockid,$size); 2735 $icon_image->show; 2736 return $icon_image; 2737} 2738 2739# widget = Gtk2::Image->new_from_stock ($stock_id, $size) 2740# $stock_id: see <man Gtk2::Stock> 2741# size : menu, small-toolbar, large-toolbar, button, dnd, dialog 2742my $tab_icon_size = 'small-toolbar'; 2743my $label_data = Gtk2::Label->new($langs{all_tab01}); 2744$label_data->show; 2745my $vbox_tab_data = Gtk2::VBox->new( $false, 1 ); 2746$vbox_tab_data->add( DrawIcons('gtk-harddisk', $tab_icon_size) ); 2747$vbox_tab_data->add($label_data); 2748$vbox_tab_data->show; 2749 2750#my $notebook_color = Gtk2::Gdk::Color->parse ("blue"); # #B8D3C1 = 184 211 193 (RGB) 2751#$label_data->modify_fg ('normal', $notebook_color); 2752 2753# for config notebook icon 2754my $label_config = Gtk2::Label->new($langs{all_tab02}); 2755$label_config->show; 2756my $vbox_tab_config = Gtk2::VBox->new( $false, 1 ); 2757$vbox_tab_config->add(DrawIcons('gtk-preferences', $tab_icon_size)); 2758$vbox_tab_config->add($label_config); 2759$vbox_tab_config->show; 2760 2761# for info notebook icon 2762my $label_info = Gtk2::Label->new($langs{all_tab03}); 2763$label_info->show; 2764my $vbox_tab_info = Gtk2::VBox->new( $false, 1 ); 2765$vbox_tab_info->add(DrawIcons('gtk-find-and-replace', $tab_icon_size)); 2766$vbox_tab_info->add($label_info); 2767$vbox_tab_info->show; 2768 2769# for rip notebook icon 2770my $label_rip = Gtk2::Label->new($langs{all_tab04}); 2771$label_rip->show; 2772my $vbox_tab_rip = Gtk2::VBox->new( $false, 1 ); 2773$vbox_tab_rip->add(DrawIcons('gtk-cdrom', $tab_icon_size)); 2774$vbox_tab_rip->add($label_rip); 2775$vbox_tab_rip->show; 2776 2777# for rip notebook icon 2778my $label_transl = Gtk2::Label->new($langs{all_tab05}); 2779$label_transl->show; 2780my $vbox_tab_transl = Gtk2::VBox->new( $false, 1 ); 2781$vbox_tab_transl->add(DrawIcons('gtk-spell-check', $tab_icon_size)); 2782$vbox_tab_transl->add($label_transl); 2783$vbox_tab_transl->show; 2784 2785# for about notebook icon 2786my $label_about = Gtk2::Label->new($langs{all_tab06}); 2787$label_about->show; 2788my $vbox_tab_about = Gtk2::VBox->new( $false, 1 ); 2789$vbox_tab_about->add(DrawIcons('gtk-dialog-info', $tab_icon_size)); 2790$vbox_tab_about->add($label_about); 2791$vbox_tab_about->show; 2792 2793#####-------------------Notebook-----------------####### 2794# we put vbox1, vbox2, vbox3, vbox4 and vbox6 inside notebook 2795# and we put notebook inside vbox_up 2796 2797$notebook = Gtk2::Notebook->new; 2798$notebook->set( 'homogeneous' => $true, 'scrollable' => $true ); 2799 2800#$notebook->append_page_menu ($child, $tab_label, $menu_label) 2801$notebook->append_page_menu ( $vbox1, $vbox_tab_data, undef ); # data 2802$notebook->append_page_menu ( $vbox2, $vbox_tab_config, undef ); # config 2803$notebook->append_page_menu ( $vbox3, $vbox_tab_info, undef ); # info 2804$notebook->append_page_menu ( $vbox4, $vbox_tab_rip, undef ); # rip 2805$notebook->append_page_menu ( $vbox5, $vbox_tab_transl, undef ); # Translation 2806$notebook->append_page_menu ( $vbox6, $vbox_tab_about, undef ); # about 2807#$box->pack_start ($child, $expand, $fill, $padding) 2808$vbox_up->pack_start( $notebook, $true, $true, 0 ); 2809#$notebook->signal_connect("switch-page", \&refresh_notebook_test); 2810#$vbox_up->add( $notebook ); 2811$notebook->show; 2812 2813#integer = $notebook->get_current_page; 2814#$notebook->set_current_page ($notebook_page_num); # see this command on the final 2815 2816#################------ItemFactory------################ 2817# Inside the vbox1 we put frame1 2818 2819###--------------frame1--------------------### 2820# Adicionamos este frame1 em vbox1 2821$frame1 = new Gtk2::Frame( $langs{name063} . ": mp3/mp4/mpc/ogg/ape/flac/wav"); 2822# Set the frame's label 2823# Align the label at the right of the frame 2824$frame1->set_label_align( 1.0, 0.0 ); 2825# Set the style of the frame 2826$frame1->set_shadow_type( 'etched_out' ); 2827$vbox1->add($frame1); 2828$frame1->show(); 2829 2830#adicionamos uma tabela dentro do frame 2831#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 2832$table1 = new Gtk2::Table (4, 6, 0); 2833$table1->set_border_width (4); 2834$table1->set_row_spacings(4); 2835$table1->set_col_spacings(4); 2836$frame1->add( $table1 ); 2837$table1->show; 2838 2839# on hbox1 we put more two frames: frame11 and frame12 2840# Gtk2::HBox->new ($homogeneous=0, $spacing=5) 2841my $hbox1 = Gtk2::HBox->new ($true, 2); 2842$vbox1->add($hbox1); 2843$hbox1->show; 2844 2845###--------------frame11--------------------### 2846# Adicionamos este frame11 em hbox1 2847my $frame11 = new Gtk2::Frame($langs{name005}); 2848$frame11->set_label_align( 1.0, 0.0 ); 2849$frame11->set_shadow_type( 'etched_out' ); 2850$hbox1->add($frame11); 2851$frame11->show(); 2852 2853#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 2854my $table11 = new Gtk2::Table (2, 2, 0); 2855$table11->set_border_width (4); 2856$table11->set_row_spacings(4); 2857$table11->set_col_spacings(0); 2858$frame11->add( $table11 ); 2859$table11->show; 2860 2861###--------------frame12--------------------### 2862# Adicionamos este frame12 em hbox1 2863my $frame12 = new Gtk2::Frame($langs{name006}); 2864$frame12->set_label_align( 1.0, 0.0 ); 2865$frame12->set_shadow_type( 'etched_out' ); 2866$hbox1->add($frame12); 2867$frame12->show(); 2868 2869my $table12 = new Gtk2::Table (2, 2, 0); 2870$table12->set_border_width (4); 2871$table12->set_row_spacings(6); 2872$table12->set_col_spacings(2); 2873$frame12->add( $table12 ); 2874$table12->show; 2875 2876###--------------frame13--------------------### 2877 2878# Adicionamos este frame13 em hbox1 2879my $frame13 = new Gtk2::Frame($langs{name106}); 2880$frame13->set_label_align( 1.0, 0.0 ); 2881$frame13->set_shadow_type( 'etched_out' ); 2882$hbox1->add($frame13); 2883$frame13->show(); 2884 2885my $table13 = new Gtk2::Table (2, 1, 0); 2886$table13->set_border_width (4); 2887$table13->set_row_spacings(6); 2888$table13->set_col_spacings(2); 2889$frame13->add( $table13 ); 2890$table13->show; 2891 2892###--------------frame2--------------------### 2893# we put frame2 inside notebook2 2894my $frame2 = new Gtk2::Frame(); 2895# Align the label at the right of the frame 2896$frame2->set_label_align( 1.0, 0.0 ); 2897# Set the style of the frame 2898$frame2->set_shadow_type( 'etched_out' ); 2899#$vbox2->add($frame2); 2900$frame2->show(); 2901 2902#adicionamos uma tabela dentro do frame 2903#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 2904my $table2 = new Gtk2::Table (3, 4, 0); 2905$table2->set_border_width (4); 2906$table2->set_row_spacings(4); 2907$table2->set_col_spacings(10); 2908$frame2->add( $table2 ); 2909$table2->show; 2910 2911###--------------frame202--------------------### 2912# we put frame202 inside notebook2 2913my $frame202 = new Gtk2::Frame(); 2914$frame202->set_label_align( 1.0, 0.0 ); 2915$frame202->set_shadow_type( 'etched_out' ); 2916$frame202->show(); 2917 2918#adicionamos uma tabela dentro do frame 2919#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 2920my $table202 = new Gtk2::Table (3, 4, 0); 2921$table202->set_border_width (4); 2922$table202->set_row_spacings(4); 2923$table202->set_col_spacings(4); 2924$frame202->add( $table202 ); 2925$table202->show; 2926 2927###--------------frame203--------------------### 2928# we put frame203 inside notebook2 2929my $frame203 = new Gtk2::Frame(); 2930$frame203->set_label_align( 1.0, 0.0 ); 2931$frame203->set_shadow_type( 'etched_out' ); 2932$frame203->show(); 2933 2934#adicionamos uma tabela dentro do frame 2935#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 2936my $table203 = new Gtk2::Table (3, 4, 0); 2937$table203->set_border_width (4); 2938$table203->set_row_spacings(4); 2939$table203->set_col_spacings(8); 2940$frame203->add( $table203 ); 2941$table203->show; 2942 2943###--------------frame204--------------------### 2944# we put frame204 inside notebook2 2945my $frame204 = new Gtk2::Frame("cdparanoia"); 2946$frame204->set_label_align( 1.0, 0.0 ); 2947$frame204->set_shadow_type( 'etched_out' ); 2948$frame204->show(); 2949 2950#adicionamos uma tabela dentro do frame 2951#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 2952my $table204 = new Gtk2::Table (3, 4, 0); 2953$table204->set_border_width (4); 2954$table204->set_row_spacings(4); 2955$table204->set_col_spacings(8); 2956$frame204->add( $table204 ); 2957$table204->show; 2958 2959###--------------frame205--------------------### 2960# we put frame205 inside notebook2 2961my $frame205 = new Gtk2::Frame("cdda2wav"); 2962$frame205->set_label_align( 1.0, 0.0 ); 2963$frame205->set_shadow_type( 'etched_out' ); 2964$frame205->show(); 2965 2966#adicionamos uma tabela dentro do frame 2967#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 2968my $table205 = new Gtk2::Table (3, 4, 0); 2969$table205->set_border_width (4); 2970$table205->set_row_spacings(4); 2971$table205->set_col_spacings(8); 2972$frame205->add( $table205 ); 2973$table205->show; 2974 2975#-------------------Notebook2----------------# 2976# we put frame2 inside notebook2 2977# and we put notebook2 inside vbox2 2978$notebook2 = Gtk2::Notebook->new; 2979# position = 'left', 'right','top', 'bottom' 2980$notebook2->set( homogeneous => $true ); # 'tab-hborder' => 20 2981$notebook2->set_tab_pos( 'left' ); 2982 2983#integer = $notebook2->get_current_page; 2984#$notebook2->set_current_page ($notebook_page_num2); # see this command on the final 2985 2986my $label_option1 = Gtk2::Label->new( $langs{all_tab07} ); 2987my $label_option2 = Gtk2::Label->new( $langs{all_tab08} ); 2988my $label_cddb = Gtk2::Label->new( $langs{all_tab09} ); 2989my $label_ripper = Gtk2::Label->new( $langs{all_tab10} ); 2990#$notebook->append_page_menu ($child, $tab_label, $menu_label) 2991$notebook2->append_page_menu ( $frame2, $label_option1, undef ); # option1 2992$notebook2->append_page_menu ( $frame202, $label_option2, undef ); # option2 2993$notebook2->append_page_menu ( $frame203, $label_cddb, undef ); # cddb 2994if ($ripper eq "cdparanoia"){ $notebook2->append_page_menu ( $frame204, $label_ripper, undef ); } # ripper 2995if ($ripper eq "cdda2wav" ){ $notebook2->append_page_menu ( $frame205, $label_ripper, undef ); } # ripper 2996 2997# $vbox->pack_start( $child, $expand, $fill, $padding ); 2998$vbox2->pack_start( $notebook2, $true, $true, 0 ); 2999#$vbox2->add( $notebook2 ); 3000$notebook2->show; 3001 3002###--------------frame21--------------------### 3003# Adicionamos este frame21 em vbox2 (vbox2 est� dentro do notebook) 3004my $frame21 = new Gtk2::Frame("lame ".$langs{msg077} ); 3005$frame21->set_label_align( 1.0, 0.0 ); 3006$frame21->set_shadow_type( 'etched_out' ); 3007# $vbox->pack_start( $child, $expand, $fill, $padding ); 3008$vbox2->pack_start( $frame21, $true, $true, 0 ); 3009#$vbox2->add($frame21); 3010$frame21->show(); 3011 3012#adicionamos uma tabela21 dentro do frame21 3013my $table21 = new Gtk2::Table (3, 7, $false); 3014$table21->set_border_width (4); 3015$table21->set_row_spacings(4); 3016$table21->set_col_spacings(4); 3017$frame21->add( $table21 ); 3018$table21->show; 3019 3020###----------------hpaned3-----------------### 3021###-----------------init-------------------### 3022# see <man Gtk2::Paned> 3023# Inside the vbox3 we put hpaned3 3024# and inside hpaned3 we put frame3 and frame31 3025 3026my $hpaned3 = Gtk2::HPaned->new; 3027$vbox3->pack_start ($hpaned3, $true, $true, 0); 3028$hpaned3->set_border_width (0); 3029$hpaned3->show; 3030 3031###--------------frame3--------------------### 3032my $frame3 = new Gtk2::Frame("Tag"); 3033# Align the label at the right of the frame 3034$frame3->set_label_align( 1.0, 0.0 ); 3035# Set the style of the frame 3036$frame3->set_shadow_type( 'etched_in' ); 3037$hpaned3->add1 ($frame3); 3038$frame3->show(); 3039 3040#adicionamos uma tabela dentro do frame 3041#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 3042my $table3 = new Gtk2::Table (6, 4, 0); 3043$table3->set_size_request( 350 ,-1 ); # width (70%), height; 3044$table3->set_border_width (4); 3045$table3->set_row_spacings(6); 3046$table3->set_col_spacings(4); 3047$frame3->add( $table3 ); 3048$table3->show; 3049 3050###--------------frame31--------------------### 3051my $frame31 = new Gtk2::Frame("MP3 Info"); 3052# Align the label at the right of the frame 3053$frame31->set_label_align( 1.0, 0.0 ); 3054# Set the style of the frame 3055$frame31->set_shadow_type( 'etched_in' ); 3056$hpaned3->add2 ($frame31); 3057$frame31->show(); 3058 3059#adicionamos uma tabela dentro do frame 3060my $table31 = new Gtk2::Table (6, 1, 0); 3061#$table31->set_size_request( 144,-1 ); #width,height 3062$table31->set_border_width (2); 3063$table31->set_row_spacings(8); 3064$table31->set_col_spacings(2); 3065$frame31->add( $table31 ); 3066$table31->show; 3067 3068# "child1_resize" determines whether the first child 3069# should expand when $paned is resized. 3070$hpaned3->child1_resize ($true); 3071$hpaned3->child2_resize ($true); 3072 3073# "If shrink is true, then that child can be made 3074# smaller than its requisition by the user." 3075$hpaned3->child1_shrink($false); 3076$hpaned3->child2_shrink($true); 3077 3078###-----------------final------------------### 3079###----------------hpaned3-----------------### 3080 3081###------------vpaned-playlist-------------### 3082###-----------------init-------------------### 3083# see <man Gtk2::Paned> 3084# Inside the window we put vpaned 3085# and inside vpaned we put vbox_up and vbox_down 3086 3087my $vpaned_play_list = Gtk2::VPaned->new; 3088$vpaned_play_list->set_border_width (0); 3089$vbox4->pack_start( $vpaned_play_list, $true, $true, 0 ); 3090$vpaned_play_list->show; 3091 3092###------------ vbox_up playlist -----------### 3093 3094my $vbox_up_play_list = new Gtk2::VBox( $false, 2 ); 3095$vbox_up_play_list->set_border_width( 1 ); 3096$vpaned_play_list->add1 ($vbox_up_play_list); 3097$vbox_up_play_list->show; 3098 3099###----------- vbox_down playlist ----------### 3100 3101#my $vbox_down_play_list = new Gtk2::VBox( $false, 2 ); 3102#$vbox_down_play_list->set_border_width( 1 ); 3103#$vpaned_play_list->add2 ($vbox_down_play_list); 3104#$vbox_down_play_list->show; 3105 3106###-----------------------------------------### 3107 3108# "child1_resize" determines whether the first child 3109# should expand when $paned is resized. 3110$vpaned_play_list->child1_resize ($true); 3111$vpaned_play_list->child2_resize ($true); 3112 3113# "If shrink is true, then that child can be made 3114# smaller than its requisition by the user." 3115$vpaned_play_list->child1_shrink($true); 3116$vpaned_play_list->child2_shrink($true); 3117 3118###-----------------final------------------### 3119###------------vpaned-playlist-------------### 3120 3121 3122###----------------hpaned-----------------### 3123###-----------------init-------------------### 3124 3125my $hpaned_play_list = Gtk2::HPaned->new; 3126$vpaned_play_list->add2 ($hpaned_play_list); 3127$hpaned_play_list->set_border_width (0); 3128$hpaned_play_list->show; 3129 3130###------------ vbox_left playlist -----------### 3131 3132my $vbox_left_play_list = new Gtk2::VBox( $false, 2 ); 3133$vbox_left_play_list->set_border_width( 1 ); 3134$hpaned_play_list->add1 ($vbox_left_play_list); 3135$vbox_left_play_list->show; 3136 3137###----------- vbox_right playlist ----------### 3138 3139my $vbox_right_play_list = new Gtk2::VBox( $false, 2 ); 3140$vbox_right_play_list->set_border_width( 1 ); 3141$hpaned_play_list->add2 ($vbox_right_play_list); 3142$vbox_right_play_list->show; 3143 3144###-----------------------------------------### 3145 3146# "child1_resize" determines whether the first child 3147# should expand when $paned is resized. 3148$hpaned_play_list->child1_resize ($true); 3149$hpaned_play_list->child2_resize ($true); 3150 3151# "If shrink is true, then that child can be made 3152# smaller than its requisition by the user." 3153$hpaned_play_list->child1_shrink($true); 3154$hpaned_play_list->child2_shrink($true); 3155 3156#$paned->set_position ($position) 3157$hpaned_play_list->set_position ( int(44*$window_width/100) ); # 44% of $window_width 3158 3159###-----------------final------------------### 3160###----------------hpaned3-----------------### 3161 3162 3163###--------------frame4--------------------### 3164# frame4 : rip and play Audio files 3165# Adicionamos este frame4 em vbox4 (vbox4 est� dentro do notebook) 3166 3167use constant COLUMN_RIP => 0; # check play/rip files 3168use constant COLUMN_FILE => 1; # file = track = row + 1 3169use constant COLUMN_ARTIST => 2; 3170use constant COLUMN_TITLE => 3; 3171use constant COLUMN_ALBUM => 4; 3172use constant COLUMN_TRACK => 5; # this is the track number 3173use constant COLUMN_LENGTH => 6; 3174use constant COLUMN_BITRATE => 7; 3175use constant COLUMN_YEAR => 8; 3176use constant COLUMN_FREQUENCY => 9; 3177use constant COLUMN_FILEPATH => 10; 3178use constant COLUMN_EXTENSION => 11; 3179use constant COLUMN_FILENAME => 12; 3180use constant COLUMN_PLAY_COUNT => 13; 3181use constant COLUMN_COLOR => 14; # to color the music playing 3182 3183my $color_row_playing = Gtk2::Gdk::Color->parse('#92D992'); # green 3184my $color_row_already_played = Gtk2::Gdk::Color->parse('#ADD8E6'); # cyan 3185 3186# see: /usr/share/doc/perl-Gtk2-1.054/gtk-demo/list_store.pl 3187my $scrolled_window = Gtk2::ScrolledWindow->new (undef, undef); 3188$scrolled_window->set_shadow_type ('etched-in'); 3189$scrolled_window->set_policy('automatic', 'always'); 3190$scrolled_window->set_size_request( 100, 120 ); # width, height : minimun size 3191# $vbox->pack_start( $child, $expand, $fill, $padding ); 3192$vbox_up_play_list->pack_start( $scrolled_window, $true, $true, 0 ); 3193$scrolled_window->show; 3194 3195# create tree view ;; $treeview_play->get_selection is an Gtk2::TreeSelection 3196my $treeview_play = Gtk2::TreeView->new( create_standard_model() ); # start with an empty array 3197$treeview_play->set ( 'rules-hint' => $true, # draw rows in alternating colors 3198 'reorderable' => $false, 3199 'enable-search' => $true, 3200 #'fixed-height-mode' => $true, 3201 'search-column' => COLUMN_ARTIST, 3202 ); 3203$treeview_play->get_selection->set_mode ('multiple'); # single,multiple 3204$treeview_play->get_selection->signal_connect (changed => \&get_selection_tree, $treeview_play); 3205$treeview_play->signal_connect (button_press_event => \&button_press_event_treeview); 3206$treeview_play->signal_connect (row_activated => sub { # Double click one track to play it - 10Jun2008 3207 my ($treeview, $path, $column) = @_; 3208 3209 my $model = $treeview->get_model; 3210 my $iter = $model->get_iter ($path) if $path; 3211 return unless $iter; 3212 3213 if ( $files_info[$selected_row]{playing} ){ # if there are some row_playing, then change its color 3214 push @rows_already_played, $selected_row; # my $row_playing = $selected_row; 3215 color_the_selected_tracks_and_scroll( select_color => 'played', scroll => $false, row => $selected_row ); 3216 } 3217 my $row = $model->get_value($iter,COLUMN_FILE) - 1; 3218 #print "\$row = $row ; last \$selected_row = $selected_row \$treeview = $treeview ; \$path = $path ; \$column = $column\n"; 3219 $selected_row = $row; # This $selected_row will be played. 3220 3221 $go_forward = $true; # See 'sub go_forward' 3222 play_selection( skip => 0 ); 3223 $go_forward = $false; 3224 }); 3225 3226$treeview_play->set_search_equal_func ( sub { 3227 my ($ListStore,$column,$search_name,$iter) = @_; 3228 my $artist = $ListStore->get_value($iter,COLUMN_ARTIST); 3229 my $row = $ListStore->get_value($iter,COLUMN_FILE) - 1; 3230 #my $num = $ListStore->iter_n_children; # model size 3231 if ( $artist =~ /$search_name/i ){ 3232 return $false; # to abandon the loop 3233 } 3234 return $true; # to don't abandon the loop 3235 }); 3236$treeview_play->columns_autosize; # lost the performance 3237$treeview_play->show; 3238 3239# add tree view to the ScrolledWindow 3240$scrolled_window->add ($treeview_play); 3241 3242sub create_model_audio_cd { 3243 my @array = @_; 3244 @files_info = (); # reset the array 3245 %albums_already_played = (); # reset the hash whose key is only the played album name 3246 %artists_already_played = (); # reset the hash whose key is only the played artist name 3247 $selected_row = 0; 3248 3249 # making array of array references - see <man perllol> 3250 for (my $i=0;$i<$#array+1;$i++){ 3251 my $num = sprintf("%02d", $i+1); 3252 push @files_info, { 3253 rip => $true, 3254 file => $num, 3255 track => $num, 3256 artist => "artist", 3257 title => "music title", 3258 album => "album", 3259 comment => '', 3260 year => '', 3261 total_track => $#array + 1, 3262 genre => "Other", 3263 length => "$array[$i]", 3264 3265 #filepath => "$audiodevice_path/$num".".cda", # mar2008 3266 #directory_remain => "$audiodevice_path", 3267 #filename => "$num".".cda", 3268 3269 # set all the 7 technical informations for cda: 3270 technical_info => "Audio CD", 3271 bitrate => "1411", 3272 frequency => "44100", 3273 bitrate_average => $false, 3274 mode => $audio_cd_channel, 3275 cda_total_time => $audio_cd_total_time, # only for cda 3276 fileSize => $audio_cd_fileSize, 3277 3278 extension_input => "cda", 3279 editable => $true, 3280 show => $true, 3281 remove => $false, #remove from playlist 3282 playing => $false, 3283 played => 0, 3284 }; 3285 } 3286 3287 for (my $i=0;$i<$#array+1;$i++){ 3288 $files_info[$i]{filepath} = make_filepath_format_for_cda($i); 3289 $files_info[$i]{filename} = make_filename_format_for_cda($i); 3290 $files_info[$i]{directory_remain} = remove_directory_base($audiodevice_path,$files_info[$i]{filepath}); 3291 } 3292 #my $model = create_standard_model(@files_info); 3293 my $model = create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@files_info ); 3294 3295 return $model; 3296} 3297 3298 3299sub make_filepath_format_for_cda { 3300 my $row = shift; 3301 3302 # Filename format for rip Audio CD 3303 # %t = title of song; %a = artist; %b = album; %c = comment 3304 # %n = track number; %y = year; %g = genre 3305 # $file_format = "%a-%n-%t"; 3306 my $file_format = $entry_format_cda->get_text; 3307 3308 if ($file_format !~ /(%t|%a|%b|%n|%y|%g)/ig){$file_format = "%n";} 3309 $file_format =~ s/%t/$files_info[$row]{title}/ig; 3310 $file_format =~ s/%a/$files_info[$row]{artist}/ig; 3311 $file_format =~ s/%b/$files_info[$row]{album}/ig; 3312 $file_format =~ s/%n/$files_info[$row]{track}/ig; 3313 $file_format =~ s/%y/$files_info[$row]{year}/ig; 3314 $file_format =~ s/%g/$files_info[$row]{genre}/ig; 3315 3316 my $filepath = '/' . $audiodevice_path . '/' . $file_format . '.cda'; 3317 $filepath =~ s/\/{2,}/\//g; # change two or more '//' character for one '/' 3318 3319 $filepath = remove_9_chars_and_let_1($filepath); # Do not change the character '/'. 3320 3321 return $filepath; 3322} 3323 3324sub make_filename_format_for_cda { 3325 my $row = shift; 3326 3327 # Filename format for rip Audio CD 3328 # %t = title of song; %a = artist; %b = album; %c = comment 3329 # %n = track number; %y = year; %g = genre 3330 # $file_format = "%a-%n-%t"; 3331 my $file_format = $entry_format_cda->get_text; 3332 3333 if ($file_format !~ /(%t|%a|%b|%n|%y|%g)/ig){$file_format = "%n";} 3334 $file_format =~ s/%t/$files_info[$row]{title}/ig; 3335 $file_format =~ s/%a/$files_info[$row]{artist}/ig; 3336 $file_format =~ s/%b/$files_info[$row]{album}/ig; 3337 $file_format =~ s/%n/$files_info[$row]{track}/ig; 3338 $file_format =~ s/%y/$files_info[$row]{year}/ig; 3339 $file_format =~ s/%g/$files_info[$row]{genre}/ig; 3340 3341 my $filename = $file_format . '.cda'; 3342 $filename =~ s/\/{2,}/\//g; # change two or more '//' character for one '/' 3343 $filename =~ s/(.*\/)(.*)/$2/g; # (path/)(filename): copy (path/)(filename) and get (filename) 3344 3345 $filename = remove_change_10_chars($filename); 3346 3347 return $filename; 3348} 3349 3350sub remove_change_10_chars { # 18Jun2008 3351 my $text = shift; 3352 return unless defined $text; 3353 3354 # 9 Windows Prohibited Characters : \/:*?"<>| 3355 # 1 perl Prohibited Character : $ 3356 # Some Permited Characters in filenames: =^~;!@#%�` 3357 #$text = 'Test�o��/{`:claudiofsr@yahoo.com;"}!$!?[]<|>&#*.com\/=6/1/Sfigato'; # only to test 3358 3359 $text =~ s/[\\\/:*?|\$\015]/_/g; # replace the 7 characters \/:*?|$ with underscore _. See 'man perlretut'. 3360 $text =~ s/[`"]/'/g; # substitute the characters " or ` by ' 3361 $text =~ tr/<>/[]/; # replace the characters <> with []. See 'man perlop'. 3362 3363 #$text =~ s/[^[:print:]]/_/g; # replace unprintable characters with underscores. 3364 #print "remove_change_10_chars --> \$text = $text\n"; 3365 return $text; 3366} 3367 3368sub remove_9_chars_and_let_1 { # 18Jun2008 - Do not change the character '/'. 3369 my $text = shift; 3370 return unless defined $text; 3371 3372 # 9 Windows Prohibited Characters in filenames: \/:*?"<>| 3373 # 1 perl Prohibited Character : $ 3374 # Remove/Change 9 Characters \:*?"<>|$ in filenames and let 1 Characters / 3375 3376 $text =~ s/[\\:*?|\$]/_/g; # replace the 6 characters \:*?|$ with underscore _. See 'man perlretut'. 3377 $text =~ s/[`"]/'/g; # substitute the characters " or ` by ' 3378 $text =~ tr/<>/[]/; # replace the characters <> with []. See 'man perlop'. 3379 3380 return $text; 3381} 3382 3383sub remove_directory_base { 3384 my ($dir_base,$file) = @_; 3385 ( my $dir = $file ) =~ s/(.*\/)(.*)/$1/g; # supose that $file = (/path1/path2/path3/path4/)(filename). So remove (filename) from full path. 3386 $dir =~ s/^\Q$dir_base\E//; # supose that $directory_base = (/path1/path2), then directory_ramin = (/path3/path4/) 3387 3388 # Caution with metacharacters: {}[]()^$.|*+?\ 3389 # To match this metacharacters use the escape sequence "\Q"..."\E" (see man perlretut) 3390 return $dir; 3391} 3392 3393sub create_model_files_to_be_played { # add more file to @files_info(); player mode 3394 3395 if ( not defined $files_info[0]{file} ){ @files_info = (); } 3396 #print "---> n = ",$#files_info + 1,"\n"; 3397 my $music_number = $#files_info + 1; # inicial size 3398 3399 my $j = 0; 3400 for (my $i = 0; $i <= $#array_of_files; $i++){ # ($#array_of_files + 1) or @array is the size 3401 3402 my %hash = determine_directory_and_filename_and_extension(filepath => $array_of_files[$i]); 3403 my $extension_input = $hash{extension_input}; 3404 3405 my $mesg = filename_from_unicode "\n<$array_of_files[$i]> : Not found a player to $extension_input files!\n"; 3406 my $playable = $true; 3407 3408 if ($extension_input eq 'mp3' and not ($mpg123_path or $mpg321_path or $madplay_path or $mplayer_path) ){ $playable = $false; } 3409 elsif ($extension_input eq 'mp4' and not $mplayer_path ){ $playable = $false; } 3410 elsif ($extension_input eq 'mpc' and not ($mpcdec_path or $mplayer_path) ){ $playable = $false; } 3411 elsif ($extension_input eq 'ogg' and not ($ogg123_path or $mplayer_path) ){ $playable = $false; } 3412 elsif ($extension_input eq 'ape' and not ( ($ape_path and ($play_path or $aplay_path)) or $mplayer_path ) ){ $playable = $false; } 3413 elsif ($extension_input eq 'flac' and not ($flac123_path or $mplayer_path) ){ $playable = $false; } 3414 elsif ($extension_input eq 'wav' and not ($aplay_path or $mplayer_path) ){ $playable = $false; } 3415 3416 if ($playable) { $j += 1; } 3417 else { print $mesg; next; } 3418 3419 # making array with anonymous hashes - see <man perlref> 3420 push @files_info, { 3421 rip => $true, 3422 file => $j + $music_number, 3423 3424 filepath => $array_of_files[$i], 3425 #filepath => eval_to_unicode($array_of_files[$i]), 3426 #filepath_local => $array_of_files[$i], 3427 3428 directory_remain => remove_directory_base($directory_base,$array_of_files[$i]), 3429 filename => $hash{filename}, 3430 directory => $hash{directory}, 3431 extension_input => $extension_input, 3432 3433 editable => $true, 3434 show => $true, 3435 remove => $false, #remove from playlist 3436 playing => $false, 3437 played => 0, 3438 }; 3439 } 3440 3441 for (my $row = $music_number; $row <= $#files_info ; $row++){ 3442 3443 # use the new Gtk2::FileChooser 3444 my $total_files = $#files_info + 1 - $music_number; 3445 my $cont = $row + 1 - $music_number; 3446 my $percentage = number_value( sprintf("%.2f", ( $cont/$total_files ) ) ); 3447 my $percentage2 = number_value( sprintf("%.2f", ( $cont/$total_files * 100) ) ); 3448 my $filename = $files_info[$row]{filename}; 3449 3450 $label_pct->set_label("$cont/$total_files (${percentage2}%)"); 3451 3452 $progbar_files_info->set_text( reduce_length_size($filename, 100) ); # Gtk2::ProgressBar to show file info 3453 $progbar_files_info->set_fraction ($percentage); # $fraction (double) 3454 3455 #printf "Percentage = $percentage ; filename = $filename\n"; 3456 #print "\ncreate_model_files_to_be_played --> \$music_number = $music_number;new files = $total_files;\$cont = $cont\n"; 3457 3458 get_info_from_file( row => $row, 3459 filepath => $files_info[$row]{filepath}, 3460 extension_input => $files_info[$row]{extension_input}, 3461 show_tag => $false, 3462 ); 3463 3464 while (Gtk2->events_pending) {Gtk2->main_iteration}; 3465 3466 # get the 8 tags 3467 #$files_info[$row]{title} = $Title; 3468 #$files_info[$row]{artist} = $Artist; 3469 #$files_info[$row]{album} = $Album; 3470 #$files_info[$row]{track} = $Track_Number; 3471 #$files_info[$row]{total_track} = $Total_Track; 3472 #$files_info[$row]{comment} = $Comment; 3473 #$files_info[$row]{year} = $Year; 3474 #$files_info[$row]{genre} = $Genre; 3475 # get all technical informations: 3476 #$files_info[$row]{technical_info} = $Technical_Info; 3477 #$files_info[$row]{bitrate} = $bitrate_original; 3478 #$files_info[$row]{bitrate_average} = $bitrate_average; 3479 #$files_info[$row]{frequency} = $Frequency; 3480 #$files_info[$row]{mode} = $mode_channel; 3481 #$files_info[$row]{length} = $Time_Min_Sec; 3482 #$files_info[$row]{fileSize} = $fileSize; 3483 } 3484 3485 # get all artists/albums one times only 3486 #for (my $i = 0; $i <= $#files_info; $i++){ 3487 3488 # $hash{'artist_names'} = [artist_1,artist_2, ..., artist_n]; # anonymous array 3489 # To append a new value: push @{ $hash{'artist_names'} }, $row; 3490 #my @artists = return_artist_name($files_info[$i]); # $files_info[$i] is a hash 3491 #foreach my $art (@artists) { push @{ $files_info[$i]{artist_names} }, $art; } 3492 3493 #$files_info[$i]{album_names} = return_album_name($files_info[$i]); 3494 #} 3495 3496 #my $model = create_standard_model(@files_info); 3497 my $model = create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@files_info ); 3498 3499 return $model; 3500} 3501 3502my %treeview_play_rows; # used to find $iter and $path without need to search inside all treeview using loop. 3503my %treeview_artist_rows; 3504my %treeview_album_rows; 3505#create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@files_info ); 3506 3507sub create_standard_model { # 12Jun2008 3508 my %args = ( treeview => 'treeview_play', # default value 3509 array_with_hash_ref => undef, 3510 @_, # argument pair list goes here 3511 ); 3512 my $model = Gtk2::ListStore->new ('Glib::Boolean', # => G_TYPE_BOOLEAN 3513 'Glib::Uint', # => G_TYPE_UINT 3514 'Glib::String', 3515 'Glib::String', # => G_TYPE_STRING 3516 'Glib::String', # => G_TYPE_STRING 3517 'Glib::String', # you get the idea 3518 'Glib::String', 'Glib::Uint', # length, bitrate 3519 'Glib::String', 'Glib::Uint', # year, freq , Glib::Double 3520 'Glib::String', 'Glib::String', # filepath, extension_input 3521 'Glib::String', # filename 3522 'Glib::Uint', # count play times 3523 'Gtk2::Gdk::Color', # to select one color 3524 ); 3525 3526 my $rrow = 0; # relative row that is showed on treeview 3527 3528 if ( $args{treeview} eq 'treeview_play' ) { %treeview_play_rows = (); } 3529 elsif ( $args{treeview} eq 'treeview_artist' ) { %treeview_artist_rows = () ; } 3530 elsif ( $args{treeview} eq 'treeview_album' ) { %treeview_album_rows = () ; } 3531 3532 # append more data to the list store 3533 foreach my $hash ( @{$args{array_with_hash_ref}} ) { # print "\$hash->{file} = $hash->{file} ; \$hash->{rip} = $hash->{rip}\n"; 3534 next if ($hash->{remove}); 3535 3536 my $iter = $model->append; 3537 $model->set ($iter, 3538 COLUMN_RIP, $hash->{rip}, # rip or play 3539 COLUMN_FILE, $hash->{file}, # file number. The total row number is: row = $hash->{file} - 1 3540 COLUMN_TRACK, $hash->{track}, 3541 COLUMN_ARTIST, $hash->{artist}, 3542 COLUMN_TITLE, $hash->{title}, 3543 COLUMN_ALBUM, $hash->{album}, 3544 COLUMN_LENGTH, $hash->{length}, 3545 COLUMN_BITRATE, $hash->{bitrate}, 3546 COLUMN_YEAR, $hash->{year}, 3547 COLUMN_FREQUENCY, $hash->{frequency}, 3548 COLUMN_FILEPATH, $hash->{filepath}, 3549 #COLUMN_FILEPATH, $hash->{directory_remain}, 3550 COLUMN_EXTENSION, $hash->{extension_input}, 3551 COLUMN_FILENAME, $hash->{filename}, 3552 COLUMN_PLAY_COUNT,$hash->{played}, # played n times 3553 COLUMN_COLOR, $hash->{playing} ? $color_row_playing : 3554 $hash->{played} ? $color_row_already_played : undef, # undef: without color; this column is hidden 3555 ); 3556 3557 if ( $args{treeview} eq 'treeview_play' ) { $treeview_play_rows { $hash->{file} - 1 } = $rrow; } # row = track - 1 3558 elsif ( $args{treeview} eq 'treeview_artist' ) { $treeview_artist_rows{ uc( $hash->{artist} ) } = $rrow; } 3559 elsif ( $args{treeview} eq 'treeview_album' ) { $treeview_album_rows { uc( $hash->{album} ) } = $rrow; } 3560 3561 #if ( $args{treeview} eq 'treeview_artist' ) { print "\$treeview_artist_rows{ $hash->{artist} } = $treeview_artist_rows{ uc( $hash->{artist} ) } \n"; } 3562 #elsif ( $args{treeview} eq 'treeview_album' ) { print "\$treeview_album_rows{ $hash->{album} } = $treeview_album_rows{ uc( $hash->{album} ) } \n"; } 3563 3564 $rrow += 1; 3565 #print "\$hash->{artist} = $hash->{artist} ; \$hash->{played} = $hash->{played}\n"; 3566 } 3567 return $model; 3568} 3569 3570 3571my $treeview_artist; 3572my $renderer_artist_playlist; my $column_artist_playlist; my $renderer_artist_play_count; 3573my $renderer_album_playlist; my $column_album_playlist; my $renderer_album_play_count; 3574 3575###-------------- scrolled_window_album ------------### 3576###---------------------- start --------------------### 3577 3578my $scrolled_window_album = Gtk2::ScrolledWindow->new (undef, undef); 3579$scrolled_window_album->set_shadow_type ('etched-in'); 3580$scrolled_window_album->set_policy('automatic', 'always'); 3581$scrolled_window_album->set_size_request( 80, 60 ); # width, height : minimun size 3582# $vbox->pack_start( $child, $expand, $fill, $padding ); 3583$vbox_right_play_list->pack_start( $scrolled_window_album, $true, $true, 0 ); 3584$scrolled_window_album->show; 3585 3586# create tree view 3587my $treeview_album = Gtk2::TreeView->new( create_standard_model() ); # start with an empty array 3588$treeview_album->set ( 'rules-hint' => $true, # draw rows in alternating colors 3589 'reorderable' => $false, 3590 ); 3591#$treeview_album->set_search_column (COLUMN_ALBUM); 3592$treeview_album->get_selection->set_mode ('multiple'); # single,multiple 3593$treeview_album->get_selection->signal_connect (changed => \&selection_album); 3594$treeview_album->show; 3595# add tree view to the ScrolledWindow 3596$scrolled_window_album->add ($treeview_album); 3597 3598# album column 3599 $renderer_album_playlist = Gtk2::CellRendererText->new; 3600 $renderer_album_playlist->set_data (column => COLUMN_ALBUM); 3601 $renderer_album_playlist->set ('font' => $window_font_name, style => 'italic', scale => '0.9'); 3602 3603 $column_album_playlist = Gtk2::TreeViewColumn->new_with_attributes ($langs{name053}, $renderer_album_playlist, text => COLUMN_ALBUM, 3604 'cell-background-gdk' => COLUMN_COLOR); 3605 $column_album_playlist->set_resizable ($true); 3606 $column_album_playlist->set (alignment => 0.0); # Alignment of the column header text 3607 $column_album_playlist->set_expand ($true); # this column expand to max width 3608 $column_album_playlist->set_sort_column_id (COLUMN_ALBUM); 3609 $treeview_album->insert_column ($column_album_playlist, COLUMN_ALBUM); 3610 3611#add_columns_album_artist( column_show_play_count => $column_show_play_count); 3612 3613#-----------------------------------------------------# 3614 3615#my %albums_already_played; # hash whose key is only the played album name 3616#$albums_already_played{uc($album)}++; # Set True to the album already played 3617#if ( $albums_already_played{uc($album)} ){ } 3618 3619#-----------------------------------------------------# 3620# See "The Schwartzian Transform" -- "Learning Perl Objects, References, and Modules", Chap.7.4, First Edition 3621# See "Perl CookBook, Chap 4.16 and 'A Fresh Look at Efficient Perl Sorting' by Uri Guttman and Larry Rosler. 3622# Perl's simple sort function is O(N) efficiency order. 3623# Perl's advanced sort function, like sort { uc($a) cmp uc($b) }, is O(N*logN) efficiency order. 3624# The 'packed-default sort' technique is quasi-O(N) behavior. 3625 3626# To obtain an array without repeated values: my %unique = map {$_ => 1}, @numbers; 3627# search for all differents albums "efficiently". Efici�ncia: uso racional do recursos, cpu, processamento. 3628 3629sub all_albums2 { # Using the 'Schwartzian Transform sort' technique. - Not used 3630 my @array_of_hash = @_; # @files_info 3631 if ( not defined $array_of_hash[0]{album} ){ return; } 3632 3633 my %seen = (); # hash ; save all differents albums indicating the total songs inside each album 3634 3635 my @temp = map { album => $_->[0] , played => $albums_already_played{uc($_->[0])} }, # set 'played' to False if $albums_already_played{uc($_)} is undef 3636 sort { $a->[1] cmp $b->[1] } # sort the uc(album name); all elements are already differents 3637 map [ $_, uc($_) ], # Sort the references to anonymous arrays that contain the original data $_ and the uc($_). 3638 #keys %{{ map {return_album_name($_) => 1} @array_of_hash }}; 3639 grep { not $seen{uc($_)} ++ } # Eliminate duplicate values from a list; Perl CookBook , Chap 4.7 3640 map return_album_name($_), # $_ is an element of @array_of_hash 3641 @array_of_hash; 3642 3643 #foreach my $k (sort keys %seen){ print "$k => $seen{$k} songs\n"; } 3644 3645 my @all_albums = ( { album => 'All' , played => 0 } ); # 'All' is Always the first element 3646 push @all_albums, @temp; 3647 3648 #foreach my $alb (@all_albums) { print "\$alb->{album} = $alb->{album}\n"; } 3649 return @all_albums; 3650} 3651 3652sub all_albums3 { # Using the 'packed-default sort' technique. - Not used 3653 my @array_of_hash = @_; # @files_info 3654 if ( not defined $array_of_hash[0]{album} ){ return; } 3655 3656 my %seen = (); # hash ; save all differents albums indicating the total songs inside each album 3657 3658 my @temp = map { album => $_->[0] , played => $albums_already_played{uc($_->[0])} }, # set 'played' to False if $albums_already_played{uc($_)} is undef 3659 sort { $a->[1] cmp $b->[1] } 3660 map [ $_, pack( 'C4' => /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ) . uc($_) ], 3661 keys %{{ map {return_album_name($_) => 1} @array_of_hash }}; 3662 3663 # The 'packed-default sort' is a little-known optimization that improves on the Schwartzian Transform (ST) by eliminating the sortsub itself, 3664 # relying on the default lexicographic sort, which is very efficient. This is the method used in the new Sort::Maker module. 3665 # The packed-default sort is about twice as fast as the ST, which is the fastest familiar Perl sorting algorithm. 3666 3667 my @all_albums = ( { album => 'All' , played => 0 } ); # 'All' is Always the first element 3668 push @all_albums, @temp; 3669 3670 #foreach my $alb (@all_albums) { print "\$alb->{album} = $alb->{album}\n"; } 3671 return @all_albums; 3672} 3673 3674sub all_albums { # Using 'My Best' technique. 3675 my @array_of_hash = @_; # @files_info 3676 if ( not defined $array_of_hash[0]{album} ){ return; } 3677 3678 #my %unique = map { uc(return_album_name($_)) => return_album_name($_) } @array_of_hash; # use the 'sub return_album_name' 2*N times 3679 my %unique1 = map { return_album_name($_) => 1 } @array_of_hash; # Eliminate duplicate values from a list. 3680 my %unique2 = map { NFKD(uc($_)) => $_ } keys %unique1; # Sort the keys and get the values from hash. 3681 3682 my @all_albums = ( { album => 'All' , played => 0 } ); # 'All' is Always the first element 3683 foreach (sort keys %unique2){ # sort compared lexicographically improves the performance of all sorting techniques 3684 push @all_albums, { album => $unique2{$_} , played => $albums_already_played{uc($unique2{$_})} }; 3685 #print "$_ => $unique{$_} \n"; # set 'played' = 0 if album not played. 3686 } 3687 return @all_albums; 3688} 3689 3690sub return_album_name { 3691 my $hash = shift; 3692 my $album = $hash->{album}; 3693 if ($album eq ""){ # if the album name is empty 3694 ($album = $hash->{filepath}) =~ s/.*\/(.*)\/.*$/\(directory\)$1/go; # get the last directory name 3695 } 3696 return $album; 3697} 3698 3699# get treeview_album selection and return the tracks inside the selected album 3700sub selection_album { 3701 my $model = $treeview_album->get_model; 3702 my $tree_selection = $treeview_album->get_selection; 3703 my @paths = $tree_selection->get_selected_rows; # sel = Gtk2::TreePath 3704 return unless @paths; 3705 3706 my %albums_selected; # hash whose key is the album name 3707 foreach my $path (@paths){ 3708 my $iter = $model->get_iter($path); 3709 next unless $iter; 3710 my $album = $model->get_value($iter,COLUMN_ALBUM); 3711 $albums_selected{uc($album)}++; # Set True to the album name; See 'Programming Perl', 24.2, 3a. Ed, "Efficiency" 3712 } 3713 #foreach my $alb (keys %albums_selected) { print "albums = $alb\n"; } 3714 my @tracks_in_the_album; 3715 3716 LOOP:for (my $i = 0; $i <= $#files_info; $i++){ 3717 next if $files_info[$i]->{remove}; # create_standard_model will filter this. 3718 my $album_guess = return_album_name($files_info[$i]); # if no album name, create a guess name from filepath 3719 3720 if ( $albums_selected{uc($album_guess)} or $albums_selected{uc('All')} ){ # Search for all tracks inside this album 3721 push @tracks_in_the_album, $files_info[$i]; 3722 next LOOP; 3723 } 3724 } 3725 return if (@tracks_in_the_album <= 0); 3726 3727 # add new files to tree model 3728 #$model = create_standard_model(@tracks_in_the_album); 3729 $model = create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@tracks_in_the_album ); 3730 3731 $treeview_play->set_model($model); # add the new model 3732 #$treeview_play->columns_autosize; # lost the performance 3733 3734 count_artists_and_album_already_played(update_model_artist => $false, update_model_album => $true); 3735 3736 #foreach (@tracks_in_the_album){print " --> array = \"$_->{artist}\"\n";} 3737 make_artist_and_album_treeview_column( make_artist_column => $true, make_album_column => $false, array_with_tracks => \@tracks_in_the_album ); 3738 3739 return unless $playing_music; 3740 color_the_selected_tracks_and_scroll( select_color => 'playing', color_album => $false ); 3741} 3742 3743sub make_artist_and_album_treeview_column { # make artist and album treeview column with an array 3744 my %args = ( make_artist_column => $true, 3745 make_album_column => $true, 3746 array_with_tracks => undef, # reference to array with hash 3747 @_, # argument pair list goes here 3748 ); 3749 my @selected_info = @{$args{array_with_tracks}}; # get array from reference_to_array 3750 return unless defined $selected_info[0]{file}; 3751 my ( $new_title, $model ); 3752 3753 if ( $args{make_artist_column} ){ 3754 my @all_dif_artist = all_artists( @selected_info ); # search for all differents artists 3755 $model = create_standard_model ( treeview => 'treeview_artist', array_with_hash_ref => \@all_dif_artist ); 3756 3757 $treeview_artist->set_model($model); # add the new model 3758 $new_title = @all_dif_artist > 0 ? $langs{name046} ." ($#all_dif_artist)" : $langs{name046} ; 3759 $column_artist_playlist->set_title( $new_title ); # artist (number) 3760 } 3761 if ( $args{make_album_column} ){ 3762 my @all_dif_album = all_albums( @selected_info ); # search for all differents albums 3763 $model = create_standard_model ( treeview => 'treeview_album', array_with_hash_ref => \@all_dif_album ); 3764 3765 $treeview_album->set_model($model); # add the new model 3766 $new_title = @all_dif_album > 0 ? $langs{name053} ." ($#all_dif_album)" : $langs{name053} ; 3767 $column_album_playlist->set_title( $new_title ); # album (number) 3768 } 3769} 3770 3771sub count_artists_and_album_already_played { # 09Jun2008 3772 my %args = ( update_model_artist => $false, 3773 update_model_album => $false, 3774 @_, # argument pair list goes here 3775 ); 3776 my $model; 3777 my @rows_checked = (); 3778 my @rows_unchecked = (); 3779 3780 for (my $row = 0; $row <= $#files_info; $row++){ 3781 if ($files_info[$row]{rip} eq $true){ push @rows_checked, $row; } # Get array_with_files_checked 3782 else { push @rows_unchecked, $row; } # To fill with the unchecked rows; 3783 } 3784 3785 %artists_already_played = (); # played artists count 3786 %albums_already_played = (); # played albums count 3787 my $debug = $false; # to print messages 3788 3789 print "\n\n --> count_artists_and_album_already_played:\n" if $debug; 3790 3791 # refresh Play Count artist 3792 3793 foreach my $row (@rows_checked){ 3794 my @artists = return_artist_name($files_info[$row]); 3795 foreach my $art (@artists) { $artists_already_played{ uc($art) } = 0; } # Set = 0 if artist not played 3796 } 3797 foreach my $row (@rows_unchecked){ 3798 my @artists = return_artist_name($files_info[$row]); 3799 foreach my $art (@artists) { $artists_already_played{ uc($art) } += 1; } # Add +1 3800 } 3801 3802 #($iter, $path) = get_iter_path_given_track_art_alb ( artist => $artist, treeview => 'treeview_artist' ); 3803 #$model->set ( $iter, COLUMN_COLOR, $color ) if $iter; # to color the selected artist line 3804 3805 if ( $args{update_model_artist} ){ 3806 $model = $treeview_artist->get_model; 3807 $model->foreach( sub{ # model is a $ListStore 3808 my($ListStore,$path,$iter) = @_; 3809 my $artist = $model->get ( $iter, COLUMN_ARTIST) if $iter; 3810 $model->set ( $iter, COLUMN_PLAY_COUNT, $artists_already_played{ uc($artist) } ) if $iter; # to color the selected artist line 3811 print "artists = $artist ; \$artists_play_count{$artist} = $artists_already_played{uc($artist)}\n" if $debug; 3812 return $false; # to don't abandon the loop 3813 } ); 3814 } 3815 3816 # refresh Play Count album 3817 3818 foreach my $row (@rows_checked){ 3819 my $album = return_album_name($files_info[$row]); # if no album name, create a guess name from filepath 3820 $albums_already_played{ uc($album) } = 0; # Set = 0 if album not played 3821 } 3822 foreach my $row (@rows_unchecked){ 3823 my $album = return_album_name($files_info[$row]); # if no album name, create a guess name from filepath 3824 $albums_already_played{ uc($album) } += 1; # Add +1 3825 } 3826 3827 if ( $args{update_model_album} ){ 3828 $model = $treeview_album->get_model; 3829 $model->foreach( sub{ # model is a $ListStore 3830 my($ListStore,$path,$iter) = @_; 3831 my $album = $model->get ( $iter, COLUMN_ALBUM) if $iter; 3832 $model->set ( $iter, COLUMN_PLAY_COUNT, $albums_already_played{ uc($album) } ) if $iter; # to color the selected artist line 3833 print "album = $album ; \$albums_already_played{$album} = $albums_already_played{uc($album)}\n" if $debug; 3834 return $false; # to don't abandon the loop 3835 } ); 3836 } 3837} 3838 3839###---------------------- final --------------------### 3840###-------------- scrolled_window_album ------------### 3841 3842###-------------- scrolled_window_artist ------------### 3843###---------------------- start --------------------### 3844 3845my $scrolled_window_artist = Gtk2::ScrolledWindow->new (undef, undef); 3846$scrolled_window_artist->set_shadow_type ('etched-in'); 3847$scrolled_window_artist->set_policy ('automatic', 'always'); 3848$scrolled_window_artist->set_size_request( 80, 20 ); # width, height : minimun size 3849# $vbox->pack_start( $child, $expand, $fill, $padding ); 3850$vbox_left_play_list->pack_start( $scrolled_window_artist, $true, $true, 0 ); 3851$scrolled_window_artist->show; 3852 3853# create tree view 3854$treeview_artist = Gtk2::TreeView->new( create_standard_model() ); # start with an empty array 3855$treeview_artist->set ( 'rules-hint' => $true, # draw rows in alternating colors 3856 'reorderable' => $false, 3857 ); 3858#$treeview_artist->set_search_column (COLUMN_ARTIST); 3859$treeview_artist->get_selection->set_mode ('multiple'); # single,multiple 3860$treeview_artist->get_selection->signal_connect (changed => \&selection_artist); 3861$treeview_artist->show; 3862# add tree view to the ScrolledWindow 3863$scrolled_window_artist->add ($treeview_artist); 3864 3865 # artist column 3866 $renderer_artist_playlist = Gtk2::CellRendererText->new; 3867 $renderer_artist_playlist->set_data (column => COLUMN_ARTIST); 3868 $renderer_artist_playlist->set ('font' => $window_font_name, style => 'italic', scale => '0.9'); 3869 3870 $column_artist_playlist = Gtk2::TreeViewColumn->new_with_attributes ($langs{name046}, $renderer_artist_playlist, text => COLUMN_ARTIST, 3871 'cell-background-gdk' => COLUMN_COLOR); 3872 $column_artist_playlist->set_resizable ($true); 3873 $column_artist_playlist->set (alignment => 0.0); # Alignment of the column header text 3874 $column_artist_playlist->set_expand ($true); # this column expand to max width 3875 $column_artist_playlist->set_sort_column_id (COLUMN_ARTIST); 3876 $treeview_artist->insert_column ($column_artist_playlist, COLUMN_ARTIST); 3877 3878add_columns_album_artist( column_show_play_count => $column_show_play_count); 3879 3880#-----------------------------------------------------# 3881 3882#my %artists_already_played; # hash whose key is only the played artist name 3883#$artists_already_played{uc($artist)}++; # Set True to the artist already played 3884 3885#-----------------------------------------------------# 3886 3887sub all_artists { 3888 my @array_of_hash = @_; 3889 if ( not defined $array_of_hash[0]{artist} ){ return; } 3890 3891 my @all_art = map return_artist_name($_), @array_of_hash; 3892 my %unique = map { NFKD(uc($_)) => $_ } @all_art; # Eliminate duplicate values from a list; 3893 3894 my @all_artists = ( { artist => 'All' , played => 0 } ); # 'All' is Always the first element 3895 foreach (sort keys %unique){ # sort compared lexicographically improves the performance of all sorting techniques 3896 push @all_artists, { artist => $unique{$_} , played => $artists_already_played{ uc($unique{$_}) } }; 3897 #print "$_ => $unique{$_} \n"; 3898 } 3899 return @all_artists; 3900} 3901 3902 3903sub return_artist_name { 3904 my $hash = shift; 3905 return undef if not $hash->{artist}; # 'if not' == 'unless' 3906 return split (/\s*&\s*/, $hash->{artist}); # split 'artist1 & artist2 & ...' to 'artist1,artist2,...' 3907} 3908 3909# get treeview_artist selection and return the track selected 3910sub selection_artist { 3911 my $model = $treeview_artist->get_model; 3912 my $tree_selection = $treeview_artist->get_selection; 3913 my @paths = $tree_selection->get_selected_rows; # sel = Gtk2::TreePath 3914 return unless @paths; 3915 3916 my %artists_selected; 3917 foreach my $path (@paths){ 3918 my $iter = $model->get_iter($path); 3919 next unless $iter; 3920 my $artist = $model->get_value($iter,COLUMN_ARTIST); 3921 $artists_selected{uc($artist)}++; # See 'Programming Perl', 24.2, 3a. Ed, "Efficiency" 3922 } 3923 my @tracks_with_artist; 3924 3925 LOOP:for (my $i = 0; $i <= $#files_info; $i++){ 3926 next if $files_info[$i]->{remove}; 3927 my @artist_cmp = return_artist_name($files_info[$i]); # 'art1 & art2' return (art1,art2) 3928 3929 foreach my $art (@artist_cmp){ 3930 if ( $artists_selected{uc($art)} or $artists_selected{uc('All')} ){ 3931 push @tracks_with_artist, $files_info[$i]; 3932 next LOOP; # to not select the same files_info, not duplicate 3933 } 3934 } 3935 } 3936 return if (@tracks_with_artist <= 0); 3937 3938 # add new files to tree model 3939 #$model = create_standard_model(@tracks_with_artist); 3940 $model = create_standard_model ( treeview => 'treeview_play', array_with_hash_ref => \@tracks_with_artist ); 3941 3942 $treeview_play->set_model($model); # add the new model 3943 #$treeview_play->columns_autosize; 3944 3945 count_artists_and_album_already_played(update_model_artist => $true, update_model_album => $false); 3946 3947 #my $row = $tracks_with_artist[0]{file} - 1; # [0] is the fisrt track 3948 make_artist_and_album_treeview_column( make_artist_column => $false, make_album_column => $true, array_with_tracks => \@tracks_with_artist ); 3949 3950 return unless $playing_music; 3951 color_the_selected_tracks_and_scroll( select_color => 'playing', color_artist => $false ); 3952} 3953 3954#-----------------------------------------------------# 3955my @paths_button; # to save the selected rows 3956 3957sub button_press_event_treeview { # see /usr/share/doc/perl-Gtk2-1.083/examples/multisel.pl 3958 my ($widget, $event, $data) = @_; # $widget = Gtk2::TreeView 3959 @paths_button = (); 3960 return unless ($event->button >= 3); # Press mouse button 3 ; see <man Glib> 3961 3962 my $selection = $widget->get_selection; 3963 @paths_button = $selection->get_selected_rows; # sel = Gtk2::TreePath 3964 #my @sel_rows = map $_->to_string, @paths_button; 3965 #print "\n button3 ---> \@sel_rows = @sel_rows"; 3966 return unless @paths_button; 3967 3968 # [[$treeview_play->get_selection]] is an Gtk2::TreeSelection 3969 #$treeview_play->get_selection->unselect_all; 3970 3971 my $menu = Gtk2::Menu->new; 3972 my $item = Gtk2::ImageMenuItem->new("$langs{msg092}"); # "remove this music from list" 3973 $item->set_image( Gtk2::Image->new_from_stock ('gtk-delete','menu') ); 3974 $item->signal_connect( "activate", \&remove_item_from_playlist, $treeview_play ); 3975 $menu->append($item); 3976 # $menu->popup ($parent_menu_shell, $parent_menu_item, $menu_pos_func, $data, $button, $activate_time) 3977 $menu->popup(undef, undef, undef,undef,$event->button,$event->time); 3978 $menu->show_all; 3979} 3980 3981# $button->signal_connect (clicked => \&remove_item, $treeview); 3982sub remove_item_from_playlist { # See /usr/share/doc/perl-Gtk2-1.083/gtk-demo/editable_cells.pl 3983 my ($widget, $treeview) = @_; 3984 my $model = $treeview->get_model; 3985 $treeview->set_reorderable ($true); 3986 3987 #while (@paths_button > 0) { 3988 # my $path = splice(@paths_button, -1); # remove the last element of @array 3989 3990 foreach my $path (reverse @paths_button){ # descending order 3991 my $iter = $model->get_iter($path); 3992 if ($iter) { 3993 my $row_abs = $model->get_value($iter,COLUMN_FILE) - 1; # absolute position into @files_info 3994 #print "row_abs = $row_abs ; remove filepath = $files_info[$row_abs]->{filepath} ; files_info_number = ",$#files_info+1,"\n"; 3995 3996 #splice (@files_info, $row_abs, 1); # remove one element 3997 $files_info[$row_abs]->{remove}=$true; 3998 $model->remove($iter); 3999 } 4000 } 4001} 4002 4003###---------------------- final --------------------### 4004###------------- scrolled_window_artist ------------### 4005 4006###--------------------- frame5 --------------------### 4007###--------------------- in�cio --------------------### 4008# we put frame5a + frame5b inside vbox5 and then inside notebook5 4009my $frame5a = new Gtk2::Frame( $langs{name058} ); 4010$frame5a->set_label_align( 1.0, 0.0 ); 4011$frame5a->set_shadow_type( 'etched_out' ); 4012$vbox5->pack_start( $frame5a, $true, $true, 0 ); 4013$frame5a->show(); 4014 4015#adicionamos uma tabela dentro do frame 4016#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 4017my $table5a = new Gtk2::Table (3, 4, 0); 4018$table5a->set_border_width (4); 4019$table5a->set_row_spacings(4); 4020$table5a->set_col_spacings(10); 4021$frame5a->add( $table5a ); 4022$table5a->show; 4023 4024my $frame5b = new Gtk2::Frame( $langs{name059} ); 4025$frame5b->set_label_align( 1.0, 0.0 ); 4026$frame5b->set_shadow_type( 'etched_out' ); 4027$vbox5->pack_start( $frame5b, $true, $true, 0 ); 4028$frame5b->show(); 4029 4030#adicionamos uma tabela dentro do frame 4031#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 4032my $table5b = new Gtk2::Table (3, 4, 0); 4033$table5b->set_border_width (4); 4034$table5b->set_row_spacings(4); 4035$table5b->set_col_spacings(10); 4036$frame5b->add( $table5b ); 4037$table5b->show; 4038 4039#-----------------------table5a-----------------------# 4040$ComboBox_Names = Gtk2::ComboBox->new_text; 4041foreach (sort keys %langs) { $ComboBox_Names->append_text ($_); } 4042$ComboBox_Names->set_active($Names_Active_Num); #init value 4043$ComboBox_Names->set_size_request( 92, -1 ); 4044$ComboBox_Names->signal_connect("changed", \&show_textview_language, $ComboBox_Names); 4045$tooltips->set_tip($ComboBox_Names, $langs{tip501}) if $show_all_tooltips; 4046$table5a->attach ($ComboBox_Names, 0, 1, 0, 1, ['expand','fill'], 'shrink', 0, 0); 4047$ComboBox_Names->set_add_tearoffs($true); # Whether dropdowns should have a tearoff menu item 4048$ComboBox_Names->show; 4049 4050$label = new Gtk2::Label( $langs{name016} . ":" ); 4051$label->set_alignment( 1.0, 0.5 ); 4052$table5a->attach ($label, 1, 2, 0, 1, 'fill', 'shrink', 0, 0); 4053$label->show; 4054 4055$ComboBox_Lang_5a = Gtk2::ComboBox->new_text; 4056foreach (sort keys %all_language) { $ComboBox_Lang_5a->append_text ($_); } 4057#foreach (sort { uc($a) cmp uc($b) } keys %all_language) { $ComboBox_Lang_5a->append_text ($_); } 4058 4059my $pos = 0; 4060foreach my $key (sort keys %all_language) { if ($key eq $language) {$ComboBox_Lang_5a->set_active($pos); last;} $pos++; } 4061 4062$ComboBox_Lang_5a->set_size_request( 92, -1 ); 4063$ComboBox_Lang_5a->signal_connect("changed", \&lang_choice5a); 4064$tooltips->set_tip($ComboBox_Lang_5a, $langs{tip502}); 4065$table5a->attach ($ComboBox_Lang_5a, 3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0); 4066$ComboBox_Lang_5a->show; 4067 4068#-----------------------table5b-----------------------# 4069my $ComboBox_NewLang = Gtk2::ComboBox->new_text; 4070foreach ( $langs{name060} , $langs{name061} ) { $ComboBox_NewLang->append_text ($_); } 4071$ComboBox_NewLang->set_active(0); 4072$ComboBox_NewLang->set_size_request( 92, -1 ); 4073$ComboBox_NewLang->signal_connect("changed", \&add_new_lang, $ComboBox_NewLang); 4074$table5b->attach ($ComboBox_NewLang, 0, 1, 0, 1, ['expand','fill'], 'shrink', 0, 0); 4075$ComboBox_NewLang->show; 4076 4077# Create the Entry to add new language 4078my $entry_lang = new Gtk2::Entry(); 4079$entry_lang->set_text( "" ); 4080$entry_lang->signal_connect("changed",\&ative_save_lang); 4081$tooltips->set_tip( $entry_lang, $langs{name062} ) if $show_all_tooltips; 4082$table5b->attach ($entry_lang, 1, 2, 0, 1, 'fill', 'shrink', 0, 0); 4083#$entry_lang->set_sensitive($false); 4084$entry_lang->hide; 4085 4086my $button_save_lang = Gtk2::Button->new; 4087$button_save_lang->add( DrawIcons('gtk-save','button') ); 4088$button_save_lang->signal_connect( "clicked", \&save_lang_button ); 4089$button_save_lang->set_sensitive($false); 4090$button_save_lang->set( 'focus-on-click' => $false, 'relief' => 'none' ); 4091$tooltips->set_tip( $button_save_lang, $langs{tip504} ) if $show_all_tooltips; 4092$table5b->attach ($button_save_lang, 2, 3, 0, 1, 'shrink', 'shrink', 0, 0); 4093$button_save_lang->show; 4094 4095 4096my $ComboBox_Lang_5b = Gtk2::ComboBox->new_text; 4097foreach (sort keys %all_language) { $ComboBox_Lang_5b->append_text ($_); } 4098 4099$pos = 0; 4100foreach my $key (sort keys %all_language) { if ($key eq $language) {$ComboBox_Lang_5b->set_active($pos); last;} $pos++; } 4101 4102$ComboBox_Lang_5b->set_size_request( 92, -1 ); 4103$ComboBox_Lang_5b->signal_connect("changed", \&lang_choice5b); 4104$tooltips->set_tip($ComboBox_Lang_5b, $langs{tip505} ) if $show_all_tooltips; 4105$table5b->attach ($ComboBox_Lang_5b, 3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0); 4106$ComboBox_Lang_5b->show; 4107 4108#-------------------textview_5a----------------------# 4109# Construct a textview to put Guidance Language 4110my $textview_5a = Gtk2::TextView->new; 4111$textview_5a->set ( 'editable' => $false, 4112 'cursor_visible' => $false, 4113 'left_margin' => 0, 4114 'right_margin' => 0, 4115 'wrap-mode' => 'word'); 4116 4117$textview_5a->set_border_width (4); 4118my $color_5a_base = Gtk2::Gdk::Color->parse ("#E6EDBD"); 4119$textview_5a->modify_base ('normal', $color_5a_base); 4120my $color_5a_bg = Gtk2::Gdk::Color->parse ("#A0B8A3"); 4121$textview_5a->modify_bg ('normal', $color_5a_bg); 4122$tooltips->set_tip($textview_5a, $langs{tip503} ) if $show_all_tooltips; 4123$table5a->attach ($textview_5a, 0, 4, 1, 2, ['expand','fill'], ['expand','fill'], 0, 0); 4124$textview_5a->show; 4125 4126# $buffer = Gtk2::TextBuffer->new; # see <man Gtk2::TextBuffer> 4127my $buffer_5a = $textview_5a->get_buffer; 4128$buffer_5a->create_tag ("italic_about", 'foreground' => "black", # see <man Gtk2::TextTag> for more options 4129 #'background' => "yellow", 4130 justification => 'left', 4131 font => "Sans", 4132 'size-points' => "14"); 4133 4134#-------------------textview_5b----------------------# 4135# Construct a textview to put Guidance Language 4136my $textview_5b = Gtk2::TextView->new; 4137$textview_5b->set ( 'editable' => $true, 4138 'cursor_visible' => $true, 4139 'left_margin' => 0, 4140 'right_margin' => 0, 4141 'wrap-mode' => 'word'); 4142 4143$textview_5b->set_border_width (4); 4144my $color_5b_base = Gtk2::Gdk::Color->parse ("#E6EDBD"); 4145$textview_5b->modify_base ('normal', $color_5b_base); 4146my $color_5b_bg = Gtk2::Gdk::Color->parse ("#A0B8A3"); 4147$textview_5b->modify_bg ('normal', $color_5b_bg); 4148$table5b->attach ($textview_5b, 0, 4, 1, 2, ['expand','fill'], ['expand','fill'], 0, 0); 4149$textview_5b->show; 4150 4151# $buffer = Gtk2::TextBuffer->new; # see <man Gtk2::TextBuffer> 4152my $buffer_5b = $textview_5b->get_buffer; 4153$buffer_5b->signal_connect( 'changed', \&ative_save_lang ); 4154$buffer_5b->create_tag ("version", 'foreground' => "blue", 4155 justification => 'left', 4156 font => "Sans", 4157 'size-points' => "14"); 4158 4159#----------------------------------------------------# 4160 4161sub show_textview_language{ 4162 lang_choice5a(); 4163 lang_choice5b(); 4164} 4165 4166sub lang_choice5a { 4167 my $entry=$ComboBox_Lang_5a->get_active_text; 4168 $language = $entry if defined $entry; #print "111a-->\$language = $language \n"; 4169 set_language(); 4170 $tooltips->set_tip($ComboBox_Lang_5a, $langs{tip502}); 4171 #$ComboBox_NewLang->set_popdown_strings ( $langs{name060} , $langs{name061} ); 4172 show_textview_language_5a($ComboBox_Names); #print "222a-->\$language = $language \n"; 4173} 4174 4175sub lang_choice5b { 4176 my $entry=$ComboBox_Lang_5b->get_active_text; 4177 $language = $entry if defined $entry; #print "111b-->\$language = $language \n"; 4178 set_language(); 4179 $tooltips->set_tip($ComboBox_Lang_5b, $langs{tip505}) if $show_all_tooltips; 4180 show_textview_language_5b($ComboBox_Names); #print "222b-->\$language = $language \n"; 4181} 4182 4183sub show_textview_language_5a { 4184 my ($combo_copy) = @_; 4185 my $key=$combo_copy->get_active_text; 4186 4187 $textview_5a->get_buffer->delete($textview_5a->get_buffer->get_bounds); #clear 4188 my $iter_5a = $buffer_5a->get_iter_at_offset (0); # get start of buffer 4189 $buffer_5a->insert_with_tags_by_name ($iter_5a, $langs{$key}, "italic_about"); 4190} 4191show_textview_language_5a($ComboBox_Names); 4192 4193sub show_textview_language_5b { 4194 my ($combo_copy) = @_; 4195 my $key=$combo_copy->get_active_text; 4196 4197 $textview_5b->get_buffer->delete($textview_5b->get_buffer->get_bounds); #clear 4198 my $iter_5b = $buffer_5b->get_iter_at_offset (0); # get start of buffer 4199 $buffer_5b->insert_with_tags_by_name ($iter_5b, $langs{$key}, "version"); 4200} 4201show_textview_language_5b($ComboBox_Names); 4202 4203sub add_new_lang { 4204 $entry_lang->hide if ( $ComboBox_NewLang->get_active == 0 ); 4205 $entry_lang->show if ( $ComboBox_NewLang->get_active == 1 ); 4206 #print "------> \$ComboBox_NewLang->get_active = ",$ComboBox_NewLang->get_active," \n"; 4207} 4208 4209sub ative_save_lang { 4210 $button_save_lang->set_sensitive($true); # if ($textview_5b->get_buffer->get_modified); 4211} 4212 4213sub save_lang_button { 4214 my $key_names = $ComboBox_Names->get_active_text; 4215 4216 if ( $ComboBox_NewLang->get_active == 1 and $entry_lang->get_text eq "" ){ 4217 $status_bar->push($context_id, $langs{msg095} ); 4218 return $false; 4219 } 4220 $language = $ComboBox_Lang_5b->get_active_text; # print "--> Old \$language = $language \n"; 4221 my $new_lang = $language; 4222 4223 if ( $ComboBox_NewLang->get_active == 1 and $entry_lang->get_text ne "" ){ 4224 $new_lang = $entry_lang->get_text; # print "\$new_lang = $new_lang\n"; 4225 4226 $ComboBox_Lang_5a->append_text ($new_lang) if not $all_language{"$new_lang"}; 4227 $ComboBox_Lang_5b->append_text ($new_lang) if not $all_language{"$new_lang"}; 4228 $all_language{"$new_lang"} = $true; 4229 } 4230 set_language(); 4231 4232 # Usage: Gtk2::TextBuffer::get_text(buffer, start, end, include_hidden_chars) 4233 $langs{$key_names} = $textview_5b->get_buffer->get_text($textview_5b->get_buffer->get_bounds,$true); 4234 4235 my $lang_file = "$lang_dir/${new_lang}.txt"; 4236 open( OUTPUT, '>:utf8', filename_from_unicode $lang_file ) or die "Couldn't open <$lang_file> for writing: $!\n"; 4237 4238 #foreach my $key ( sort keys %langs ) { ( my $value = $langs{$key}) =~ s/\"/\\\"/g; print OUTPUT '$langs{',$key,'} = "',$value,"\";\n"; } 4239 foreach my $key ( sort keys %langs ) { print OUTPUT $key, '<===>', $langs{$key}, "\n"; } 4240 4241 close( OUTPUT ); 4242 4243 print $key_names, ' = ', $langs{$key_names}, "\n"; 4244 print "--> \"$lang_file\" \n"; 4245 $status_bar->push($context_id, "--> \"$lang_file\""); 4246 $button_save_lang->set_sensitive($false); 4247} 4248 4249 4250###---------------------- final --------------------### 4251###--------------------- frame5 --------------------### 4252 4253###--------------------- frame6 --------------------### 4254###--------------------- in�cio --------------------### 4255# Adicionamos este frame6 em vbox6 (vbox6 est� dentro do notebook) 4256my $frame6 = new Gtk2::Frame(); 4257# Set the frame's label 4258# Align the label at the right of the frame 4259$frame6->set_label_align( 1.0, 0.0 ); 4260# Set the style of the frame 4261$frame6->set_shadow_type( 'etched_out' ); 4262# $vbox->pack_start( $child, $expand, $fill, $padding ); 4263$vbox6->pack_start( $frame6, $true, $true, 0 ); 4264#$vbox6->add($frame6); 4265$frame6->show(); 4266 4267###-------------------------------------------------### 4268 4269###------------------frame_normalize----------------### 4270 4271# we put this $frame_normalize inside the vbox_up 4272# Adicionamos este $frame_normalize em vbox_up ;; Este frame cont�m o bot�o normalize 4273my $frame_normalize = new Gtk2::Frame(); 4274$frame_normalize->set_label_align( 1.0, 0.0 ); 4275$frame_normalize->set_shadow_type( 'etched_out' ); 4276#$box->pack_start ($child, $expand, $fill, $padding) 4277$vbox_up->pack_start( $frame_normalize, $false, $true, 0 ); 4278#$vbox_up->add( $frame_normalize ); 4279$frame_normalize->show(); 4280 4281# adicionamos um hbox dentro do $frame_normalize 4282# Gtk2::HBox->new ($homogeneous=0, $spacing=5) 4283my $hbox_normalize = new Gtk2::HBox ( $false, 2 ); 4284$hbox_normalize->set_border_width(2); 4285$frame_normalize->add($hbox_normalize); 4286$hbox_normalize->show; 4287 4288###----------------frame_prog_bar--------------------### 4289# we put this frame_prog_bar inside the vbox_up ;; This frame contain the Progress Bar 4290# Adicionamos este frame em vbox_up ;; Este frame cont�m os 'progress bar' 4291$frame_prog_bar = new Gtk2::Frame(); 4292# Set the style of the frame 4293$frame_prog_bar->set_shadow_type( 'etched_out' ); 4294#$box->pack_start ($child, $expand, $fill, $padding) 4295$vbox_up->pack_start( $frame_prog_bar, $false, $true, 0 ); 4296$frame_prog_bar->show ; 4297 4298#adicionamos uma tabela dentro do frame_prog_bar 4299#$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 4300$table_down = new Gtk2::Table (3, 4, $false); 4301$table_down->set_border_width (4); 4302$table_down->set_row_spacings(4); 4303$table_down->set_col_spacings(2); 4304#$table_down->set_size_request( 510, 90 ); # width, height 4305$frame_prog_bar->add( $table_down ); 4306$table_down->show; 4307 4308###------------------frame_debug----------------------### 4309# we put this frame_debug inside the vbox_down 4310# Adicionamos este frame em vbox_down 4311# Este frame cont�m os comandos utilizados , debug 4312$frame_debug = new Gtk2::Frame(); 4313$frame_debug->set_label_align( 1.0, 0.0 ); 4314$frame_debug->set_shadow_type( 'etched_out' ); 4315#$box->pack_start ($child, $expand, $fill, $padding) 4316$vbox_down->pack_start( $frame_debug, $true, $true, 0 ); 4317#$frame_debug->show; 4318 4319## --------------------- Statusbar ------------------- ## 4320$status_bar = Gtk2::Statusbar->new; 4321$vbox_main->pack_start( $status_bar, $false, $true, 0 ); 4322$status_bar->set_has_resize_grip ($true); 4323#$status_bar->signal_connect ( button_press_event => \&event_bar_button ); 4324$status_bar->show; 4325 4326sub event_bar_button{ # not used, only for test 4327 my $widget = shift; # Gtk2::Statusbar 4328 my $event = shift; # GdkEventButton *event : see Gtk2::Gdk::Event 4329 4330 #print "fora \n"; 4331 if ($event->button == 1) { 4332 #print "button 1\n"; 4333 $table3->set_size_request( ($window->allocation->width) * 0.70 ,-1 ); # width (70%), height; 4334 my $height_fd = $frame_debug->allocation->height; 4335 print "height_fd = $height_fd \n"; 4336 } 4337} 4338 4339###----------------------------------------------------### 4340####################----------------###################### 4341##------------------------------------------------------## 4342 4343#--------------------- I c o n s ----------------------# 4344 4345my @items = ( { stock_id => "gtk-apply", label => "_unselect" }, 4346 { stock_id => "gtk-go-down", label => "" }, 4347 { stock_id => "gtk-open", label => "" }, 4348 { stock_id => "gtk-add", label => "" }, 4349 { stock_id => "gtk-go-up", label => "" }, 4350 { stock_id => "gtk-cdrom", label => "" }, 4351 { stock_id => "gtk-close", label => "" }, 4352 { stock_id => "gtk-cancel", label => "" }, 4353 { stock_id => "gtk-refresh", label => "" }, 4354 { stock_id => "gtk-go-back", label => "" }, 4355 { stock_id => "gtk-go-forward", label => "" }, 4356 { stock_id => "gtk-goto-first", label => "" }, 4357 { stock_id => "gtk-goto-last", label => "" }, 4358 { stock_id => "gtk-goto-bottom", label => "_Show" }, 4359 { stock_id => "gtk-goto-top", label => "_Hide" }, 4360 { stock_id => "gtk-yes", label => "_normalize", }, 4361 ); 4362Gtk2::Stock->add (@items); # Register our stock items 4363#print Gtk2::Stock->list_ids; 4364 4365###--------------------------------------------------### 4366 4367#####------------------T a b l e 1 ------------------##### 4368# Now, we put the widgets in table1 4369 4370# criar um label (etiqueta - r�tulo) ao lado do menu 4371$label = new Gtk2::Label( $langs{name001} . ":"); 4372$label->set_alignment( 1.0, 0.5 ); # right 4373$table1->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0); 4374$label->show(); 4375 4376#####------------ start of ComboBox ----------##### 4377my @normalize_type = ( 'Track', 'Album', 'None' ); 4378 4379my $ComboBox_Norm_Type = Gtk2::ComboBox->new_text; 4380foreach my $type (@normalize_type) { $ComboBox_Norm_Type->append_text ($type); } 4381 4382$pos = 0; 4383#$ComboBox_Norm_Type->set_active($pos); # set default value: $norm_type = 'Track'; 4384foreach my $type (@normalize_type) { if ($type eq $norm_type) {$ComboBox_Norm_Type->set_active($pos); last;} $pos++; } 4385 4386#$ComboBox_Norm_Type->set_size_request( 92, -1 ); 4387$ComboBox_Norm_Type->signal_connect("changed", \&change_norm_type); 4388$tooltips->set_tip( $ComboBox_Norm_Type, $langs{tip101} ) if $show_all_tooltips; 4389$table1->attach ($ComboBox_Norm_Type, 1, 2, 0, 1, 'fill', 'shrink', 0, 0); 4390$ComboBox_Norm_Type->show; 4391 4392sub change_norm_type { 4393 my ($ComboBox_copy) = @_; 4394 $norm_type = $ComboBox_copy->get_active_text; 4395 4396 if ($norm_type eq "Track" ) {$spinner->set_sensitive($true );} 4397 if ($norm_type eq "Album" ) {$spinner->set_sensitive($false);} 4398 if ($norm_type eq "None" ) {$spinner->set_sensitive($false);} 4399 return $norm_type; 4400} 4401 4402#####------------ final of ComboBox ----------##### 4403 4404# Create a centering alignment object; 4405$align = Gtk2::Alignment->new(0.0, 0.5, 0, 0); 4406$table1->attach_defaults ($align, 2, 3, 0, 1); 4407$align->show; 4408 4409# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 4410my $adj = new Gtk2::Adjustment( $gain, -12.00, 12.00, 0.01, 0, 0 ); 4411#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits ); 4412$spinner = new Gtk2::SpinButton( $adj, 5, 2 ); 4413$spinner->set_wrap( $true ); 4414$spinner->set_editable($true); 4415$spinner->set_numeric ($true); 4416$spinner->set_update_policy( 'if_valid' ); 4417$tooltips->set_tip( $spinner, $langs{tip102} ) if $show_all_tooltips; 4418$align->add($spinner); 4419$spinner->show; 4420 4421#-------------------------------------# 4422 4423change_norm_type($ComboBox_Norm_Type); 4424 4425#-------------------------------------# 4426 4427$label = new Gtk2::Label( $langs{name002} . ":" ); 4428$label->set_alignment( 1.0, 0.5 ); # right 4429$table1->attach ($label, 3, 4, 0, 1, 'fill', 'shrink', 0, 0); 4430$label->show(); 4431 4432$align = Gtk2::Alignment->new(0.0, 0.5, 0, 0); 4433$table1->attach ($align, 4, 5, 0, 1, 'fill', 'shrink', 0, 0); 4434$align->show; 4435 4436# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 4437$insensibility = number_value($insensibility); 4438$adj = new Gtk2::Adjustment( $insensibility, 0.2, 5.0, 0.1, 0, 0 ); 4439#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits ); 4440$spinner_sensi = new Gtk2::SpinButton( $adj, 0.2, 1 ); 4441$spinner_sensi->set_wrap( $false ); 4442$spinner_sensi->set_editable($false); 4443$spinner_sensi->set_update_policy( 'if_valid' ); 4444$tooltips->set_tip( $spinner_sensi, $langs{tip103} ) if $show_all_tooltips; 4445$align->add($spinner_sensi); 4446$spinner_sensi->show(); 4447 4448$label = new Gtk2::Label( "dB" ); 4449$label->set_alignment( 0.0, 0.5 ); # right 4450$table1->attach ($label, 5, 6, 0, 1, 'fill', 'shrink', 0, 0); 4451$label->show(); 4452 4453# criar um label (etiqueta - r�tulo) ao lado do menu 4454$label = new Gtk2::Label( $langs{name003} . ":" ); 4455$label->set_alignment( 1.0, 0.5 ); # right 4456$table1->attach ($label, 0, 1, 1, 2, 'fill', 'fill', 0, 0); 4457$label->show(); 4458 4459# Create the Entry to put the file to normalize 4460$entry_f = new Gtk2::Entry( ); 4461#$entry_f->set_max_length (100); 4462$entry_f->set_text( " " ); 4463$tooltips->set_tip( $entry_f, $langs{msg063} ) if $show_all_tooltips; 4464$entry_f->select_region( 0, length( $entry_f->get_text() ) ); 4465$table1->attach_defaults ($entry_f, 1, 6, 1, 2 ); 4466$entry_f->set_sensitive($false); 4467$entry_f->set('editable' => $false ); 4468$entry_f->show(); 4469 4470#--------------- Input Directory -----------------# 4471 4472$label = new Gtk2::Label( $langs{name004} . ":" ); 4473$label->set_alignment( 1.0, 0.5 ); # right 4474$table1->attach ($label, 0, 1, 2, 3, 'fill', 'fill', 0, 0); 4475$label->show(); 4476 4477# Create the Entry to put the directory path 4478$entry_dir_input = new Gtk2::Entry( ); 4479#$entry_dir_input->set_max_length (100); 4480 4481$directory = $ENV{'PWD'}; # start value 4482eval { $directory = filename_to_unicode $directory; }; # convert filename to unicode 4483$directory =~ s/\/{1,}$//; # remove the '/' character from final if it exists. 4484$directory_base = $directory; # used to find 'directory_ramain' with remove_directory_base() 4485 4486$entry_dir_input->set_text( $directory ); 4487$tooltips->set_tip( $entry_dir_input, "$directory") if $show_all_tooltips; 4488$entry_dir_input->select_region( 0, length( $entry_dir_input->get_text() ) ); 4489$table1->attach_defaults ($entry_dir_input, 1, 5, 2, 3 ); 4490$entry_dir_input->set_sensitive($false); 4491$entry_dir_input->set('editable' => $false ); 4492$entry_dir_input->show; 4493 4494# Create Dir_Selection button 4495#$button = Gtk2::Button->new_from_stock ('gtk-open'); 4496$button = Gtk2::Button->new; 4497$button->add( DrawIcons('gtk-open','button') ); # 'button' is the size 4498 4499$tooltips->set_tip( $button, $langs{tip104} ) if $show_all_tooltips; 4500$button->signal_connect( "clicked", \&dir_selection ); 4501$table1->attach ($button, 5, 6, 2, 3, 'shrink', 'shrink', 0, 0); 4502$button->show_all; 4503# This makes it so the button is the default. 4504$button->can_default($true); 4505# This grabs this button to be the default button. Simply hitting the "Enter" 4506# key will cause this button to activate. 4507$button->grab_default; 4508$button->set( 'focus-on-click' => $false, 'relief' => 'none' ); 4509 4510#--------------- Output Directory -----------------# 4511 4512$label = new Gtk2::Label( $langs{name052} . ":" ); 4513$label->set_alignment( 1.0, 0.5 ); # right 4514$table1->attach ($label, 0, 1, 3, 4, 'fill', 'fill', 0, 0); 4515$label->show(); 4516 4517my $entry_dir_output = new Gtk2::Entry(); 4518if ( ! -e filename_from_unicode $directory_output ){ $directory_output = $home;} 4519$entry_dir_output->set_text( $directory_output ); 4520$tooltips->set_tip( $entry_dir_output, $directory_output ) if $show_all_tooltips; 4521$entry_dir_output->set('editable' => $false ); 4522$table1->attach_defaults ($entry_dir_output, 1, 5, 3, 4 ); 4523$entry_dir_output->show; 4524 4525$button = Gtk2::Button->new; 4526$button->add( DrawIcons('gtk-go-down','button') ); 4527$tooltips->set_tip( $button, $langs{tip105} ) if $show_all_tooltips; 4528$button->signal_connect( "clicked", \&dir_selection_output); 4529$button->set( 'focus-on-click' => $false, 'relief' => 'none' ); 4530$table1->attach ($button, 5, 6, 3, 4, 'shrink', 'shrink', 0, 0); 4531$button->show; 4532 4533#----------- Scrolling Label Viewport -------------# 4534#my $viewport_directory_input = scrolling_label_viewport( $directory, 60, 2); 4535#$table1->attach ( $viewport_directory_input, 1, 5, 2, 3, ['expand','fill'], 'shrink', 0, 0); 4536 4537#$table1->remove( $viewport_directory_output ); 4538#$viewport_directory_output = scrolling_label_viewport( $directory_output, 60, 2); 4539#$table1->attach( $viewport_directory_output, 1, 5, 3, 4, ['expand','fill'], 'shrink', 0, 0); 4540 4541my $timer_label; my $hadj; 4542sub scrolling_label_viewport { # not used 4543 my ($text, $interval, $incremental) = @_; 4544 4545 # $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 4546 $hadj = new Gtk2::Adjustment( 5, 1.0, 30.0, 1.0, 1.0, 50.0 ); 4547 4548 my $label = Gtk2::Label->new( $text ); 4549 $label->set_alignment(0.0, 0.5); 4550 $label->show; 4551 4552 # See <man Gtk2::Viewport> and Gtk2::Adjustment 4553 #widget = Gtk2::Viewport->new ($hadjustment=undef, $vadjustment=undef) 4554 my $viewport = Gtk2::Viewport->new($hadj, undef); 4555 $viewport->set_shadow_type('out'); 4556 $viewport->add ($label); 4557 $viewport->set_size_request(20,-1); 4558 $viewport->signal_connect ( 'enter-notify-event' => sub { 4559 if ( defined($timer_label) ){ Glib::Source->remove($timer_label);} # to not duplicate the MainLoop 4560 $timer_label = Glib::Timeout->add ($interval, \&scroll_label, $incremental); # see <man Glib::MainLoop> 4561 }); 4562 $viewport->signal_connect ( 'leave_notify_event' => sub { if ( defined $timer_label ){ Glib::Source->remove($timer_label); } } ); 4563 $viewport->set_events ([ @{ $viewport->get_events }, 'exposure-mask', 'enter-notify-mask', 'leave-notify-mask'] ); 4564 $viewport->show; 4565 return $viewport; #widget 4566} 4567 4568my $sign = 1; my $i=1; 4569sub scroll_label { 4570 my $incremental = shift; 4571 my $upper = $hadj->upper; 4572 my $page_size = $hadj->page_size; 4573 my $offset = $upper - $page_size; 4574 if ( $offset <= 0 ){ return; } 4575 my $x=$hadj->get_value; 4576 4577 if ( $x <= 0 or $x >= $offset ) { $sign = - $sign; } 4578 $i = $i + $sign * $incremental; 4579 4580 $hadj->set_value($i); 4581 #print "x = $x ; sign = $sign ; offset = $offset ; upper = $upper ; page_size = $page_size\n"; 4582 return $timer_label; 4583} 4584 4585# Output : Lossy Compression 4586# Output : Lossless Compression 4587# Output : Uncompressed 4588 4589 4590################-----Output--------################## Output : Lossy Compression 4591#######---------Lossy Compression-----------######### 4592 4593# veja: man perlnumber ou perlop ou man overload 4594 4595my $button_output_mp3 = new Gtk2::RadioButton( undef , "mp3"); 4596$tooltips->set_tip( $button_output_mp3, $langs{tip108} . "\n\n" . $langs{tip115} ) if $show_all_tooltips; 4597$table11->attach_defaults($button_output_mp3, 0, 1, 0, 1); 4598$button_output_mp3->signal_connect( "toggled", \&set_extension_output ); 4599$button_output_mp3->show; 4600 4601my $button_output_mp4 = new Gtk2::RadioButton( $button_output_mp3, "mp4"); 4602$tooltips->set_tip( $button_output_mp4, $langs{tip109} . "\n\n" . $langs{tip115} ) if $show_all_tooltips; 4603$table11->attach_defaults($button_output_mp4, 1, 2, 0, 1); 4604$button_output_mp4->signal_connect( "toggled", \&set_extension_output ); 4605$button_output_mp4->show; 4606 4607my $button_output_mpc = new Gtk2::RadioButton( $button_output_mp4, "mpc"); 4608$tooltips->set_tip( $button_output_mpc, $langs{tip110} . "\n\n" . $langs{tip115} ) if $show_all_tooltips; 4609$table11->attach_defaults($button_output_mpc, 0, 1, 1, 2); 4610$button_output_mpc->signal_connect( "toggled", \&set_extension_output ); 4611$button_output_mpc->show; 4612 4613my $button_output_ogg = new Gtk2::RadioButton( $button_output_mpc, "ogg"); 4614$tooltips->set_tip( $button_output_ogg, $langs{tip111} . "\n\n" . $langs{tip115} ) if $show_all_tooltips; 4615$table11->attach_defaults($button_output_ogg, 1, 2, 1, 2); 4616$button_output_ogg->signal_connect( "toggled", \&set_extension_output ); 4617$button_output_ogg->show; 4618 4619################-----Output--------################## Output : Lossless Compression 4620#######-------Lossless Compression----------######### 4621 4622# see /usr/share/doc/perl-Gtk2-doc/examples/assistant.pl for RadioButton 4623 4624my $button_output_ape = new Gtk2::RadioButton( $button_output_ogg, "ape"); 4625$tooltips->set_tip( $button_output_ape, $langs{tip112} . "\n\n" . $langs{tip116} ) if $show_all_tooltips; 4626$table12->attach_defaults($button_output_ape, 0, 1, 0, 1); 4627$button_output_ape->signal_connect( "toggled", \&set_extension_output ); 4628$button_output_ape->show; 4629 4630my $button_output_flac = new Gtk2::RadioButton( $button_output_ape, "flac"); 4631$tooltips->set_tip( $button_output_flac, $langs{tip113} . "\n\n" . $langs{tip116} ) if $show_all_tooltips; 4632$table12->attach_defaults($button_output_flac, 1, 2, 0, 1); 4633$button_output_flac->signal_connect( "toggled", \&set_extension_output ); 4634$button_output_flac->show; 4635 4636################-----Output--------################## Output : Uncompressed 4637#######------------Uncompressed-------------######### 4638 4639my $button_output_wav = new Gtk2::RadioButton( $button_output_flac, "wav"); 4640$tooltips->set_tip( $button_output_wav, $langs{tip114} ) if $show_all_tooltips; 4641$table13->attach_defaults($button_output_wav, 0, 1, 0, 1); 4642$button_output_wav->signal_connect( "toggled", \&set_extension_output ); 4643$button_output_wav->show; 4644 4645##----------------------------------------------------## 4646#####----------------T a b l e 2 ------------------##### 4647 4648$check_button_del_wav = Gtk2::CheckButton->new ( $langs{name009} ); 4649$check_button_del_wav->set_active($delete_wave); 4650$tooltips->set_tip( $check_button_del_wav, $langs{tip201} ) if $show_all_tooltips; 4651#$check_button_del_wav->set_alignment (6,0); 4652$table2->attach($check_button_del_wav, 0, 1, 0, 1, ['expand','fill'], 'shrink', 0, 0); 4653$check_button_del_wav->show; 4654 4655$check_button_tooltips = Gtk2::CheckButton->new ($langs{name057}); 4656$check_button_tooltips->set_active($show_all_tooltips); 4657$tooltips->set_tip( $check_button_tooltips, $langs{tip204} ."\n". $langs{tip502} ); 4658$table2->attach($check_button_tooltips, 1, 2, 0, 1, 'fill', 'shrink', 0, 0); 4659$check_button_tooltips->show; 4660 4661 4662$label = new Gtk2::Label( $langs{name012} . ":" ); 4663$label->set_alignment( 1.0, 0.5 ); 4664$table2->attach ($label, 2, 3, 0, 1, ['fill','expand'], 'shrink', 0, 0); 4665$label->show(); 4666 4667$adj = new Gtk2::Adjustment( $priority, 0, 19, 1, 0, 0 ); 4668$spinner_pri = new Gtk2::SpinButton( $adj, 0.1, 0 ); 4669$spinner_pri->set_editable($false); 4670$spinner_pri->set_size_request( 72, -1 ); 4671$spinner_pri->set_update_policy( 'if_valid' ); 4672$spinner_pri->set_wrap( $true ); 4673$tooltips->set_tip( $spinner_pri, $langs{tip206} ) if $show_all_tooltips; 4674$table2->attach($spinner_pri, 3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0); 4675$spinner_pri->show(); 4676 4677$check_change_properties = Gtk2::CheckButton->new ($langs{name010}); 4678$check_change_properties->set_active($change_properties); 4679$check_change_properties->signal_connect( "clicked", \&encode_choice_sensitive ); 4680$tooltips->set_tip( $check_change_properties, $langs{tip202} ) if $show_all_tooltips; 4681$table2->attach($check_change_properties, 0, 1, 1, 2, 'fill', 'fill', 0, 0); 4682$check_change_properties->show; 4683 4684$check_button_animation = Gtk2::CheckButton->new ( $langs{name055} ); 4685$check_button_animation->set_active($show_tux_animation); 4686$check_button_animation->signal_connect( "clicked", \&tux_animation_textview ); 4687$tooltips->set_tip( $check_button_animation, $langs{tip205} ) if $show_all_tooltips; 4688$table2->attach($check_button_animation, 1, 2, 1, 2, ['expand','fill'], 'shrink', 0, 0); 4689$check_button_animation->show; 4690 4691#####---------------------------------------------##### 4692 4693$check_button_overwrite = Gtk2::CheckButton->new ($langs{name011}); 4694$check_button_overwrite->set_active($overwrite); 4695$tooltips->set_tip( $check_button_overwrite, $langs{tip203} ) if $show_all_tooltips; 4696$table2->attach($check_button_overwrite, 0, 1, 2, 3, 'fill', 'fill', 0, 0); 4697$check_button_overwrite->show; 4698 4699#####---------------------------------------------##### 4700 4701$label = new Gtk2::Label( $langs{name014} . ":" ); 4702$label->set_alignment( 1.0, 0.5 ); 4703$table2->attach ($label, 2, 3, 1, 2, ['fill','expand'], 'shrink', 0, 0); 4704$label->show; 4705 4706$entry_format_cda = new Gtk2::Entry( ); 4707$entry_format_cda->set_text( $file_format_cda_rip ); 4708$tooltips->set_tip( $entry_format_cda, $langs{tip207} ) if $show_all_tooltips; 4709$table2->attach($entry_format_cda, 3, 4, 1, 2, ['fill','expand'], 'shrink', 0, 0); 4710$entry_format_cda->show; 4711 4712#####---------------------------------------------##### 4713 4714$label = new Gtk2::Label( "Comment Tag" . ":" ); 4715$label->set_alignment( 1.0, 0.5 ); 4716$table2->attach ($label, 2, 3, 2, 3, ['fill','expand'], 'shrink', 0, 0); 4717$label->show; 4718 4719$entry_def_comment = new Gtk2::Entry; # see 'sub normalize' 4720$entry_def_comment->set_text( $comment_tag ); 4721$tooltips->set_tip( $entry_def_comment, $langs{tip250} ) if $show_all_tooltips; 4722$table2->attach($entry_def_comment, 3, 4, 2, 3, ['fill','expand'], 'shrink', 0, 0); 4723$entry_def_comment->show; 4724 4725##----------------------------------------------------## 4726#####---------------T a b l e 202 -----------------##### 4727 4728#####--------------------Combo---------------------##### 4729 4730# criar um label (etiqueta - r�tulo) ao lado do menu 4731$label = new Gtk2::Label( $langs{name015} . ":" ); 4732$label->set_alignment( 1.0, 0.5 ); 4733$table202->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0); 4734$label->show(); 4735 4736my @all_encodings = Encode->encodings(":all"); # see <man Encode> 4737#print ("Encode list = @all_encodings\n"); 4738 4739$ComboBox_char = Gtk2::ComboBox->new_text; 4740#foreach (@all_encodings) { $ComboBox_char->append_text ($_); } 4741#$pos = 0; foreach my $key (@all_encodings) { if ($key eq $id3tag_character) {$ComboBox_char->set_active($pos); last;} $pos++; } 4742ComboBox_fill_with_array(\$ComboBox_char,\@all_encodings); 4743ComboBox_select_this_text(\$ComboBox_char,\@all_encodings,\$id3tag_character); 4744$ComboBox_char->set_size_request( 90, -1 ); 4745$ComboBox_char->signal_connect("changed", \&ComboBox_choice,\$id3tag_character); 4746$table202->attach ($ComboBox_char, 1, 2, 0, 1, ['expand','fill'], 'shrink', 0, 0); 4747$tooltips->set_tip( $ComboBox_char, $langs{tip229} ) if $show_all_tooltips; # "Used to encode ID3v2.3.0 Tag for MP3 files." 4748$ComboBox_char->show; 4749 4750sub ComboBox_choice { # see 'sub player_choice' 4751 my ($ComboBox_copy, $scalar_ref) = @_; 4752 my $char = $ComboBox_copy->get_active_text; 4753 4754 $$scalar_ref = $char; 4755 #print "\nComboBox_copy = $ComboBox_copy ;; \n\$scalar_ref = $scalar_ref ;; scalar_ref value = $$scalar_ref \n"; 4756} 4757 4758sub ComboBox_fill_with_array { 4759 my ($ref_ComboBox, $ref_array) = @_; 4760 $$ref_ComboBox->remove_text(0) while ( $$ref_ComboBox->get_active >= 0 ); # remove all old values 4761 $$ref_ComboBox->append_text($_) foreach (@$ref_array); 4762} 4763 4764sub ComboBox_select_this_text { 4765 my ($ref_ComboBox, $ref_array, $ref_val) = @_; # the selected text is $ref_val 4766 return if ( not defined $$ref_val or @$ref_array <= 0 ); # print "ref_val = $$ref_val \n"; 4767 4768 my $index = 0; 4769 foreach my $key (@$ref_array) { if ($key eq $$ref_val) {$$ref_ComboBox->set_active($index); last;} $index++; } 4770 4771 # if no one selection, then select the first array element 4772 if ($$ref_ComboBox->get_active < 0 and @$ref_array > 0){ 4773 $$ref_ComboBox->set_active(0); # print "antes ref_val = $$ref_val \n"; 4774 $$ref_val = $$ref_ComboBox->get_active_text; # print "depois ref_val = $$ref_val \n"; 4775 } 4776} 4777 4778#####-------------------final of Combo-------------##### 4779 4780#####--------------------Combo---------------------##### 4781 4782$label = new Gtk2::Label( $langs{name029} . ":" ); 4783$label->set_alignment( 1.0, 0.5 ); 4784$table202->attach ($label, 0, 1, 1, 2, 'fill', 'shrink', 0, 0); 4785$label->show; 4786 4787my @rippers = ( "cdparanoia", "cdda2wav" ); 4788 4789$ComboBox_rip = Gtk2::ComboBox->new_text; 4790ComboBox_fill_with_array(\$ComboBox_rip,\@rippers); 4791#ComboBox_set_popdown_strings($ComboBox_rip,@rippers); 4792ComboBox_select_this_text(\$ComboBox_rip,\@rippers,\$ripper); 4793$ComboBox_rip->set_size_request( 90, -1 ); 4794$ComboBox_rip->signal_connect("changed", \&ripperChanged); 4795$table202->attach ($ComboBox_rip, 1, 2, 1, 2, ['expand','fill'], 'shrink', 0, 0); 4796$ComboBox_rip->show; 4797 4798sub ripperChanged { 4799 my ($ComboBox_copy) = @_; 4800 $ripper = $ComboBox_copy->get_active_text; 4801 4802 if ($ripper eq "cdparanoia"){ 4803 $notebook2->remove_page (3); 4804 $notebook2->append_page_menu ( $frame204, $label_ripper, undef ); 4805 change_font_for_all_child($window_font_name,$frame204); 4806 } 4807 if ($ripper eq "cdda2wav"){ 4808 $notebook2->remove_page (3); 4809 $notebook2->append_page_menu ( $frame205, $label_ripper, undef ); 4810 change_font_for_all_child($window_font_name,$frame205); 4811 } 4812} 4813 4814#####-------------------final of Combo-------------##### 4815 4816#####--------------------Combo---------------------##### 4817 4818$label = new Gtk2::Label( $langs{name064} . ":" ); 4819$label->set_alignment( 1.0, 0.5 ); 4820$table202->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0); 4821$label->show; 4822 4823my @all_cdplayer; 4824 4825sub Make_ComboBox_cdplayer { # See the cdplayer_available() subroutine to search the cdplayer 4826 my $ComboBox_cdplayer = Gtk2::ComboBox->new_text; 4827 ComboBox_fill_with_array(\$ComboBox_cdplayer,\@all_cdplayer); 4828 ComboBox_select_this_text(\$ComboBox_cdplayer,\@all_cdplayer,\$cdplayer); 4829 $ComboBox_cdplayer->signal_connect("changed", \&cdplayerChanged); 4830 $table202->attach ($ComboBox_cdplayer, 1, 2, 2, 3, ['expand','fill'], 'shrink', 0, 0); 4831 $ComboBox_cdplayer->show; 4832} 4833 4834sub cdplayerChanged { ## choose cdplayer 4835 my ($ComboBox_copy) = @_; 4836 $cdplayer = $ComboBox_copy->get_active_text; # $cdplayer = "gnormalize::cdplay", "Audio::CD", "cdcd" 4837 # print "cdplayer = $cdplayer\n"; 4838 4839 if ( $cdplayer eq "Audio::CD" and $use_audiocd ){ # see <man Audio::CD> 4840 $audiocd = Audio::CD->init("$audiodevice_path"); 4841 $have_current_track = audio_cd_have_current_track($audiodevice_path); 4842 } 4843} 4844 4845#####-------------------final of Combo-------------##### 4846 4847#------------------------- Font -----------------------# 4848# criar um label (etiqueta - r�tulo) ao lado do menu 4849$label = new Gtk2::Label( $langs{name017} . ":" ); 4850$label->set_alignment( 1.0, 0.5 ); 4851$table202->attach ($label, 2, 3, 0, 1, 'fill', 'shrink', 0, 0); 4852$label->show; 4853 4854# Build the font-button 4855$button_font = Gtk2::Button->new($window_font_name); 4856$button_font->signal_connect( 'clicked', \&window_select_font ); 4857#$button_font->signal_connect( 'clicked', \&gnome_font); 4858$table202->attach ($button_font, 3, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0); 4859$tooltips->set_tip( $button_font, $langs{tip208} ) if $show_all_tooltips; 4860$button_font->set_sensitive($true); 4861$button_font->show; 4862 4863#------------------------------------------------------# 4864 4865# my $widget = Glib::Object->new( veja histogram 4866my $window_bg_color = color_bg($window); 4867#print "window_bg_color = $window_bg_color \n"; #E6E7E6 4868 4869# return the background color of widget in hexdecimal format 4870sub color_bg { # not used 4871 my ( $widget ) = @_; 4872 my $color; 4873 my $red; 4874 my $green; 4875 my $blue; 4876 4877 # see man Gtk2::Style 4878 $red = $widget->get_style->bg('normal')->red; 4879 $green = $widget->get_style->bg('normal')->green; 4880 $blue = $widget->get_style->bg('normal')->blue; 4881 4882 # Convert to HTML format. There are better ways to do this. 4883 # uc: Returns an uppercased version of EXPR. 4884 # %x an unsigned integer, in hexadecimal ; l: long 4885 $red = uc( sprintf( "%02lx", $red/256 ) ); #print "red = $red\n"; 4886 $green = uc( sprintf( "%02lx", $green/256 ) ); 4887 $blue = uc( sprintf( "%02lx", $blue/256 ) ); 4888 4889 $color = "#$red$green$blue"; # print "color = $color\n"; # like #E6E7E6 4890 return $color; 4891} 4892 4893sub window_select_font { 4894 my $widget = $label; 4895 4896 # repair the standard cancel label 4897 my @items = ( { stock_id => "gtk-cancel", label => "_Cancel" } ); 4898 Gtk2::Stock->add (@items); # Register our stock items 4899 4900 my $fsd = Gtk2::FontSelectionDialog->new ('Font Selection Dialog'); 4901 $fsd->set_position('mouse'); 4902 $fsd->set_preview_text('abcdefghijk ABCDEFGHIJK 1234567890'); 4903 4904 my $original_font_name = $widget->get_style->font_desc->to_string; 4905 $fsd->set_font_name ($original_font_name); 4906 #print "original_font_name = $original_font_name\n"; 4907 4908 $fsd->signal_connect ('response' => sub { 4909 my (undef, $response) = @_; 4910 if ($response eq 'ok') { 4911 my $font_name = $fsd->get_font_name; 4912 return unless $font_name; 4913 $button_font->set_label($font_name); 4914 change_font_for_all_child($font_name, $window); 4915 $window_font_name = $font_name; 4916 #print "aquui -> window_font_name = $window_font_name\n"; 4917 } 4918 $fsd->destroy; 4919 }); 4920 4921 $fsd->show; 4922} 4923 4924sub change_font_for_all_child { 4925 my $font_name = shift || 'Sans 10'; 4926 my $container = shift || $window; 4927 4928 my $font_desc = Gtk2::Pango::FontDescription->from_string($font_name); 4929 4930 # notebook: notebook labels 4931 $label_data->modify_font($font_desc); $label_config->modify_font($font_desc); 4932 $label_info->modify_font($font_desc); $label_rip->modify_font($font_desc); 4933 $label_about->modify_font($font_desc); 4934 4935 # notebook2: notebook labels 4936 $label_option1->modify_font($font_desc); $label_option2->modify_font($font_desc); 4937 $label_cddb->modify_font($font_desc); $label_ripper->modify_font($font_desc); 4938 4939 # TreeViewColumn : treeview_play 4940 my @cols = $treeview_play->get_columns; # Retuns an array of columns. 4941 foreach my $col (@cols){ 4942 # list = $tree_column->get_cell_renderers ; see <man Gtk2::TreeViewColumn> 4943 my $renderer = $col->get_cell_renderers; 4944 next if ($renderer =~ /Toggle/); 4945 $renderer->set ('font' => $font_name); 4946 } 4947 $renderer_track->set ('font' => $font_name, 'xalign' => 0.5) if $renderer_track; 4948 $renderer_artist->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_artist; 4949 $renderer_title->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_title; 4950 $renderer_album->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_album; 4951 4952 # TreeViewColumn : treeview_album 4953 $renderer_album_playlist->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_album_playlist; 4954 $renderer_album_play_count->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_album_play_count; 4955 # TreeViewColumn : treeview_artist 4956 $renderer_artist_playlist->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_artist_playlist; 4957 $renderer_artist_play_count->set ('font' => $font_name, style => 'italic', scale => '0.9') if $renderer_artist_play_count; 4958 4959 foreach my $child0 ($container->get_children) { 4960 if (not child_has_child ($font_desc, $child0) ) { next; } 4961 foreach my $child1 ($child0->get_children) { 4962 if (not child_has_child ($font_desc, $child1) ) { next; } 4963 foreach my $child2 ($child1->get_children) { 4964 if (not child_has_child ($font_desc, $child2) ) { next; } 4965 foreach my $child3 ($child2->get_children) { 4966 if (not child_has_child ($font_desc, $child3) ) { next; } 4967 foreach my $child4 ($child3->get_children) { 4968 if (not child_has_child ($font_desc, $child4) ) { next; } 4969 foreach my $child5 ($child4->get_children) { 4970 if (not child_has_child ($font_desc, $child5) ) { next; } 4971 foreach my $child6 ($child5->get_children) { 4972 if (not child_has_child ($font_desc, $child6) ) { next; } 4973 foreach my $child7 ($child6->get_children) { 4974 if (not child_has_child ($font_desc, $child7) ) { next; } 4975 foreach my $child8 ($child7->get_children) { 4976 if (not child_has_child ($font_desc, $child8) ) { next; } 4977 foreach my $child9 ($child8->get_children) { 4978 if (not child_has_child ($font_desc, $child9) ) { next; } 4979 $child9->modify_font($font_desc); 4980 } 4981 } 4982 } 4983 } 4984 } 4985 } 4986 } 4987 } 4988 } 4989 } 4990 4991} 4992 4993sub child_has_child { 4994 my $font_desc = shift; 4995 my $child = shift; 4996 # Don't change the font of this widget child, so don't search for its child 4997 if ( $child =~ /(Gtk2::Label|Gtk2::SpinButton|Gtk2::Entry|Gtk2::HSeparator|Gtk2::AccelLabel|Gtk2::TextView)/i or 4998 $child =~ /(Gtk2::HSeparator|Gtk2::ProgressBar|Gtk2::DrawingArea|Gtk2::Image|Gtk2::Arrow|Gtk2::ComboBox)/i ){ 4999 $child->modify_font($font_desc); 5000 return $false; 5001 } 5002 return $true; 5003} 5004 5005sub gnome_font { # not more used 5006 exec_cmd_system2("gnome-font-properties"); 5007 $change_fonte = $true; 5008 $change_fonte_norm = $true; 5009 $change_font_layout = $true; 5010 $change_font_rand = $true; 5011} 5012 5013# change_font_for_all_child($window_font_name); # change the font at the end 5014 5015##-------------------------------------------------------## 5016#####----------------- T a b l e 203 -----------------##### 5017 5018$check_button_cddb = Gtk2::CheckButton->new ( $langs{name018} ); 5019$check_button_cddb->set_active($discDB); 5020$check_button_cddb->signal_connect( "clicked", \&cddb_sensitive ); 5021$tooltips->set_tip( $check_button_cddb, $langs{tip209} ) if $show_all_tooltips; 5022$table203->attach($check_button_cddb, 0, 1, 0, 1, 'fill', 'shrink', 0, 0); 5023$check_button_cddb->show; 5024 5025$check_button_overwrite_cddb = Gtk2::CheckButton->new ( $langs{name019} ); 5026$check_button_overwrite_cddb->set_active($overwrite_cddb); 5027$tooltips->set_tip( $check_button_overwrite_cddb, $langs{tip210} ) if $show_all_tooltips; 5028$table203->attach($check_button_overwrite_cddb, 1, 2, 0, 1, 'fill', 'shrink', 0, 0); 5029$check_button_overwrite_cddb->show; 5030 5031$label = new Gtk2::Label( $langs{name020} . ":" ); 5032$label->set_alignment( 1.0, 0.5 ); 5033$table203->attach ($label, 0, 1, 1, 2, 'fill', 'shrink', 0, 0); 5034$label->show(); 5035 5036$entry_CDDB_server = new Gtk2::Entry( ); 5037$entry_CDDB_server->set_text( $CDDB_server ); 5038$tooltips->set_tip( $entry_CDDB_server, $langs{tip211} ) if $show_all_tooltips; 5039$table203->attach($entry_CDDB_server, 1, 2, 1, 2, ['fill','expand'], 'fill', 0, 0); 5040$entry_CDDB_server->show; 5041 5042$label = new Gtk2::Label( $langs{name021} . ":" ); 5043$label->set_alignment( 1.0, 0.5 ); 5044$table203->attach ($label, 2, 3, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5045$label->show(); 5046 5047$adj = new Gtk2::Adjustment( $cddb_port, 0, 9999, 1, 0, 0 ); 5048$spinner_cddb_port = new Gtk2::SpinButton( $adj, 0.9, 0 ); 5049$spinner_cddb_port->set_editable($true); 5050$spinner_cddb_port->set_size_request( 72, -1 ); 5051$spinner_cddb_port->set_update_policy( 'if_valid' ); 5052$spinner_cddb_port->set_wrap( $false ); 5053$tooltips->set_tip( $spinner_cddb_port, $langs{tip212} ) if $show_all_tooltips; 5054$table203->attach($spinner_cddb_port, 3, 4, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5055$spinner_cddb_port->show(); 5056 5057$label = new Gtk2::Label( $langs{name022} . ":" ); 5058$label->set_alignment( 1.0, 0.5 ); 5059$table203->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0); 5060$label->show(); 5061 5062#####--------------------Combo---------------------##### 5063 5064my @transport = ( "cddb", "http" ); 5065 5066my $ComboBox_cddb_transport = Gtk2::ComboBox->new_text; 5067foreach (@transport) { $ComboBox_cddb_transport->append_text ($_); } 5068$pos = 0; 5069foreach my $key (@transport) { if ($key eq $cddb_transport) {$ComboBox_cddb_transport->set_active($pos); last;} $pos++; } 5070$ComboBox_cddb_transport->signal_connect("changed", \&ComboBox_choice, \$cddb_transport); 5071$table203->attach ($ComboBox_cddb_transport, 1, 2, 2, 3, 'fill', 'shrink', 0, 0); 5072$ComboBox_cddb_transport->show; 5073 5074#####-------------------final of Combo-------------##### 5075 5076sub cddb_sensitive{ 5077 if ($check_button_cddb->get_active ){ 5078 $check_button_overwrite_cddb->set_sensitive ($true); 5079 $entry_CDDB_server->set_sensitive ($true); 5080 $spinner_cddb_port->set_sensitive ($true); 5081 $ComboBox_cddb_transport->set_sensitive ($true); 5082 } 5083 else{ 5084 $check_button_overwrite_cddb->set_sensitive ($false); 5085 $entry_CDDB_server->set_sensitive ($false); 5086 $spinner_cddb_port->set_sensitive ($false); 5087 $ComboBox_cddb_transport->set_sensitive ($false); 5088 } 5089} 5090cddb_sensitive(); 5091 5092##-------------------------------------------------------## 5093#####----------------- T a b l e 204 -----------------##### 5094 5095$button_noia1 = Gtk2::CheckButton->new ( $langs{name023} ); 5096$button_noia1->set_active($disable_paranoia); 5097$tooltips->set_tip( $button_noia1, $langs{tip213} ) if $show_all_tooltips; 5098$table204->attach($button_noia1, 0, 1, 0, 1, ['fill','expand'], 'shrink', 0, 0); 5099$button_noia1->show; 5100 5101$button_noia2 = Gtk2::CheckButton->new ( $langs{name026} ); 5102$button_noia2->set_active($never_skip_repair); 5103$tooltips->set_tip( $button_noia2, $langs{tip214} ) if $show_all_tooltips; 5104$table204->attach($button_noia2, 1, 2, 0, 1, ['fill','expand'], 'shrink', 0, 0); 5105$button_noia2->show; 5106 5107$button_noia3 = Gtk2::CheckButton->new ( $langs{name024} ); 5108$button_noia3->set_active($disable_extra_paranoia); 5109$tooltips->set_tip( $button_noia3, $langs{tip215} ) if $show_all_tooltips; 5110$table204->attach($button_noia3, 0, 1, 1, 2, ['fill','expand'], 'shrink', 0, 0); 5111$button_noia3->show; 5112 5113$button_noia4 = Gtk2::CheckButton->new ( $langs{name025} ); 5114$button_noia4->set_active($abort_on_skip); 5115$tooltips->set_tip( $button_noia4, $langs{tip216} ) if $show_all_tooltips; 5116$table204->attach($button_noia4, 0, 1, 2, 3, ['fill','expand'], 'shrink', 0, 0); 5117$button_noia4->show; 5118 5119##-------------------------------------------------------## 5120#####----------------- T a b l e 205 -----------------##### 5121 5122$button_cdda1 = Gtk2::CheckButton->new ("paranoia"); 5123$button_cdda1->set_active($paranoia); 5124$tooltips->set_tip( $button_cdda1, $langs{tip217} ) if $show_all_tooltips; 5125$table205->attach($button_cdda1, 0, 1, 0, 1, ['fill','expand'], 'shrink', 0, 0); 5126$button_cdda1->show; 5127 5128$button_cdda2 = Gtk2::CheckButton->new ( $langs{name028} ); 5129$button_cdda2->set_active($paranoia_disable); 5130$tooltips->set_tip( $button_cdda2, $langs{tip218} ) if $show_all_tooltips; 5131$table205->attach($button_cdda2, 1, 2, 0, 1, ['fill','expand'], 'shrink', 0, 0); 5132$button_cdda2->show; 5133 5134$button_cdda3 = Gtk2::CheckButton->new ( $langs{name027} ); 5135$button_cdda3->set_active($paranoia_no_verify); 5136$tooltips->set_tip( $button_cdda3, $langs{tip219} ) if $show_all_tooltips; 5137$table205->attach($button_cdda3, 0, 1, 1, 2, ['fill','expand'], 'shrink', 0, 0); 5138$button_cdda3->show; 5139 5140 5141###-----------------------------------------------------### 5142#####----------------T a b l e 21 --------------------##### 5143 5144# criar um label (etiqueta - r�tulo) ao lado do menu 5145$label = new Gtk2::Label( $langs{name030} . ":" ); 5146$label->set_alignment( 1.0, 0.5 ); 5147$table21->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0); 5148$label->show(); 5149 5150#####--------------------Combo---------------------##### 5151 5152my @encode_type_mp3 = ( "average", "constant", "variable" ); 5153my @encode_type_mp4 = ( "average", "variable" ); 5154my @encode_type_ogg = ( "average", "variable" ); 5155my @encode_type_mpc = ( "variable" ); 5156# The hash %encode_type save the last encode type 5157 5158my $model_encode = Gtk2::ListStore->new ('Glib::String'); 5159foreach (@encode_type_mp3) { $model_encode->set ($model_encode->append, 0, $_); } # fill model 5160 5161 5162$ComboBox_encode_type = Gtk2::ComboBox->new ($model_encode); 5163 5164my $renderer = Gtk2::CellRendererPixbuf->new; 5165$ComboBox_encode_type->pack_start ($renderer, $false); 5166$ComboBox_encode_type->add_attribute ($renderer, stock_id => 0); 5167$renderer = Gtk2::CellRendererText->new; 5168$ComboBox_encode_type->pack_start ($renderer, $true); 5169$ComboBox_encode_type->add_attribute ($renderer, text => 0); 5170 5171#ComboBox_fill_with_array(\$ComboBox_encode_type,\@encode_type_mp3); 5172ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_mp3); 5173ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_mp3,\$encode_type{'mp3'}); 5174 5175$table21->attach($ComboBox_encode_type, 1, 2, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5176$ComboBox_encode_type->signal_connect("changed", \&encode_choice,$ComboBox_encode_type); 5177$ComboBox_encode_type->set_sensitive($change_properties); 5178$ComboBox_encode_type->show; 5179 5180sub ComboBox_set_popdown_strings { 5181 my ($ComboBox_copy, @array) = @_; 5182 return if ($ComboBox_copy->get_active < 0); # return if empty 5183 5184 $ComboBox_copy->get_model->clear; # $model->clear ;; remove all old values 5185 foreach (@array) { $model_encode->set ($model_encode->append, 0, $_); } # fill the model with new values 5186} 5187 5188## encode type: constant, average or variable bitrate ;; show or hide some widgets 5189sub encode_choice { 5190 my ($self, $ComboBox_copy) = @_; 5191 return if ($ComboBox_copy->get_active < 0); # return if empty 5192 $encode = $ComboBox_copy->get_active_text; 5193 #print "\n---> \$encode = $encode\n"; 5194 5195 encode_choice_sensitive(); 5196 $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate." ); 5197 5198 # set the last encode type 5199 if ($button_output_mp3->get_active ){$encode_type{'mp3'} = $encode;} 5200 if ($button_output_mp4->get_active ){$encode_type{'mp4'} = $encode;} 5201 if ($button_output_ogg->get_active ){$encode_type{'ogg'} = $encode;} 5202 if ($button_output_mpc->get_active ){$encode_type{'mpc'} = $encode;} 5203 5204 #foreach my $k (sort keys %encode_type){ print "$k => $encode_type{$k}\n"; } 5205} 5206 5207# Set widget sensitive according to encoder choice 5208sub encode_choice_sensitive { 5209 #$encode = $ComboBox_encode_type->get_active_text; # refresh $encode value 5210 5211 $vb_Max = $ComboBox_Max->get_active_text;; #refresh value 5212 $vb_Min = $ComboBox_Min->get_active_text; 5213 5214 if ($button_output_mp3->get_active ){ 5215 if ( $check_change_properties->get_active){ 5216 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);} 5217 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);} 5218 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);} 5219 } 5220 else{ 5221 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);} 5222 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);} 5223 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);} 5224 } 5225 } 5226 if ($button_output_mp4->get_active ){ 5227 if ( $check_change_properties->get_active){ 5228 if ( $encode eq "average" ) { encode_sensitive(1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,2,3,1,2);} 5229 if ( $encode eq "variable" ){ encode_sensitive(1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,2,3,1,2);} 5230 } 5231 else{ encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,1,2); } 5232 } 5233 if ($button_output_ogg->get_active ){ 5234 if ( $check_change_properties->get_active){ 5235 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);} 5236 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);} 5237 } 5238 else{ encode_sensitive(0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,3,4,1,4); } 5239 } 5240 if ($button_output_mpc->get_active ){ 5241 if ( $check_change_properties->get_active){ 5242 encode_sensitive(1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0,3); } 5243 else{ encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,3); } 5244 } 5245 if ($button_output_ape->get_active ){ 5246 if ( $check_change_properties->get_active){ 5247 encode_sensitive(0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,5,2,5); } 5248 else{ encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,2,5); } 5249 } 5250 if ($button_output_flac->get_active ){ 5251 if ( $check_change_properties->get_active){ 5252 encode_sensitive(0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,6,2,6); } 5253 else{ encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6,2,6); } 5254 } 5255 if ($button_output_wav->get_active ){ 5256 encode_sensitive(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,1,7); 5257 } 5258 5259 if ($button_output_mp3->get_active){ 5260 if ( not $check_change_properties->get_active){ 5261 if ( $bitrate_average ){ $status_bar->push($context_id, $langs{msg065}."$extension_output with average bitrate.");} 5262 else { $status_bar->push($context_id, $langs{msg065}."$extension_output with constant bitrate.");} 5263 } 5264 else { $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate.");} 5265 } 5266 if ($button_output_mp4->get_active){ 5267 if ( not $check_change_properties->get_active){ 5268 { $status_bar->push($context_id, $langs{msg065}."$extension_output with average bitrate.");} 5269 } 5270 else { $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate.");} 5271 } 5272 if ($button_output_ogg->get_active){ 5273 if ( not $check_change_properties->get_active){ 5274 { $status_bar->push($context_id, $langs{msg065}."$extension_output with average bitrate.");} 5275 } 5276 else { $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate.");} 5277 } 5278 if ($button_output_mpc->get_active){ 5279 $status_bar->push($context_id, $langs{msg065}."$extension_output with $encode bitrate."); 5280 } 5281 if ($button_output_ape->get_active){ 5282 my $comp_ape = $spinner_compress->get_value_as_int(); 5283 $status_bar->push($context_id, $langs{msg065}."$extension_output with compression level = $comp_ape."); 5284 } 5285 if ($button_output_flac->get_active){ 5286 my $comp_flac = $spinner_compress_flac->get_value(); 5287 $status_bar->push($context_id, $langs{msg065}."$extension_output with compression level = $comp_flac."); 5288 } 5289 if ($button_output_wav->get_active){ 5290 $status_bar->push($context_id, $langs{msg065}."$extension_output without compression."); 5291 } 5292 5293} 5294 5295sub encode_sensitive { # there are 20 widget - the order is important 5296 my $opt1 = shift; my $opt2 = shift; my $opt3 = shift; my $opt4 = shift; 5297 my $opt5 = shift; my $opt6 = shift; my $opt7 = shift; my $opt8 = shift; 5298 my $opt9 = shift; my $opt10 = shift; my $opt11 = shift; my $opt12 = shift; 5299 my $opt13 = shift; my $opt14 = shift; my $opt15 = shift; my $opt16 = shift; 5300 my $opt17 = shift; my $opt18 = shift; my $opt19 = shift; my $opt20 = shift; 5301 $ComboBox_encode_type->set_sensitive($opt1); 5302 $ComboBox_const_bitrate->set_sensitive($opt2); 5303 $spinner_bitrate_mp3->set_sensitive($opt3); 5304 $spinner_bitrate_mp4->set_sensitive($opt4); 5305 $spinner_bitrate_ogg->set_sensitive($opt5); 5306 $spinner_compress->set_sensitive($opt6); 5307 $spinner_compress_flac->set_sensitive($opt7); 5308 $ComboBox_Min->set_sensitive($opt8); 5309 $ComboBox_mode->set_sensitive($opt9); 5310 $spinner_V->set_sensitive($opt10); 5311 $spinner_Vmp4->set_sensitive($opt11); 5312 $spinner_Vogg->set_sensitive($opt12); 5313 $spinner_Vmpc->set_sensitive($opt13); 5314 $ComboBox_Max->set_sensitive($opt14); 5315 $spinner_q->set_sensitive($opt15); 5316 $ComboBox_freq->set_sensitive($opt16); 5317 if ($opt17 == 1){ 5318 $spinner_V->show; 5319 $spinner_Vmp4->hide; 5320 $spinner_Vogg->hide; 5321 $spinner_Vmpc->hide; 5322 } 5323 if ($opt17 == 2){ 5324 $spinner_V->hide; 5325 $spinner_Vmp4->show; 5326 $spinner_Vogg->hide; 5327 $spinner_Vmpc->hide; 5328 } 5329 if ($opt17 == 3){ 5330 $spinner_V->hide; 5331 $spinner_Vmp4->hide; 5332 $spinner_Vogg->show; 5333 $spinner_Vmpc->hide; 5334 } 5335 if ($opt17 == 4){ 5336 $spinner_V->hide; 5337 $spinner_Vmp4->hide; 5338 $spinner_Vogg->hide; 5339 $spinner_Vmpc->show; 5340 } 5341 if ($opt18 == 1){ 5342 $ComboBox_const_bitrate->show; 5343 $spinner_bitrate_mp3->hide; 5344 $spinner_bitrate_mp4->hide; 5345 $spinner_bitrate_ogg->hide; 5346 $spinner_compress->hide; 5347 $spinner_compress_flac->hide; 5348 } 5349 if ($opt18 == 2){ 5350 $ComboBox_const_bitrate->hide; 5351 $spinner_bitrate_mp3->show; 5352 $spinner_bitrate_mp4->hide; 5353 $spinner_bitrate_ogg->hide; 5354 $spinner_compress->hide; 5355 $spinner_compress_flac->hide; 5356 } 5357 if ($opt18 == 3){ # mp4 5358 $ComboBox_const_bitrate->hide; 5359 $spinner_bitrate_mp3->hide; 5360 $spinner_bitrate_mp4->show; 5361 $spinner_bitrate_ogg->hide; 5362 $spinner_compress->hide; 5363 $spinner_compress_flac->hide; 5364 } 5365 if ($opt18 == 4){ # ogg 5366 $ComboBox_const_bitrate->hide; 5367 $spinner_bitrate_mp3->hide; 5368 $spinner_bitrate_mp4->hide; 5369 $spinner_bitrate_ogg->show; 5370 $spinner_compress->hide; 5371 $spinner_compress_flac->hide; 5372 } 5373 if ($opt18 == 5){ 5374 $ComboBox_const_bitrate->hide; 5375 $spinner_bitrate_mp3->hide; 5376 $spinner_bitrate_mp4->hide; 5377 $spinner_bitrate_ogg->hide; 5378 $spinner_compress->show; 5379 $spinner_compress_flac->hide; 5380 } 5381 if ($opt18 == 6){ 5382 $ComboBox_const_bitrate->hide; 5383 $spinner_bitrate_mp3->hide; 5384 $spinner_bitrate_mp4->hide; 5385 $spinner_bitrate_ogg->hide; 5386 $spinner_compress->hide; 5387 $spinner_compress_flac->show; 5388 } 5389 if ($opt19 == 1){ 5390 $label_mp3b->show; 5391 $label_comp->hide; 5392 } 5393 if ($opt19 == 2){ 5394 $label_mp3b->hide; 5395 $label_comp->show; 5396 } 5397 if ($opt20 == 1){ 5398 $entry_command_mp3->show; 5399 $entry_command_mp4->hide; 5400 $entry_command_mpc->hide; 5401 $entry_command_ogg->hide; 5402 $entry_command_ape->hide; 5403 $entry_command_flac->hide; 5404 } 5405 if ($opt20 == 2){ # mp4 5406 $entry_command_mp3->hide; 5407 $entry_command_mp4->show; 5408 $entry_command_mpc->hide; 5409 $entry_command_ogg->hide; 5410 $entry_command_ape->hide; 5411 $entry_command_flac->hide; 5412 } 5413 if ($opt20 == 3){ # mpc 5414 $entry_command_mp3->hide; 5415 $entry_command_mp4->hide; 5416 $entry_command_mpc->show; 5417 $entry_command_ogg->hide; 5418 $entry_command_ape->hide; 5419 $entry_command_flac->hide; 5420 } 5421 if ($opt20 == 4){ # ogg 5422 $entry_command_mp3->hide; 5423 $entry_command_mp4->hide; 5424 $entry_command_mpc->hide; 5425 $entry_command_ogg->show; 5426 $entry_command_ape->hide; 5427 $entry_command_flac->hide; 5428 } 5429 if ($opt20 == 5){ 5430 $entry_command_mp3->hide; 5431 $entry_command_mp4->hide; 5432 $entry_command_mpc->hide; 5433 $entry_command_ogg->hide; 5434 $entry_command_ape->show; 5435 $entry_command_flac->hide; 5436 } 5437 if ($opt20 == 6){ #flac 5438 $entry_command_mp3->hide; 5439 $entry_command_mp4->hide; 5440 $entry_command_mpc->hide; 5441 $entry_command_ogg->hide; 5442 $entry_command_ape->hide; 5443 $entry_command_flac->show; 5444 } 5445 if ($opt20 == 7){ #wav 5446 $entry_command_mp3->hide; 5447 $entry_command_mp4->hide; 5448 $entry_command_mpc->hide; 5449 $entry_command_ogg->hide; 5450 $entry_command_ape->hide; 5451 $entry_command_flac->hide; 5452 } 5453} 5454 5455#####-------------------final of Combo-------------##### 5456 5457# criar um label (etiqueta - r�tulo) ao lado do menu 5458$label_mp3b = new Gtk2::Label( "Bitrate:" ); 5459$label_mp3b->set_alignment( 1, 0.5 ); 5460$table21->attach ($label_mp3b, 4, 5, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5461$label_mp3b->show(); 5462 5463$label_comp = new Gtk2::Label( "Comp:" ); 5464$label_comp->set_alignment( 1, 0.5 ); 5465$table21->attach ($label_comp, 4, 5, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5466#$label_comp->show(); 5467 5468#####--------------------ComboBox------------------##### 5469my @all_const_bitrate = ( "32", "40", "48", "56", "64", "80", "96", "112", "128", "160", "192", "224", "256", "320" ); 5470 5471$ComboBox_const_bitrate = Gtk2::ComboBox->new_text; 5472ComboBox_fill_with_array(\$ComboBox_const_bitrate,\@all_const_bitrate); 5473ComboBox_select_this_text(\$ComboBox_const_bitrate,\@all_const_bitrate,\$bitrate_constant); #standard value 5474$ComboBox_const_bitrate->set_size_request( 72, -1 ); 5475$ComboBox_const_bitrate->signal_connect("changed", \&BitrateChanged); 5476$table21->attach ($ComboBox_const_bitrate, 5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5477#$ComboBox_const_bitrate->show; 5478 5479## audio mp3 bitrate is changed 5480sub BitrateChanged { 5481 $bitrate_constant = $ComboBox_const_bitrate->get_active_text; # copy the value of bitrate changed 5482 $status_bar->push($context_id, " constant $extension_output bitrate set to $bitrate_constant Kb/s"); 5483 #print "\$bitrate_constant = $bitrate_constant \n"; 5484} 5485 5486#####----------------final of ComboBox-------------##### 5487 5488###--------------------SpinButton--------------------### 5489 5490# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 5491$adj = new Gtk2::Adjustment( $bitrate_avr_mp3, 8, 320, 1, 5, 0 ); 5492#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits ); 5493$spinner_bitrate_mp3 = new Gtk2::SpinButton( $adj, 0.5, 0 ); 5494$spinner_bitrate_mp3->set_wrap( $true ); 5495$spinner_bitrate_mp3->set_size_request( 72, -1 ); 5496$spinner_bitrate_mp3->set_editable($false); 5497$spinner_bitrate_mp3->set_update_policy( 'if_valid' ); 5498$tooltips->set_tip( $spinner_bitrate_mp3, $langs{tip220} ) if $show_all_tooltips; 5499$table21->attach($spinner_bitrate_mp3, 5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5500$spinner_bitrate_mp3->signal_connect("value-changed", sub{ $bitrate_avr_mp3 = $spinner_bitrate_mp3->get_value_as_int(); } ); 5501#$spinner_bitrate_mp3->set_sensitive($false); 5502$spinner_bitrate_mp3->show(); 5503 5504$adj = new Gtk2::Adjustment( $bitrate_avr_ogg, 8, 320, 1, 5, 0 ); 5505$spinner_bitrate_ogg = new Gtk2::SpinButton( $adj, 0.5, 0 ); 5506$spinner_bitrate_ogg->set_wrap( $true ); 5507$spinner_bitrate_ogg->set_size_request( 72, -1 ); 5508$spinner_bitrate_ogg->set_editable($false); 5509$spinner_bitrate_ogg->set_update_policy( 'if_valid' ); 5510$tooltips->set_tip( $spinner_bitrate_ogg, $langs{tip220} ) if $show_all_tooltips; 5511$table21->attach($spinner_bitrate_ogg, 5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5512$spinner_bitrate_ogg->signal_connect("value-changed", sub{ $bitrate_avr_ogg = $spinner_bitrate_ogg->get_value_as_int(); } ); 5513#$spinner_bitrate_mp3->set_sensitive($false); 5514#$spinner_bitrate_mp3->show(); 5515 5516$adj = new Gtk2::Adjustment( $bitrate_avr_mp4, 8, 320, 1, 5, 0 ); 5517$spinner_bitrate_mp4 = new Gtk2::SpinButton( $adj, 0.5, 0 ); 5518$spinner_bitrate_mp4->set_wrap( $true ); 5519$spinner_bitrate_mp4->set_size_request( 72, -1 ); 5520$spinner_bitrate_mp4->set_editable($false); 5521$spinner_bitrate_mp4->set_update_policy( 'if_valid' ); 5522$tooltips->set_tip( $spinner_bitrate_mp4, $langs{tip220} ) if $show_all_tooltips; 5523$table21->attach($spinner_bitrate_mp4, 5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5524$spinner_bitrate_mp4->signal_connect("value-changed", sub{ $bitrate_avr_mp4 = $spinner_bitrate_mp4->get_value_as_int(); } ); 5525#$spinner_bitrate_mp3->set_sensitive($false); 5526#$spinner_bitrate_mp3->show(); 5527 5528# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 5529$adj = new Gtk2::Adjustment( $comp_ape, 1000, 5000, 1000, 0, 0 ); 5530#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits ); 5531$spinner_compress = new Gtk2::SpinButton( $adj, 0.1, 0 ); 5532$spinner_compress->set_wrap( $true ); 5533$spinner_compress->set_size_request( 72, -1 ); 5534$spinner_compress->set_editable($false); 5535$spinner_compress->set_update_policy( 'if_valid' ); 5536$spinner_compress->signal_connect("value-changed", 5537sub{ 5538 my $comp_ape = $spinner_compress->get_value_as_int(); 5539 $status_bar->push($context_id, $langs{msg065}."$extension_output with compression level = $comp_ape."); 5540} ); 5541$tooltips->set_tip( $spinner_compress, $langs{tip226} ) if $show_all_tooltips; 5542$table21->attach($spinner_compress, 5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5543#$spinner_compress->show(); 5544# $comp = $spinner_compress->get_value_as_int(); 5545 5546# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 5547$adj = new Gtk2::Adjustment( $comp_flac, 0, 8, 1, 0, 0 ); 5548#$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits ); 5549$spinner_compress_flac = new Gtk2::SpinButton( $adj, 0.1, 0 ); 5550$spinner_compress_flac->set_wrap( $true ); 5551$spinner_compress_flac->set_size_request( 72, -1 ); 5552$spinner_compress_flac->set_editable($false); 5553$spinner_compress_flac->set_update_policy( 'if_valid' ); 5554$spinner_compress_flac->signal_connect("value-changed", 5555sub{ 5556 my $comp_flac = $spinner_compress_flac->get_value_as_int(); 5557 $status_bar->push($context_id, $langs{msg065}."$extension_output with compression level = $comp_flac."); 5558} ); 5559$tooltips->set_tip( $spinner_compress_flac, $langs{tip227} ) if $show_all_tooltips; 5560$table21->attach($spinner_compress_flac, 5, 6, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5561#$spinner_compress->show(); 5562# $comp = $spinner_compress->get_value_as_int(); 5563 5564###-------------final-of--SpinButton-----------------### 5565 5566# criar um label (etiqueta - r�tulo) ao lado do menu 5567$label = new Gtk2::Label( "Kb/s" ); 5568$label->set_alignment( 0.0, 0.5 ); 5569$table21->attach ($label, 6, 7, 0, 1, 'fill', 'shrink', 0, 0); 5570$label->show(); 5571 5572#####--------------------Combo---------------------##### 5573# Min BitRate Quality 5574 5575# criar um label (etiqueta - r�tulo) ao lado do menu 5576$label = new Gtk2::Label( "Min:" ); 5577$label->set_alignment( 1, 0.5 ); 5578$table21->attach ($label, 7, 8, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5579$label->show; 5580 5581$ComboBox_Min = Gtk2::ComboBox->new_text; 5582ComboBox_fill_with_array(\$ComboBox_Min,\@all_const_bitrate); 5583ComboBox_select_this_text(\$ComboBox_Min,\@all_const_bitrate,\$vb_Min); #standard value 5584$ComboBox_Min->set_size_request( 72, -1 ); 5585$ComboBox_Min->signal_connect("changed", \&bit_Min); 5586$table21->attach ($ComboBox_Min, 8, 9, 0, 1, ['expand','fill'], 'shrink', 0, 0); 5587$ComboBox_Min->set_sensitive($true); 5588$ComboBox_Min->show; 5589 5590## Minimum Bitrate with variable encode 5591sub bit_Min { 5592 $vb_Min = $ComboBox_Min->get_active_text; 5593 5594 if ( $vb_Min > $vb_Max ) { # always assert this condition 5595 $vb_Min = $vb_Max; 5596 ComboBox_select_this_text(\$ComboBox_Min,\@all_const_bitrate,\$vb_Min); 5597 } 5598} 5599#####-------------------final of Combo-------------##### 5600 5601 5602#####--------------------Combo---------------------##### 5603# Mode for mp3 files 5604 5605# criar um label (etiqueta - r�tulo) ao lado do menu 5606my $label_combo_mode = new Gtk2::Label( $langs{name031} . ":" ); 5607$label_combo_mode->set_alignment( 1, 0.5 ); 5608$table21->attach ($label_combo_mode, 0, 1, 1, 2, 'fill', 'shrink', 0, 0); 5609$label_combo_mode->show(); 5610 5611my @all_mode = ( 'joint stereo', 'stereo', 'forced joint stereo', 'dual channels', 'mono' ); 5612 5613$ComboBox_mode = Gtk2::ComboBox->new_text; 5614ComboBox_fill_with_array(\$ComboBox_mode,\@all_mode); 5615ComboBox_select_this_text(\$ComboBox_mode,\@all_mode,\$mode); #standard value 5616$ComboBox_mode->set_size_request( 104, -1 ); 5617$table21->attach ($ComboBox_mode, 1, 2, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5618$ComboBox_mode->show; 5619 5620#####-------------------final of Combo-------------##### 5621#####--------------------Combo---------------------##### 5622# Variable BitRate Quality 5623 5624# criar um label (etiqueta - r�tulo) ao lado do menu 5625$label_VB = new Gtk2::Label( $langs{name033} . ":" ); 5626$label_VB->set_alignment( 1, 0.5 ); 5627$table21->attach ($label_VB, 4, 5, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5628$label_VB->show(); 5629 5630###--------------------SpinButton--------------------### 5631 5632$adj = new Gtk2::Adjustment( $V, 0, 9, 1, 0, 0 ); 5633$spinner_V = new Gtk2::SpinButton( $adj, 0.1, 0 ); 5634$spinner_V->set_editable($false); 5635$spinner_V->set_size_request( 72, -1 ); 5636$spinner_V->set_update_policy( 'if_valid' ); 5637$spinner_V->set_wrap( $false ); 5638$tooltips->set_tip( $spinner_V, $langs{tip221} ) if $show_all_tooltips; 5639$table21->attach($spinner_V, 5, 6, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5640$spinner_V->set_sensitive($false); 5641$spinner_V->show(); 5642 5643# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 5644$adj = new Gtk2::Adjustment( $Vogg, -1.0, 10.0, 0.1, 0, 0 ); 5645$spinner_Vogg = new Gtk2::SpinButton($adj, 0.4, 1); 5646$spinner_Vogg->set_editable($false); 5647$spinner_Vogg->set_size_request( 72, -1 ); 5648$spinner_Vogg->set_update_policy( 'if_valid' ); 5649$spinner_Vogg->set_wrap( $false ); 5650$tooltips->set_tip( $spinner_Vogg, $langs{tip222} ) if $show_all_tooltips; 5651$table21->attach($spinner_Vogg, 5, 6, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5652#$spinner_Vogg->set_sensitive($false); 5653#$spinner_Vogg->show(); 5654 5655# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 5656$adj = new Gtk2::Adjustment( $Vmpc, 2, 8, 1, 0, 0 ); 5657$spinner_Vmpc = new Gtk2::SpinButton($adj, 0.4, 0); 5658$spinner_Vmpc->set_editable($false); 5659$spinner_Vmpc->set_size_request( 72, -1 ); 5660$spinner_Vmpc->set_update_policy( 'if_valid' ); 5661$spinner_Vmpc->set_wrap( $false ); 5662$tooltips->set_tip( $spinner_Vmpc, $langs{tip225} ) if $show_all_tooltips; 5663$table21->attach($spinner_Vmpc, 5, 6, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5664#$spinner_Vogg->set_sensitive($false); 5665#$spinner_Vogg->show(); 5666 5667# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 5668$adj = new Gtk2::Adjustment( $Vmp4, 10, 500, 1, 0, 0 ); 5669$spinner_Vmp4 = new Gtk2::SpinButton($adj, 0.8, 0); 5670$spinner_Vmp4->set_editable($false); 5671$spinner_Vmp4->set_size_request( 72, -1 ); 5672$spinner_Vmp4->set_update_policy( 'if_valid' ); 5673$spinner_Vmp4->set_wrap( $false ); 5674$tooltips->set_tip( $spinner_Vmp4, $langs{tip224} ) if $show_all_tooltips; 5675$table21->attach($spinner_Vmp4, 5, 6, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5676#$spinner_Vogg->set_sensitive($false); 5677#$spinner_Vogg->show(); 5678 5679###-------------final-of--SpinButton-----------------### 5680#####--------------------Combo---------------------##### 5681# Max BitRate Quality 5682 5683# criar um label (etiqueta - r�tulo) ao lado do menu 5684$label = new Gtk2::Label( "Max:" ); 5685$label->set_alignment( 1, 0.5 ); 5686$table21->attach ($label, 7, 8, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5687$label->show; 5688 5689$ComboBox_Max = Gtk2::ComboBox->new_text; 5690ComboBox_fill_with_array(\$ComboBox_Max,\@all_const_bitrate); 5691ComboBox_select_this_text(\$ComboBox_Max,\@all_const_bitrate,\$vb_Max); #standard value 5692$ComboBox_Max->set_size_request( 72, -1 ); 5693$ComboBox_Max->signal_connect("changed", \&bit_Max); 5694$table21->attach ($ComboBox_Max, 8, 9, 1, 2, ['expand','fill'], 'shrink', 0, 0); 5695$ComboBox_Max->set_sensitive($true); 5696$ComboBox_Max->show; 5697 5698sub bit_Max { 5699 $vb_Max = $ComboBox_Max->get_active_text; 5700 5701 if ( $vb_Max < $vb_Min ) { # always assert this condition 5702 $vb_Max = $vb_Min; 5703 ComboBox_select_this_text(\$ComboBox_Max,\@all_const_bitrate,\$vb_Max); 5704 } 5705} 5706 5707#####-------------------final of Combo-------------##### 5708 5709#####-------------------final of Combo-------------##### 5710 5711# criar um label (etiqueta - r�tulo) ao lado do menu 5712$label = new Gtk2::Label( $langs{name032} . ":" ); 5713$label->set_alignment( 1.0, 0.5 ); 5714$table21->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0); 5715$label->show(); 5716 5717###--------------------SpinButton--------------------### 5718 5719# $adj = new Gtk::Adjustment( $value,$lower,$upper,$step_increment,$page_increment,$page_size ); 5720$adj = new Gtk2::Adjustment( $quality, 0, 9, 1, 5, 0 ); 5721#$spin = new Gtk2::SpinButton( $adjustment, $climb_rate, $digits ); 5722$spinner_q = new Gtk2::SpinButton( $adj, 0, 0 ); 5723$spinner_q->set_wrap( $true ); 5724$spinner_q->set_editable($false); 5725$spinner_q->set_size_request( 72, -1 ); 5726$spinner_q->set_update_policy( 'if_valid' ); 5727$tooltips->set_tip( $spinner_q, $langs{tip223} ) if $show_all_tooltips; 5728$table21->attach($spinner_q, 1, 2, 2, 3, ['expand','fill'], 'shrink', 0, 0); 5729$spinner_q->signal_connect("value-changed", sub{ $quality = $spinner_q->get_value; } ); 5730$spinner_q->show(); 5731 5732###-------------final-of--SpinButton-----------------### 5733 5734#####--------------------Combo---------------------##### 5735# Frequency 5736 5737# criar um label (etiqueta - r�tulo) ao lado do menu 5738$label = new Gtk2::Label( $langs{name041} . ":" ); 5739$label->set_alignment( 1, 0.5 ); 5740$table21->attach ($label, 4, 5, 2, 3, ['expand','fill'], 'shrink', 0, 0); 5741$label->show(); 5742 5743my @all_freq = ( "8000", "11025", "12000", "16000", "22050", "24000", "32000", "44100", "48000" ); 5744 5745$ComboBox_freq = Gtk2::ComboBox->new_text; 5746ComboBox_fill_with_array(\$ComboBox_freq,\@all_freq); 5747ComboBox_select_this_text(\$ComboBox_freq,\@all_freq,\$freq); #standard value 5748$ComboBox_freq->set_size_request( 72, -1 ); 5749#$ComboBox_freq->signal_connect("changed", \&BitrateChanged); 5750$table21->attach ($ComboBox_freq, 5, 6, 2, 3, ['expand','fill'], 'shrink', 0, 0); 5751$ComboBox_freq->set_sensitive($change_properties); 5752$ComboBox_freq->show; 5753 5754$label = new Gtk2::Label( "Hz" ); 5755$label->set_alignment( 0.0, 0.5 ); 5756$table21->attach ($label, 6, 7, 2, 3, 'fill', 'shrink', 0, 0); 5757$label->show(); 5758 5759#####-------------------final of Combo-------------##### 5760 5761$label = new Gtk2::Label( $langs{name013} . ":" ); 5762$label->set_alignment( 1.0, 0.5 ); 5763$table21->attach ($label, 0, 1, 3, 4, 'fill', 'shrink', 0, 0); 5764$label->show(); 5765 5766# Create the Entry to put additional command line 5767$entry_command_mp3 = new Gtk2::Entry( ); 5768$entry_command_mp3->set_text( $additional_command_mp3 ); 5769$tooltips->set_tip( $entry_command_mp3, $langs{tip228} ) if $show_all_tooltips; 5770$table21->attach($entry_command_mp3, 1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0); 5771 5772$entry_command_mp4 = new Gtk2::Entry( ); 5773$entry_command_mp4->set_text( $additional_command_mp4 ); 5774$tooltips->set_tip( $entry_command_mp4, $langs{tip228} ) if $show_all_tooltips; 5775$table21->attach($entry_command_mp4, 1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0); 5776 5777$entry_command_mpc = new Gtk2::Entry( ); 5778$entry_command_mpc->set_text( $additional_command_mpc ); 5779$tooltips->set_tip( $entry_command_mpc, $langs{tip228} ) if $show_all_tooltips; 5780$table21->attach($entry_command_mpc, 1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0); 5781 5782$entry_command_ogg = new Gtk2::Entry( ); 5783$entry_command_ogg->set_text( $additional_command_ogg ); 5784$tooltips->set_tip( $entry_command_ogg, $langs{tip228} ) if $show_all_tooltips; 5785$table21->attach($entry_command_ogg, 1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0); 5786 5787$entry_command_ape = new Gtk2::Entry( ); 5788$entry_command_ape->set_text( $additional_command_ape ); 5789$tooltips->set_tip( $entry_command_ape, $langs{tip228} ) if $show_all_tooltips; 5790$table21->attach($entry_command_ape, 1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0); 5791 5792$entry_command_flac = new Gtk2::Entry( ); 5793$entry_command_flac->set_text( $additional_command_flac ); 5794$tooltips->set_tip( $entry_command_flac, $langs{tip228} ) if $show_all_tooltips; 5795$table21->attach($entry_command_flac, 1, 9, 3, 4, ['fill','expand'], 'fill', 0, 0); 5796 5797 5798###-----------------------------------------------------### 5799#####---------------- T a b l e 3 --------------------##### 5800 5801###----------------id3 tag & mpeg info---------------### 5802 5803$label = new Gtk2::Label( $langs{name034} . ":" ); # table 'info' 5804$label->set_alignment( 1.0, 0.5 ); 5805$table3->attach ($label, 0, 1, 0, 1, 'fill', 'shrink', 0, 0); 5806$label->show(); 5807 5808# Create the Entry to put the title of mp3 music 5809my $entry_title = new Gtk2::Entry(); 5810$entry_title->set_text( "" ); 5811$entry_title->signal_connect("changed",\&change_tag); 5812$table3->attach_defaults ($entry_title, 1, 6, 0, 1 ); 5813$entry_title->show(); 5814 5815$label = new Gtk2::Label( $langs{name035} . ":" ); 5816$label->set_alignment( 1.0, 0.5 ); 5817$table3->attach ($label, 0, 1, 1, 2, 'fill', 'shrink', 0, 0); 5818$label->show(); 5819 5820# Create the Entry to put the artist of mp3 music 5821my $entry_artist = new Gtk2::Entry(); 5822$entry_artist->set_text( "" ); 5823$entry_artist->signal_connect("changed",\&change_tag); 5824$tooltips->set_tip( $entry_artist, $langs{tip301}) if $show_all_tooltips; 5825$table3->attach_defaults ($entry_artist, 1, 6, 1, 2 ); 5826$entry_artist->show(); 5827 5828$label = new Gtk2::Label( $langs{name036} . ":" ); 5829$label->set_alignment( 1.0, 0.5 ); 5830$table3->attach ($label, 0, 1, 2, 3, 'fill', 'shrink', 0, 0); 5831$label->show(); 5832 5833# Create the Entry to put the album of mp3 music 5834my $entry_album = new Gtk2::Entry(); 5835$entry_album->set_text( "" ); 5836$entry_album->signal_connect("changed",\&change_tag); 5837$table3->attach_defaults ($entry_album, 1, 6, 2, 3 ); 5838$entry_album->show(); 5839 5840$label = new Gtk2::Label( $langs{name037} . ":" ); 5841$label->set_alignment( 1.0, 0.5 ); 5842$table3->attach ($label, 0, 1, 3, 4, 'fill', 'shrink', 0, 0); 5843$label->show(); 5844 5845# Create the Entry to put the comment of mp3 music 5846my $entry_comment = new Gtk2::Entry(); 5847$entry_comment->set_text( "" ); 5848$entry_comment->signal_connect("changed",\&change_tag); 5849$table3->attach_defaults ($entry_comment, 1, 6, 3, 4 ); 5850$entry_comment->show(); 5851 5852$label = new Gtk2::Label( $langs{name038} . ":" ); 5853$label->set_alignment( 1.0, 0.5 ); 5854$table3->attach ($label, 0, 1, 4, 5, 'fill', 'shrink', 0, 0); 5855$label->show(); 5856 5857my $entry_year = new Gtk2::Entry(); 5858$entry_year->set_text( "" ); 5859$entry_year->set_size_request(50); 5860$entry_year->signal_connect("changed",\&change_tag); 5861$table3->attach_defaults ($entry_year, 1, 2, 4, 5 ); 5862$entry_year->show(); 5863 5864$label = new Gtk2::Label( $langs{name039} . ":" ); 5865$label->set_alignment( 1.0, 0.5 ); 5866$table3->attach ($label, 2, 3, 4, 5, 'fill', 'shrink', 0, 0); 5867$label->show(); 5868 5869# Create the Entry to put the track number of mp3 music 5870my $entry_tn = new Gtk2::Entry(); 5871$entry_tn->set_text( "" ); 5872$entry_tn->set_size_request(40); 5873$tooltips->set_tip( $entry_tn, $langs{tip302} ) if $show_all_tooltips; 5874$entry_tn->signal_connect("changed",\&change_tag); 5875$table3->attach_defaults ($entry_tn, 3, 4, 4, 5 ); 5876$entry_tn->show(); 5877 5878$label = new Gtk2::Label( "/" ); 5879$label->set_alignment( 1.0, 0.5 ); 5880$table3->attach ($label, 4, 5, 4, 5, 'fill', 'shrink', 0, 0); 5881$label->show(); 5882 5883my $entry_tt = new Gtk2::Entry(); 5884$entry_tt->set_text( "" ); 5885$entry_tt->set_size_request(40); 5886$tooltips->set_tip( $entry_tt, $langs{tip303} ) if $show_all_tooltips; 5887$entry_tt->signal_connect("changed",\&change_tag); 5888$table3->attach_defaults ($entry_tt, 5, 6, 4, 5 ); 5889$entry_tt->show(); 5890 5891#####----------------Combo---mp3 info--------------##### 5892# Genre of mp3 info - see mp3info -G 5893 5894# criar um label (etiqueta - r�tulo) ao lado do menu 5895$label = new Gtk2::Label( $langs{name040} . ":" ); 5896$label->set_alignment( 1.0, 0.5 ); 5897$table3->attach ($label, 0, 1, 5, 6, 'fill', 'shrink', 0, 0); 5898$label->show(); 5899 5900# my $cmd = "mp3info -G"; 5901# my $cmd = "lame --genre-list"; # see the command: < lame --genre-list > 5902# my $list_genre = exec_cmd_system($cmd); # list with all mp3 genre 5903# $list_genre =~ s/\s*(\d+)\s(.*)/ $1 => "$2", /g; 5904# print "$list_genre"; 5905 5906# A hash represents a set of key/value pairs: --- see perlintro, perlref, perlreftut 5907# 0 - 147 genre are default;; more than 148 is personal ;; max number = 255 5908my %genre_hash = ( 123 => "A Cappella", 34 => "Acid", 74 => "Acid Jazz", 73 => "Acid Punk", 99 => "Acoustic", 590920 => "Alternative", 40 => "Alt. Rock", 26 => "Ambient", 145 => "Anime", 90 => "Avantgarde", 116 => "Ballad", 591041 => "Bass", 135 => "Beat", 85 => "Bebob", 96 => "Big Band", 138 => "Black Metal", 89 => "Bluegrass", 0 => "Blues", 5911107 => "Booty Bass", 132 => "BritPop", 65 => "Cabaret", 88 => "Celtic", 104 => "Chamber Music", 102 => "Chanson", 591297 => "Chorus", 136 => "Christian Gangsta Rap", 61 => "Christian Rap", 141 => "Christian Rock", 32 => "Classical", 59131 => "Classic Rock", 112 => "Club", 128 => "Club-House", 57 => "Comedy", 140 => "Contemporary Christian", 2 => "Country", 5914139 => "Crossover", 58 => "Cult", 3 => "Dance", 125 => "Dance Hall", 50 => "Darkwave", 22 => "Death Metal", 4 => "Disco", 591555 => "Dream", 127 => "Drum & Bass", 122 => "Drum Solo", 120 => "Duet", 98 => "Easy Listening", 52 => "Electronic", 591648 => "Ethnic", 54 => "Eurodance", 124 => "Euro-House", 25 => "Euro-Techno", 84 => "Fast-Fusion", 80 => "Folk", 5917115 => "Folklore", 81 => "Folk/Rock", 119 => "Freestyle", 5 => "Funk", 30 => "Fusion", 36 => "Game", 591859 => "Gangsta Rap", 126 => "Goa", 38 => "Gospel", 49 => "Gothic", 91 => "Gothic Rock", 6 => "Grunge", 5919129 => "Hardcore", 79 => "Hard Rock", 137 => "Heavy Metal", 7 => "Hip-Hop", 35 => "House", 100 => "Humour", 5920131 => "Indie", 19 => "Industrial", 33 => "Instrumental", 46 => "Instrumental Pop", 47 => "Instrumental Rock", 59218 => "Jazz", 29 => "Jazz+Funk", 146 => "JPop", 63 => "Jungle", 86 => "Latin", 71 => "Lo-Fi", 45 => "Meditative", 5922142 => "Merengue", 9 => "Metal", 77 => "Musical", 82 => "National Folk", 64 => "Native American", 133 => "Negerpunk", 592310 => "New Age", 66 => "New Wave", 39 => "Noise", 11 => "Oldies", 103 => "Opera", 12 => "Other", 75 => "Polka", 5924134 => "Polsk Punk", 13 => "Pop", 53 => "Pop-Folk", 62 => "Pop/Funk", 109 => "Porn Groove", 117 => "Power Ballad", 592523 => "Pranks", 108 => "Primus", 92 => "Progressive Rock", 67 => "Psychedelic", 93 => "Psychedelic Rock", 43 => "Punk", 5926121 => "Punk Rock", 15 => "Rap", 68 => "Rave", 14 => "R&B", 16 => "Reggae", 76 => "Retro", 87 => "Revival", 5927118 => "Rhythmic Soul", 17 => "Rock", 78 => "Rock & Roll", 143 => "Salsa", 114 => "Samba", 110 => "Satire", 592869 => "Showtunes", 21 => "Ska", 111 => "Slow Jam", 95 => "Slow Rock", 105 => "Sonata", 42 => "Soul", 37 => "Sound Clip", 592924 => "Soundtrack", 56 => "Southern Rock", 44 => "Space", 101 => "Speech", 83 => "Swing", 94 => "Symphonic Rock", 5930106 => "Symphony", 147 => "Synthpop", 113 => "Tango", 18 => "Techno", 51 => "Techno-Industrial", 130 => "Terror", 5931144 => "Thrash Metal", 60 => "Top 40", 70 => "Trailer", 31 => "Trance", 72 => "Tribal", 27 => "Trip-Hop", 28 => "Vocal", 5932# this is additional genre from Brazilian music 5933148 => "MPB", 149 => "Bossa Nova", 150 => "Capoeira", 151 => "Chorinho", 152 => "Forr�", 153 => "Maracatu", 5934154 => "Timbalada", 155 => "Ax�", 156 => "Sertanejo", 157 => "Pagode", 5935# this is additional genre 5936158 => "World Music" 5937); 5938 5939# print "\nhash of genre --- element 32: ",$genre_hash{"32"}," \n"; 5940my $count_pairs = keys %genre_hash; # Get the number of elements (key-value pairs) in the hash. 5941#print "count_pairs = $count_pairs\n"; 5942 5943my @array_genre = (); # array with only the names 5944for my $key (0..158) { 5945 #print "$key => $genre_hash{$key}\n"; 5946 push @array_genre,$genre_hash{$key}; 5947} 5948@array_genre = sort @array_genre; 5949 5950my $ComboBoxEntry_genre = Gtk2::ComboBoxEntry->new_text; 5951ComboBox_fill_with_array(\$ComboBoxEntry_genre,\@array_genre); 5952#ComboBox_select_this_text(\$ComboBoxEntry_genre,\@array_genre,""); #standard value 5953$ComboBoxEntry_genre->child->set_text( "" ); #standard value 5954$ComboBoxEntry_genre->signal_connect("changed", \&change_tag); 5955$table3->attach ($ComboBoxEntry_genre, 1, 6, 5, 6, 'fill', 'fill', 0, 0); 5956$ComboBoxEntry_genre->show; 5957 5958 5959# when whatever tag is changed, the button_save_tag is set to set_sensitive($true) 5960my $abandon_change_tag = $false; # if '$abandon_change_tag eq $true' then force to abandon the 'sub change_tag' 5961 5962sub change_tag { # sub cell_edited { 5963 5964 return if $abandon_change_tag; 5965 5966 # get selected row from 'sub get_selection_tree' that will be used by 'sub change_tag' and 'sub save_tag' 5967 my $row = $files_info[0]{get_selection_row}; 5968 5969 return unless defined $row; 5970 5971 my $filepath = $files_info[$row]{filepath}; 5972 #$filepath = filename_from_unicode $filepath if( ! -e $filepath ); 5973 my $extension_input = $files_info[$row]{extension_input}; 5974 5975 # get all current 8 entries: 5976 my $Title = $files_info[$row]{title}; 5977 my $Artist = $files_info[$row]{artist}; 5978 my $Comment = $files_info[$row]{comment}; 5979 my $Album = $files_info[$row]{album}; 5980 my $Genre = $files_info[$row]{genre}; 5981 my $Year = $files_info[$row]{year}; 5982 my $Track_Number = $files_info[$row]{track}; 5983 my $Total_Track = $files_info[$row]{total_track}; 5984 5985 #print "\n sub change_tag --->1 \$row = $row \$filepath = $filepath ;; \$Title = $Title ;; \$Album = $Album ;; \$extension_input = $extension_input\n"; 5986 5987 5988 my $title = $entry_title->get_text; 5989 my $artist = $entry_artist->get_text; 5990 my $album = $entry_album->get_text; 5991 my $comment= $entry_comment->get_text; 5992 my $genre = $ComboBoxEntry_genre->child->get_text; 5993 5994 # some verifications/validations 5995 my $year = "invalid"; 5996 if ( $entry_year->get_text =~ /^(\d{1,4})$/ ) { $year = $1; } 5997 if ( $entry_year->get_text eq "" ) { $year = ""; } 5998 my $tn = "invalid"; # track number 5999 if ( $entry_tn->get_text =~ /^(\d+)$/ ) { $tn = $1; } 6000 if ( $entry_tn->get_text eq "" ) { $tn = ""; } 6001 my $tt = "invalid"; # track total 6002 if ( $entry_tt->get_text =~ /^(\d+)$/ ) { $tt = $1; } 6003 if ( $entry_tt->get_text eq "" ) { $tt = ""; } 6004 6005 # verify any change in tag: Title, Artist, ... 6006 if ( ($extension_input =~ /(mp3|mpc|ogg|ape|flac|wav)/) and ($title ne $Title or $artist ne $Artist or $album ne $Album 6007 or $comment ne $Comment or $year ne $Year or $tn ne $Track_Number or $tt ne $Total_Track or $genre ne $Genre) ) 6008 { 6009 # Test if the $filepath is writable. '-w' File is writable by effective uid/gid. 6010 if ( not file_is_writable($filepath) ) { 6011 $button_save_tag->set_sensitive($false); 6012 return $false; 6013 } 6014 if ( $tn =~ /^(\d+)$/ and $tt =~ /^(\d+)$/ ) { 6015 if ( $tt < $tn ){ # only compare for numbers 6016 $status_bar->push($context_id, $langs{msg080} ); 6017 $button_save_tag->set_sensitive($false); 6018 return $false; 6019 } 6020 } 6021 if ( ( $tn eq "" and $tt =~ /^(\d+)$/ ) or $tn eq "invalid" or $tt eq "invalid" or $year eq "invalid" ) { 6022 $status_bar->push($context_id, $langs{msg080} ); 6023 $button_save_tag->set_sensitive($false); 6024 return $false; 6025 } 6026 $tooltips->set_tip( $button_save_tag, $langs{tip304} ) if $show_all_tooltips; 6027 } 6028 elsif ( ($extension_input =~ /(cda)/) and ($title ne $Title or $artist ne $Artist or $album ne $Album 6029 or $year ne $Year or $genre ne $Genre) ) 6030 { 6031 if ( $year eq "invalid" ) { 6032 $status_bar->push($context_id, $langs{msg080} ); 6033 $button_save_tag->set_sensitive($false); 6034 return $false; 6035 } 6036 $tooltips->set_tip( $button_save_tag, $langs{tip305} ) if $show_all_tooltips; 6037 } 6038 elsif ( $extension_input =~ /(mp4)/ ){ # for mp4 file 6039 # get info to be saved on normalized file 6040 $status_bar->push($context_id, $langs{msg061} ); 6041 return $false; 6042 } 6043 else { # $extension_input = other 6044 $status_bar->push($context_id, "" ); 6045 $button_save_tag->set_sensitive($false); 6046 return $false; 6047 } 6048 6049 update_tags($title,$artist,$album,$comment,$year,$tn,$tt,$genre); 6050 6051 $button_save_tag->set_sensitive($true); 6052 $status_bar->push($context_id, $langs{msg070} ); 6053 6054 #print "\n sub change_tag --->2 \$row = $row \$filepath = $filepath ;; title = $title ;; album = $album\n"; 6055 6056 return $true; 6057} 6058 6059my %temp_tags; # the hash %temp_tags is a temporaty variables only used on sub change_tag 6060 6061sub update_tags { # used by save_tag 6062 my ($title,$artist,$album,$comment,$year,$tn,$tt,$genre) = @_; 6063 6064 %temp_tags = (); 6065 6066 # the hash %temp_tags is a temporaty variables only used on 'sub change_tag'. 6067 $temp_tags{title} = remove_change_10_chars($title); 6068 $temp_tags{artist} = remove_change_10_chars($artist); 6069 $temp_tags{album} = remove_change_10_chars($album); 6070 $temp_tags{comment} = remove_change_10_chars($comment); 6071 $temp_tags{genre} = remove_change_10_chars($genre); 6072 $temp_tags{year} = remove_change_10_chars($year); 6073 $temp_tags{track} = remove_change_10_chars($tn); # $Track_Number 6074 $temp_tags{total_track} = remove_change_10_chars($tt); 6075 6076 #print "\n sub update_tags ---> Title = $temp_tags{title} ;; Artist = $temp_tags{artist} ;; Album = $temp_tags{album}\n"; 6077} 6078 6079sub file_is_writable { 6080 # Test if the $filepath is writable. 6081 # '-w' file is writable by effective uid/gid. 6082 my $filepath = shift; 6083 if ( not -w filename_from_unicode $filepath ) { 6084 $status_bar->push($context_id, " $filepath ".$langs{msg012} ); 6085 return $false; 6086 } 6087 return $true; 6088} 6089 6090#####-------------final of Combo---mp3 info--------##### 6091 6092 6093###----------------------table 31 -------------------### 6094 6095my $label_mpeg = new Gtk2::Label( "MPEG" ); 6096#$label_mpeg->set_justify( 'left' ); 6097$label_mpeg->set_alignment( 0, 0.5 ); 6098$table31->attach ($label_mpeg, 0, 1, 1, 2, 'fill', ['expand','fill'], 0, 0 ); 6099$label_mpeg->show(); 6100#$label_mpeg->set_label ($str); 6101 6102my $label_kbps = new Gtk2::Label( "Bitrate:" ); 6103$label_kbps->set_alignment( 0, 0.5 ); 6104$table31->attach ($label_kbps, 0, 1, 2, 3, 'fill', ['expand','fill'], 0, 0 ); 6105$label_kbps->show(); 6106 6107my $label_freq = new Gtk2::Label( $langs{name041} . ":" ); 6108$label_freq->set_alignment( 0, 0.5 ); 6109$table31->attach ($label_freq, 0, 1, 3, 4, 'fill', ['expand','fill'], 0, 0); 6110$label_freq->show(); 6111 6112my $label_mode = new Gtk2::Label( $langs{name031} . ":" ); 6113$label_mode->set_alignment( 0, 0.5 ); 6114$table31->attach ($label_mode, 0, 1, 4, 5, 'fill', ['expand','fill'], 0, 0); 6115$label_mode->show(); 6116 6117my $label_time = new Gtk2::Label( $langs{name042} . ":" ); 6118$label_time->set_alignment( 0, 0.5 ); 6119$table31->attach ($label_time, 0, 1, 5, 6, 'fill', ['expand','fill'], 0, 0); 6120$label_time->show(); 6121 6122my $label_size = new Gtk2::Label( $langs{name048} . ":" ); 6123$label_size->set_alignment( 0, 0.5 ); 6124$table31->attach ($label_size, 0, 1, 6, 7, 'fill', ['expand','fill'], 0, 0); 6125$label_size->show(); 6126 6127$separator = Gtk2::HSeparator->new; 6128$table31->attach ( $separator, 0, 1, 7, 8, ['expand','fill'],['expand','fill'], 0, 0 ); 6129$separator->show; 6130 6131 6132$button_save_tag = Gtk2::Button->new; 6133$button_save_tag->add( DrawIcons('gtk-save','button') ); 6134#$tooltips->set_tip( $button_save_tag, "Save changes of tag to $extension_input file."); 6135$button_save_tag->signal_connect( "clicked", \&save_tag ); 6136$table31->attach ($button_save_tag, 0, 1, 8, 9 , 'shrink', 'shrink', 0, 0); 6137$button_save_tag->set_sensitive($false); 6138$button_save_tag->set( 'focus-on-click' => $false, 'relief' => 'none' ); 6139$button_save_tag->show(); 6140 6141 6142###----------------id3 tag & mpeg info---------------### 6143######--------------------------------------------###### 6144 6145###----------------------table 4 --------------------### 6146#--------------------------Rip-------------------------# 6147 6148# some buttons 6149my $hbox4 = Gtk2::HBox->new ($false, 2); 6150#$box->pack_start ($child, $expand, $fill, $padding) 6151$vbox4->pack_start ($hbox4, $false, $false, 0); 6152$hbox4->show; 6153 6154$label = new Gtk2::Label( " cdrom:" ); 6155$label->set_alignment( 1.0, 0.5 ); 6156$hbox4->pack_start ($label, $false, $false, 0); 6157$label->show(); 6158 6159# Create the Entry to put the cdrom drive path 6160$entry_cda = new Gtk2::Entry(); 6161$entry_cda->set_text($audiodevice_path); 6162$tooltips->set_tip( $entry_cda, $langs{tip401} ) if $show_all_tooltips; 6163$entry_cda->set_size_request(120); 6164$entry_cda->signal_connect("changed", \&entry_cda_change ); 6165$hbox4->pack_start ($entry_cda, $false, $false, 0); 6166$entry_cda->show(); 6167 6168$button = Gtk2::Button->new; 6169$button->add( DrawIcons('gtk-refresh','button') ); 6170$button->set( 'focus-on-click' => $false, 'relief' => 'none' ); 6171$tooltips->set_tip( $button, $langs{tip402} ) if $show_all_tooltips; 6172$button->signal_connect (clicked => \&refresh_cda); 6173$hbox4->pack_start ($button, $false, $false, 0); 6174$button->show; 6175 6176# my $button_selec = Gtk2::Button->new ("unselect all"); 6177my $button_selec = Gtk2::Button->new; 6178$button_selec->add( DrawIcons('gtk-close','button') ); 6179$button_selec->set( 'focus-on-click' => $false, 'relief' => 'none' ); 6180$tooltips->set_tip( $button_selec, $langs{tip404} ) if $show_all_tooltips; 6181$button_selec->signal_connect (clicked => \&unselect_cda); 6182#$button_selec->set_sensitive($false); 6183$button_selec->show; 6184 6185my $button_unselec = Gtk2::Button->new; 6186$button_unselec->add( DrawIcons('gtk-cancel','button') ); 6187$button_unselec->set( 'focus-on-click' => $false, 'relief' => 'none' ); 6188$tooltips->set_tip( $button_unselec, $langs{tip403} ) if $show_all_tooltips; 6189$button_unselec->signal_connect (clicked => \&unselect_cda); 6190$button_unselec->set_sensitive($false); 6191$button_unselec->show; 6192 6193# this align is a container that hold two buttons alternately 6194my $align_selec = Gtk2::Alignment->new(0.5, 0.5 , 0, 0); 6195$align_selec->add ($button_unselec); 6196$hbox4->pack_start ($align_selec, $false, $false, 0); 6197$align_selec->show; 6198 6199# to fill the empty space 6200$label = new Gtk2::Label( " " ); 6201$label->set_alignment( 0.5, 0.5 ); 6202$hbox4->pack_start ($label, $true, $true, 0); 6203$label->show; 6204 6205 6206###---------------------- Display --------------------### 6207#------------------------- start -----------------------# 6208 6209# convert sound.png -resize 32x32 -enhance -colors 16 sound.xpm or use gimp > Image > Mode > Indexed 6210# convert sound.xpm -resample 12x40 -colors 16 -enhance sound2.xpm 6211# cat sound.xpm | sed "s/\\\$/S/g" | sed "s/\@/x/g"|sed "/pixels/d" >sound3.xpm 6212my @sound = ( 6213# /* columns rows colors chars-per-pixel */ 6214"160 186 41 1", 6215" c None", 6216". c #2C2827", 6217"+ c #39312E", 6218"x c #453331", 6219"# c #413739", 6220"S c #413A35", 6221"% c #453935", 6222"& c #483C38", 6223"* c #46403A", 6224"= c #4A4041", 6225"- c #524641", 6226"; c #514647", 6227"> c #5C4750", 6228", c #594A51", 6229"' c #5A4D49", 6230") c #594E4E", 6231"! c #62535A", 6232"~ c #605555", 6233"{ c #645752", 6234"] c #695A61", 6235"^ c #675C5D", 6236"/ c #716169", 6237"( c #6F635E", 6238"_ c #6E6364", 6239": c #766964", 6240"< c #75696B", 6241"[ c #796E6E", 6242"} c #7D7272", 6243"| c #827676", 6244"1 c #867A7B", 6245"2 c #8B7F7F", 6246"3 c #8F8384", 6247"4 c #92837F", 6248"5 c #968A8A", 6249"6 c #9C9090", 6250"7 c #A29697", 6251"8 c #A99D9E", 6252"9 c #B0A3A4", 6253"0 c #B6AAAA", 6254"a c #BCB0B0", 6255"b c #DBD5D3", 6256" ", 6257" ", 6258" 888888888888888888 ", 6259" 88888888888888888888888888 ", 6260" 888888888888888888888888888888888 ", 6261" 88888888888888888888888888888888888888 ", 6262" 8888888888888888888888888888888888888888888 ", 6263" 88888888888888888876553333556788888888888888888 ", 6264" 88888888888888863|[<<::::__(____<[13688888888888888 ", 6265" 888888888888865|[<<<<<_({{{''''{{{^__((<158888888888888 ", 6266" 8888888888885|<<<:_{'-&&&&&&&&&&&&&&&-''{((:1688888888888 ", 6267" 8888888888861[<<:({-&&&&&&&&&&&&&&&&&&&&&&&&-{((<588888888888 ", 6268" 88888888886|<<<_{-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-{^<38888888888 ", 6269" 888888888861[<<('&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-'^<5888888888 ", 6270" 88888888872[[<{-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'(|788888888 ", 6271" 8888888885[[[(-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-{_5888888888 ", 6272" 888888886|[[:'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-{|888888888 ", 6273" 8888888885[[<{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'<688888888 ", 6274" 8888888882[[_-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-{588888888 ", 6275" 888888886|[[{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{288888888 ", 6276" 888888885}[<'&&&&&&&&&&&&&&&&&&&&&&&&&%%%%%%%&&&&&&&&&&&&&&&&&&&&&&&&&&&'|88888888 ", 6277" 888888883[[(*&&&&&&&&&&&&&&&&&&&&---------*SSSSSSSSS%&&&&&&&&&&&&&&&&&&&&&'|8888888 ", 6278" 888888882[[{&&&&&&&&&&&&&&&&&'{{^________<<<<_~'*SSSSSSSS%&&&&&&&&&&&&&&&&&&-}8888888 ", 6279" 888888881[['&&&&&&&&&&&&&&-{__^^^_________<<<<<<[[_{*SSSSSSSS%&&&&&&&&&&&&&&&&-|8888888 ", 6280" 888888881[['&&&&&&&&&&&&&{<<^^^^^^^_________<<<<<[[[[[_'SSSSSSSSS&&&&&&&&&&&&&&&-18888888 ", 6281" 888888881[<-&&&&&&&&&&&-(<_^^^^^^^^^^________<<<<<<[[[[[[<{*SSSSSSSS&&&&&&&&&&&&&&-38888888 ", 6282" 88888881}[-&&&&&&&&&&-_[^^^^^^^^^^^^^^________<<<<<[[[[[[[[<'SSSSSSSS%&&&&&&&&&&&&&'5888888 ", 6283" 88888882}[-&&&&&&&&&&^[^^^^^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[_-SSSSSSSS%&&&&&&&&&&&&{6888888 ", 6284" 88888883}[-&&&&&&&&&{[^^^^^^^^^^^^^^^^^^^________<<<<<[[[[[[[[[[[{SSSSSSSSS&&&&&&&&&&&&_8888888 ", 6285" 88888885}['&&&&&&&&-<_~~~~~^^^^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[_*SSSSSSSSS&&&&&&&&&&&}888888 ", 6286" 88888886}['&&&&&&&&'<^~~~~~~~~~^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[[<'SSSSSSSSS&&&&&&&&&&*5888888 ", 6287" 8888886|}{&&&&&&&&(_~~~~~~~~~~~~~^^^^^^^^^^^^______<<<<<[[[[[[[[[[[[[[[{SSSSSSSSS&&&&&&&&&&'7888888 ", 6288" 8888887|}{&&&&&&&-<^~~~~~~~~~~~~~~~^^^^^^^^^^^_______<<<<[[[[[[[[[[[[[[[[{SSSSSSSSS&&&&&&&&&&<888888 ", 6289" 88888882}_&&&&&&&-_~~~~~~~~~~~~~~~~~~^^^^^^^^^^^______<<<<<[[[[[[[[[[[[[[[[{SSSSSSSSS&&&&&&&&&&3888888 ", 6290" 8888885}<-&&&&&&'_~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^______<<<<<[[[[[[[[[[[[[[[[[^SSSSSSSSS&&&&&&&&&'888888 ", 6291" 8888886|}'&&&&&&'^~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^______<<<<<[[[[[[[[[[[[[[[[[[~SSSSSSSSS&&&&&&&&&[888888 ", 6292" 88888881}{&&&&&&'^~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^_____<<<<<[[[[[[[[[[[[[[[[[[[{SSSSSSSSS&&&&&&&&*6888888 ", 6293" 8888883}(&&&&&&'~~~~~~~~~~~~~~)~~~~~~~~~~~^^^^^^^^^______<<<<[[[[[[[[[[[[[[[[[[[['SSSSSSSSS&&&&&&&&(888888 ", 6294" 8888886}[-&&&&&'~~~~)~))))))))))~)~~~~~~~~~~^^^^^^^^______<<<<[[[[[[[[[[[[[[[[[[[[<*SSSSSSSSS&&&&&&&&5888888 ", 6295" 8888888|}'&&&&&-~~~))))))))))))))))~~~~~~~~~~^^^^^^^^______<<<<[[[[[[[[[[[[[[[[[[[[[_*SSSSSSSSS&&&&&&&{888888 ", 6296" 8888883}^&&&&&-~~~))))))))))))))))))~~~~~~~~~~^^^^^^^______<<<<[[[[[[[[[[[[[[[[[[[[[[{SSSSSSSSS%&&&&&&&5888888 ", 6297" 8888886|[&&&&&&~~~)))))))))'''))))))))~~~~~~~~~^^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[-SSSSSSSSS&&&&&&&{888888 ", 6298" 8888882}'&&&&&)~~)))))))))''')))'))))))~~~~~~~~^^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[<*SSSSSSSSS&&&&&&&588888 ", 6299" 8888885|_&&&&&)))))))))'''''''')'')'))))))~~~~~~~^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[[^SSSSSSSSSS&&&&&&(888888 ", 6300" 888888|}-&&&&-~))))))''''''''''''''))))))~~~~~~~~^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[[[-SSSSSSSSS&&&&&&&688888 ", 6301" 8888885|{&&&&*)))))''''''))))))))'''))')))))~~~~~~^^^^^^^_____<<<<[[[[[[[[[[[[[[[[[[[[[[[[[_SSSSSSSSSS&&&&&&<888888 ", 6302" 888887|[-&&&%))))))''''))))))))))))''))))))~~~~~~~^^^^^^^____<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[['SSSSSSSSS%&&&&&-788888 ", 6303" 8888883|{&&&%-)))'''')))))------))))))''))))))~~~~~^^^^^^^____<<<<[[[[[}}}}}}}}}}}}}[[[[[[[[[<SSSSSSSSSS&&&&&&288888 ", 6304" 888888|[&&&&*)))''''))))-;;;;;;;;-))))'''')))~~~~~~~^^^^^^____<<<<[[[}}}}}}}}}}}}}}}}}[[[[[[[['SSSSSSSSSS&&&&&{888888 ", 6305" +%5888883|{&&&%)))''')'));;;;;;;;;;;;;-))''')))))~~~~~~^^^^^^____<<<<[[}}}}}}}}}}}}}}}}}}}}[[[[[[<*SSSSSSSSS&&&&&&688888 ", 6306" +++%{888887|[&&&%-)))'')))-;;;;;;;;;;;;;;;-)''''')))~~~~~~^^^^^^___<<<<[[}}}}}}}}}}}}}}}}}}}}}}}[[[[['SSSSSSSSSS&&&&&}88888 ", 6307" ++-:47888885|{&&&%))''')));;;;;;;;;;;;;;;;;;)))'')))))~~~~~^^^^^^___<<<<[[}}}}}}}|||||||}}}}}}}}}}[[[[_SSSSSSSSSS&&&&&'888888 ", 6308" ++'|444888888|[&&&%;)'''))-;;;;;;;;;;;;;;;;;;;;)))'')))~~~~~~^^^^^___<<<<[[[}}}||||||||||||||}}}}}}}}}[[[-SSSSSSSSS%&&&&&688888 ", 6309" +%:44447888885|{&&S&)'''))-;;;;;;;--;;;-;;;;;;;;-))''')))~~~~~^^^^^___<<<<[[}}|||||||||||||||||||}}}}}}}[[{%SSSSSSSSS&&&&&[88888 ", 6310" +-|444448888882}&&&&)'''))-;;;;;;-;--;;--;;;;;;;;;)''''))~~~~~~^^^^^___<<<[[}}|||||||||||||||||||||}}}}}}}[[*%SSSSSSSS%&&&&'888888 ", 6311" +'4444446888886|^&&%=)''))-;;;;;-;;;------;-;;;;;;;-)''))))~~~~~^^^^^__<<<<[[}}|||||||||||||||||||||||}}}}}}['%%SSSSSSSS&&&&&688888 ", 6312" +'44444448888883|-&&%)''))-;;;;;;--;-=====---;=-===;;))'')))~~~~{^^^^___<<<[[}}||||||1111111111|||||||||}}}}}}_S%SSSSSSSS&&&&&188888 ", 6313" +-44444445888887|(&&%=)'')-;;;;;;;--========S+........+S-))))~~~~~^^^____<<[[[}||||111111111111111||||||||}}}}}[*S%SSSSSSSS&&&&(888888 ", 6314" +&444444446888885|'&%%'''));;;;---;=======#+...............S))~~~~~^^^___<<<[[}}||1111112222222211111|||||||}}}}}{%%%SSSSSSS&&&&-888888 ", 6315" +%|444444448888881[&&S=''));;;;---=======#....................=)~~{^^^^___<<[[}}|||111222222222222221111||||||}}}}_SS%SSSSSSS&&&&&588888 ", 6316" ++:44444446b888887|{&S%)')';;;;---=====-*+......................+)~^^^^^__<<<[[}|||11222222444442222221111||||||}}}[-%S%SSSSSSS&&&&|88888 ", 6317" +'44444444ba888885}-&S&'')-;;;---====-&+..........................){^^^___<<[[}}||1122222343333333242222111|||||}}}}'SS%SSSSSSS&&&&(888888 ", 6318" +%44444444ba7888881<&&%;'');;;;-;====**+............................)^^^___<<[}}||112222333333333333322222111|||||}}}^S%%%SSSSSS&&&&'888888 ", 6319" +(4444444ab/888886|{&S%'));;;;;-===-**..............................+)^___<<[[}|||1222333333333333333342222111||||}}}<*SS%SSSSSS%&&&&688888 ", 6320" +-44444448b<<888883|-&%=')-;;;;-===-&*...............................++~__<<<[}}||12233333555555555533333222211|||||}}[-SS%SSSSSSS&&&&588888 ", 6321" +:4444444b7>5888881:&%%'));;;-;-==-&*...............................+++S^_<<[[}||1122333555555555555553333232211||||}}}'*S%%SSSSSS&&&&|88888 ", 6322" +-4444444ab>>888887|{&%&');;;;-;==-&*................................++++;<<<[}}||12233355555555555555555333222111||||}}{*SS%SSSSSS&&&&_88888 ", 6323" +:4444445b|>/888885|-%+-'-;;;;-===&&+...............................+++++#^<[[}||123335555555565555555555533322211||||}}_*SS%SSSSSSS&&&'888888 ", 6324" +%4444444aa>>1888882<&%%));;;-;===*&+...............................+++++++=<[}||11223555556666666666655555533322211||||}[&*SS%SSSSS%&&&-888888 ", 6325" +{4444446b/>>688887|{&%='-;;;-;==*&S.................+##====#++.....+++++#SS^[}||12333555566666666666666555553322211||||}}-*SS%SSSSSS&&&&788888 ", 6326" +|444444aa>>!888886|-%+;);;;--==-*&................#;,,,,,,,,,,=#..++++++#SS;[||1223355566666666666666666555433342211|||}}'&SS%SSSSSS&&&&588888 ", 6327" +-4444444b|>>/888885[&%%)-;;;--==&&+..............#,,,,,,,,,,,,,,,,#+++++#SS==_||1223555666666677777766666655553332211||||}{&*%%SSSSSS&&&&188888 ", 6328" +(4444449b>>>1888882(&+&);;;;-==*&S.............#,,,,,,,,,,,,,,,,,,,,+++#SSS==~|12333556666677777777777666665555332211||||}{&*S%%SSSSS&&&&[88888 ", 6329" +|444444b7>>>588888|{%+=-;;;--==&=.............=,,,,,,,,,,,,,,,,,,,,,,#++SS===;|123355666667777777777777666665553322211|||}(**S%%SSSSSS&&&_88888 ", 6330" +%4444444b/>>>788886|-%+;;;;;-==*=S..........++;!!!!!!,,,,,,,,,,,,,,,,!!=SSS==;;<223555666677777888887777766665555332211|||}:&&SS%SSSSS%&&&{888888 ", 6331" +'4444440b>>>]888885}&SS-;;;;===*&.........++#;]]]]]]!!!,,,,,,,,,,,,,!!!!=S===;;^233556667777888888888877776666555332211||||[&*SS%SSSSSS&&&'888888 ", 6332" +(444444b8>>><888883_S+&;;;;-==**S........++S;////////]]!!,,,,,,,,,,,!!!!!===;;)~2355566777788888888888887776665553322211|||[-&*%%SSSSSS&&&-888888 ", 6333" +|444444b1>>>3888881{%+=;;;--==*=+.......++#;/<|11111<//]]!,,,,,,,,,!!!!!]!==;;))1355667778888888998888888777666555332211|||}-&&%SSSSSS%&&&*888888 ", 6334" +%4444446b!>>>6888871'%+;;;-;==*&#.......++S=]<133553331<//]!!,,,,,,,!!!!!]]);;))~|556667788888999999998888777666555332211|||}'**S%SSSSSS&&&&788888 ", 6335" +-4444440b>>>>888886|-%S;;;;;==&&+.......++=)<13577777531|//]!!,,,,,,!!!!]]]];;))~[556677888899999999999888877766655332211|||}'**SSSSSSSS&&&&688888 ", 6336" +'444444a0>>>!888885[&+%;;;;==-&=........+#=/|3578999977531//]!!,,,,!!!!!]]]/~))~~<566777888999999999999988877766655332211|||}'&&SSSSSSSS&&&&588888 ", 6337" +{444444b6>>>/888883_S+&;;;-==*&#........+#;/13679000098751|/]!!,,,,!!!!!]]///))~^<566778889999999999999998887766655533221||||'*&SSSSSSSS&&&&588888 ", 6338" +(444444b1>>>|888882{%+-;;-;==*=+........+S!/136790aaa098731</]!!,,,!!!!]]]///~~~^<6677888999999900009999998887766555332211|||{*&SS%SSSSS&&&&588888 ", 6339" +:444444b/>>>1888881'S+;;;;==-&&+........+#]/|357900aa009753|/]!!,,!!!!!]]]///^~~^<667788999999000000099999888776655533221||||{&*SS%SSSSS&&&&388888 ", 6340" +}444446b!>>>5888871-%%;;--==*&&.........+#]/<1367900a009753|/]!!,,!!!!!]]/////~^^<6678889999000000000099999887766655332211|||{&*SS%SSSSS&&&&388888 ", 6341" +|444446b!>>>688887|&+%;;;;==&=#..........=!]/<1367990099753|/]!!!!!!!!]]]////<^^^<6778899990000000000009999887766655332211|||{&*SS%SSSSS&&&&388888 ", 6342" +|444447b>>>>788886[*+%;;--==&&+..........=!!]/|136779887631</]!!!!!!!!]]]////<^^_<6788899900000000000000999888776655332211|||{&*SS%SSSSS&&&&388888 ", 6343" +|444448b>>>!888885<%+=;;;==-&=+..........,,!]//<1335676531|//]!!!!!!!!]]////<<_^_[6788999900000aaaa00000999988776655532211|||{**SS%SSSSS&&&&388888 ", 6344" +|444448b>>>]888885(S+=;--==*&=+..........;,,!!]//|1133311|//]!!!,!!!!!]]////<<<^_}788899900000aaaaaa0000099988776655532211|||'**SS%SSSSS&&&&588888 ", 6345" +|444448b>>>/888883{S+=;;-==&&&...........;,,,!!]///<|||<///]!!!,,!!!!]]]////<|<_<|78899900000aaaaaaaa000099988776655532211|||'&*SS%SSSSS&&&&588888 ", 6346" +:444448b>>>/888882{%+;;;;==&&%...........,,,,,!!!]]/////]]!!!!,,,!!!!]]]////<|<_<17889990000aaaaaaaaa000099988776655532211|||'&*SS%SSSS%&&&&588888 ", 6347" +:444447b>>><888882'%+;;--==*=#...........,,,,,,,,!!!!!!!!!!!,,,,,!!!!]]]///<<|<_<3788999000aaaaaaaaaaa00099988776655532211||}-&*SS%SSSSS&&&&688888 ", 6348" +(444446b!>>1888881'%%;;;==-*=#...........=,,,,,,,,,,,!!,,,,,,,,,!!!!!]]////<<|<_<5889990000aaaaaaaaaaa00099988776655532211||}-&*SS%SSSS%&&&&688888 ", 6349" +'444444b/>>1888881-+%;-;==-&=#...........#,,,,,,,,,,,,,,,,,,,,,,!!!!!]]////<|1<_<688999000aaaaaaaaaaaaa0099988776655532211||}-*&SSSSSSS%&&&&788888 ", 6350" +-444444b|>>388888|-+%;-;==-&=#...........#,,,,,,,,,,,,,,,,,,,,,,!!!!]]]////<||_<[788999000aaaaaaaaaaaa0009998877665533421|||[&*&SSSSSSS&&&&-888888 ", 6351" +%444444b3>>388888}&+%;;-==-&=#...........+,,,,,,,,,,,,,,,,,,,,,,!!!!]]]////<||_<|788999000aaaaaaaaaaaa00099988776655332211||:&&*SSSSSSS&&&&-888888 ", 6352" +|44444b9>>388887}&+%;;-==-*&%............;,,,,,,,,,,,,,,,,,,,,,!!!!]]]////<|<_<3788999000aaaaaaaaaaaaa009998877665433221|||(&**S%SSSSS&&&&'888888 ", 6353" +(44444ab>>588887[&+%;;-==-*&#............#,,,,,,,,,,,,,,,,,,,,,!!!!]]]///<<|__<688999000aaaaaaaaaaaaa0009998877665533221|||{&**SSSSSSS&&&&{888888 ", 6354" +-444447b>>588887[%+%;;-==-&&&............+,,,,,,,,,,,,,,,,,,,,,!!!!]]]///<<<^_[788999000aaaaaaaaaaaaa0009998876665533221|||{&&&%%SSSS%&&&&(88888 ", 6355" +%444444b<>588887[S+%;;-===&*&.............=,,,,,,,,,,,,,,,,,,,,!!!!]]]///<<_^_17889990000aaaaaaaaaaaa0009998776655533211|||'*&*S%SSSS%&&&&[88888 ", 6356" +(44444b8>588887<%+%;;-===*&=+............+,,,,,,,,,,,,,,,,,,,,!!!!]]]///<<^^_57889999000aaaaaaaaaaa00009998876655532211|||-&*SS%SSSSS&&&&188888 ", 6357" +&444440b>588887<%+%;-;===**&+.............=,,,,,,,,,,,,,,,,,,,!!!!]]]///<^^^[67889999000aaaaaaaaaaa00099988776655334211||[**&SS%SSSS&&&&&588888 ", 6358" +:44444b/588887<%+%;-;-==-&&S..............;,,,,,,,,,,,,,,,,,,!!!!]]]///_~^^2778889990000aaaaaaaaa00009998877665533221|||:&&*S%%SSSS&&&&&688888 ", 6359" +-44444b8588887<%+%;--;===***..............+,,,,,,,,,,,,,,,,,,!!!!]]]///~~^_6677889990000aaaaaaaaa00099998876665533221|||{&**%SSSSSS&&&&*888888 ", 6360" +(44449b788887<&+%;;--===-*&...............#,,,,,,,,,,,,,,,,,!!!!]]]//~)~^|66778899900000aaaaaaa000099988776655533211|||'*&*%%SSSS%&&&&'888888 ", 6361" +x|4444b088887<&+%;;;-====-*+...............#,,,,,,,,,,,,,,,,!!!!]]]])))~^5667788999900000aaaa00000999988776655332211||}-&*SS%SSSS&&&&&(888888 ", 6362" +-4444aa88888[&%%;;;;;====-S................#;,,,,,,,,,,,,,,!!!!]]]);))~}6667788999900000000000000999887766655332211||[**&SS%SSSS&&&&&[88888 ", 6363" +-4444088888[&%%;;---=====&.................+;,,,,,,,,,,,,,!!!!])=;;))^5666778889999000000000000999988776655533221|||(&&*S%SSSS%&&&&&288888 ", 6364" +-444788888}&S%;;;;;;=====+..................#,,,,,,,,,,,,!!!,===;;))15566777889999900000000009999887776655332211|||{&&*%%SSSS%&&&&&688888 ", 6365" +&:4788888|&S+;;;----=====....................#=,,,,,,,,,,;=S#==;;)_55566677888999990000000099999887766655332211||}-&*SS%SSSS&&&&&-788888 ", 6366" ++-3888881*S+;;;;;;-;====+......................+##===##++#SS===;~25556667788899999900000999999887766655533221|||[-&&SS%SSSS&&&&&{888888 ", 6367" ++{888882-%+=;;;;;;--;--=............................++++#SS===;|35556667778889999999999999998887766655332211|||(&**S%SSSS%&&&&&<88888 ", 6368" _888883-%+=;;;;;;-;;---S...........................+++++SSS==<233555666778889999999999999988877666555332211|||'&&S%%SSSS&&&&&&388888 ", 6369" 888885'&+&;;;;;;-;;---;+..........................++++++SS=^223355566677788899999999999988877766555332211|||}-&&SS%SSSS&&&&&&688888 ", 6370" 888886{&%%;;;;;;;;;--;;=..........................++++++SS~1223355556667788888999999998888777666555332211|||(&**S%SSSS%&&&&&'888888 ", 6371" 888886{&SS;;;;;;;;;;;;;;=..........................++++#S~|122333556666777888888999988888777666655332221||||{&*S%%SSSS&&&&&&(888888 ", 6372" 888888(&S+-;;;;;;;;;;;;;;S.........................++++#~||122233555666677788888888888887776666555332211|||}-&&SS%SSSS&&&&&&288888 ", 6373" 888888<&%+--;;;;;;;;;;;;;;S........................++++^}||11223355556666777788888888887776666555332221||||(*&*S%SSSSS&&&&&&688888 ", 6374" 888888}&&+-)-;;;;;;;;;;;-))=.......................++=_}}||11223334556666677777888887777766665543332211|||}'**SS%SSSS&&&&&&'888888 ", 6375" 888882&&S&)))--;;;;;;-))))';+.....................+)<[}}||1122233555566666777777777777766666555332221||||[***SS%SSS%&&&&&&[88888 ", 6376" 888885-&S%''))))))))))))'''''=..................+;_<[[}||||112233355556666677777777776666665553322211|||}{**S%%SSSS&&&&&&&588888 ", 6377" 888886'&%+)))'))))))')'''')')))=+.............+;^<<<[[}||||11222335555566666677777766666665553332211||||}-&*SS%SSS%&&&&&&-888888 ", 6378" 888887{&&%-''')))))'''')''))))~~~)=+......+S;~__<<<<[[}|||||1122333555556666666666666666555533322211|||}:&*S%%SSSS&&&&&&&_888888 ", 6379" 888888<&&S&)'''''''''''))))))~~~~~~~~~~~~^^^____<<<<[[}}||||112223335555566666666666666555553322211||||}'**SS%SSS%&&&&&&&388888 ", 6380" 888881&&%%'''')''''))')))))~~~~~~~~^^^^^^^^____<<<[[}}}|||||1122233355555666666666665555553322211||||}:&*S%%SSSS&&&&&&&-788888 ", 6381" 888885&&&%-'))))))')))))))~~~~~~~~^^^^^^^^_____<<<[[}}}}||||1122233335555555656555555545333222111||||}{**SS%SSS%&&&&&&&<888888 ", 6382" 888886'&&%&)))))))))))))~~~~~~~~~^^^^^^^^_____<<<<[[}}}}|||||11224333355555555555555555333232211||||}<&*S%%SSSS&&&&&&&&588888 ", 6383" 888888{&&%%)))))))))))~)~~~~~~~~^^^^^^^^______<<<[[[}}}}}||||1112223333555555555554553333222211||||}}{&*SS%SSS%&&&&&&&'888888 ", 6384" 888888[&&&%'))))))))~~~~~~~~~~~^^^^^^^^______<<<<[[[[}}}}|||||11122433333555555555533333222211|||||}<-&SS%SSSS&&&&&&&&}888888 ", 6385" 888883&&&%=)))))~~)~~~~~~~~~~^^^^^^^^^_____<<<<[[[[[}}}}}|||||112222333333335533333333222211|||||}}{*SSS%SSS&&&&&&&&&688888 ", 6386" 888886-&&&%)~~))~~~~~~~~~~~~^^^^^^^^^_____<<<<[[[[[[[}}}}|||||11122222333333333333332222111|||||}}:**SS%SSSS&&&&&&&&(888888 ", 6387" 888888^&&&%-~~~~~~~~~~~~~~^^^^^^^^^^______<<<<[[[[[[[}}}}}||||||11122222333333333422222111|||||}}}'&S%%%SSS&&&&&&&&&3888888 ", 6388" 888888|&&&&*~~~~~~~~~~~~~^^^^^^^^^^______<<<<[[[[[[[[[}}}}}||||||111222222422242222222111||||||}}_*SSS%SSS&&&&&&&&&'888888 ", 6389" 888885*&&&S)~~~~~~~~~~~^^^^^^^^^^______<<<<<[[[[[[[[[}}}}}}||||||111122222222222222111|||||||}}[-SSS%SSS%&&&&&&&&&1888888 ", 6390" 888888{&&&&-~~~~~~~~~^^^^^^^^^^^______<<<<<[[[[[[[[[[[}}}}}}||||||1111112222222211111|||||||}}}{*SS%SSSS&&&&&&&&&-888888 ", 6391" 888888[&&&&S~~~~~~~^^^^^^^^^^^^______<<<<<[[[[[[[[[[[[[}}}}}}|||||||111111111111111|||||||}}}}<*SS%%SSS&&&&&&&&&&[888888 ", 6392" 888885&&&&&-~~~~^^^^^^^^^^^^^_______<<<<[[[[[[[[[[[[[[[}}}}}}|||||||||1111111111||||||||}}}}[-SSS%SSSS&&&&&&&&&-788888 ", 6393" 888888{&&&&&~~^^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[[[[[}}}}}}|||||||||||||||||||||||||}}}}}{SSS%SSSS&&&&&&&&&&[888888 ", 6394" 888888|&&&&&-^^^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[[[[[[[}}}}}}||||||||||||||||||||||}}}}}}<&%S%SSSS&&&&&&&&&&-788888 ", 6395" 888887&&&&&&~^^^^^^^^^^^^_______<<<<<[[[[[[[[[[[[[[[[[[[[}}}}}}}||||||||||||||||||}}}}}}}[-SS%SSSS&&&&&&&&&&&[888888 ", 6396" 888888(&&&&&-^^^^^^^^^^________<<<<<[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}||||||||||||||}}}}}}}}['SS%SSSS&&&&&&&&&&&-7888888 ", 6397" 888883&&&&&&~^^^^^^^^________<<<<<[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}||||||||}}}}}}}}}}[^%S%SSSS&&&&&&&&&&&&|888888 ", 6398" 888888'&&&&&-_^^^^^^________<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}}}}}}}}}}}}}}}}}[_&S%SSSS&&&&&&&&&&&&'788888 ", 6399" 888888|&&&&&&{_^^^_________<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}}}}}}}}}}}}}[[<&%%SSSS&&&&&&&&&&&&&2888888 ", 6400" 888887-&&&&&&(___________<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}}}}}}}}}[[[[-%%SSSS&&&&&&&&&&&&&{888888 ", 6401" 888888[&&&&&&*[________<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[}}}}}}}}}}}}[[[[[[-%SSSSSS&&&&&&&&&&&&&6888888 ", 6402" 888887-&&&&&&'}______<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[['%SSSSSS&&&&&&&&&&&&&[888888 ", 6403" 888888[&&&&&&&{|____<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[['SSSSSSS&&&&&&&&&&&&&'7888888 ", 6404" 888887-&&&&&&&_|__<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[['SSSSSS&&&&&&&&&&&&&&&3888888 ", 6405" 888888}&&&&&&&&[|<<<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<'SSSSSS&&&&&&&&&&&&&&&[888888 ", 6406" 888887'&&&&&&&&[1<<<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<-SSSSSS&&&&&&&&&&&&&&&'8888888 ", 6407" 8888882&&&&&&&&&}2<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<*SSSSS%&&&&&&&&&&&&&&&&5888888 ", 6408" 888888{&&&&&&&&&[3[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[^*SSSSS&&&&&&&&&&&&&&&&&18888888 ", 6409" 8888886&&&&&&&&&&<3|[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{SSSSS%&&&&&&&&&&&&&&&&&(8888888 ", 6410" 888888}&&&&&&&&&&{32[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<-SSSS%&&&&&&&&&&&&&&&&&&'8888888 ", 6411" 8888888{&&&&&&&&&&'23|[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{*SSSS%&&&&&&&&&&&&&&&&&&-6888888 ", 6412" 8888886-&&&&&&&&&&&[52}[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[_-SSSS%&&&&&&&&&&&&&&&&&&&&58888888 ", 6413" 8888882&&&&&&&&&&&&{252}[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<{SSSS%&&&&&&&&&&&&&&&&&&&&&18888888 ", 6414" 8888888<&&&&&&&&&&&&&_352}[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<{*SSS%&&&&&&&&&&&&&&&&&&&&&&}8888888 ", 6415" 8888888{&&&&&&&&&&&&&-_353|[[[[[[[[[[[[[[[[[[[[[[[[[[[[<{*SSS&&&&&&&&&&&&&&&&&&&&&&&&<8888888 ", 6416" 8888886'&&&&&&&&&&&&&&-(1552|[[[[[[[[[[[[[[[[[[[[[[<_'SSS&&&&&&&&&&&&&&&&&&&&&&&&&&(88888888 ", 6417" 88888885-&&&&&&&&&&&&&&&&'<15531|}[[[[[[[[[[[[[[<_'*S%&&&&&&&&&&&&&&&&&&&&&&&&&&&&_88888888 ", 6418" 88888883&&&&&&&&&&&&&&&&&&&-{[135332211||||}<{'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(88888888 ", 6419" 88888882&&&&&&&&&&&&&&&&&&&&&&&-'{{{{{{'-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&:88888888 ", 6420" 88888881&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&[88888888 ", 6421" 788888881&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-188888888 ", 6422" 788888882&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-588888888 ", 6423" 888888885-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{688888888 ", 6424" 888888886'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&[888888888 ", 6425" 888888887(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-3888888888 ", 6426" 8888888881*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&_7888888888 ", 6427" 7888888886{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'3888888888 ", 6428" 78888888881-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-}7888888888 ", 6429" 78888888886<&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&<68888888888 ", 6430" 88888888886(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-:68888888888 ", 6431" 788888888886<-&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'|788888888888 ", 6432" 78888888888882{*&&&&&&&&&&&&&&&&&&&&&&&&&&&-<5888888888888 ", 6433" 788888888888872(-&&&&&&&&&&&&&&&&&&&&&{[588888888888888 ", 6434" 788888888888888861:{'-&&&&&&&&&-'(}37888888888888888 ", 6435" 788888888888888888886655555678888888888888888888 ", 6436" 78888888888888888888888888888888888888888888 ", 6437" 7788888888888888888888888888888888888888 ", 6438" 77888888888888888888888888888888888 ", 6439" 77888888888888888888888888887 ", 6440" 77888888888888888887 ", 6441" "); 6442 6443my $pixbuf_sound = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@sound); 6444# $pixbuf_sound->scale_simple ($dest_width, $dest_height, $interp_type) 6445my $sound_size_w = 14; # (36 46) scale the pixbuf_sound button 6446my $sound_size_h = 16; 6447$pixbuf_sound = $pixbuf_sound->scale_simple ( $sound_size_w, $sound_size_h, 'bilinear'); # hyper, bilinear 6448 6449 6450my @random = ( 6451# /* columns rows colors chars-per-pixel */ 6452"200 200 3 1", 6453" c None", 6454". c $color_cdplayer_arrows", 6455"+ c $color_cdplayer_shadow", 6456" ", 6457" ", 6458" ", 6459" ", 6460" ", 6461" ............................ ", 6462" ...................................... ", 6463" .............................................. ", 6464" ...................................................... ", 6465" ............................................................ ", 6466" .................................................................. ", 6467" ........................................................................ ", 6468" ............................................................................ ", 6469" ................................................................................ ", 6470" ..............................++++++++++++++++++++++++++.............................. ", 6471" ..........................++++++++++++++++++++++++++++++++++++.......................... ", 6472" ........................++++++++++++++++++++++++++++++++++++++++++++........................ ", 6473" ......................++++++++++++++++++++++++++++++++++++++++++++++++++++...................... ", 6474" .....................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................... ", 6475" ....................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................... ", 6476" ...................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................... ", 6477" ..................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................. ", 6478" ..................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................. ", 6479" .................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................. ", 6480" ................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................ ", 6481" ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6482" ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6483" ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6484" ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6485" ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6486" ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............. ", 6487" .............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............. ", 6488" ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............. ", 6489" .............++++++++++++++++++++++++++++++++++++++++++++......................++++++++++++++++++++++++++++++++++++++++++++............. ", 6490" .............++++++++++++++++++++++++++++++++++++++++.................................+++++++++++++++++++++++++++++++++++++++............. ", 6491" ............++++++++++++++++++++++++++++++++++++++.........................................+++++++++++++++++++++++++++++++++++++............. ", 6492" ............++++++++++++++++++++++++++++++++++++...............................................+++++++++++++++++++++++++++++++++++............ ", 6493" .............++++++++++++++++++++++++++++++++++...................................................+++++++++++++++++++++++++++++++++............. ", 6494" ............++++++++++++++++++++++++++++++++++........................................................++++++++++++++++++++++++++++++++............ ", 6495" ............+++++++++++++++++++++++++++++++++............................................................+++++++++++++++++++++++++++++++............ ", 6496" ............++++++++++++++++++++++++++++++++..............................................................++++++++++++++++++++++++++++++............ ", 6497" ...........++++++++++++++++++++++++++++++++..................................................................++++++++++++++++++++++++++++++........... ", 6498" ...........+++++++++++++++++++++++++++++++.....................................................................++++++++++++++++++++++++++++++........... ", 6499" ............++++++++++++++++++++++++++++++........................................................................++++++++++++++++++++++++++++............ ", 6500" ............++++++++++++++++++++++++++++++..........................................................................++++++++++++++++++++++++++++............ ", 6501" ...........++++++++++++++++++++++++++++++............................................................................++++++++++++++++++++++++++++........... ", 6502" ...........++++++++++++++++++++++++++++++..............................................................................++++++++++++++++++++++++++++........... ", 6503" ...........++++++++++++++++++++++++++++++................................................................................++++++++++++++++++++++++++++........... ", 6504" ...........+++++++++++++++++++++++++++++..................................................................................+++++++++++++++++++++++++++........... ", 6505" ...........+++++++++++++++++++++++++++++....................................................................................+++++++++++++++++++++++++++........... ", 6506" ...........+++++++++++++++++++++++++++++......................................................................................+++++++++++++++++++++++++++........... ", 6507" ...........++++++++++++++++++++++++++++.......................................................................................+++++++++++++++++++++++++++........... ", 6508" ...........+++++++++++++++++++++++++++++........................................................................................+++++++++++++++++++++++++++........... ", 6509" ..........+++++++++++++++++++++++++++++.........................................................................................++++++++++++++++++++++++++++.......... ", 6510" ..........+++++++++++++++++++++++++++++...........................................................................................++++++++++++++++++++++++++++.......... ", 6511" ..........+++++++++++++++++++++++++++++........................................+++++++++++........................................++++++++++++++++++++++++++++.......... ", 6512" ..........+++++++++++++++++++++++++++++.....................................++++++++++++++++++++....................................++++++++++++++++++++++++++++.......... ", 6513" ...........++++++++++++++++++++++++++++....................................++++++++++++++++++++++++..................................++++++++++++++++++++++++++++........... ", 6514" ..........+++++++++++++++++++++++++++++..................................+++++++++++++++++++++++++++.................................+++++++++++++++++++++++++++++.......... ", 6515" ..........+++++++++++++++++++++++++++++................................+++++++++++++++++++++++++++++++................................++++++++++++++++++++++++++++.......... ", 6516" ..........+++++++++++++++++++++++++++++................................+++++++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++.......... ", 6517" ..........+++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++..............................+++++++++++++++++++++++++++++.......... ", 6518" ..........+++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++++..............................+++++++++++++++++++++++++++++.......... ", 6519" ..........+++++++++++++++++++++++++++++..............................+++++++++++++++++++++++++++++++++++++++.............................+++++++++++++++++++++++++++++.......... ", 6520" ..........++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++.......... ", 6521" ..........+++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++.......... ", 6522" .........++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++......... ", 6523" ..........++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++.......... ", 6524" ..........++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++.......... ", 6525" .........++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++......... ", 6526" ..........++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++.......... ", 6527" .........+++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++......... ", 6528" .........+++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++.......... ", 6529" ..........++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++...........................+++++++++++++++++++++++++++++++++.......... ", 6530" .........+++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++...........................++++++++++++++++++++++++++++++++++......... ", 6531" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++......... ", 6532" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++......... ", 6533" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++.......... ", 6534" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................+++++++++++++++++++++++++++++++++++......... ", 6535" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++......... ", 6536" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++......... ", 6537" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................+++++++++++++++++++++++++++++++++++++.......... ", 6538" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++......... ", 6539" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............................++++++++++++++++++++++++++++++++++++++......... ", 6540" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............................+++++++++++++++++++++++++++++++++++++++......... ", 6541" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++++++......... ", 6542" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................................++++++++++++++++++++++++++++++++++++++++.......... ", 6543" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................................++++++++++++++++++++++++++++++++++++++++++......... ", 6544" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................................++++++++++++++++++++++++++++++++++++++++++......... ", 6545" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................................+++++++++++++++++++++++++++++++++++++++++++......... ", 6546" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................................++++++++++++++++++++++++++++++++++++++++++++......... ", 6547" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................................+++++++++++++++++++++++++++++++++++++++++++++......... ", 6548" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................++++++++++++++++++++++++++++++++++++++++++++++......... ", 6549" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................+++++++++++++++++++++++++++++++++++++++++++++++......... ", 6550" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6551" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................+++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6552" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6553" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................+++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6554" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.....................................++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6555" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6556" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................+++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6557" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++....................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6558" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6559" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6560" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6561" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6562" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6563" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6564" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6565" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6566" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6567" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6568" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6569" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6570" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6571" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6572" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6573" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6574" ..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6575" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6576" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6577" .........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++...........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6578" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6579" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6580" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6581" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6582" ..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..........................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6583" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6584" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6585" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6586" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6587" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6588" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6589" .........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++......... ", 6590" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6591" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6592" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6593" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6594" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6595" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6596" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6597" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6598" ...........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6599" ..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6600" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6601" ..........++++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6602" ..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.......... ", 6603" ...........++++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6604" ...........+++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6605" ...........+++++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6606" ...........++++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6607" ...........+++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6608" ...........+++++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6609" ...........++++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6610" ...........+++++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6611" ............++++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++++............ ", 6612" ............+++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++............ ", 6613" ...........+++++++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++++++........... ", 6614" ...........++++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++++............ ", 6615" ............++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++............ ", 6616" ............++++++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++++++............ ", 6617" ............+++++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++++............ ", 6618" .............+++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++............. ", 6619" ............+++++++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++++++............ ", 6620" .............++++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++++............. ", 6621" .............++++++++++++++++++++++++++++++++++++++............................++++++++++++++++++++++++++++++++++++++++++++++............. ", 6622" .............+++++++++++++++++++++++++++++++++++++............................+++++++++++++++++++++++++++++++++++++++++++++............. ", 6623" ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............. ", 6624" .............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............. ", 6625" ..............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.............. ", 6626" ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6627" ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6628" ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6629" ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6630" ...............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++............... ", 6631" ................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................. ", 6632" .................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................. ", 6633" ..................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................. ", 6634" ..................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................. ", 6635" ...................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................... ", 6636" ....................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.................... ", 6637" .....................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..................... ", 6638" ......................++++++++++++++++++++++++++++++++++++++++++++++++++++...................... ", 6639" ........................++++++++++++++++++++++++++++++++++++++++++++........................ ", 6640" ..........................++++++++++++++++++++++++++++++++++++.......................... ", 6641" ..............................++++++++++++++++++++++++++.............................. ", 6642" ................................................................................ ", 6643" ............................................................................ ", 6644" ........................................................................ ", 6645" .................................................................. ", 6646" ............................................................ ", 6647" ........................................................ ", 6648" .............................................. ", 6649" ...................................... ", 6650" ............................ ", 6651" ", 6652" ", 6653" ", 6654" ", 6655" "); 6656 6657 6658my $pixbuf_random = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@random); 6659# $pixbuf_sound->scale_simple ($dest_width, $dest_height, $interp_type) 6660my $random_w = 14; # (38 64) scale 6661my $random_h = 14; 6662$pixbuf_random = $pixbuf_random->scale_simple ( $random_w, $random_h, 'bilinear'); # hyper, bilinear 6663 6664my @random2 = @random; # To change the color of the random button, then make copy 6665$random2[3] = ". c #BFBFBF"; # #BFBFBF 6666my $pixbuf_random2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@random2); 6667$pixbuf_random2 = $pixbuf_random2->scale_simple ( $random_w, $random_h, 'bilinear'); 6668 6669 6670my @loop = ( 6671# /* columns rows colors chars-per-pixel */ 6672"100 98 3 1", 6673" c None", 6674". c $color_cdplayer_shadow", 6675"+ c $color_cdplayer_arrows", 6676" ........................................ ", 6677" ........................................... ", 6678" ............................................ ", 6679" . ...++++++++++++++++++++++++++++++++++++++... ", 6680" ....... ...+++++++++++++++++++++++++++++++++++++.... ", 6681" ........... ...++++++++++++++++++++++++++++++++++++.... ", 6682" .........++... ...+++++++++++++++++++++++++++++++++++.... ", 6683" .......++++..... ...++++++++++++++++++++++++++++++++++.... ", 6684" ......++++++..... ...+++++++++++++++++++++++++++++++++.... ", 6685" ......++++++..... ...++++++++++++++++++++++++++++++++.... ", 6686" .....+++++++.... ...+++++++++++++++++++++++++++++++.... ", 6687" .....++++++++.... ...++++++++++++++++++++++++++++++.... ", 6688" ....++++++++++... ...++++++++++++++++++++++++++++..... ", 6689" ....++++++++++... ...+++++++++++++++++++++++++++..... ", 6690" ....++++++++++... ...++++++++++++++++++++++++++..... ", 6691" ...+++++++++++.... ...+++++++++++++++++++++++++++..... ", 6692" ...++++++++++++... ...+++++++++++++++++++++++++++++..... ", 6693" ...++++++++++++... ...++++++++++++++++++++++++++++++..... ", 6694" ....+++++++++++.... ...++++++++++++++++++++++++++++++++.... ", 6695" ...++++++++++++... ...+++++++++++++++++++++++++++++++++.... ", 6696" ...++++++++++++... ...++++++++++++++++++++++++++++++++++.... ", 6697" ...+++++++++++++... ...+++++++++++++++++++++++++++++++++++.... ", 6698" ...++++++++++++... ...++++++++++++++++++++++++++++++++++++.... ", 6699" ...+++++++++++++... ...+++++++++++++++++++++++++++++++++++++.... ", 6700" ...+++++++++++++... ...++++++++++++++++++++++++++++++++++++++... ", 6701" ...+++++++++++++... ...+++++++++++++++++++++++++++++++++++++++... ", 6702" ...+++++++++++++... ...+++++++++++++++++++++++++++++++++++++++.... ", 6703" ...++++++++++++++.. ...++++++++++++++++++++++++++++++++++++++++.... ", 6704" ...+++++++++++++... ...+++++++++++++++++++++++++++++++++++++++++... ", 6705" ..++++++++++++++... ...+++++++++++.+++++++++++++++++++++++++++++.... ", 6706" ...++++++++++++++... ...++++++++++...+++++++++++++++++++++++++++++... ", 6707" ...++++++++++++++.. ...++++++++++.....++++++++++++++++++++++++++++... ", 6708" ..+++++++++++++++.. ...+++++++++.......+++++++++++++++++++++++++++... ", 6709" ...++++++++++++++... ...++++++++.... .....++++++++++++++++++++++++++... ", 6710" ...++++++++++++++... ...+++++++.... .....+++++++++++++++++++++++++... ", 6711" ..+++++++++++++++... ...++++++.... ....+++++++++++++++++++++++++... ", 6712" ..+++++++++++++++... ...+++++.... ....++++++++++++++++++++++++... ", 6713" ...+++++++++++++++... ...+++++... ....+++++++++++++++++++++++... ", 6714" ...++++++++++++++++.. ...++++... ....+++++++++++++++++++++++... ", 6715" ...++++++++++++++++.. ...+++.... ....++++++++++++++++++++++... ", 6716" ..+++++++++++++++++.. ...++.... ....+++++++++++++++++++++... ", 6717" ..+++++++++++++++++... ...+.... ...++++++++++++++++++++++... ", 6718" ..+++++++++++++++++... ....... ...+++++++++++++++++++++... ", 6719" ..+++++++++++++++++... ...... ....++++++++++++++++++++... ", 6720" ..++++++++++++++++++.. .... ...++++++++++++++++++++... ", 6721"...++++++++++++++++++... .. ...+++++++++++++++++++... ", 6722"...++++++++++++++++++... ...+++++++++++++++++++... ", 6723"...++++++++++++++++++... ...+++++++++++++++++++.. ", 6724" ..+++++++++++++++++++... ...+++++++++++++++++++... ", 6725" ..+++++++++++++++++++... ...+++++++++++++++++++... ", 6726" ..++++++++++++++++++++... ...++++++++++++++++++... ", 6727" ..++++++++++++++++++++... .. ...++++++++++++++++++... ", 6728" ...++++++++++++++++++++... ..... ...++++++++++++++++++... ", 6729" ...++++++++++++++++++++... ..... ...+++++++++++++++++.. ", 6730" ...+++++++++++++++++++++... ...+.. ...++++++++++++++++... ", 6731" ..+++++++++++++++++++++.... ...++.. ...++++++++++++++++... ", 6732" ...+++++++++++++++++++++.... ...+++.. ...++++++++++++++++... ", 6733" ...++++++++++++++++++++++... ....+++.. ...++++++++++++++++... ", 6734" ...+++++++++++++++++++++++... ....++++.. ...++++++++++++++++... ", 6735" ...+++++++++++++++++++++++... ....+++++.. ...++++++++++++++++... ", 6736" ...++++++++++++++++++++++++... ....++++++.. ..+++++++++++++++... ", 6737" ..+++++++++++++++++++++++++.... ....+++++++.. ..+++++++++++++++... ", 6738" ...+++++++++++++++++++++++++.... ...++++++++.. ...+++++++++++++++... ", 6739" ...++++++++++++++++++++++++++..... ...+++++++++... ...+++++++++++++++... ", 6740" ...++++++++++++++++++++++++++.......++++++++++... ...++++++++++++++... ", 6741" ...++++++++++++++++++++++++++++....+++++++++++... ...++++++++++++++... ", 6742" ...+++++++++++++++++++++++++++++..+++++++++++... ...++++++++++++++... ", 6743" ...+++++++++++++++++++++++++++++++++++++++++... ..++++++++++++++... ", 6744" ...+++++++++++++++++++++++++++++++++++++++++... ...++++++++++++++... ", 6745" ...++++++++++++++++++++++++++++++++++++++++... ...++++++++++++++... ", 6746" ...+++++++++++++++++++++++++++++++++++++++... ...+++++++++++++... ", 6747" ....++++++++++++++++++++++++++++++++++++++... ...++++++++++++++... ", 6748" ....+++++++++++++++++++++++++++++++++++++... ...+++++++++++++... ", 6749" ....++++++++++++++++++++++++++++++++++++... ...++++++++++++++... ", 6750" ....+++++++++++++++++++++++++++++++++++... ...+++++++++++++... ", 6751" ....++++++++++++++++++++++++++++++++++... ...+++++++++++++.... ", 6752" ....+++++++++++++++++++++++++++++++++... ...+++++++++++++... ", 6753" ....++++++++++++++++++++++++++++++++... ...+++++++++++++... ", 6754" .....++++++++++++++++++++++++++++++... ...++++++++++++.... ", 6755" .....+++++++++++++++++++++++++++++... ...++++++++++++.... ", 6756" .....+++++++++++++++++++++++++++... ....+++++++++++.... ", 6757" .....++++++++++++++++++++++++++... ....+++++++++++.... ", 6758" ....+++++++++++++++++++++++++++... ....+++++++++++.... ", 6759" ....++++++++++++++++++++++++++++... ...+++++++++++.... ", 6760" ....+++++++++++++++++++++++++++++... ....++++++++++..... ", 6761" ....++++++++++++++++++++++++++++++... ....++++++++++..... ", 6762" ....+++++++++++++++++++++++++++++++... ....+++++++++..... ", 6763" ....++++++++++++++++++++++++++++++++... .....++++++++...... ", 6764" ....+++++++++++++++++++++++++++++++++... .....++++++....... ", 6765" ....++++++++++++++++++++++++++++++++++... .....+++......... ", 6766" ....+++++++++++++++++++++++++++++++++++... ............... ", 6767" ....++++++++++++++++++++++++++++++++++++... ........... ", 6768" ....+++++++++++++++++++++++++++++++++++++... ...... ", 6769" ...++++++++++++++++++++++++++++++++++++++... ", 6770" ............................................ ", 6771" .......................................... ", 6772" ...... ", 6773" "); 6774 6775my $pixbuf_loop = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@loop); 6776# $pixbuf_sound->scale_simple ($dest_width, $dest_height, $interp_type) 6777my ( $loop_w , $loop_h ) = ( 15, 15 ); # Scale (60, 50) 6778$pixbuf_loop = $pixbuf_loop->scale_simple ( $loop_w, $loop_h, 'bilinear'); # hyper, bilinear 6779 6780my @loop2 = @loop; # To change the color of the loop button, then make copy 6781$loop2[3] = ". c #BFBFBF"; # #A7B1BE 6782my $pixbuf_loop2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@loop2); 6783$pixbuf_loop2 = $pixbuf_loop2->scale_simple ( $loop_w, $loop_h, 'bilinear'); 6784 6785 6786my @buttons = ( # 8 buttons ; (x,y) = (256,128) = (4,2)*64 ; the dimension of each button is 64x64 6787# /* columns rows colors chars-per-pixel */ 6788"256 128 3 1", 6789#" c #000000", 6790" c None", 6791". c $color_cdplayer_arrows", # RGB = ( 0, 0, 0) = black 6792#". c #FFFFFF", # RGB = (255,255,255) = white 6793#"& c #6e95ef", # azul m�dio 6794"& c $color_cdplayer_shadow", 6795" ", 6796" ", 6797" &&&&&&&&&&&&&&&& &&&&&&&& &&&&&&&&&&&&&&&& &&&&&&&& ", 6798" &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& ", 6799" &&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& ", 6800" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6801" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6802" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6803" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6804" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6805" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6806" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6807" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6808" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6809" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6810" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6811" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&............&&&&&&&&............&&&&&&&&& &&&&&&&&&&&&..&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6812" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&............&&&&&&&&............&&&&&&&&&& &&&&&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&& ", 6813" &&&&&&&&&&&&&............................&&&&&&&&&&&&& &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&& &&&&&&&&&&&&&.....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&....&&&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&& ", 6814" &&&&&&&&&&&&&&............................&&&&&&&&&&&&&& &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&& &&&&&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&& ", 6815" &&&&&&&&&&&&&&............................&&&&&&&&&&&&&& &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&& &&&&&&&&&&&&&&.........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&& ", 6816" &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&& &&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&& &&&&&&&&&&&&&&&............&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&.........&&&&&&&&&&&&&&&&.......&&&&&&&&&&&& ", 6817" &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&& &&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&& &&&&&&&&&&&&&&&..............&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&..........&&&&&&&&&&&&&&&.......&&&&&&&&&&&& ", 6818" &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&................&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&&&&&&.......&&&&&&&&&&&&& ", 6819" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&&..................&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.............&&&&&&&&&&&&.......&&&&&&&&&&&&& ", 6820" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&&....................&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&...............&&&&&&&&&&.......&&&&&&&&&&&&& ", 6821" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&&......................&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&................&&&&&&&&&.......&&&&&&&&&&&&& ", 6822" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&&........................&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&..................&&&&&&&.......&&&&&&&&&&&&& ", 6823" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&..........................&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&...................&&&&&&.......&&&&&&&&&&&&&& ", 6824" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&.....................&&&&.......&&&&&&&&&&&&&& ", 6825" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&..............................&&&&&&&&&&&&&& &&&&&&&&&&&&&&......................&&&.......&&&&&&&&&&&&&& ", 6826" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&................................&&&&&&&&&&&& &&&&&&&&&&&&&&........................&.......&&&&&&&&&&&&&& ", 6827" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&................................&&&&&&&&&&&& &&&&&&&&&&&&&&........................&.......&&&&&&&&&&&&&& ", 6828" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&..............................&&&&&&&&&&&&&& &&&&&&&&&&&&&&.......................&&.......&&&&&&&&&&&&&& ", 6829" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&.....................&&&&.......&&&&&&&&&&&&&& ", 6830" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&..........................&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&....................&&&&&.......&&&&&&&&&&&&&& ", 6831" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&&........................&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&..................&&&&&&&.......&&&&&&&&&&&&& ", 6832" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&&......................&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.................&&&&&&&&.......&&&&&&&&&&&&& ", 6833" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&&....................&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&...............&&&&&&&&&&.......&&&&&&&&&&&&& ", 6834" &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&&..................&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&..............&&&&&&&&&&&.......&&&&&&&&&&&&& ", 6835" &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&&& &&&&&&&&&&&&&&&................&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&............&&&&&&&&&&&&&.......&&&&&&&&&&&&& ", 6836" &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&& &&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&& &&&&&&&&&&&&&&&..............&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&...........&&&&&&&&&&&&&&.......&&&&&&&&&&&& ", 6837" &&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&& &&&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&&& &&&&&&&&&&&&&&&............&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&.........&&&&&&&&&&&&&&&&.......&&&&&&&&&&&& ", 6838" &&&&&&&&&&&&&&............................&&&&&&&&&&&&&& &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&& &&&&&&&&&&&&&&..........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&& ", 6839" &&&&&&&&&&&&&&............................&&&&&&&&&&&&&& &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&& &&&&&&&&&&&&&&........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&& ", 6840" &&&&&&&&&&&&&............................&&&&&&&&&&&&& &&&&&&&&&&&............&&&&&&&&............&&&&&&&&&&& &&&&&&&&&&&&&.....&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&....&&&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&& ", 6841" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&............&&&&&&&&............&&&&&&&&&& &&&&&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&& ", 6842" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&............&&&&&&&&............&&&&&&&&& &&&&&&&&&&&&..&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6843" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6844" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6845" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6846" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6847" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6848" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6849" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6850" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6851" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6852" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6853" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6854" &&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& ", 6855" &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& ", 6856" &&&&&&&&&&&&&&&& &&&&&&&& &&&&&&&&&&&&&&&& &&&&&&&& ", 6857" ", 6858" ", 6859" ", 6860" ", 6861" &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& ", 6862" &&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& ", 6863" &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& ", 6864" &&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6865" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6866" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6867" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6868" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6869" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6870" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6871" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6872" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6873" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&..&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6874" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&....&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6875" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.&&&&&&&&& ", 6876" &&&&&&&&.&&&&&&&&&&&&&&&&&&.&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&........&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&&...&&&&&&&&&& ", 6877" &&&&&&&&&...&&&&&&&&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&.&&&&&&&&&&&&&&&&&&.&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&..........&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&....&&&&&&&&&&& ", 6878" &&&&&&&&&....&&&&&&&&&&&&&&&.....&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&...&&&&&&&&&&&&&&&&...&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&............&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&& ", 6879" &&&&&&&&&......&&&&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&.....&&&&&&&&&&&&&&&....&&&&&&&&& &&&&&&&&&&&&&&&&&&&&..............&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&& ", 6880" &&&&&&&&&&.......&&&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&&&&......&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&................&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&.......&&&&&&&&&&&&&&&&.........&&&&&&&&&&&& ", 6881" &&&&&&&&&&.........&&&&&&&&&&.........&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&&.......&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&................&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&.......&&&&&&&&&&&&&&&..........&&&&&&&&&&&& ", 6882" &&&&&&&&&&&...........&&&&&&&&...........&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&.........&&&&&&&&&&.........&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&..................&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&&&&&&&............&&&&&&&&&&&&& ", 6883" &&&&&&&&&&&............&&&&&&&............&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&...........&&&&&&&&...........&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&....................&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&&&&&&.............&&&&&&&&&&&&& ", 6884" &&&&&&&&&&&..............&&&&&..............&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&............&&&&&&&............&&&&&&&&&&& &&&&&&&&&&&&&&&&&&......................&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&&&&...............&&&&&&&&&&&&& ", 6885" &&&&&&&&&&&...............&&&&...............&&&&&&&&&&&&& &&&&&&&&&&&&&&..............&&&&&..............&&&&&&&&&&& &&&&&&&&&&&&&&&&&........................&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&&&................&&&&&&&&&&&&& ", 6886" &&&&&&&&&&&.................&&.................&&&&&&&&&&& &&&&&&&&&&&&&...............&&&&...............&&&&&&&&&&& &&&&&&&&&&&&&&&&&........................&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&..................&&&&&&&&&&&&& ", 6887" &&&&&&&&&&&&..................&...................&&&&&&&&&& &&&&&&&&&&&&.................&&.................&&&&&&&&&&&& &&&&&&&&&&&&&&&&&..........................&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&.......&&&&&&...................&&&&&&&&&&&&&& ", 6888" &&&&&&&&&&&&.......................................&&&&&&&&& &&&&&&&&&&...................&..................&&&&&&&&&&&& &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&.......&&&&.....................&&&&&&&&&&&&&& ", 6889" &&&&&&&&&&&&........................................&&&&&&&& &&&&&&&&&.......................................&&&&&&&&&&&& &&&&&&&&&&&&&&&&............................&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&.......&&&......................&&&&&&&&&&&&&& ", 6890" &&&&&&&&&&&&.........................................&&&&&&& &&&&&&&&........................................&&&&&&&&&&&& &&&&&&&&&&&&&&&..............................&&&&&&&&&&&&&&& &&&&&&&&&&&&&&.......&........................&&&&&&&&&&&&&& ", 6891" &&&&&&&&&&&&.........................................&&&&&&& &&&&&&&.........................................&&&&&&&&&&&& &&&&&&&&&&&&&&................................&&&&&&&&&&&&&& &&&&&&&&&&&&&&.......&........................&&&&&&&&&&&&&& ", 6892" &&&&&&&&&&&&........................................&&&&&&&& &&&&&&&.........................................&&&&&&&&&&&& &&&&&&&&&&&&&&................................&&&&&&&&&&&&&& &&&&&&&&&&&&&&.......&&.......................&&&&&&&&&&&&&& ", 6893" &&&&&&&&&&&&.......................................&&&&&&&&& &&&&&&&&........................................&&&&&&&&&&&& &&&&&&&&&&&&&..................................&&&&&&&&&&&&& &&&&&&&&&&&&&&.......&&&&.....................&&&&&&&&&&&&&& ", 6894" &&&&&&&&&&&&..................&..................&&&&&&&&&&& &&&&&&&&&.......................................&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&.......&&&&&....................&&&&&&&&&&&&&& ", 6895" &&&&&&&&&&&................&&&................&&&&&&&&&&&& &&&&&&&&&&..................&..................&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&..................&&&&&&&&&&&&& ", 6896" &&&&&&&&&&&...............&&&&...............&&&&&&&&&&&&& &&&&&&&&&&&&................&&&................&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&&.................&&&&&&&&&&&&& ", 6897" &&&&&&&&&&&.............&&&&&&.............&&&&&&&&&&&&&&& &&&&&&&&&&&&&...............&&&&...............&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&&&&...............&&&&&&&&&&&&& ", 6898" &&&&&&&&&&&..........&&&&&&&&&..........&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&.............&&&&&&.............&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&&&&&..............&&&&&&&&&&&&& ", 6899" &&&&&&&&&&&.........&&&&&&&&&&.........&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&..........&&&&&&&&&..........&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&.......&&&&&&&&&&&&&............&&&&&&&&&&&&& ", 6900" &&&&&&&&&&.......&&&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&.........&&&&&&&&&&.........&&&&&&&&&& &&&&&&&&&&&&...............................&&&&&&&&&&&&& &&&&&&&&&&&&.......&&&&&&&&&&&&&&...........&&&&&&&&&&&& ", 6901" &&&&&&&&&&.....&&&&&&&&&&&&&&......&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&&&.......&&&&&&&&&& &&&&&&&&&&&&...............................&&&&&&&&&&&&& &&&&&&&&&&&&.......&&&&&&&&&&&&&&&&.........&&&&&&&&&&&& ", 6902" &&&&&&&&&....&&&&&&&&&&&&&&&....&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&&&&&.....&&&&&&&&& &&&&&&&&&&&...............................&&&&&&&&&&&& &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&.......&&&&&&&&&&& ", 6903" &&&&&&&&&...&&&&&&&&&&&&&&&&...&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&....&&&&&&&&&&&&&&&....&&&&&&&&& &&&&&&&&&&&...............................&&&&&&&&&&&& &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&......&&&&&&&&&&& ", 6904" &&&&&&&&&.&&&&&&&&&&&&&&&&&&.&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&...&&&&&&&&&&&&&&&&...&&&&&&&&& &&&&&&&&&&&...............................&&&&&&&&&&&& &&&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&....&&&&&&&&&&& ", 6905" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&.&&&&&&&&&&&&&&&&&&.&&&&&&&& &&&&&&&&&&...............................&&&&&&&&&&& &&&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&&...&&&&&&&&&& ", 6906" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&...............................&&&&&&&&&& &&&&&&&&&.......&&&&&&&&&&&&&&&&&&&&&&&&.&&&&&&&&& ", 6907" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&...............................&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6908" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&...............................&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6909" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6910" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6911" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6912" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6913" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6914" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6915" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6916" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6917" &&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&& ", 6918" &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&& ", 6919" &&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&& ", 6920" &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& ", 6921" ", 6922" "); 6923 6924 6925 6926my $pixbuf_buttons = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons); 6927my ( $buttons_w, $buttons_h ) = ( 15 , 15 ); 6928my ( $buttons_ws, $buttons_hs ) = ( 4*$buttons_w , 2*$buttons_h ); # (256,128) = (4,2)*64 6929$pixbuf_buttons = $pixbuf_buttons->scale_simple ( $buttons_ws, $buttons_hs, 'bilinear'); # hyper, bilinear 6930 6931# To change the color of buttons (shadow) - Motion 6932my @buttons2 = @buttons; # make copy 6933$buttons2[2] = ". c $color_cdplayer_arrows_motion"; 6934$buttons2[3] = "& c $color_cdplayer_shadow_motion"; 6935#"& c #FFFFFF"; # white color 6936my $pixbuf_buttons2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons2); 6937$pixbuf_buttons2 = $pixbuf_buttons2->scale_simple ( $buttons_ws, $buttons_hs, 'bilinear'); # hyper, bilinear 6938 6939# To change the color of buttons (arrows), - Pressed 6940my @buttons3 = @buttons; # make copy 6941$buttons3[2] = ". c #000000"; 6942#"& c #FFFFFF"; # white color 6943my $pixbuf_buttons3 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons3); 6944$pixbuf_buttons3 = $pixbuf_buttons3->scale_simple ( $buttons_ws, $buttons_hs, 'bilinear'); # hyper, bilinear 6945 6946my @posbar = ( # position bar of cd player 6947# /* columns rows colors chars-per-pixel */ 6948"30 10 16 1", 6949" c None", 6950". c #2451BA", 6951"+ c #2C61C2", 6952"x c #2E6BC5", 6953"# c #487AD0", 6954"S c #4081D3", 6955"% c #4C8FDE", 6956"& c #598ECF", 6957"* c #589DEB", 6958"= c #64A1E4", 6959"- c #72ADEC", 6960"; c #6AB0F8", 6961"> c #83B1E5", 6962", c #7BC3FF", 6963"' c #89CFFF", 6964") c #95D9FF", 6965" .....++++++++++++++..... ", 6966" +++x#######SSSS#####xxx++. ", 6967" ..S=>>>>>>>>>>>>>>>>>>>-&#.. ", 6968"..x%=>>>>>>>>>>>>>>>>>>>-=%+.+", 6969"+x#%**=****===--====*****%Sx++", 6970"x#S%********=;---;;=****%%S#xx", 6971"xS**;;;;;;;;;,,,,,;;;;;;***%S#", 6972" S*;;,,,,,,,'')))'',,,,,;;=&S ", 6973" &-,,'''''')))))))))'',,-=& ", 6974" x##########SS#########xx "); 6975 6976my $pixbuf_posbar = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@posbar); 6977my ( $posbar_w, $posbar_h ) = ( 12 , 5 ); # (30,10) = (3,1)*10 6978$pixbuf_posbar = $pixbuf_posbar->scale_simple ( $posbar_w, $posbar_h, 'bilinear'); # hyper, bilinear 6979 6980 6981my @numbers2 = ( # min:sec of cd player 6982# /* columns rows colors chars-per-pixel */ 6983"420 40 3 1", 6984" c None", 6985". c $color_cdplayer_digit", 6986"+ c None", # none, background color 6987#"+ c #ADD8E6", 6988" .................... ++++++++++++++++++++ .................... .................... ++++++++++++++++++++ .................... .................... .................... .................... .................... ... ++++++++++++++++++++ ", 6989" .................... ++++++++++++++++++++ .................... .................... ++++++++++++++++++++ .................... .................... .................... .................... .................... .... ++++++++++++++++++++ ", 6990" .. ................ .. ++ ++++++++++++++++ .. ++ ................ .. ++ ................ .. .. ++++++++++++++++ .. .. ................ ++ .. ................ ++ ++ ................ .. .. ................ .. .. ................ .. ..... ++ ++++++++++++++++ ++ ", 6991" .. ................ .. ++ ++++++++++++++++ .. ++ ................ .. ++ ................ .. .. ++++++++++++++++ .. .. ................ ++ .. ................ ++ ++ ................ .. .. ................ .. .. ................ .. .... ++ ++++++++++++++++ ++ ", 6992" .... .............. .... ++++ .... ++++ .............. .... ++++ .............. .... .... .... .... .............. ++++ .... .............. ++++ ++++ .............. .... .... .............. .... .... .............. .... .... ++++ ++++ ", 6993" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... ... ++++ ++++ ", 6994" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ++++ ++++ ", 6995" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ...... ++++ ++++ ", 6996" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ...... ++++ ++++ ", 6997" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ...... ++++ ++++ ", 6998" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ...... ++++ ++++ ", 6999" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ...... ++++ ++++ ", 7000" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ...... ++++ ++++ ", 7001" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ++++ ++++ ", 7002" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ++++ ++++ ", 7003" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ++++ ++++ ", 7004" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ++++ ++++ ", 7005" ..... ..... ++++ ..... ++++ ..... ++++ ..... ..... ..... ..... ++++ ..... ++++ ++++ ..... ..... ..... ..... ..... .... ++++ ++++ ", 7006" .. ++++++++++++++++ .. ++ ++++++++++++++++ .. ++ ................ .. ++ ................ .. .. ................ .. .. ................ ++ .. ................ ++ ++ ++++++++++++++++ .. .. ................ .. .. ................ .. .... .................. ++ ++++++++++++++++ ++ ", 7007" .. ++++++++++++++++ .. ++ ++++++++++++++++ .. ++ ................ .. ++ ................ .. .. ................ .. .. ................ ++ .. ................ ++ ++ ++++++++++++++++ .. .. ................ .. .. ................ .. .... .................. ++ ++++++++++++++++ ++ ", 7008" .. ++++++++++++++++ .. ++ ++++++++++++++++ .. .. ................ ++ ++ ................ .. ++ ................ .. ++ ................ .. .. ................ .. ++ ++++++++++++++++ .. .. ................ .. ++ ................ .. .... .................. ++ ++++++++++++++++ ++ ", 7009" .. ++++++++++++++++ .. ++ ++++++++++++++++ .. .. ................ ++ ++ ................ .. ++ ................ .. ++ ................ .. .. ................ .. ++ ++++++++++++++++ .. .. ................ .. ++ ................ .. .... .................. ++ ++++++++++++++++ ++ ", 7010" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... .................. ++++ ++++ ", 7011" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ++++ ++++ ", 7012" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ++++ ++++ ", 7013" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ...... ++++ ++++ ", 7014" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ...... ++++ ++++ ", 7015" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ...... ++++ ++++ ", 7016" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ...... ++++ ++++ ", 7017" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ...... ++++ ++++ ", 7018" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ...... ++++ ++++ ", 7019" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ++++ ++++ ", 7020" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ++++ ++++ ", 7021" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ++++ ++++ ", 7022" ..... ..... ++++ ..... ..... ++++ ++++ ..... ++++ ..... ++++ ..... ..... ..... ++++ ..... ..... ..... ++++ ..... .... ++++ ++++ ", 7023" .... .............. .... ++++ .... .... .............. ++++ ++++ .............. .... ++++ .... ++++ .............. .... .... .............. .... ++++ .... .... .............. .... ++++ .............. .... .... ++++ ++++ ", 7024" .. ................ .. ++ ++++++++++++++++ .. .. ................ ++ ++ ................ .. ++ ++++++++++++++++ .. ++ ................ .. .. ................ .. ++ ++++++++++++++++ .. .. ................ .. ++ ................ .. .... ++ ++++++++++++++++ ++ ", 7025" .. ................ .. ++ ++++++++++++++++ .. .. ................ ++ ++ ................ .. ++ ++++++++++++++++ .. ++ ................ .. .. ................ .. ++ ++++++++++++++++ .. .. ................ .. ++ ................ .. .... ++ ++++++++++++++++ ++ ", 7026" .................... ++++++++++++++++++++ .................... .................... ++++++++++++++++++++ .................... .................... ++++++++++++++++++++ .................... .................... .... ++++++++++++++++++++ ", 7027" .................... ++++++++++++++++++++ .................... .................... ++++++++++++++++++++ .................... .................... ++++++++++++++++++++ .................... .................... .... ++++++++++++++++++++ "); 7028 7029 7030my $pixbuf_numbers = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@numbers2); 7031my ( $numbers_w, $numbers_h ) = ( 9 , 12 ); # (30,40) = 10 * (3,4) = (width,height) of the the 14 digits 7032my ( $numbers_ws, $numbers_hs ) = ( 14*$numbers_w , 1*$numbers_h ); # (420,40) = (14*30,1*40) 7033$pixbuf_numbers = $pixbuf_numbers->scale_simple ( $numbers_ws, $numbers_hs, 'bilinear'); # hyper, bilinear 7034 7035# To change the color of numbers on the display - lapsed time color 7036my @numbers3 = @numbers2; # make copy and change only the color information 7037$numbers3[2] = ". c $color_cdplayer_digit_remaining"; #red , color information 7038 7039my $pixbuf_numbers2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@numbers3); 7040$pixbuf_numbers2 = $pixbuf_numbers2->scale_simple ( $numbers_ws, $numbers_hs, 'bilinear'); # hyper, bilinear 7041 7042 7043my @skin_xTunes = ( # cd player skin_xTunes 7044# /* columns rows colors chars-per-pixel */ 7045"225 90 80 1", 7046". c none", 7047" c #484342", 7048"+ c #595553", 7049"Q c #636562", 7050"# c #666B6D", 7051"P c #6A6B69", 7052"% c #6E6D65", 7053"S c #747672", 7054"* c #7D7E78", 7055"= c #828677", 7056"- c #848683", 7057"; c #8C8D8A", 7058"> c #8F9283", 7059", c #939491", 7060"R c #989B8C", 7061") c #989B97", 7062"! c #A0A29F", 7063"~ c #A1A495", 7064"{ c #A6A1A0", 7065"] c #9FA4A6", 7066"^ c #A4A2A6", 7067"/ c #A0A69C", 7068"( c #A3A5A2", 7069"_ c #A7AA94", 7070": c #A6A8A5", 7071"< c #ACA7A6", 7072"[ c #A9ABA2", 7073"} c #A6ABAE", 7074"| c #ABA9AD", 7075"1 c #A9ABA8", 7076"2 c #ABADAA", 7077"3 c #B1ABAA", 7078"4 c #ACB0A0", 7079"5 c #AFB1AE", 7080"6 c #B2B1A9", 7081"7 c #ADB3B5", 7082"8 c #B6B0AF", 7083"9 c #B3B1B5", 7084"0 c #B2B4B1", 7085"a c #B6B8B5", 7086"b c #BDB8B6", 7087"c c #B9BCAC", 7088"d c #BBB8BD", 7089"e c #B8C0A8", 7090"f c #BABCB9", 7091"g c #B7BDBF", 7092"h c #BBC0C3", 7093"i c #BEC0BD", 7094"j c #BEC2B8", 7095"k c #BDC5AE", 7096"l c #C0C4B4", 7097"m c #C3C0C5", 7098"n c #C6C0BF", 7099"o c #BEC3C6", 7100"p c #C2C4C1", 7101"q c #C6C9B9", 7102"r c #C4CBB4", 7103"s c #CBC5C4", 7104"t c #C8C6CA", 7105"u c #C6C8C5", 7106"v c #C7C9C6", 7107"w c #C8CCBB", 7108"x c #C9CBC8", 7109"y c #CEC9C9", 7110"z c #CACCC9", 7111"A c #CBD1B7", 7112"B c #CCCECB", 7113"C c #CED0CC", 7114"D c #CFD1CE", 7115"E c #D0D2CF", 7116"F c #D1D9C1", 7117"G c #D4DABC", 7118"H c #DADCD8", 7119"I c #DFDAD8", 7120"J c #DBE1C2", 7121"K c #DFE1DE", 7122"L c #E4E3DA", 7123"M c #E5E4DB", 7124"N c #E6E9E5", 7125"O c #EDF0EC", 7126".....NNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOON.....", 7127"...HHHCuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvpBHHH...", 7128"..CEu35780aaffniiptttyzBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBxytttpiindfaa0812apCB..", 7129".ipa|<11|3500abfbfimptuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzvvtumpinfbaaa089223|aif.", 7130".aa:<:1125500aafffmipptvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBxtuppmifffaaa0052211:aa.", 7131":2!{(]:||225508aaffiiopuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuupoiifffab00522||:]:{!:(", 7132"!::1322500aaafffipppuvxzBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBxvuuppiifffaa05552131::(", 7133",(^::11129500ddfffiipsutyvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBytvspopiifddaa09522111^:;", 7134"((]::1127500aadffihnptuvvvvvvvBBBBzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvvvvvvvvvutpnhiffdaa0057211::]((,", 7135"11312550aaafffiippuvxztCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCtzxvuppiifffaaa05521311)", 7136"(((::11|5509adfffinoputtvvvvvvBBBBBBBBzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvvvvvvvvttuponifffda9055|11::(((,", 7137"::|}33508aaaffiipptuvxzDBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBDzxvutppiiffaaa80533}|::)", 7138"(]:|1122900abdffifa!;SSSPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPSSS;!afiffdba0092211|:](,", 7139"((:}1225580aaaa:;SQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQS;:aaaa0855221}:((,", 7140"!^]<:11238800:;SQ%*=>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>=*%QS;:00883211:<]^!,", 7141"(]::11225550,SP%=R_ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkke_R=%PS,05552211::](,", 7142":^|3}225002;PP=_erGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFGGGre_=PP;200522}3|^:)", 7143":112255501-PSReAGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGAeRSP-105552211:)", 7144"(({::118:-P*_kGGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGGk_*P-:811::{((,", 7145":1112252;S*_AGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGA_*S;2522111:)", 7146":::}11a,S*_rGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGr_*S,a11}:::)", 7147"!](<:a:-*~rFJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJFr~*-:a:<(]!,", 7148"!!(^5a)*RkGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGkR*)a5^(!!,", 7149"((:(f1;-eFJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJFe-;1f(:((,", 7150"::12a!-_rGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGr_-!a21::)", 7151"!!]b0)-eGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGe-)0b]!!,", 7152"({!f1,RrJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJrR,1f!{(,", 7153"::1f1,_GJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJG_,1f1::)", 7154"!)5f1,cGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGc,1f5)!,", 7155":!ff1ReGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGeR1ff!:)", 7156":)fa1/kJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJk/1af):)", 7157":!ii5/rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr/5ii!:)", 7158":)ff5~rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr~5ff):)", 7159":!ipf[rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr[fpi!:)", 7160"!!aif[kJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJk[fia!!,", 7161"(!5pi[cJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJc[ip5!(,", 7162"1(<pu0cGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGc0up<(1)", 7163"(({fpf4GJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJG4fpf{((,", 7164"(()fpv6rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr6vpf)((,", 7165"!]!3uBpcGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGcpBu3!]!,", 7166"!!(:ivB6rJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJr6Bvi:(!!,", 7167"!^(!2vCvcGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGcvCv2!(^!,", 7168":111{fvCjkGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGkjCvf{111:)", 7169"!((:{1pCCjrGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGrjCCp1{:((!,", 7170"!^((:(8xHElrJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJrlEHx8(:((^!,", 7171"::1221:0BHEjrGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGrjEHB0:1221::)", 7172"!!((::11aCHKjkGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGkjKHCa11::((!!,", 7173"1112955518zHKClrGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGrlCKHz8155592111)", 7174":11}3250925vHNKCqrAGGJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJGGArqCKNHv5290523}11:)", 7175"(({::1125558bEKNKHwwqeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeqwwHKNKEb8555211::{((,", 7176"!!]]^:|3225508avHNNKKKLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMLLLLLLLLLLKKKNNHva8055223|:^]]!!,", 7177"111225509aaffff0afpEKNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNKEpfa0ffffaa905522111)", 7178"::122550aaafffnipppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppnnnpnppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppinfffaaa055221::)", 7179"!^(::}|235500aabffioopuyvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvyupooiffbaa005532|}::(^!,", 7180"::11322507aaagbhionsuvxDBBBBBBzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBDxvusnoihbgaaa70522311::)", 7181":::1129509aaafnihmpuvvxBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBxvvupmhinfaaa9059211:::)", 7182",((]}1122588adbbfiippoutxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBtvtsppiinbdab805521}}::)", 7183",((:|1233580aadffiiopuuvxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBzvvuopiifdfaa808322|:::)", 7184"):|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|:)", 7185",!!^^::1112(({!{!(!!{{{!{{{({{!{!{{{!{{{{{{!{{{!!(!{!{!!(!!{{{!{{{({{!{!{{{!{{{{{{!{{{!!(!{!{!{!{!(!!{{{!{{{({{!{!{{{!{{{{{{!{{{!!(!{!{!{!{!(!!{{{!{{{({{!{!{{{!{{{{{{!{{{!!(!{!{!{!{!(!!{{{!{{{{!{{{{{{!{{{!!(!{!{!((2211::^^!!,", 7186"):11|}5508bpHIHIHHIHHIHHHHHHIHIIIHHHHHHHHHHHHIHHIHHIHHHHHIHHIHHHHHHIHIIIHHHHHHHHHHHHIHHIHHIHHHHHIHHIHHIHHHHHHIHIIIHHHHHHHHHHHHIHHIHHIHHHHHIHHIHHIHHHHHHIHIIIHHHHHHHHHHHHIHHIHHIHHHHHIHHIHHIHHHHHHHHHHHHHHHIHHIHHIHIHHpb8055}|11:)", 7187",!((^:113552500aaffiippppppppppppppppiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiippppppppppppppppuuuuuuuupppppuuuuuppppppppppppppppppppppppiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiipppppppppppppiffaa0052053221|:((,", 7188",!!{(:|11|57908aadgiipppvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvpppiigdaa80975|11|:({!!,", 7189"):11325509abdffiippstvxBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBxvtsppiiffdba90552311:)", 7190"):::122253500abfbfimptuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvvvvvvvvttupnnmgffaa0085211::(((,", 7191",!!^{<:115500aafffmipptvvvvvvvvvvvvvvvvvvvvvvvvvvvvvppppppppppppppppppppppppppppppppppppppppppppppppnnnpnpppppppppppppppppppppppppppppppuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuspmpinffaa78952}11:<{^!!,", 7192",!((:|112225508aaffiiopuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuppnihdfaaa9559211|:((!,", 7193")::1132250aaafffipppuvxzBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBDxvusnoihbgaaa70522311::)", 7194"):::112959500ddfffiipsutyvvvvvvvvvvvvvvvvvvvvvvvvvvvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBBBBBBBxvvupmhinfaaa9059211:::)", 7195",!!{(]:11500aadffihnptuvvvvvvvBBBBzzzzzzzzzzzzzzzzzzvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvpppiigdaa80975|11|:({!!,", 7196":|2255009500ddfffiipsutyvvvvvvvvvvvvvvvvvvvvvvvvvvvppppppppppppppppppppppppppppppppppppppppppppppppnnnpnppppppppppppppppppppppppppppppppppppppnnnpnppppppppppppppppppppppppnnnpnpppppppppppppppvvvvvvvvvvpppiigdaa80975|11|:({!!,", 7197"<1125590500aadffihnptuvvvvvvvBBBBzzzzzzzzzzzzzzzzzzvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvCCCCCCCCCBBxvtsppiiffdba90552311:)", 7198"!^::}12270aadgfiimppuvyxxxxxxvvvvvvvvvvvvvvvvvvvvvvzzzzzzzzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzzxxxxxxvvvvvvvvttupnnmgffaa0085211::(((,", 7199"^:}322553500abfbfimptuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBuuuuuuuuuspmpinffaa78952}11:<{^!!,", 7200"!(]:<1135500aafffmipptvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvuppnihdfaaa9559211|:((!,", 7201"(:::1129225508aaffiiopuuuuuuuuuuuuuuuuuuuuuuuuuuuuuzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzCCBBBBBBBDxvusnoihbgaaa70522311::)", 7202"112}550a0aaafffipppuvxzBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCvvvvvvvvvvpppiigdaa80975|11|:({!!,", 7203"(^:111|59500ddfffiipsutyvvvvvvvvvvvvvvvvvvvvvvvvvvvCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBBxvtsppiiffdba90552311:)", 7204"]{(::1}}500aadffihnptuvvvvvvvBBBBzzzzzzzzzzzzzzzzzzvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxvvvvvvvvttupnnmgffaa0085211::(((,", 7205"1}12250070aadgfiimppuvyxxxxxxvvvvvvvvvvvvvvvvvvvvvvzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxzzzxxxxxxxzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxzzzzzzzzzzzzzzzxxxxxuuuuuuuuuspmpinffaa78952}11:<{^!!,", 7206"]112227500aafffioppuvtzzzzzzzvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvuppnihdfaaa9559211|:((!,", 7207":}}12550550adagffinpputvvvvvvvvvvvvvvvvvvvvvvvvvvvvzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzCCBBBBBBBDxvusnoihbgaaa70522311::)", 7208"-!!](::1aafbhhppsuvvzBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCuuuuuuuspppiiffaba7552|11::(]!!-", 7209"-,((^:1|32550ababpuuvxyBBBBBBBBBBBBBBBBBBBBBBBBzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxxxxxvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvtuppiiffbaba05523|1:^((,-", 7210"*;:|13125580adfffinppttuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzztvvupniifffda08552131|:;*", 7211".S;1235500aadffhituvvyBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDBzyyupmihffdaa0055321;S.", 7212".QP;22557aaaffmhipsvvzBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCyxvystpihmffaaa75522;PQ.", 7213"..++*,!(700aadffimipppuvvvvvvvvvvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzBBBBBBBBBxvupppmiffdaa007(!,*++..", 7214"... +P-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------P+ ...", 7215"..... ....."); 7216 7217 7218my ($scroll_w, $scroll_h); 7219 7220sub scale_buttons { 7221 my ( $width, $height, $corner, $delta ) = @_ ; # ( $widht , $heigth ); 7222 7223 my $dist_dig = 1; #distance between numbers digits 7224 7225 $buttons_h = int ( $height/2 - 4 ) - 1; # min:(15,15) max:(22,22) 7226 $buttons_w = int ( ($width/2 - 4*$delta - $corner) * 2 / 9 - 1.2 ); 7227 7228 if ( $buttons_w >= 22 ){ $buttons_w = 22; } # Set the max w values. 7229 if ( $buttons_h >= 22 ){ $buttons_h = 22; } # Set the max h values 7230 7231 $numbers_w = int( ( 2*$width/3 - 10*$dist_dig - $corner )/11 - 1); # min:(9,12) max:(13,18) 7232 $numbers_h = int ( $height/2 - $corner - 4 ); 7233 if ( $numbers_w >= 13 ){ $numbers_w = 13; } # Set the max w values. 7234 if ( $numbers_h >= 18 ){ $numbers_h = 18; } # Set the max h values 7235 7236 ( $sound_size_w , $sound_size_h ) = ( $buttons_w - 5, $buttons_h - 3 ); 7237 ( $loop_w , $loop_h ) = ( $buttons_w - 1, $buttons_h - 4 ); # min:(15,15) - (1,4) = (14,11) max:(18,16) 7238 #print "loop_w = $loop_w ; loop_h = $loop_h\n"; 7239 if ( $loop_w >= 18 ){ $loop_w = 18; } 7240 if ( $loop_h >= 16 ){ $loop_h = 16; } 7241 7242 ( $random_w , $random_h ) = ( $buttons_w - 3, $buttons_h - 3 ); # min:(12,12) max:(17,17) 7243 if ( $random_w >= 17 ){ $random_w = 17; } 7244 if ( $random_h >= 17 ){ $random_h = 17; } 7245 7246 ( $posbar_w, $posbar_h ) = ( int( (2*$width/3) / 8 - 2 ) , int( $height/10 + 1 ) ); # min:(12,5) max:(20,8) 7247 if ( $posbar_w >= 20 ){ $posbar_w = 20; } 7248 if ( $posbar_h >= 8 ){ $posbar_h = 8; } 7249 #print "buttons_h = $buttons_h ; buttons_w = $buttons_w ; numbers_w = $numbers_w ; numbers_h = $numbers_h\n"; 7250 #print "posbar_w = $posbar_w ; posbar_h = $posbar_h\n"; 7251 7252 $scroll_h = $buttons_h - 2; 7253 $scroll_h = 16 if $scroll_h >= 16; 7254 7255 if ( $buttons_w <= 5 or $buttons_h <= 3 ){ return; } 7256 scale_pixbuf(); 7257} 7258 7259sub scale_pixbuf { 7260 $pixbuf_buttons = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons); 7261 $pixbuf_buttons = $pixbuf_buttons->scale_simple ( 4*$buttons_w , 2*$buttons_h, 'bilinear'); 7262 $pixbuf_buttons2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons2); 7263 $pixbuf_buttons2 = $pixbuf_buttons2->scale_simple ( 4*$buttons_w , 2*$buttons_h, 'bilinear'); 7264 $pixbuf_buttons3 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@buttons3); 7265 $pixbuf_buttons3 = $pixbuf_buttons3->scale_simple ( 4*$buttons_w , 2*$buttons_h, 'bilinear'); 7266 7267 $pixbuf_sound = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@sound); 7268 $pixbuf_sound = $pixbuf_sound->scale_simple ( $sound_size_w, $sound_size_h, 'bilinear'); 7269 7270 $pixbuf_numbers = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@numbers2); 7271 $pixbuf_numbers = $pixbuf_numbers->scale_simple ( 14*$numbers_w , 1*$numbers_h, 'bilinear'); 7272 $pixbuf_numbers2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@numbers3); 7273 $pixbuf_numbers2 = $pixbuf_numbers2->scale_simple ( 14*$numbers_w , 1*$numbers_h, 'bilinear'); 7274 7275 $pixbuf_posbar = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@posbar); 7276 $pixbuf_posbar = $pixbuf_posbar->scale_simple ( $posbar_w, $posbar_h, 'bilinear'); 7277 7278 $pixbuf_loop = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@loop); 7279 $pixbuf_loop = $pixbuf_loop->scale_simple ( $loop_w, $loop_h, 'bilinear'); # hyper, bilinear 7280 $pixbuf_loop2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@loop2); 7281 $pixbuf_loop2 = $pixbuf_loop2->scale_simple ( $loop_w, $loop_h, 'bilinear'); 7282 7283 $pixbuf_random = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@random); 7284 $pixbuf_random = $pixbuf_random->scale_simple ( $random_w, $random_h, 'bilinear'); # hyper, bilinear 7285 $pixbuf_random2 = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@random2); 7286 $pixbuf_random2 = $pixbuf_random2->scale_simple ( $random_w, $random_h, 'bilinear'); 7287} 7288 7289# see /usr/share/doc/perl-Gtk2-1.080/gtk-demo/drawingarea.pl and examples/scribble.pl 7290# GtkDrawingArea is a blank area where you can draw custom displays 7291# of various kinds. See man Gtk2::Gdk::Drawable, Gtk2::Curve 7292 7293$da = Gtk2::DrawingArea->new; 7294$da->set_size_request (170, 40); # set a minimum size: (width,height) = (170, 40) 7295$hbox4->pack_start ($da, $false, $false, 0); 7296$da->signal_connect ( 'expose_event' => \&expose_event_cdplayer); 7297$da->signal_connect ( 'configure_event' => \&configure_event_cdplayer); 7298$da->signal_connect ( 'button_press_event' => \&button_press_event_cdplayer); 7299$da->signal_connect ( 'button_release_event' => \&button_release_event_cdplayer); 7300$da->signal_connect ( 'motion_notify_event' => \&motion_notify_event_cdplayer); 7301$da->set_events ([ @{ $da->get_events }, 7302 'exposure-mask', 7303 'leave-notify-mask', 7304 'button-press-mask', 7305 'button-release-mask', 7306 'pointer-motion-mask', 7307 #'pointer-motion-hint-mask', 7308 #'all-events-mask' 7309 ]); 7310$da->set_sensitive($false); 7311$da->show; 7312 7313# --- Colors --- # See <man Gtk2::Gdk::Color> 7314 7315my $gc_bg; my $gc_blue; my $gc_green; 7316my $gc_skin; my $gc_skin2; my $color_skin2; 7317 7318# #E6EDBD = (230,237,189) : yellow #FFFFFF=(255,255,255):white #000000=(0,0,0):black 7319my $color_bg = Gtk2::Gdk::Color->parse ($color_bg_cdplay); # #E6EDBD , background color default 7320my $color_blue = Gtk2::Gdk::Color->new (85*256, 90*256, 190*256); # RGB = 85 90 190 ; my color blue 7321my $color_green = Gtk2::Gdk::Color->new (167*256, 177*256, 190*256); # '#A7B1BE' ; my green color 7322 7323my $delta = 2; # distance inter buttons 7324my $dista = 7; # distance (shift) from center 7325my $corner = 4; 7326my $dist_dig = 1; # distance between numbers digits 7327 7328# text scrolling position on the $da 7329my ($xdest, $ydest); # inicial position on the $drawing_area 7330 7331#numbers position on the $da 7332my $xdest_numbers; my $ydest_numbers; 7333 7334# progress bar of elapsed time; position on the $da 7335my $xdest_posbar; my $ydest_posbar; my $posbar_length; 7336 7337# loop button; position on the $da 7338my $xdest_loop; my $ydest_loop; 7339 7340# random button; position on the $da 7341my $xdest_random; my $ydest_random; 7342 7343# sound button; position on the $da 7344my $xdest_sound; my $ydest_sound; 7345 7346# buttons (Stop button); position on the $da 7347my $xdest_buttons; my $ydest_buttons; 7348 7349# Pixmap for cd player 7350my ($pixmap, $pixmap_mask) = (undef, undef); 7351 7352sub expose_event_cdplayer { 7353 my ($widget, $event ) = @_; # $widget = $da = Gtk2::DrawingArea 7354 # $drawable = $widget->state; Gtk2::Gdk::Drawable 7355 7356 $widget->window->draw_drawable ($widget->style->fg_gc($widget->state), # (Gtk2::Gdk::GC) 7357 $pixmap, 7358 # Only copy the area that was exposed. 7359 $event->area->x, $event->area->y, # $xsrc, $ysrc, 7360 $event->area->x, $event->area->y, # $xdest, $ydest 7361 $event->area->width, $event->area->height); 7362 return $false; 7363} 7364 7365# Redraw the screen from the pixmap 7366sub configure_event_cdplayer { 7367 my ($widget, $event, @color) = @_; # $widget = $da = Gtk2::DrawingArea 7368 # $drawable = $widget->state; Gtk2::Gdk::Drawable 7369 # color = Gtk2::Gdk::Color 7370 7371 my $height = $widget->allocation->height; # height of $widget $da 7372 my $width = $widget->allocation->width; 7373 7374 # background color definition 7375 $gc_bg = Gtk2::Gdk::GC->new ($widget->window); # ($da->window) = Gtk2::Gdk::Drawable 7376 $color_bg_cdplay = $color[0] if defined($color[0]); 7377 $color_bg = Gtk2::Gdk::Color->parse ($color_bg_cdplay); 7378 $gc_bg->set_rgb_fg_color ($color_bg); 7379 7380 # background skin color definition 7381 $gc_skin = Gtk2::Gdk::GC->new ($widget->window); # ($da->window) = Gtk2::Gdk::Drawable 7382 $gc_skin->set_rgb_fg_color ( Gtk2::Gdk::Color->parse ('#C8C8C8') ); 7383 7384 # background display skin color definition 7385 $gc_skin2 = Gtk2::Gdk::GC->new ($widget->window); # ($da->window) = Gtk2::Gdk::Drawable 7386 $color_skin2 = Gtk2::Gdk::Color->parse ('#DBE1C2'); 7387 $gc_skin2->set_rgb_fg_color ($color_skin2); 7388 7389 # my blue color definition 7390 $gc_blue = Gtk2::Gdk::GC->new ($widget->window); # ($widget->window) = Gtk2::Gdk::Drawable 7391 $gc_blue->set_rgb_fg_color ($color_blue); 7392 7393 # my green color definition ; limite lines 7394 $gc_green = Gtk2::Gdk::GC->new ($widget->window); 7395 $gc_green->set_rgb_fg_color ($color_green); 7396 7397 # button color (shadow) - Static 7398 $buttons[3] = "& c $color[1]" if defined($color[1]); 7399 $color_cdplayer_shadow = $color[1] if defined($color[1]); 7400 7401 # button color (arrows) - Static 7402 $buttons[2] = ". c $color[2]" if defined($color[2]); 7403 $color_cdplayer_arrows = $color[2] if defined($color[2]); 7404 7405 # button color - random ? - when active 7406 $random[2] = ". c $color[2]" if defined($color[2]); 7407 $random[3] = "+ c $color[1]" if defined($color[1]); 7408 7409 # button color - loop - when active 7410 $loop[2] = ". c $color[1]" if defined($color[1]); 7411 $loop[3] = "+ c $color[2]" if defined($color[2]); 7412 7413 # button color (shadow) - Motion 7414 $buttons2[3] = "& c $color[3]" if defined($color[3]); 7415 $color_cdplayer_shadow_motion = $color[3] if defined($color[3]); 7416 7417 # button color (arrows) - Motion 7418 $buttons2[2] = ". c $color[4]" if defined($color[4]); 7419 $color_cdplayer_arrows_motion = $color[4] if defined($color[4]); 7420 7421 # button color (shadow) - Pressed 7422 $buttons3[3] = "& c $color_cdplayer_shadow_motion"; 7423 7424 # button color (digit) 7425 $numbers2[2] = ". c $color[5]" if defined($color[5]); 7426 $color_cdplayer_digit = $color[5] if defined($color[5]); 7427 7428 # button color (digit_remaining) 7429 $numbers3[2] = ". c $color[6]" if defined($color[6]); 7430 $color_cdplayer_digit_remaining = $color[6] if defined($color[6]); 7431 7432 $pixmap = undef if $pixmap; # get rid of the old one 7433 $pixmap_mask = undef if $pixmap_mask; 7434 7435 if ($show_cdplayer_skin and defined $window_cd_player){ # with skin_xTunes 7436 $widget->set_size_request (225, 90); # set a minimum size: (width,height) ; skin_xTunes 7437 7438 #(pixmap, mask) = Gtk2::Gdk::Pixmap->create_from_xpm ($drawable, $transparent_color, $filename) 7439 #($pixmap, $pixmap_mask) = Gtk2::Gdk::Pixmap->create_from_xpm ($widget->window, undef, '/tmp/skin_xTunes.xpm'); 7440 ($pixmap, $pixmap_mask) = Gtk2::Gdk::Pixmap->create_from_xpm_d($widget->window, undef, @skin_xTunes); 7441 7442 #my $pixmap_widget = Gtk2::Image->new_from_pixmap ($gdkpixmap, $mask); 7443 $window_cd_player->shape_combine_mask( $pixmap_mask, 0, 0 ) if not $window_cd_player->get_decorated; 7444 7445 ($xdest, $ydest) = (74, 22); # inicial position on the $drawing_area 7446 ($scroll_w, $scroll_h) = (138, 14); # width and height of scrolling text 7447 7448 #numbers position on the $da 7449 $xdest_numbers = 16; $ydest_numbers = 22; 7450 $numbers_w = 9; $numbers_h = 13; 7451 7452 # progress bar of elapsed time; position on the $da 7453 $xdest_posbar = 10; 7454 $ydest_posbar = 55; 7455 $posbar_length = 204; 7456 $posbar_w = 18; $posbar_h = 6; 7457 7458 # buttons; position on the $da 7459 $xdest_buttons = 80; # x_destination of Stop button on the $da 7460 $ydest_buttons = 63; 7461 ($buttons_w, $buttons_h) = (20,20); 7462 7463 # loop button; position on the $da 7464 $xdest_loop = 170; 7465 $ydest_loop = 36; 7466 7467 # random button; position on the $da 7468 $xdest_random = 152; 7469 $ydest_random = 36; 7470 7471 # sound button; position on the $da 7472 $xdest_sound = 186; 7473 $ydest_sound = 63; 7474 ($sound_size_w, $sound_size_h) = (18,20); 7475 7476 scale_pixbuf(); 7477 } 7478 if (not defined $pixmap){ # without skin_xTunes 7479 $gc_skin = $gc_bg; 7480 $gc_skin2 = $gc_bg; 7481 $color_skin2 = $color_bg; 7482 7483 $widget->set_size_request (170, 40); 7484 # pixmap = Gtk2::Gdk::Pixmap->new ($drawable, $width, $height, $depth) ; $depth (number of colors) 7485 $pixmap = Gtk2::Gdk::Pixmap->new ($widget->window, $width, $height, -1); 7486 7487 $pixmap->draw_rectangle ( $window->style->bg_gc($window->state), # fill with window bg color 7488 $true, 0, 0, $width, $height); 7489 7490 my ($xc,$yc,$r,$n) = (6,6,6,10); # ( x, y ) = ( xc, yc ) + r * ( cos(theta), sin(theta) ) 7491 7492 my @coord_up_left = coordinates_rounded_corner( $xc, $yc,$r,180,270,$n); 7493 my @coord_up_right = coordinates_rounded_corner($width - $xc, $yc,$r,270,360,$n); 7494 my @coord_down_left = coordinates_rounded_corner($width - $xc,$height - $yc,$r, 0, 90,$n); 7495 my @coord_down_right = coordinates_rounded_corner( $xc,$height - $yc,$r, 90,180,$n); 7496 7497 $pixmap->draw_polygon ($gc_bg, $true, # fill whith color $gc_bg 7498 @coord_up_left, @coord_up_right, 7499 @coord_down_left, @coord_down_right ); 7500 7501 @coord_up_left = coordinates_rounded_corner( $xc - 0.1, $yc - 0.1,$r,180,270,$n); 7502 @coord_up_right = coordinates_rounded_corner($width - $xc - 0.1, $yc - 0.1,$r,270,360,$n); 7503 @coord_down_left = coordinates_rounded_corner($width - $xc - 0.1,$height - $yc - 0.1,$r, 0, 90,$n); 7504 @coord_down_right = coordinates_rounded_corner( $xc - 0.1,$height - $yc - 0.1,$r, 90,180,$n); 7505 7506 # draw the limite lines 7507 # $drawable->draw_polygon ($gc, $filled, $x1, $y1, ...) 7508 $pixmap->draw_polygon ($gc_green, $false, # $widget->style->black_gc, 7509 @coord_up_left, @coord_up_right, 7510 @coord_down_left, @coord_down_right ); 7511 7512 # refresh the sizes and scale 7513 scale_buttons($width, $height, $corner, $delta); 7514 7515 ($xdest, $ydest) = (int($corner + 5*($numbers_w + $dist_dig) + $numbers_w/2), int($corner/2) ); # inicial position on the $drawing_area 7516 ($scroll_w, $scroll_h) = (int($width - $xdest - $corner), $scroll_h); # width and height of scrolling text 7517 7518 #numbers position on the $da 7519 $xdest_numbers = $corner; $ydest_numbers = $corner; 7520 7521 # progress bar of elapsed time; position on the $da 7522 $xdest_posbar = int($corner + 5*($numbers_w + $dist_dig) + $numbers_w/2); 7523 7524 $ydest_posbar = int($scroll_h + $corner); 7525 $posbar_length = int($width - $xdest_posbar - $corner); 7526 7527 # loop button; position on the $da 7528 $xdest_loop = $corner; 7529 $ydest_loop = $height - $corner - $loop_h; 7530 7531 # random button; position on the $da 7532 $xdest_random = $corner + $loop_w + 2; 7533 $ydest_random = $height - $corner - $random_h; 7534 7535 # sound button; position on the $da 7536 $xdest_sound = $width/2 - $sound_size_w - 5*$buttons_w/2 - 4*$delta + $dista; 7537 $ydest_sound = $height - $corner - $sound_size_h; 7538 7539 # buttons; position on the $da 7540 $xdest_buttons = $width/2 + $dista; # Stop button x_destination drawing on the $da 7541 $ydest_buttons = $height - $buttons_h - 2; 7542 } 7543 draw_buttons( All => $true ); 7544 7545 # show current time 7546 my ($hour,$min,$sec) = sec_to_time($count); 7547 draw_play_time($da, undef, ($min,$sec,$hour) ); 7548 7549 # sound button 7550 draw_sound_button($da,undef); 7551 7552 # random button ? 7553 draw_random($da,undef); 7554 7555 # loop button 7556 draw_loop($da,undef); 7557 7558 # draw lapsed time, progress bar 7559 my $pct = 0; 7560 if ($total_time>0){$pct = number_value( sprintf("%.2f", $count/$total_time) );} 7561 draw_lapsed_time($da, undef, $pct); 7562 7563 # draw scrolling text 7564 show_scrolling_text(); 7565 7566 # return TRUE because we've handled this event, so no further processing is required. 7567 return $true; 7568} 7569 7570sub coordinates_rounded_corner { # arc of circle - (10Jul2008) 7571 my ($xc,$yc,$r,$t1,$t2,$n) = @_; # ( x, y ) = ( xc, yc ) + r * ( cos(theta), sin(theta) ) :polar coordinate 7572 my @coordinates = (); 7573 my $pi = 3.141592654; 7574 7575 foreach my $i ( 0 .. $n ) { # arc is divided by n equal segments 7576 my $theta_i = ( $t1 + ($i/$n)*($t2 - $t1) )*($pi/180); 7577 my $x_i = number_value( sprintf("%.4f", $xc + $r * cos($theta_i)) ); # sin(), cos(): see man perlfunc 7578 my $y_i = number_value( sprintf("%.4f", $yc + $r * sin($theta_i)) ); 7579 push @coordinates, ( $x_i, $y_i ); 7580 } 7581 #foreach my $i ( 0 .. 2*$n+1 ) { print "\$coordinates($i) = $coordinates[$i] \n"; } 7582 return @coordinates; 7583} 7584 7585my $button_press_stop = $false; my $button_press_play = $false; my $button_press_pause = $false; 7586my $button_press_forward = $false; my $button_press_eject = $false; my $button_press_rewind = $false; 7587my $button_press_next = $false; my $button_press_back = $false; 7588 7589sub button_release_event_cdplayer { 7590 # Set the default color to all buttons that is released. 7591 if ($button_press_stop ){ draw_buttons(Draw_Stop => $true ); $button_press_stop = $false; } 7592 elsif ($button_press_play ){ draw_buttons(Draw_Play => $true ); $button_press_play = $false; } 7593 elsif ($button_press_pause ){ draw_buttons(Draw_Pause => $true ); $button_press_pause = $false; } 7594 elsif ($button_press_forward){ draw_buttons(Draw_Forward => $true); $button_press_forward = $false;} 7595 elsif ($button_press_eject ){ draw_buttons(Draw_Eject => $true ); $button_press_eject = $false; } 7596 elsif ($button_press_rewind ){ draw_buttons(Draw_Rewind => $true ); $button_press_rewind = $false; } 7597 elsif ($button_press_next ){ draw_buttons(Draw_Next => $true ); $button_press_next = $false; } 7598 elsif ($button_press_back ){ draw_buttons(Draw_Back => $true ); $button_press_back = $false; } 7599 return $true; 7600} 7601 7602sub draw_buttons { # Get the 8 buttons from @buttons. Redraw only the button that is pressed. 7603 my %args = ( 7604 Press_Stop => $false, Draw_Stop => $false, Shadow_Stop => $false, # If 'Press_Stop = $true' then change the button color 7605 Press_Play => $false, Draw_Play => $false, Shadow_Play => $false, # default value, 7606 Press_Pause => $false, Draw_Pause => $false, Shadow_Pause => $false, 7607 Press_Forward => $false,Draw_Forward => $false, Shadow_Forward => $false, 7608 Press_Eject => $false, Draw_Eject => $false, Shadow_Eject => $false, 7609 Press_Rewind => $false, Draw_Rewind => $false, Shadow_Rewind => $false, 7610 Press_Next => $false, Draw_Next => $false, Shadow_Next => $false, 7611 Press_Back => $false, Draw_Back => $false, Shadow_Back => $false, 7612 All => $false, # draw all buttons 7613 @_, # argument pair list goes here 7614 ); 7615 my $widget = $da; 7616 my $height = $widget->allocation->height; # height of $widget $da 7617 my $width = $widget->allocation->width ; 7618 my $pixbuf_copy = $pixbuf_buttons; 7619 # $buttons_h is the height of buttons and $buttons_w is the width of buttons 7620 7621 my @update_rect; 7622 $update_rect[0] = $xdest_buttons; 7623 $update_rect[1] = $ydest_buttons; 7624 $update_rect[2] = $buttons_w; 7625 $update_rect[3] = $buttons_h; 7626 #$widget->queue_draw_area (@update_rect); 7627 return if not defined $pixmap; 7628 7629 # -------------------- 8 buttons ---------------------- # 7630 if ( $args{Draw_Stop} or $args{All} ){ # Draw independently the 8 buttons 7631 7632 $update_rect[0] = $xdest_buttons - 1*$buttons_w/2 + 0*$delta; 7633 $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first 7634 if ($args{Shadow_Stop}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button 7635 elsif ($args{Press_Stop} ){ $pixbuf_copy = $pixbuf_buttons3; } 7636 # stop button , on the center of display 7637 # $drawable->draw_pixbuf ($gc, $pixbuf, $src_x, $src_y, $dest_x, $dest_y, $width, $height, $dither, $x_dither, $y_dither) 7638 $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 0*$buttons_w, 0*$buttons_h, @update_rect, 'normal', 0, 0); 7639 $widget->queue_draw_area (@update_rect); 7640 } 7641 if ( $args{Draw_Play} or $args{All} ){ 7642 7643 $update_rect[0] = $xdest_buttons + 1*$buttons_w/2 + 1*$delta; 7644 $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first 7645 if ($args{Shadow_Play}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button 7646 elsif ($args{Press_Play} ){ $pixbuf_copy = $pixbuf_buttons3; } 7647 # play or pause button 7648 my $button_y = 2*$buttons_w; 7649 unless ( $pause eq $true or $playing_music eq $false ){ $button_y = 1*$buttons_w; } 7650 $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, $button_y, 0*$buttons_h, @update_rect, 'normal', 0, 0); 7651 $widget->queue_draw_area (@update_rect); 7652 } 7653 if ( $args{Draw_Forward} or $args{All} ){ 7654 $update_rect[0] = $xdest_buttons + 3*$buttons_w/2 + 2*$delta; 7655 $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first 7656 if ($args{Shadow_Forward}){ $pixbuf_copy = $pixbuf_buttons2; } 7657 elsif ($args{Press_Forward} ){ $pixbuf_copy = $pixbuf_buttons3; } 7658 # fastforward button 7659 $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 0*$buttons_w, 1*$buttons_h, @update_rect, 'normal', 0, 0); 7660 $widget->queue_draw_area (@update_rect); 7661 } 7662 if ( $args{Draw_Next} or $args{All} ){ 7663 $update_rect[0] = $xdest_buttons + 5*$buttons_w/2 + 3*$delta; 7664 $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first 7665 if ($args{Shadow_Next}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button 7666 elsif ($args{Press_Next} ){ $pixbuf_copy = $pixbuf_buttons3; } 7667 # next button 7668 $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 3*$buttons_w, 0*$buttons_h, @update_rect, 'normal', 0, 0); 7669 $widget->queue_draw_area (@update_rect); 7670 } 7671 if ( $args{Draw_Eject} or $args{All} ){ 7672 $update_rect[0] = $xdest_buttons + 7*$buttons_w/2 + 4*$delta; 7673 $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first 7674 if ($args{Shadow_Eject}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button 7675 elsif ($args{Press_Eject} ){ $pixbuf_copy = $pixbuf_buttons3; } 7676 # eject button 7677 $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 2*$buttons_w, 1*$buttons_h, @update_rect, 'normal', 0, 0); 7678 $widget->queue_draw_area (@update_rect); 7679 } 7680 if ( $args{Draw_Rewind} or $args{All} ){ 7681 $update_rect[0] = $xdest_buttons - 3*$buttons_w/2 - 1*$delta; 7682 $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first 7683 if ($args{Shadow_Rewind}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button 7684 elsif ($args{Press_Rewind} ){ $pixbuf_copy = $pixbuf_buttons3; } 7685 # rewind button 7686 $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 1*$buttons_w, 1*$buttons_h, @update_rect, 'normal', 0, 0); 7687 $widget->queue_draw_area (@update_rect); 7688 } 7689 if ( $args{Draw_Back} or $args{All} ){ 7690 $update_rect[0] = $xdest_buttons - 5*$buttons_w/2 - 2*$delta; 7691 $pixmap->draw_rectangle ($gc_skin, $true, @update_rect ); # erase first 7692 if ($args{Shadow_Back}){ $pixbuf_copy = $pixbuf_buttons2; } # Choose the color button 7693 elsif ($args{Press_Back} ){ $pixbuf_copy = $pixbuf_buttons3; } 7694 # back button 7695 $pixmap->draw_pixbuf ($gc_skin, $pixbuf_copy, 3*$buttons_w, 1*$buttons_h, @update_rect, 'normal', 0, 0); 7696 $widget->queue_draw_area (@update_rect); 7697 } 7698 #while (Gtk2->events_pending()) {Gtk2->main_iteration()}; NEVER use this here 7699} 7700 7701sub draw_play_time { 7702 my ($widget, $event, @data) = @_; # $widget = $da = Gtk2::DrawingArea 7703 7704 return if not defined $pixmap; 7705 #draw_play_time($da, undef, ($min,$sec,$hour) ); 7706 my ($min, $sec, $hour) = @data; # the format "00:00" have 5 digits 7707 7708 my ($digit1,$digit2) = (13*$numbers_w,13*$numbers_w); #start value with background color 7709 my ($digit3,$digit4) = (13*$numbers_w,13*$numbers_w); 7710 my ($digit5,$digit6) = (13*$numbers_w,13*$numbers_w); 7711 my $two_points = 11*$numbers_w; # " : " 7712 my $division = 10*$numbers_w; # " / " 7713 7714 if ( $min != -2 ){ # not blink - n�o piscar 7715 $digit1 = ( int($min/10) )*$numbers_w; 7716 $digit2 = ( $min % 10 )*$numbers_w; 7717 $digit3 = ( int($sec/10) )*$numbers_w; # 35 : int($sec/10) $sec%10 7718 $digit4 = ( $sec % 10 )*$numbers_w; 7719 $digit5 = ( int($hour/10) )*$numbers_w if defined($hour); 7720 $digit6 = ( $hour % 10 )*$numbers_w if defined($hour); 7721 } 7722 my $height = $widget->allocation->height; # height of $widget $da 7723 my $width = $widget->allocation->width ; 7724 my $pixbuf_copy = $show_time_remaining ? $pixbuf_numbers2 : $pixbuf_numbers; # to change the colors. 7725 7726 my @update_rect; 7727 $update_rect[0] = $xdest_numbers; #$corner 7728 $update_rect[1] = $ydest_numbers; 7729 $update_rect[2] = $numbers_w; 7730 $update_rect[3] = $numbers_h; 7731 7732 #print "\$update_rect[1] = $update_rect[1]\n"; 7733 #$widget->queue_draw_area (@update_rect); 7734 7735 # "00:00"; there are 5 digits; Each button have (width,height) = ($numbers_w, $numbers_h) 7736 7737 # erase all ; rectangle : $drawable->draw_rectangle ($gc, $filled, $x, $y, $width, $height); See <man Gtk2::Gdk::Drawable> 7738 $pixmap->draw_rectangle ($gc_skin2, $true, $xdest_numbers, $ydest_numbers, 5*($numbers_w + $dist_dig), $numbers_h); # erase all 7739 7740 # -------------------- 5 digits ---------------------- # 7741 # 1o. digit : $drawable->draw_pixbuf ($gc, $pixbuf, $src_x, $src_y, $dest_x, $dest_y, $width, $height, $dither, $x_dither, $y_dither) 7742 $update_rect[0] = $xdest_numbers + 0*($numbers_w + $dist_dig); 7743 $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $digit1, 0*$numbers_h, @update_rect, 'normal', 0, 0); 7744 7745 # 2o. digit 7746 $update_rect[0] = $xdest_numbers + 1*($numbers_w + $dist_dig); 7747 $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $digit2, 0*$numbers_h, @update_rect, 'normal', 0, 0); 7748 7749 # : Two points 7750 $update_rect[0] = $xdest_numbers + 2*($numbers_w + $dist_dig); 7751 $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $two_points, 0*$numbers_h, @update_rect, 'normal', 0, 0); 7752 7753 # 3o. digit 7754 $update_rect[0] = $xdest_numbers + 3*($numbers_w + $dist_dig); 7755 $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $digit3, 0*$numbers_h, @update_rect, 'normal', 0, 0); 7756 7757 # 4o. digit 7758 $update_rect[0] = $xdest_numbers + 4*($numbers_w + $dist_dig); 7759 $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, $digit4, 0*$numbers_h, @update_rect, 'normal', 0, 0); 7760 7761 # See man Gtk2::Widget 7762 $widget->queue_draw_area ($xdest_numbers, $ydest_numbers, 5*($numbers_w + $dist_dig), $numbers_h); 7763} 7764 7765 7766sub draw_lapsed_time { # progress bar of elapsed time 7767 my ($widget, $event, $pct) = @_; # $widget = $da = Gtk2::DrawingArea 7768 7769 return if not defined $pixmap; 7770 my $height = $widget->allocation->height; # height of $widget $da 7771 my $width = $widget->allocation->width; 7772 7773 # pct vary from 0.000 to 1.000 7774 my $max_length = $posbar_length - $posbar_w; #posbar_w is the button width 7775 my $lapsed_time = $pct * $max_length; 7776 7777 my $rail_h = 2; 7778 my $y = $ydest_posbar; 7779 my $y_rail = int ( ( 2*$y + $posbar_h - $rail_h )/2 ); 7780 #print "y = $y ; y_rail = $y_rail, posbar_h = $posbar_h\n"; 7781 7782 # rectangle $drawable->draw_rectangle ($gc, $filled, $x, $y, $width, $height); See <man Gtk2::Gdk::Drawable> 7783 $pixmap->draw_rectangle ($gc_skin, $true, $xdest_posbar - 1, $y, $posbar_length + 2, $posbar_h ); # erase all first 7784 $pixmap->draw_rectangle ($gc_green, $false, $xdest_posbar, $y_rail , $posbar_length, $rail_h ); # path, rail 7785 # posbar button 7786 # $drawable->draw_pixbuf ($gc, $pixbuf, $src_x, $src_y, $dest_x, $dest_y, $width, $height, $dither, $x_dither, $y_dither) 7787 $pixmap->draw_pixbuf ($gc_bg, $pixbuf_posbar, 0, 0, 7788 $xdest_posbar + $lapsed_time, $y, 7789 $posbar_w, $posbar_h, 'normal', 0, 0); 7790 my @update_rect; 7791 $update_rect[0] = $xdest_posbar - 1; 7792 $update_rect[1] = $y; 7793 $update_rect[2] = $posbar_length + 2; 7794 $update_rect[3] = $posbar_h; 7795 $widget->queue_draw_area (@update_rect); 7796} 7797 7798sub draw_sound_button { 7799 my ($widget, $event, @data) = @_; # $widget = $da = Gtk2::DrawingArea 7800 # @data is an array 7801 return if not defined $pixmap; 7802 my $height = $widget->allocation->height; # height of $widget $da 7803 my $width = $widget->allocation->width; 7804 7805 my @update_rect; 7806 $update_rect[0] = $xdest_sound; 7807 $update_rect[1] = $ydest_sound; 7808 $update_rect[2] = $sound_size_w; 7809 $update_rect[3] = $sound_size_h; 7810 7811 $pixmap->draw_rectangle ($gc_skin, $true, @update_rect); # erase first 7812 $pixmap->draw_pixbuf ($gc_skin, $pixbuf_sound, 0, 0, @update_rect, 'normal', 0, 0); # sound button 7813 $widget->queue_draw_area (@update_rect); #update the $da = Gtk2::DrawingArea 7814} 7815 7816sub draw_random { 7817 my ($widget, $event, @data) = @_; # $widget = $da = Gtk2::DrawingArea 7818 # @data is an array 7819 return if not defined $pixmap; 7820 my $height = $widget->allocation->height; # height of $widget $da 7821 my $width = $widget->allocation->width; 7822 7823 my $pixbuf_copy = $pixbuf_random; 7824 $pixbuf_copy = $play_random ? $pixbuf_random : $pixbuf_random2; 7825 7826 my @update_rect; 7827 $update_rect[0] = $xdest_random; $update_rect[1] = $ydest_random; 7828 $update_rect[2] = $random_w; $update_rect[3] = $random_h; 7829 7830 $pixmap->draw_rectangle ($gc_skin2, $true, @update_rect); # erase first 7831 $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, 0, 0, @update_rect, 'normal', 0, 0); 7832 $widget->queue_draw_area (@update_rect); #update the $da = Gtk2::DrawingArea 7833} 7834 7835sub draw_loop { 7836 my ($widget, $event, @data) = @_; # $widget = $da = Gtk2::DrawingArea 7837 # @data is an array 7838 return if not defined $pixmap; 7839 my $height = $widget->allocation->height; # height of $widget $da 7840 my $width = $widget->allocation->width; 7841 7842 my $pixbuf_copy = $pixbuf_loop; 7843 $pixbuf_copy = $loop_tracks ? $pixbuf_loop : $pixbuf_loop2; 7844 7845 my @update_rect; 7846 $update_rect[0] = $xdest_loop; $update_rect[1] = $ydest_loop; 7847 $update_rect[2] = $loop_w; $update_rect[3] = $loop_h; 7848 7849 $pixmap->draw_rectangle ($gc_skin2, $true, @update_rect); # erase first 7850 $pixmap->draw_pixbuf ($gc_skin2, $pixbuf_copy, 0, 0, @update_rect, 'normal', 0, 0); 7851 $widget->queue_draw_area (@update_rect); #update the $da = Gtk2::DrawingArea 7852 7853 #if ($loop_tracks){print "Loop ON\n";} 7854 #else{print "Loop OFF\n";} 7855} 7856 7857#------------------ Scrolling Text -------------------# 7858#--------------------- Start -------------------------# 7859 7860my $timer_scroll; my $timer_wait; 7861my $pixmap_layout = undef; 7862my ($width_layout, $height_layout); 7863my $xsrc = 0; my $ysrc = 0; 7864my $sinal = 1; # sign: +1 or -1 7865my @array_text_layout; my @array_width_layout; my @array_height_layout; 7866my $scroll_count = 0; my $scroll_count_h3 = 0; my $ind1 = 0; # matrix indice 7867my $scrolling_type_temp; 7868 7869sub show_scrolling_text { # choose the scrolling direction 7870 return unless defined $scrolling_type; 7871 7872 @array_text_layout = (); @array_width_layout = (); @array_height_layout = (); # clear 7873 7874 my @all_scrolling = ( 'horinzontal1', 'horinzontal2', 'horinzontal3', 'vertical' ); # all scrolling types 7875 my $rand = int( rand($#all_scrolling + 1) ); # pick one random element: 0 <= rand() < $#all_scrolling + 1 7876 7877 $scrolling_type_temp = $scrolling_type eq 'random' ? $all_scrolling[$rand] : $scrolling_type; 7878 #print "scrolling_type = $scrolling_type ;; scrolling_type_temp = $scrolling_type_temp\n"; 7879 7880 #print "sub show_scrolling_text --> \$scrolling_type = $scrolling_type ; \$rand = $rand ; \$scrolling_type_temp = $scrolling_type_temp\n"; 7881 7882 if ( $scrolling_type_temp eq 'horinzontal1' or $scrolling_type_temp eq 'vertical' ){ show_scrolling_text_special(); } 7883 elsif ( $scrolling_type_temp eq 'horinzontal2' or $scrolling_type_temp eq 'horinzontal3' ){ show_scrolling_text_normal(); } 7884 return $false; # to stop the loop of $timer_wait for "loop on", "random on", ... 7885} 7886 7887sub show_scrolling_text_normal { # horizontal2 and horizontal3 7888 my ($pixmap_layout, $width_layout, $height_layout); 7889 my $row = $selected_row; 7890 my $scrol_text; 7891 7892 if ( defined $files_info[$row]{artist} ){ 7893 $scrol_text = " *** $files_info[$row]{file}. "; 7894 $scrol_text .= "$files_info[$row]{artist} - " if $files_info[$row]{artist}; 7895 $scrol_text .= "$files_info[$row]{title} - " if $files_info[$row]{title}; 7896 $scrol_text .= "$files_info[$row]{album} - " if $files_info[$row]{album}; 7897 7898 if ($files_info[$row]{artist} eq "" and $files_info[$row]{title} eq "" and $files_info[$row]{album} eq ""){ 7899 (my $file = $files_info[$row]{filename}) =~ s/\.(...|flac)$//i; # remove extension_input 7900 $scrol_text .= "$file - " 7901 } 7902 $scrol_text .= "track $files_info[$row]{track} " if $files_info[$row]{track}; 7903 $scrol_text .= "($files_info[$row]{length}) - $files_info[$row]{bitrate} kb/s "; 7904 } 7905 7906 ($pixmap_layout, $width_layout, $height_layout) = defined $scrol_text ? draw_layout( text => "$scrol_text" ) : draw_layout( ); 7907 push @array_text_layout, $pixmap_layout; 7908 push @array_width_layout, $width_layout; 7909 push @array_height_layout, $height_layout; 7910 7911 my $ind = ($ind1)%($#array_text_layout+1); # cyclic indices ;; always $ind = 0 ;; $ind is local 7912 draw_text_scrolling(layout => $array_text_layout[$ind], center => int(($scroll_w - $array_width_layout[$ind])/2) ); 7913} 7914 7915sub show_scrolling_text_special { # horizontal1 or vertical 7916 my ($pixmap_layout, $width_layout, $height_layout); 7917 my $row = $selected_row; 7918 7919 if ( defined $files_info[$row]{artist} ){ 7920 7921 my @all_artist = return_artist_name($files_info[$row]); # 'art1 & art2' return (art1,art2) 7922 7923 foreach my $artist ( @all_artist ) { 7924 next unless $artist; 7925 ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "$artist" ); 7926 push @array_text_layout, $pixmap_layout; 7927 push @array_width_layout, $width_layout; 7928 push @array_height_layout, $height_layout; 7929 } 7930 foreach my $item ( 'title', 'album' ) { 7931 next unless $files_info[$row]{$item}; 7932 ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "$files_info[$row]{$item}" ); 7933 push @array_text_layout, $pixmap_layout; 7934 push @array_width_layout, $width_layout; 7935 push @array_height_layout, $height_layout; 7936 } 7937 if (@array_text_layout <= 0){ 7938 (my $file = $files_info[$row]{filename}) =~ s/\.(...|flac)$//i; # remove extension_input 7939 ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "$file" ); 7940 push @array_text_layout, $pixmap_layout; 7941 push @array_width_layout, $width_layout; 7942 push @array_height_layout, $height_layout; 7943 } 7944 if ($files_info[$row]{track}){ 7945 ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "track $files_info[$row]{track} ($files_info[$row]{length})" ); 7946 push @array_text_layout, $pixmap_layout; 7947 push @array_width_layout, $width_layout; 7948 push @array_height_layout, $height_layout; 7949 } 7950 if ($files_info[$row]{frequency}){ 7951 ($pixmap_layout, $width_layout, $height_layout) = draw_layout( text => "$files_info[$row]{frequency} Hz ($files_info[$row]{bitrate} kb/s)" ); 7952 push @array_text_layout, $pixmap_layout; 7953 push @array_width_layout, $width_layout; 7954 push @array_height_layout, $height_layout; 7955 } 7956 } 7957 else{ 7958 ($pixmap_layout, $width_layout, $height_layout) = draw_layout(); 7959 push @array_text_layout, $pixmap_layout; 7960 push @array_width_layout, $width_layout; 7961 push @array_height_layout, $height_layout; 7962 } 7963 7964 $ind1 = ($ind1)%($#array_text_layout+1); # cyclic indices ;; $ind1 is global 7965 draw_text_scrolling(layout => $array_text_layout[$ind1], center => int(($scroll_w - $array_width_layout[$ind1])/2) ); 7966} 7967 7968sub draw_text_scrolling { 7969 my %args = ( 7970 widget => $da, # $widget = $da = Gtk2::DrawingArea 7971 event => undef, 7972 scrolling => $true, 7973 center => int(($scroll_w - $width_layout)/2), # put the text on the center 7974 @_, # argument pair list goes here 7975 ); 7976 my $widget = $args{widget}; 7977 my $text = $args{text}; 7978 $pixmap_layout = $args{layout}; 7979 return if not defined $pixmap_layout; 7980 7981 # init values 7982 if ($scrolling_type_temp eq 'horinzontal2' or $scrolling_type_temp eq 'horinzontal3'){ $xsrc = 0; $scroll_count_h3 = 170; } 7983 $scroll_count = 0 if ( $scroll_count >= 3 ); # for 'horinzontal1' and 'vertical' 7984 $sinal = +1; 7985 7986 my @update_rect; 7987 $update_rect[0] = $xdest; 7988 $update_rect[1] = $ydest; 7989 $update_rect[2] = $scroll_w; 7990 $update_rect[3] = $scroll_h; 7991 7992 $pixmap->draw_rectangle ($gc_skin2, $true, @update_rect); # erase all first 7993 #$drawable->draw_drawable ($gc, $src, $xsrc, $ysrc, $xdest, $ydest, $width, $height) 7994 $pixmap->draw_drawable ($gc_skin2, $pixmap_layout, -$args{center}, 0, $xdest, $ydest, $scroll_w, $scroll_h); # draw the layout 7995 $widget->queue_draw_area (@update_rect); # refresh 7996 7997 begin_scroll_loop(scrolling => $args{scrolling}); 7998} 7999 8000sub begin_scroll_loop { 8001 my %args = ( 8002 scrolling => $true, 8003 @_, # argument pair list goes here 8004 ); 8005 8006 if ( defined($timer_scroll) ){ Glib::Source->remove($timer_scroll);} # to not duplicate the MainLoop 8007 if ( defined($timer_wait) ){ Glib::Source->remove($timer_scroll);} # to not duplicate "loop on", "random on", ... 8008 if ($args{scrolling}){ # 250 milliseconds = 0.250 second 8009 # integer = Glib::Timeout->add ($interval, $callback, $data=undef, $priority=G_PRIORITY_DEFAULT); see <man Glib::MainLoop> 8010 $timer_scroll = Glib::Timeout->add ($scrolling_text_speed, \&scroll_text_v, undef, 0) if ($scrolling_type_temp eq 'vertical'); 8011 $timer_scroll = Glib::Timeout->add ($scrolling_text_speed, \&scroll_text_h1, undef, 0) if ($scrolling_type_temp eq 'horinzontal1'); 8012 $timer_scroll = Glib::Timeout->add ($scrolling_text_speed, \&scroll_text_h2, undef, 0) if ($scrolling_type_temp eq 'horinzontal2'); 8013 $timer_scroll = Glib::Timeout->add ($scrolling_text_speed, \&scroll_text_h3, undef, 0) if ($scrolling_type_temp eq 'horinzontal3'); 8014 } 8015} 8016 8017sub draw_layout { # return the $pixmap_layout->draw_layout_with_colors with text 8018 my %args = ( 8019 widget => $da, # $widget = $da = Gtk2::DrawingArea 8020 text => " *** artist - title - album - track (length) ", 8021 @_, # argument pair list goes here 8022 ); 8023 my $widget = $args{widget}; 8024 my $text = $args{text}; 8025 return if not defined $pixmap; 8026 8027 my $height = $widget->allocation->height; # height of $widget $da 8028 my $width = $widget->allocation->width; 8029 8030 #my $purple = Gtk2::Gdk::Color->parse ('purple'); 8031 my $purple = Gtk2::Gdk::Color->parse ('#6419b8'); 8032 8033 #my $desc = Gtk2::Pango::FontDescription->new(); 8034 #my $context = Gtk2::Pango::Context->new(); 8035 #my $layout = Gtk2::Pango::Layout->new ($context); 8036 my $layout = $widget->create_pango_layout (""); 8037 my $context = $layout->get_context; 8038 my $fontdesc = $context->get_font_description; 8039 # Choose the Fonts: "Sans", "Fixed", "Utopia", "Courier", "LucidaTypewriter", "Luxi Mono" etc 8040 $fontdesc->set_family ("Sans"); 8041 $fontdesc->set_style ("normal"); 8042 8043 # find the nice height size and change the font 8044 my $max_height = $scroll_h; 8045 $height_layout = $max_height - 1; # start value 8046 my $max_font_size = 2; # start height size 8047 while ( $height_layout <= $max_height ){ # to determine the maximum height size 8048 $fontdesc->set_size ( $max_font_size * PANGO_SCALE ); 8049 $layout->set_text ("0�g�X_"); # only to get its width and height 8050 ($width_layout, $height_layout) = $layout->get_pixel_size; 8051 #print "height_layout = $height_layout ; max_height = $max_height ; max_font_size = $max_font_size\n"; 8052 $max_font_size += 1 if ($height_layout <= $max_height) ; 8053 } 8054 $max_font_size -= 1 if ($height_layout > $max_height); 8055 8056 $fontdesc->set_size ( $max_font_size * PANGO_SCALE ); 8057 $layout->set_text ($text); 8058 ($width_layout, $height_layout) = $layout->get_pixel_size; # get its width and height ; global variable 8059 #print "-> height_layout = $height_layout <= max_height = $scroll_h ; max_font_size = $max_font_size\n"; 8060 8061 $layout->set_text ($text." "); # Put adicional pixels to fix border problem. 8062 8063 #pixmap = Gtk2::Gdk::Pixmap->new ($drawable, $width, $height, $depth) 8064 $pixmap_layout = Gtk2::Gdk::Pixmap->new ($widget->window, $width_layout, $height_layout, -1); 8065 #$drawable->draw_layout_with_colors ($gc, $x, $y, $layout, $foreground, $background); see <man Gtk2::Gdk::Drawable> 8066 $pixmap_layout->draw_layout_with_colors ($gc_bg, 0, 0, $layout, $purple, $color_skin2); 8067 8068 return ($pixmap_layout, $width_layout, $height_layout); 8069} 8070 8071sub scroll_text_h1 { 8072 my $incremental = $scrolling_text_incremental || 1; # 1 is default (1 pixel). 8073 my $sep = 16; # separation 8074 8075 $ind1 = ($ind1)%($#array_text_layout+1); # cyclic indices 8076 my $ind2 = $scrolling_text_orientation > 0 ? ($ind1 + 1)%($#array_text_layout+1) : # next crescent : 0 1 2 3 0 1 2 8077 ($ind1 + $#array_text_layout)%($#array_text_layout+1); # next decrescent : 0 3 2 1 0 3 2 8078 8079 $xsrc = $xsrc + $scrolling_text_orientation * abs($incremental); # $scrolling_text_orientation : + (up) ; - (down) 8080 $ysrc = 0; 8081 8082 if ( abs($xsrc) > int(($array_width_layout[$ind1] + $array_width_layout[$ind2])/2) + $sep ){ 8083 $xsrc = 0; 8084 $scroll_count += 1; 8085 } 8086 if ( $scroll_count < 4 ){ return $true; } 8087 if ( $scroll_count > 4 ){ $scroll_count = 0; $ind1 = $ind2; return $true; } 8088 8089 my @update_rect; 8090 $update_rect[0] = $xdest; $update_rect[1] = $ydest; 8091 $update_rect[2] = $scroll_w; $update_rect[3] = $scroll_h; 8092 $pixmap->draw_rectangle($gc_skin2, $true, @update_rect); # erase all first 8093 8094 my $center1h = int(($scroll_w - $array_width_layout[$ind1])/2); 8095 8096 my $i = $ind1; # the center indice 8097 my $ini = $center1h - $xsrc; 8098 my $remain = $scroll_w - $ini; 8099 while ( $remain > 0 ){ # the right side from the center layout 8100 my $ind = ($i)%($#array_text_layout+1); # cyclic indices 8101 my $wid = $array_width_layout[$ind] + $sep; 8102 my $x0 = $ini > 0 ? 0 : abs($ini); 8103 $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind], # $src (Gtk2::Gdk::Drawable) 8104 $x0, $ysrc, # $xsrc, $ysrc, 8105 $xdest + maximum($ini,0), $ydest, # $xdest, $ydest 8106 minimum($remain,$scroll_w), $scroll_h); # $width, $height 8107 $remain -= $wid; 8108 $ini += $wid; 8109 $i += 1; 8110 } 8111 8112 $i = $ind1 + $#array_text_layout; # the next decrescent array element : 0 3 2 1 0 3 2 1 8113 $remain = $center1h - $xsrc; 8114 while ( $remain > 0 ){ # the left side from the center layout 8115 my $ind = ($i)%($#array_text_layout+1); # cyclic indices 8116 my $wid = $array_width_layout[$ind] + $sep; 8117 $remain -= $wid; 8118 my $x0 = $remain >= 0 ? 0 : abs($remain); 8119 $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind], # $src (Gtk2::Gdk::Drawable) 8120 $x0, $ysrc, # $xsrc, $ysrc, 8121 $xdest + maximum($remain,0), $ydest, # $xdest, $ydest 8122 minimum($wid - $x0,$scroll_w), $scroll_h); # $width, $height 8123 $i -= 1; 8124 } 8125 8126 $da->queue_draw_area (@update_rect); # refresh the area 8127 return $true; 8128} 8129 8130sub scroll_text_h2 { 8131 my $incremental = $scrolling_text_incremental || 1; # 1 is default (1 pixel). 8132 my $ind = ($ind1)%($#array_text_layout+1); # $ind = 0, because the @array_width_layout has only one element 8133 my $center1h = int(($scroll_w - $array_width_layout[$ind])/2); 8134 my $wid = $array_width_layout[$ind]; 8135 8136 $xsrc = $xsrc + $sinal * $scrolling_text_orientation * abs($incremental); 8137 $ysrc = 0; 8138 8139 my @update_rect; 8140 $update_rect[0] = $xdest; $update_rect[1] = $ydest; 8141 $update_rect[2] = $scroll_w; $update_rect[3] = $scroll_h; 8142 $pixmap->draw_rectangle($gc_skin2, $true, @update_rect); # erase all first 8143 8144 if ( $center1h <= 0 ) { # closed loop 8145 my $ini = $center1h - $xsrc; 8146 my $remain = $scroll_w - $ini; 8147 while ( $remain > 0 ){ # the right side from the center layout 8148 my $x0 = $ini > 0 ? 0 : abs($ini); 8149 $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind], # $src (Gtk2::Gdk::Drawable) 8150 $x0, $ysrc, # $xsrc, $ysrc, 8151 $xdest + maximum($ini,0), $ydest, # $xdest, $ydest 8152 minimum($remain,$scroll_w), $scroll_h); # $width, $height 8153 $remain -= $wid; 8154 $ini += $wid; 8155 } 8156 8157 $remain = $center1h - $xsrc; 8158 while ( $remain > 0 ){ # the left side from the center layout 8159 $remain -= $wid; 8160 my $x0 = $remain >= 0 ? 0 : abs($remain); 8161 $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind], # $src (Gtk2::Gdk::Drawable) 8162 $x0, $ysrc, # $xsrc, $ysrc, 8163 $xdest + maximum($remain,0), $ydest, # $xdest, $ydest 8164 minimum($wid - $x0,$scroll_w), $scroll_h); # $width, $height 8165 } 8166 } 8167 elsif ( $center1h > 0 ) { # zig-zag, movimento de vai e vem. 8168 if ( abs($xsrc) > abs($center1h) ) { # when the layout touches one extreme, change the $sinal. 8169 $scroll_count_h3 = 0; 8170 $sinal = -$sinal; 8171 } 8172 8173 $pixmap->draw_drawable ($gc_bg, $pixmap_layout, # $src (Gtk2::Gdk::Drawable) 8174 $xsrc - $center1h, $ysrc, # $xsrc, $ysrc, 8175 $xdest, $ydest, # $xdest, $ydest 8176 $scroll_w, $scroll_h); # $width, $height 8177 } 8178 8179 $da->queue_draw_area (@update_rect); # refresh the area 8180 return $true; 8181} 8182 8183sub scroll_text_h3 { 8184 my $incremental = $scrolling_text_incremental || 1; # 1 is default (1 pixel). 8185 my $center1h = int( ($scroll_w - $width_layout)/2 ); 8186 $ysrc = 0; 8187 8188 $scroll_count_h3 += 1; 8189 if ( $scroll_count_h3 < 200 or $center1h >= 0 ) { return $true; } 8190 8191 $xsrc = $xsrc + $sinal * $scrolling_text_orientation * abs($incremental); 8192 $xsrc = 0 if ( abs($xsrc) > abs($center1h) + abs($incremental) ); 8193 8194 if ( abs($xsrc) > abs($center1h) ) { # when the layout touches one extreme, the $sinal is changed. 8195 $scroll_count_h3 = 0; 8196 $sinal = -$sinal; 8197 } 8198 8199 my @update_rect; 8200 $update_rect[0] = $xdest; $update_rect[1] = $ydest; 8201 $update_rect[2] = $scroll_w; $update_rect[3] = $scroll_h; 8202 $pixmap->draw_rectangle($gc_skin2, $true, @update_rect); # erase all first 8203 8204 $pixmap->draw_drawable ($gc_bg, $pixmap_layout, # $src (Gtk2::Gdk::Drawable) 8205 $xsrc - $center1h, $ysrc, # $xsrc, $ysrc, 8206 $xdest, $ydest, # $xdest, $ydest 8207 $scroll_w, $scroll_h); # $width, $height 8208 8209 $da->queue_draw_area (@update_rect); # refresh the area 8210 return $true; 8211} 8212 8213sub scroll_text_v { 8214 my $incremental = $scrolling_text_incremental || 1; # 1 is default (1 pixel). 8215 my $sep = 2; # separation 8216 8217 $ind1 = ($ind1)%($#array_text_layout+1); # cyclic indices 8218 my $ind2 = $scrolling_text_orientation > 0 ? ($ind1 + 1)%($#array_text_layout+1) : # next crescent : 0 1 2 3 0 1 2 8219 ($ind1 + $#array_text_layout)%($#array_text_layout+1); # next decrescent : 0 3 2 1 0 3 2 8220 8221 $xsrc = 0; 8222 $ysrc = $ysrc - $scrolling_text_orientation * abs($incremental); # $scrolling_text_orientation : + (down) ; - (up) 8223 8224 if ( abs($ysrc) > $array_height_layout[$ind1] + $sep ){ 8225 $ysrc = 0; 8226 $scroll_count += 1; 8227 } 8228 if ( $scroll_count < 14 ){ return $true; } 8229 if ( $scroll_count > 14 ){ $scroll_count = 0; $ind1 = $ind2; return $true;} 8230 8231 my $center1 = int(($scroll_w - $array_width_layout[$ind1])/2); $center1 = 0 if $center1 < 0; 8232 my $center2 = int(($scroll_w - $array_width_layout[$ind2])/2); $center2 = 0 if $center2 < 0; 8233 8234 my @update_rect; 8235 $update_rect[0] = $xdest; $update_rect[1] = $ydest; 8236 $update_rect[2] = $scroll_w; $update_rect[3] = $scroll_h; 8237 $pixmap->draw_rectangle($gc_skin2, $true, @update_rect); # erase all first 8238 8239 $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind1], # $src (Gtk2::Gdk::Drawable) 8240 $xsrc, $ysrc, # $xsrc, $ysrc, 8241 $xdest + $center1, $ydest, # $xdest, $ydest 8242 $scroll_w, $scroll_h); # $width, $height 8243 if ( $ysrc > $sep ) { # up 8244 $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind2], # $src (Gtk2::Gdk::Drawable) 8245 $xsrc, 0, # $xsrc, $ysrc, 8246 $xdest + $center2, $ydest + $scroll_h - ( $ysrc - $sep ), # $xdest, $ydest 8247 $scroll_w, $ysrc - $sep); # $width, $height 8248 } 8249 if ( $ysrc + $sep < 0 ) { # down 8250 $pixmap->draw_drawable ($gc_bg, $array_text_layout[$ind2], # $src (Gtk2::Gdk::Drawable) 8251 $xsrc, $array_height_layout[$ind2] + $ysrc + $sep, # $xsrc, $ysrc, 8252 $xdest + $center2, $ydest, # $xdest, $ydest 8253 $scroll_w, abs($ysrc + $sep)); # $width, $height 8254 } 8255 $da->queue_draw_area (@update_rect); # refresh the area 8256 return $true; 8257} 8258 8259#--------------------- Final -------------------------# 8260#------------------ Scrolling Text -------------------# 8261 8262#----------- CD player Color Selection ---------------# 8263#--------------------- Start -------------------------# 8264 8265# see /usr/share/doc/perl-Gtk2-1.054/gtk-demo/colorsel.pl 8266 8267my $window_cdplayer_color; my $notebook_cdplayer; my $button_cdplayer_color; 8268my $darea1; my $darea2; my $darea3; my $darea4; 8269my $darea5; my $darea6; my $darea7; 8270 8271sub make_window_cdplayer_color { 8272 8273 $window_cdplayer_color = Gtk2::Window->new('toplevel'); # 'toplevel' or 'popup' 8274 $window_cdplayer_color->set_title ("gnormalize player"); 8275 $window_cdplayer_color->set_border_width (4); 8276 $window_cdplayer_color->signal_connect (destroy => \&Quit_window_cdplayer_color); 8277 $window_cdplayer_color->set_position ('none'); # none, center-always, center-on-parent , mouse 8278 $window_cdplayer_color->set( 'resizable' => $true, 'allow-shrink' => $false, 'allow-grow' => $true); 8279 $window_cdplayer_color->realize; 8280 8281 my $vbox_cdplayer_color = Gtk2::VBox->new ($false, 8); 8282 $vbox_cdplayer_color->set_border_width (2); 8283 $window_cdplayer_color->add ($vbox_cdplayer_color); 8284 8285 my $frame_cdplayer_color = Gtk2::Frame->new; 8286 $frame_cdplayer_color->set_shadow_type ('in'); 8287 8288 my $frame_cdplayer_players = Gtk2::Frame->new; 8289 $frame_cdplayer_players->set_shadow_type ('in'); 8290 8291 my $frame_cdplayer_columns = Gtk2::Frame->new; 8292 $frame_cdplayer_columns->set_shadow_type ('in'); 8293 8294 my $frame_cdplayer_skins = Gtk2::Frame->new; 8295 $frame_cdplayer_skins->set_shadow_type ('in'); 8296 8297 #----Notebook----# 8298 $notebook_cdplayer = Gtk2::Notebook->new; 8299 $notebook_cdplayer->set( 'homogeneous' => $true, 'scrollable' => $true ); 8300 $notebook_cdplayer->append_page( $frame_cdplayer_color, $langs{all_tab11} ); # Colors 8301 $notebook_cdplayer->append_page( $frame_cdplayer_players, $langs{all_tab12} ); # Players 8302 $notebook_cdplayer->append_page( $frame_cdplayer_columns, $langs{all_tab13} ); # Columns 8303 $notebook_cdplayer->append_page( $frame_cdplayer_skins, $langs{all_tab14} ); # Skins 8304 $vbox_cdplayer_color->pack_start( $notebook_cdplayer, $true, $true, 0 ); 8305 8306 #$notebook_cd_player_num = $notebook->get_current_page; 8307 #$notebook->set_current_page ($notebook_cd_player_num); # see this command on the final 8308 8309 #$table = new Gtk::Table( $num_rows, $num_columns, $homogeneous ); 8310 my $table_cdplayer_color = new Gtk2::Table (6, 3, 0); 8311 $table_cdplayer_color->set_border_width (4); 8312 $table_cdplayer_color->set_row_spacings(4); 8313 $table_cdplayer_color->set_col_spacings(2); 8314 $frame_cdplayer_color->add( $table_cdplayer_color ); 8315 8316 my $label_cdplayer_color1 = Gtk2::Label->new("Background color: "); 8317 $label_cdplayer_color1->set_alignment( 1.0, 0.5 ); 8318 $table_cdplayer_color->attach ($label_cdplayer_color1, 0, 1, 0, 1, 'fill', 'fill', 0, 0); 8319 8320 my @def_size = (90,24); # color button size 8321 8322 $darea1 = Gtk2::DrawingArea->new; 8323 #my $color_bg = Gtk2::Gdk::Color->parse ($color_bg_cdplay); 8324 $darea1->modify_bg ('normal', $color_bg ); # set the color 8325 8326 #my $button_cdplayer_color = Gtk2::Button->new; 8327 $button_cdplayer_color = Gtk2::Button->new; 8328 $button_cdplayer_color->add ($darea1); # ->set_image ($darea1); 8329 $button_cdplayer_color->set_size_request (@def_size); # set a minimum size 8330 $button_cdplayer_color->signal_connect (clicked => \&change_color_cdplayer_bg, "display" ); 8331 $table_cdplayer_color->attach ($button_cdplayer_color, 1, 2, 0, 1, 'shrink', 'fill', 0, 0); 8332 8333 #-------- Static --------# 8334 8335 my $hsep = Gtk2::HSeparator->new; 8336 $table_cdplayer_color->attach ($hsep, 0, 2, 1, 2, ['fill','expand'], 'fill', 0, 0); 8337 my $label_stat = Gtk2::Label->new("Static Appearance"); 8338 $table_cdplayer_color->attach ($label_stat, 0, 2, 2, 3, 'fill', 'fill', 0, 0); 8339 8340 my $label_cdplayer_color2 = Gtk2::Label->new("Buttons (shadow): "); 8341 $label_cdplayer_color2->set_alignment( 1.0, 0.5 ); 8342 $table_cdplayer_color->attach ($label_cdplayer_color2, 0, 1, 3, 4, 'fill', 'fill', 0, 0); 8343 8344 $darea2 = Gtk2::DrawingArea->new; 8345 $darea2->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_shadow) ); # set the color 8346 8347 my $button_cdplayer_color2 = Gtk2::Button->new; 8348 $button_cdplayer_color2->add ($darea2); 8349 $button_cdplayer_color2->set_size_request (@def_size); # set a minimum size 8350 $button_cdplayer_color2->signal_connect (clicked => \&change_color_cdplayer_bg, "shadow" ); 8351 $table_cdplayer_color->attach ($button_cdplayer_color2, 1, 2, 3, 4, 'shrink', 'fill', 0, 0); 8352 8353 my $label_cdplayer_color3 = Gtk2::Label->new("Buttons (arrows): "); 8354 $label_cdplayer_color3->set_alignment( 1.0, 0.5 ); 8355 $table_cdplayer_color->attach ($label_cdplayer_color3, 0, 1, 4, 5, 'fill', 'fill', 0, 0); 8356 8357 $darea3 = Gtk2::DrawingArea->new; 8358 $darea3->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_arrows) ); # set the color 8359 8360 my $button_cdplayer_color3 = Gtk2::Button->new; 8361 $button_cdplayer_color3->add ($darea3); 8362 $button_cdplayer_color3->set_size_request (@def_size); # set a minimum size 8363 $button_cdplayer_color3->signal_connect (clicked => \&change_color_cdplayer_bg, "arrows" ); 8364 $table_cdplayer_color->attach ($button_cdplayer_color3, 1, 2, 4, 5, 'shrink', 'fill', 0, 0); 8365 8366 #-------- Motion --------# 8367 8368 my $hsep2 = Gtk2::HSeparator->new; 8369 $table_cdplayer_color->attach ($hsep2, 0, 2, 5, 6, ['fill','expand'], 'fill', 0, 0); 8370 my $label_mov = Gtk2::Label->new("Motion Appearance"); 8371 $table_cdplayer_color->attach ($label_mov, 0, 2, 6, 7, 'fill', 'fill', 0, 0); 8372 8373 my $label_cdplayer_color4 = Gtk2::Label->new("Buttons (shadow): "); 8374 $label_cdplayer_color4->set_alignment( 1.0, 0.5 ); 8375 $table_cdplayer_color->attach ($label_cdplayer_color4, 0, 1, 7, 8, 'fill', 'fill', 0, 0); 8376 8377 $darea4 = Gtk2::DrawingArea->new; 8378 $darea4->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_shadow_motion) ); # set the color 8379 8380 my $button_cdplayer_color4 = Gtk2::Button->new; 8381 $button_cdplayer_color4->add ($darea4); 8382 $button_cdplayer_color4->set_size_request (@def_size); # set a minimum size 8383 $button_cdplayer_color4->signal_connect (clicked => \&change_color_cdplayer_bg, "shadow_motion" ); 8384 $table_cdplayer_color->attach ($button_cdplayer_color4, 1, 2, 7, 8, 'shrink', 'fill', 0, 0); 8385 8386 8387 my $label_cdplayer_color5 = Gtk2::Label->new("Buttons (arrows): "); 8388 $label_cdplayer_color5->set_alignment( 1.0, 0.5 ); 8389 $table_cdplayer_color->attach ($label_cdplayer_color5, 0, 1, 8, 9, 'fill', 'fill', 0, 0); 8390 8391 $darea5 = Gtk2::DrawingArea->new; 8392 $darea5->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_arrows_motion) ); # set the color 8393 8394 my $button_cdplayer_color5 = Gtk2::Button->new; 8395 $button_cdplayer_color5->add ($darea5); 8396 $button_cdplayer_color5->set_size_request (@def_size); # set a minimum size 8397 $button_cdplayer_color5->signal_connect (clicked => \&change_color_cdplayer_bg, "arrows_motion" ); 8398 $table_cdplayer_color->attach ($button_cdplayer_color5, 1, 2, 8, 9, 'shrink', 'fill', 0, 0); 8399 8400 8401 #-------- Digits --------# 8402 8403 my $hsep3 = Gtk2::HSeparator->new; 8404 $table_cdplayer_color->attach ($hsep3, 0, 2, 9, 10, ['fill','expand'], 'fill', 0, 0); 8405 my $label_dig = Gtk2::Label->new("Digits"); 8406 $table_cdplayer_color->attach ($label_dig, 0, 2, 10, 11, 'fill', 'fill', 0, 0); 8407 8408 my $label_cdplayer_color6 = Gtk2::Label->new("Current time: "); 8409 $label_cdplayer_color6->set_alignment( 1.0, 0.5 ); 8410 $table_cdplayer_color->attach ($label_cdplayer_color6, 0, 1, 11, 12, 'fill', 'fill', 0, 0); 8411 8412 $darea6 = Gtk2::DrawingArea->new; 8413 $darea6->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_digit) ); # set the color 8414 8415 my $button_cdplayer_color6 = Gtk2::Button->new; 8416 $button_cdplayer_color6->add ($darea6); 8417 $button_cdplayer_color6->set_size_request (@def_size); # set a minimum size 8418 $button_cdplayer_color6->signal_connect (clicked => \&change_color_cdplayer_bg, "digit" ); 8419 $table_cdplayer_color->attach ($button_cdplayer_color6, 1, 2, 11, 12, 'shrink', 'fill', 0, 0); 8420 8421 8422 my $label_cdplayer_color7 = Gtk2::Label->new("Remaining time: "); 8423 $label_cdplayer_color7->set_alignment( 1.0, 0.5 ); 8424 $table_cdplayer_color->attach ($label_cdplayer_color7, 0, 1, 12, 13, 'fill', 'fill', 0, 0); 8425 8426 $darea7 = Gtk2::DrawingArea->new; 8427 $darea7->modify_bg ('normal', Gtk2::Gdk::Color->parse ($color_cdplayer_digit_remaining) ); # set the color 8428 8429 my $button_cdplayer_color7 = Gtk2::Button->new; 8430 $button_cdplayer_color7->add ($darea7); 8431 $button_cdplayer_color7->set_size_request (@def_size); # set a minimum size 8432 $button_cdplayer_color7->signal_connect (clicked => \&change_color_cdplayer_bg, "digit_remaining" ); 8433 $table_cdplayer_color->attach ($button_cdplayer_color7, 1, 2, 12, 13, 'shrink', 'fill', 0, 0); 8434 8435 8436 #------- Players -------# 8437 my $table_cdplayer_players = new Gtk2::Table (6, 3, 0); 8438 $table_cdplayer_players->set_border_width (4); 8439 $table_cdplayer_players->set_row_spacings(4); 8440 $table_cdplayer_players->set_col_spacings(2); 8441 $frame_cdplayer_players->add( $table_cdplayer_players ); 8442 8443 my $label_cdplayer_players0 = Gtk2::Label->new("player"); 8444 $label_cdplayer_players0->set_alignment( 0.5, 0.5 ); 8445 $table_cdplayer_players->attach ($label_cdplayer_players0, 1, 2, 0, 1, 'fill', 'fill', 0, 0); 8446 8447 my $label_cdplayer_players01 = Gtk2::Label->new("device type"); 8448 $label_cdplayer_players01->set_alignment( 0.5, 0.5 ); 8449 $table_cdplayer_players->attach ($label_cdplayer_players01, 3, 4, 0, 1, 'fill', 'fill', 0, 0); 8450 8451 my $label_cdplayer_players02 = Gtk2::Label->new("device path"); 8452 $label_cdplayer_players02->set_alignment( 0.5, 0.5 ); 8453 $table_cdplayer_players->attach ($label_cdplayer_players02, 3, 4, 2, 3, 'fill', 'fill', 0, 0); 8454 8455 my $label_cdplayer_players1 = Gtk2::Label->new("mp3: "); 8456 $label_cdplayer_players1->set_alignment( 1.0, 0.5 ); 8457 $table_cdplayer_players->attach ($label_cdplayer_players1, 0, 1, 1, 2, 'fill', 'fill', 0, 0); 8458 8459 my $label_cdplayer_players2 = Gtk2::Label->new("mp4: "); 8460 $label_cdplayer_players2->set_alignment( 1.0, 0.5 ); 8461 $table_cdplayer_players->attach ($label_cdplayer_players2, 0, 1, 2, 3, 'fill', 'fill', 0, 0); 8462 8463 my $label_cdplayer_players3 = Gtk2::Label->new("mpc: "); 8464 $label_cdplayer_players3->set_alignment( 1.0, 0.5 ); 8465 $table_cdplayer_players->attach ($label_cdplayer_players3, 0, 1, 3, 4, 'fill', 'fill', 0, 0); 8466 8467 my $label_cdplayer_players4 = Gtk2::Label->new("ogg: "); 8468 $label_cdplayer_players4->set_alignment( 1.0, 0.5 ); 8469 $table_cdplayer_players->attach ($label_cdplayer_players4, 0, 1, 4, 5, 'fill', 'fill', 0, 0); 8470 8471 my $label_cdplayer_players5 = Gtk2::Label->new("ape: "); 8472 $label_cdplayer_players5->set_alignment( 1.0, 0.5 ); 8473 $table_cdplayer_players->attach ($label_cdplayer_players5, 0, 1, 5, 6, 'fill', 'fill', 0, 0); 8474 8475 my $label_cdplayer_players6 = Gtk2::Label->new("flac: "); 8476 $label_cdplayer_players6->set_alignment( 1.0, 0.5 ); 8477 $table_cdplayer_players->attach ($label_cdplayer_players6, 0, 1, 6, 7, 'fill', 'fill', 0, 0); 8478 8479 my $label_cdplayer_players7 = Gtk2::Label->new("wav: "); 8480 $label_cdplayer_players7->set_alignment( 1.0, 0.5 ); 8481 $table_cdplayer_players->attach ($label_cdplayer_players7, 0, 1, 7, 8, 'fill', 'fill', 0, 0); 8482 8483 8484 #---mp3---# 8485 8486 my $ComboBox_mp3_player = Gtk2::ComboBox->new_text; # "mpg321", "mpg123", "madplay", "mplayer" 8487 foreach (sort keys %all_mp3_player) { $ComboBox_mp3_player->append_text ($_); } 8488 my $pos = 0; 8489 foreach my $key (sort keys %all_mp3_player) { if ($key eq $player_mp3) {$ComboBox_mp3_player->set_active($pos); last;} $pos++; } 8490 $ComboBox_mp3_player->set_size_request( 90, -1 ); 8491 $ComboBox_mp3_player->signal_connect("changed", \&player_choice, \$player_mp3); 8492 $table_cdplayer_players->attach ($ComboBox_mp3_player, 1, 2, 1, 2, ['fill','expand'], 'fill', 0, 0); 8493 $ComboBox_mp3_player->show; 8494 8495 sub player_choice { 8496 my ($ComboBox_copy, $ref_player) = @_; 8497 my $entry = $ComboBox_copy->get_active_text; 8498 8499 # See 'man perlref', 'man perlop' and 'man perlobj'. 8500 # "\" operator for taking a reference; "$" operator for taking a dereference to scalar variable. 8501 # "$player" is a scalar variable that references to a variable. 8502 # "\$player" typically creates another reference to a variable, because there's already a reference to the variable in the symbol table. 8503 # "$$player" is the value that the reference "\$player" points to. 8504 8505 $$ref_player = $entry; 8506 #print "\nComboBox_copy = $ComboBox_copy ;; \nref_player = $ref_player ;; ref_palyer value = $$ref_player \n"; 8507 } 8508 8509 #---------# 8510 my @device_type_array = ( "arts", "oss", "alsa", "esd", "jack", "nas", "sun" ); 8511 8512 my $ComboBoxEntry_device_type = Gtk2::ComboBoxEntry->new_text; 8513 ComboBox_fill_with_array(\$ComboBoxEntry_device_type,\@device_type_array); 8514 $ComboBoxEntry_device_type->child->set_text( $device_type ); #standard value 8515 $ComboBoxEntry_device_type->set_size_request( 90, -1 ); 8516 $ComboBoxEntry_device_type->child->set_editable ($true); 8517 $ComboBoxEntry_device_type->signal_connect("changed", \&device_choice, \$device_type); 8518 $table_cdplayer_players->attach ($ComboBoxEntry_device_type, 3, 4, 1, 2, ['fill','expand'], 'fill', 0, 0); 8519 #$ComboBoxEntry_device_type->show; 8520 8521 sub device_choice { 8522 my ($combo_copy, $ref_device) = @_; 8523 my $entry=$combo_copy->child->get_text; 8524 if ( $entry eq "" ){ return; } # return if empty 8525 $$ref_device = $entry; 8526 } 8527 8528 my @device_path_array = ( "/dev/audio", "/dev/sound/adsp", "/dev/dsp" ); 8529 8530 my $ComboBoxEntry_device_path = Gtk2::ComboBoxEntry->new_text; 8531 ComboBox_fill_with_array(\$ComboBoxEntry_device_path,\@device_path_array); 8532 $ComboBoxEntry_device_path->child->set_text( $device_path ); #standard value 8533 $ComboBoxEntry_device_path->set_size_request( 140, -1 ); 8534 $ComboBoxEntry_device_path->child->set_editable ($true); 8535 $ComboBoxEntry_device_path->signal_connect("changed", \&device_choice, \$device_path); 8536 $table_cdplayer_players->attach ($ComboBoxEntry_device_path, 3, 4, 3, 4, ['fill','expand'], 'fill', 0, 0); 8537 8538 #---mp4---# 8539 my $ComboBox_mp4_player = Gtk2::ComboBox->new_text; # "mplayer" 8540 foreach (sort keys %all_mp4_player) { $ComboBox_mp4_player->append_text ($_); } 8541 $pos = 0; 8542 foreach my $key (sort keys %all_mp4_player) { if ($key eq $player_mp4) {$ComboBox_mp4_player->set_active($pos); last;} $pos++; } 8543 $ComboBox_mp4_player->set_size_request( 90, -1 ); 8544 $ComboBox_mp4_player->signal_connect("changed", \&player_choice, \$player_mp4); 8545 $table_cdplayer_players->attach ($ComboBox_mp4_player, 1, 2, 2, 3, ['fill','expand'], 'fill', 0, 0); 8546 $ComboBox_mp4_player->show; 8547 8548 #---mpc---# 8549 my $ComboBox_mpc_player = Gtk2::ComboBox->new_text; # "mpcdec", "mplayer" 8550 foreach (sort keys %all_mpc_player) { $ComboBox_mpc_player->append_text ($_); } 8551 $pos = 0; 8552 foreach my $key (sort keys %all_mpc_player) { if ($key eq $player_mpc) {$ComboBox_mpc_player->set_active($pos); last;} $pos++; } 8553 $ComboBox_mpc_player->set_size_request( 90, -1 ); 8554 $ComboBox_mpc_player->signal_connect("changed", \&player_choice, \$player_mpc); 8555 $table_cdplayer_players->attach ($ComboBox_mpc_player, 1, 2, 3, 4, ['fill','expand'], 'fill', 0, 0); 8556 $ComboBox_mpc_player->show; 8557 8558 #---ogg---# 8559 my $ComboBox_ogg_player = Gtk2::ComboBox->new_text; # "ogg123", "mplayer" 8560 foreach (sort keys %all_ogg_player) { $ComboBox_ogg_player->append_text ($_); } 8561 $pos = 0; 8562 foreach my $key (sort keys %all_ogg_player) { if ($key eq $player_ogg) {$ComboBox_ogg_player->set_active($pos); last;} $pos++; } 8563 $ComboBox_ogg_player->set_size_request( 90, -1 ); 8564 $ComboBox_ogg_player->signal_connect("changed", \&player_choice, \$player_ogg); 8565 $table_cdplayer_players->attach ($ComboBox_ogg_player, 1, 2, 4, 5, ['fill','expand'], 'fill', 0, 0); 8566 $ComboBox_ogg_player->show; 8567 8568 #---ape---# 8569 my $ComboBox_ape_player = Gtk2::ComboBox->new_text; # "mac + play", "mplayer" 8570 foreach (sort keys %all_ape_player) { $ComboBox_ape_player->append_text ($_); } 8571 $pos = 0; 8572 foreach my $key (sort keys %all_ape_player) { if ($key eq $player_ape) {$ComboBox_ape_player->set_active($pos); last;} $pos++; } 8573 $ComboBox_ape_player->set_size_request( 90, -1 ); 8574 $ComboBox_ape_player->signal_connect("changed", \&player_choice, \$player_ape); 8575 $table_cdplayer_players->attach ($ComboBox_ape_player, 1, 2, 5, 6, ['fill','expand'], 'fill', 0, 0); 8576 $ComboBox_ape_player->show; 8577 8578 #---flac---# 8579 my $ComboBox_flac_player = Gtk2::ComboBox->new_text; # "flac123", "mplayer" 8580 foreach (sort keys %all_flac_player) { $ComboBox_flac_player->append_text ($_); } 8581 $pos = 0; 8582 foreach my $key (sort keys %all_flac_player) { if ($key eq $player_flac) {$ComboBox_flac_player->set_active($pos); last;} $pos++; } 8583 $ComboBox_flac_player->set_size_request( 90, -1 ); 8584 $ComboBox_flac_player->signal_connect("changed", \&player_choice, \$player_flac); 8585 $table_cdplayer_players->attach ($ComboBox_flac_player, 1, 2, 6, 7, ['fill','expand'], 'fill', 0, 0); 8586 $ComboBox_flac_player->show; 8587 8588 #---wav---# 8589 my $ComboBox_wav_player = Gtk2::ComboBox->new_text; # "mplayer" 8590 foreach (sort keys %all_wav_player) { $ComboBox_wav_player->append_text ($_); } 8591 $pos = 0; 8592 foreach my $key (sort keys %all_wav_player) { if ($key eq $player_wav) {$ComboBox_wav_player->set_active($pos); last;} $pos++; } 8593 $ComboBox_wav_player->set_size_request( 90, -1 ); 8594 $ComboBox_wav_player->signal_connect("changed", \&player_choice, \$player_wav); 8595 $table_cdplayer_players->attach ($ComboBox_wav_player, 1, 2, 7, 8, ['fill','expand'], 'fill', 0, 0); 8596 $ComboBox_wav_player->show; 8597 8598 #----------- play_with_filter -----------# 8599 my @all_filter = ( $langs{name429} , # = 'Play Tracks Without Any Filters'; 8600 $langs{name430} , # = 'Play Tracks From Different Albums'; 8601 $langs{name431} , # = 'Play Tracks From Different Artists'; 8602 $langs{name432} , # = 'Play Tracks From Different Genres'; 8603 $langs{name433} , # = 'Play Tracks From Different Years'; 8604 ); 8605 8606 $ComboBox_player_with_filter = Gtk2::ComboBox->new_text; # filter can be albums, artists, ... 8607 foreach (@all_filter) { $ComboBox_player_with_filter->append_text ($_); } 8608 $ComboBox_player_with_filter->set_active($use_filter); # default value 8609 $ComboBox_player_with_filter->set_size_request( 90, -1 ); 8610 $ComboBox_player_with_filter->signal_connect("changed", \&change_filter); 8611 $table_cdplayer_players->attach ($ComboBox_player_with_filter, 0, 4, 8, 9, ['fill','expand'], 'fill', 0, 0); 8612 $tooltips->set_tip( $ComboBox_player_with_filter, $langs{tip429} ) if $show_all_tooltips; # "Play choosing only tracks that satisfies established filters..."; 8613 $ComboBox_player_with_filter->show; 8614 8615 sub change_filter { # see 'sub choose_filter' 8616 $use_filter = $ComboBox_player_with_filter->get_active; # $use_filter is a number 8617 8618 #@rows_already_played = (); # if change the filter, then reset playlist of rows_already_played. 8619 } 8620 8621 #---------------- Columns ---------------# 8622 my $table_cdplayer_columns = new Gtk2::Table (10, 3, 0); 8623 $table_cdplayer_columns->set_border_width (4); 8624 $table_cdplayer_columns->set_row_spacings(4); 8625 $table_cdplayer_columns->set_col_spacings(2); 8626 $frame_cdplayer_columns->add( $table_cdplayer_columns ); 8627 8628 8629 my $check_button_file = Gtk2::CheckButton->new ("Show File Number"); 8630 $check_button_file->set_active($column_show_file); 8631 $check_button_file->signal_connect( "clicked", sub{ 8632 $column_show_file = $check_button_file->get_active; 8633 add_columns( show_play => $true); 8634 show_scrolling_text(); 8635 }); 8636 $table_cdplayer_columns->attach ($check_button_file, 0, 1, 0, 1, 'fill', 'fill', 0, 0); 8637 8638 8639 my $check_button_artist = Gtk2::CheckButton->new ("Show Artist"); 8640 $check_button_artist->set_active($column_show_artist); 8641 $check_button_artist->signal_connect( "clicked", sub{ 8642 $column_show_artist = $check_button_artist->get_active; 8643 add_columns( show_play => $true); 8644 show_scrolling_text(); 8645 }); 8646 $table_cdplayer_columns->attach ($check_button_artist, 0, 1, 1, 2, 'fill', 'fill', 0, 0); 8647 8648 my $check_button_album = Gtk2::CheckButton->new ("Show Album"); 8649 $check_button_album->set_active($column_show_album); 8650 $check_button_album->signal_connect( "clicked", sub{ 8651 $column_show_album = $check_button_album->get_active; 8652 add_columns( show_play => $true); 8653 show_scrolling_text(); 8654 }); 8655 $table_cdplayer_columns->attach ($check_button_album, 0, 1, 2, 3, 'fill', 'fill', 0, 0); 8656 8657 my $check_button_track = Gtk2::CheckButton->new ("Show Track"); 8658 $check_button_track->set_active($column_show_track); 8659 $check_button_track->signal_connect( "clicked", sub{ 8660 $column_show_track = $check_button_track->get_active; 8661 add_columns( show_play => $true); 8662 show_scrolling_text(); 8663 }); 8664 $table_cdplayer_columns->attach ($check_button_track, 0, 1, 3, 4, 'fill', 'fill', 0, 0); 8665 8666 my $check_button_bitrate = Gtk2::CheckButton->new ("Show Bitrate"); 8667 $check_button_bitrate->set_active($column_show_bitrate); 8668 $check_button_bitrate->signal_connect( "clicked", sub{ 8669 $column_show_bitrate = $check_button_bitrate->get_active; 8670 add_columns( show_play => $true); 8671 show_scrolling_text(); 8672 }); 8673 $table_cdplayer_columns->attach ($check_button_bitrate, 0, 1, 4, 5, 'fill', 'fill', 0, 0); 8674 8675 my $check_button_year = Gtk2::CheckButton->new ("Show Year"); 8676 $check_button_year->set_active($column_show_year); 8677 $check_button_year->signal_connect( "clicked", sub{ 8678 $column_show_year = $check_button_year->get_active; 8679 add_columns( show_play => $true); 8680 }); 8681 $table_cdplayer_columns->attach ($check_button_year, 0, 1, 5, 6, 'fill', 'fill', 0, 0); 8682 8683 8684 my $check_button_frequency = Gtk2::CheckButton->new ("Show Frequency"); 8685 $check_button_frequency->set_active($column_show_frequency); 8686 $check_button_frequency->signal_connect( "clicked", sub{ 8687 $column_show_frequency = $check_button_frequency->get_active; 8688 add_columns( show_play => $true); 8689 }); 8690 $table_cdplayer_columns->attach ($check_button_frequency, 0, 1, 6, 7, 'fill', 'fill', 0, 0); 8691 8692 my $check_button_filepath = Gtk2::CheckButton->new ("Show Filepath"); 8693 $check_button_filepath->set_active($column_show_filepath); 8694 $check_button_filepath->signal_connect( "clicked", sub{ 8695 $column_show_filepath = $check_button_filepath->get_active; 8696 add_columns( show_play => $true); 8697 }); 8698 $table_cdplayer_columns->attach ($check_button_filepath, 0, 1, 7, 8, 'fill', 'fill', 0, 0); 8699 8700 8701 my $check_button_filename = Gtk2::CheckButton->new ("Show Filename"); 8702 $check_button_filename->set_active($column_show_filename); 8703 $check_button_filename->signal_connect( "clicked", sub{ 8704 $column_show_filename = $check_button_filename->get_active; 8705 add_columns( show_play => $true); 8706 }); 8707 $table_cdplayer_columns->attach ($check_button_filename, 0, 1, 8, 9, 'fill', 'fill', 0, 0); 8708 8709 8710 my $check_button_extension = Gtk2::CheckButton->new ("Show Extension"); 8711 $check_button_extension->set_active($column_show_extension); 8712 $check_button_extension->signal_connect( "clicked", sub{ 8713 $column_show_extension = $check_button_extension->get_active; 8714 add_columns( show_play => $true); 8715 }); 8716 $table_cdplayer_columns->attach ($check_button_extension, 0, 1, 9, 10, 'fill', 'fill', 0, 0); 8717 8718 my $check_button_play_count = Gtk2::CheckButton->new ("Show Play Count"); 8719 $check_button_play_count->set_active($column_show_play_count); 8720 $check_button_play_count->signal_connect( "clicked", sub{ 8721 $column_show_play_count = $check_button_play_count->get_active; 8722 add_columns_album_artist( column_show_play_count => $column_show_play_count); 8723 }); 8724 $table_cdplayer_columns->attach ($check_button_play_count, 0, 1, 10, 11, 'fill', 'fill', 0, 0); 8725 8726 #---------------- Skins ---------------# 8727 my $table_cdplayer_skins = new Gtk2::Table (6, 3, 0); 8728 $table_cdplayer_skins->set_border_width (4); 8729 $table_cdplayer_skins->set_row_spacings(4); 8730 $table_cdplayer_skins->set_col_spacings(4); 8731 $frame_cdplayer_skins->add( $table_cdplayer_skins ); 8732 8733 my $label_st = Gtk2::Label->new("Scrolling Text"); 8734 $table_cdplayer_skins->attach ($label_st, 0, 2, 0, 1, 'fill', 'fill', 0, 0); 8735 8736 ###---### 8737 my $label_scrolling_type = new Gtk2::Label( "Type:" ); 8738 $label_scrolling_type->set_alignment( 1.0, 0.5 ); 8739 $table_cdplayer_skins->attach ($label_scrolling_type, 0, 1, 1, 2, 'fill', 'fill', 0, 0); 8740 8741 my @all_scrolling = ( "horinzontal1", "horinzontal2", "horinzontal3", "vertical", "random" ); 8742 8743 my $ComboBox_scrolling = Gtk2::ComboBox->new_text; 8744 ComboBox_fill_with_array(\$ComboBox_scrolling,\@all_scrolling); 8745 ComboBox_select_this_text(\$ComboBox_scrolling,\@all_scrolling,\$scrolling_type); #standard value 8746 $ComboBox_scrolling->set_size_request( 120, -1 ); 8747 $ComboBox_scrolling->signal_connect("changed", \&scrolling_choice, $ComboBox_scrolling); 8748 $table_cdplayer_skins->attach ($ComboBox_scrolling, 1, 2, 1, 2, ['fill','expand'], 'fill', 0, 0); 8749 #$ComboBox_scrolling->show; 8750 8751 sub scrolling_choice { 8752 my ($self, $ComboBox_copy) = @_; 8753 $scrolling_type = $ComboBox_copy->get_active_text; 8754 show_scrolling_text(); 8755 } 8756 ###---### 8757 8758 my $label_sts = new Gtk2::Label( "Interval:" ); 8759 $label_sts->set_alignment( 1.0, 0.5 ); 8760 $table_cdplayer_skins->attach ($label_sts, 0, 1, 2, 3, 'fill', 'fill', 0, 0); 8761 8762 my $adj = new Gtk2::Adjustment( $scrolling_text_speed, 10, 2000, 5, 0, 0 ); 8763 my $spinner_text = new Gtk2::SpinButton( $adj, 1.2, 0 ); 8764 $spinner_text->set_editable($true); 8765 $spinner_text->set_size_request( 120, -1 ); 8766 $spinner_text->set_update_policy( 'if_valid' ); 8767 $spinner_text->set_wrap( $false ); 8768 $tooltips->set_tip( $spinner_text, $langs{tip407} ) if $show_all_tooltips; 8769 $spinner_text->signal_connect( "value-changed", sub{ 8770 $scrolling_text_speed = $spinner_text->get_value_as_int; 8771 begin_scroll_loop(); 8772 #print "scrolling_text_speed = $scrolling_text_speed\n"; 8773 }); 8774 $table_cdplayer_skins->attach ($spinner_text, 1, 2, 2, 3, ['fill','expand'], 'fill', 0, 0); 8775 8776 8777 my $label_step = new Gtk2::Label( "Step:" ); 8778 $label_step->set_alignment( 1.0, 0.5 ); 8779 $table_cdplayer_skins->attach ($label_step, 0, 1, 3, 4, 'fill', 'fill', 0, 0); 8780 8781 $adj = new Gtk2::Adjustment( $scrolling_text_incremental, 1, 20, 1, 0, 0 ); 8782 my $spinner_step = new Gtk2::SpinButton( $adj, 0.2, 0 ); 8783 $spinner_step->set_editable($true); 8784 $spinner_step->set_size_request( 120, -1 ); 8785 $spinner_step->set_update_policy( 'if_valid' ); 8786 $spinner_step->set_wrap( $false ); 8787 $tooltips->set_tip( $spinner_step, $langs{tip408} ) if $show_all_tooltips; 8788 $spinner_step->signal_connect( "value-changed", sub{ 8789 $scrolling_text_incremental = $spinner_step->get_value_as_int; 8790 #print "scrolling_text_incremental = $scrolling_text_incremental\n"; 8791 }); 8792 $table_cdplayer_skins->attach ($spinner_step, 1, 2, 3, 4, 'fill', 'fill', 0, 0); 8793 8794 8795 my $check_button_orientation = Gtk2::CheckButton->new ("Scrolling text orientation"); 8796 $tooltips->set_tip( $check_button_orientation, $langs{tip409} ) if $show_all_tooltips; 8797 $check_button_orientation->set_active( $scrolling_text_orientation == 1 ? $true : $false ); 8798 $check_button_orientation->signal_connect( "clicked", sub{ 8799 $scrolling_text_orientation = $check_button_orientation->get_active ? +1 : -1; 8800 }); 8801 $table_cdplayer_skins->attach ($check_button_orientation, 0, 2, 4, 5, 'fill', 'fill', 0, 0); 8802 8803 my $hsepSkin = Gtk2::HSeparator->new; 8804 $table_cdplayer_skins->attach ($hsepSkin, 0, 2, 5, 6, ['fill','expand'], 'fill', 0, 0); 8805 8806 8807 my $check_button_skin = Gtk2::CheckButton->new ("Show skin"); 8808 $tooltips->set_tip( $check_button_skin, $langs{tip410} ) if $show_all_tooltips; 8809 $check_button_skin->set_active($show_cdplayer_skin); 8810 $check_button_skin->signal_connect( "clicked", sub{ 8811 $show_cdplayer_skin = $check_button_skin->get_active; 8812 sensitive_bg_color(); 8813 }); 8814 $table_cdplayer_skins->attach ($check_button_skin, 0, 1, 6, 7, 'fill', 'fill', 0, 0); 8815 8816 my $check_button_border = Gtk2::CheckButton->new ("Show border"); 8817 $check_button_border->set_active($show_cdplayer_border); 8818 $check_button_border->signal_connect( "clicked", sub{ 8819 $show_cdplayer_border = $check_button_border->get_active; 8820 }); 8821 $table_cdplayer_skins->attach ($check_button_border, 0, 1, 7, 8, 'fill', 'fill', 0, 0); 8822 8823 my $check_button_keep_above = Gtk2::CheckButton->new ("Keep above"); 8824 $tooltips->set_tip( $check_button_keep_above, $langs{tip411} ) if $show_all_tooltips; 8825 $check_button_keep_above->set_active($show_cdplayer_keep_above); 8826 $check_button_keep_above->signal_connect( "clicked", sub{ 8827 $show_cdplayer_keep_above = $check_button_keep_above->get_active; 8828 }); 8829 $table_cdplayer_skins->attach ($check_button_keep_above, 0, 1, 8, 9, 'fill', 'fill', 0, 0); 8830 8831 #---------------- hbox ----------------# 8832 8833 my $hbox2 = Gtk2::HBox->new ($false, 0); 8834 $hbox2->set_border_width (2); 8835 $vbox_cdplayer_color->pack_start ($hbox2, $false, $false, 0); 8836 8837 my $label_empty2 = Gtk2::Label->new(" "); 8838 $hbox2->pack_start ($label_empty2, $true, $false, 0); 8839 8840 my $button = Gtk2::Button->new; 8841 $button->add( DrawIcons('gtk-close','button') ); 8842 $tooltips->set_tip( $button, $langs{tip406} ) if $show_all_tooltips; 8843 $button->signal_connect( "clicked", \&Quit_window_cdplayer_color ); 8844 $hbox2->pack_start ($button, $false, $false, 0); 8845 8846 my $label_empty3 = Gtk2::Label->new(" "); 8847 $hbox2->pack_start ($label_empty3, $true, $false, 0); 8848} 8849 8850sub sensitive_bg_color{ 8851 if ( defined $window_cdplayer_color ){ 8852 $button_cdplayer_color->set_sensitive($true); 8853 if (defined $pixmap_mask){ # have skin_xTunes 8854 $button_cdplayer_color->set_sensitive($false); 8855 } 8856 } 8857} 8858 8859sub cdplayer_color_selection { 8860 8861 if ( not defined($window_cdplayer_color) ) { 8862 make_window_cdplayer_color(); 8863 $window_cdplayer_color->show_all; 8864 8865 #---- $notebook->set_current_page ----# 8866 8867 $notebook_cdplayer->set_current_page ($notebook_cd_player_num); 8868 #$notebook_cd_player_num = $notebook->get_current_page; 8869 #$notebook->set_current_page ($notebook_cd_player_num); # see this command on the final 8870 #print "\ncdplayer_color_selection -->1 \$notebook_cd_player_num = $notebook_cd_player_num\n"; 8871 } 8872 else { 8873 Quit_window_cdplayer_color(); 8874 } 8875} 8876 8877sub Quit_window_cdplayer_color { 8878 $notebook_cd_player_num = $notebook_cdplayer->get_current_page; 8879 #print "\ncdplayer_color_selection -->2 \$notebook_cd_player_num = $notebook_cd_player_num\n"; 8880 8881 $window_cdplayer_color->destroy; 8882 $window_cdplayer_color = undef; 8883} 8884 8885sub change_color_cdplayer_bg { 8886 my ( $self, $region ) = @_; 8887 my $color; 8888 8889 # repair the standard cancel label 8890 my @items = ( { stock_id => "gtk-cancel", label => "_Cancel" } ); 8891 Gtk2::Stock->add (@items); # Register our stock items 8892 8893 my $dialog = Gtk2::ColorSelectionDialog->new ("Change the color"); 8894 $dialog->set_transient_for ($window); 8895 my $colorsel = $dialog->colorsel; 8896 8897 my $previous_color; 8898 # $color_bg_cdplay = '#E6EDBD'; $color_cdplayer_shadow = '#6E95EF'; $color_cdplayer_arrows = '#000000'; 8899 if ($region eq 'display'){ $previous_color = Gtk2::Gdk::Color->parse ($color_bg_cdplay); } 8900 elsif ($region eq 'shadow' ){ $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_shadow); } 8901 elsif ($region eq 'arrows' ){ $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_arrows); } 8902 elsif ($region eq 'shadow_motion' ){ $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_shadow_motion); } 8903 elsif ($region eq 'arrows_motion' ){ $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_arrows_motion); } 8904 elsif ($region eq 'digit' ){ $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_digit); } 8905 elsif ($region eq 'digit_remaining' ){ $previous_color = Gtk2::Gdk::Color->parse ($color_cdplayer_digit_remaining); } 8906 8907 $colorsel->set_previous_color ($previous_color); 8908 $colorsel->set_current_color ($previous_color); 8909 $colorsel->set_has_palette ($true); 8910 $colorsel->set_has_opacity_control ($false); 8911 8912 my $response = $dialog->run; 8913 8914 if ($response eq 'ok') { 8915 my $color_gdk = $colorsel->get_current_color; # $color = Gtk2::Gdk::Color 8916 my ($red, $green, $blue) = ( $color_gdk->red, $color_gdk->green, $color_gdk->blue ); 8917 8918 # uc: Returns an uppercased version of EXPR. 8919 # %x an unsigned integer, in hexadecimal ; l: long 8920 $red = uc( sprintf( "%02lx", $red/256 ) ); #print "red = $red\n"; 8921 $green = uc( sprintf( "%02lx", $green/256 ) ); 8922 $blue = uc( sprintf( "%02lx", $blue/256 ) ); 8923 8924 $color = "#${red}${green}${blue}"; # print "color = $color\n"; # like #E6E7E6 ; HTML-style hexadecimal 8925 8926 if ($region eq 'display'){ 8927 configure_event_cdplayer( $da, undef, ($color, undef) ); # change display color 8928 $darea1->modify_bg ( 'normal', $color_gdk ); 8929 } 8930 elsif ($region eq 'shadow'){ 8931 configure_event_cdplayer( $da, undef, (undef, $color) ); # change buttons color (shadow) 8932 $darea2->modify_bg ( 'normal', $color_gdk ); 8933 } 8934 elsif ($region eq 'arrows'){ 8935 configure_event_cdplayer( $da, undef, (undef, undef, $color) ); # change buttons color (arrows) 8936 $darea3->modify_bg ( 'normal', $color_gdk ); 8937 } 8938 elsif ($region eq 'shadow_motion'){ 8939 configure_event_cdplayer( $da, undef, (undef, undef, undef, $color) ); # change buttons color (shadow_motion) 8940 $darea4->modify_bg ( 'normal', $color_gdk ); 8941 } 8942 elsif ($region eq 'arrows_motion'){ 8943 configure_event_cdplayer( $da, undef, (undef, undef, undef, undef, $color) ); # change buttons color (arrows_motion) 8944 $darea5->modify_bg ( 'normal', $color_gdk ); 8945 } 8946 elsif ($region eq 'digit'){ 8947 configure_event_cdplayer( $da, undef, (undef, undef, undef, undef, undef, $color) ); # change buttons color (digit) 8948 $darea6->modify_bg ( 'normal', $color_gdk ); 8949 } 8950 elsif ($region eq 'digit_remaining'){ 8951 configure_event_cdplayer( $da, undef, (undef, undef, undef, undef, undef, undef, $color) ); # change buttons color (digit_remaining) 8952 $darea7->modify_bg ( 'normal', $color_gdk ); 8953 } 8954 # refresh the whole area $da 8955 $da->queue_draw_area (0, 0, $da->allocation->width, $da->allocation->height); 8956 } 8957 $dialog->destroy; 8958 return $color; 8959} 8960 8961#--------------------- Final -------------------------# 8962#----------- CD player Color Selection ---------------# 8963my ($click_x, $click_y) = (0,0); 8964 8965sub button_press_event_cdplayer { 8966 my ($widget, $event, $data) = @_; # $widget = $da = Gtk2::DrawingArea 8967 8968 my (undef, $x, $y, $state) = $event->window->get_pointer; 8969 if ( $cdplayer eq "Audio::CD" ){ $audiocd = Audio::CD->init("$audiodevice_path"); } 8970 8971 ($click_x, $click_y) = ($x, $y); 8972 8973 $go_back = $false; 8974 $go_forward = $false; 8975 8976 my $width_r = $buttons_w - 0; # 14 8977 my $height_r = $buttons_h - 2; # height of buttons 8978 8979 # Press mouse button 2 or 3 on cdplayer display to hide the main window 8980 if ($event->button >= 2) { 8981 show_only_cd_display(); 8982 sensitive_bg_color(); # cd_player bg color change 8983 } 8984 8985 if ($event->button == 1) { 8986 my $height = $widget->allocation->height; 8987 my $width = $widget->allocation->width ; 8988 8989 # stop button 8990 my $xdest_but = $xdest_buttons - 1*$buttons_w/2 + 0*$delta; 8991 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 8992 draw_buttons(Press_Stop => $true, Draw_Stop => $true); 8993 $button_press_stop = $true; 8994 #print "vc clicou em stop: x = $x, y = $y ;; height = $height ;; width = $width ;; dcentery = $dcentery\n"; 8995 stop_playing_music(); 8996 show_time(); 8997 $pause = $false; 8998 return $true; 8999 } 9000 # (play || pause) buttons display 9001 $xdest_but = $xdest_buttons + 1*$buttons_w/2 + 1*$delta; 9002 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9003 draw_buttons(Press_Play => $true, Draw_Play => $true); # change button color 9004 $button_press_play = $true; 9005 if ( $playing_music eq $false or $pause eq $true){ 9006 # Set volume level to play audio cd. 9007 change_volume_level( undef, $audio_cd_volume ); # 0 - 100 9008 9009 if ( $pause eq $false and $playing_music eq $false ){ play_selection();} 9010 9011 if ( $pause eq $true){ 9012 9013 if ($files_info[$selected_row]{extension_input} ne 'cda'){ 9014 if(defined $pid_player){kill 18,$pid_player}; # to resume; See "Signals" in perlipc 9015 $pause = $false; 9016 return $true; 9017 } 9018 9019 if ( $cdplayer eq "cdcd" ){ 9020 my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'resume' ); 9021 exec_cmd_system2(@cmd); 9022 } 9023 elsif ( $cdplayer eq "gnormalize::cdplay" ){ 9024 gnormalize::cdplay::resume_cdrom(); 9025 } 9026 elsif ( $cdplayer eq "Audio::CD" ){ 9027 $audiocd->resume; 9028 } 9029 } 9030 $pause = $false; 9031 } 9032 else{ 9033 if ( $playing_music eq $false ){ return;} 9034 9035 if ($files_info[$selected_row]{extension_input} ne 'cda'){ 9036 if(defined $pid_player){kill 19,$pid_player}; # see <kill -l> 9037 $pause = $true; 9038 return $true; 9039 } 9040 9041 if ( $cdplayer eq "cdcd" ){ 9042 my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'pause' ); 9043 exec_cmd_system2(@cmd); 9044 } 9045 elsif ( $cdplayer eq "gnormalize::cdplay" ){ 9046 gnormalize::cdplay::pause_cdrom(); 9047 } 9048 elsif ( $cdplayer eq "Audio::CD" ){ 9049 $audiocd->pause; 9050 } 9051 $pause = $true; 9052 } 9053 return $true; 9054 } 9055 # fastforward button display 9056 $xdest_but = $xdest_buttons + 3*$buttons_w/2 + 2*$delta; 9057 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9058 draw_buttons(Press_Forward => $true, Draw_Forward => $true); 9059 $button_press_forward = $true; 9060 #print "vc clicou em ff: x = $x, y = $y ;; height = $height ;; width = $width ;; dcenterx = $dcenterx\n"; 9061 if ( $playing_music eq $false ){ return;} 9062 9063 if ($files_info[$selected_row]{extension_input} ne 'cda'){ 9064 $count = $count+15; 9065 play_selection( skip => $count ); 9066 $pause = $false; 9067 return $true; 9068 } 9069 9070 if ( $cdplayer eq "cdcd" ){ 9071 my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'ff', '00:15' ); # advance 15 seconds 9072 exec_cmd_system2(@cmd); 9073 } 9074 elsif ( $cdplayer eq "gnormalize::cdplay" ){ 9075 gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1, Advance => 15); # advance 15 seconds 9076 } 9077 elsif ( $cdplayer eq "Audio::CD" ){ 9078 $audiocd->advance(0, 15); # advance 15 seconds 9079 } 9080 $count = $count+15; 9081 #show_time(); 9082 $pause = $false; 9083 return $true; 9084 } 9085 # next button display 9086 $xdest_but = $xdest_buttons + 5*$buttons_w/2 + 3*$delta; 9087 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9088 draw_buttons(Press_Next => $true, Draw_Next => $true); 9089 $button_press_next = $true; 9090 #print "vc clicou em next: x = $x, y = $y ;; height = $height ;; width = $width ;; dcenterx = $dcenterx\n"; 9091 if ( $playing_music eq $true ){ go_forward(); } 9092 else { $go_forward = $false; } 9093 return $true; 9094 } 9095 # eject button display 9096 $xdest_but = $xdest_buttons + 7*$buttons_w/2 + 4*$delta; 9097 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9098 draw_buttons(Press_Eject => $true, Draw_Eject => $true); 9099 $button_press_eject = $true; 9100 stop_playing_music(); 9101 if ( $cdplayer eq "gnormalize::cdplay" ){ 9102 gnormalize::cdplay::eject_cdrom(); 9103 } 9104 elsif ( $cdplayer eq "cdcd" ){ 9105 my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'eject' ); 9106 exec_cmd_system2(@cmd); 9107 # system("/usr/bin/eject /dev/hdc") || die " Error: $! \n"; 9108 # print " here, eject\n"; 9109 } 9110 if ( $cdplayer eq "Audio::CD" ){ $audiocd->eject; } 9111 exec_cmd_system2( 'eject', $audiodevice_path ); 9112 entry_cda_change(); 9113 if ( not $window->is_active ) { show_only_cd_display(); } 9114 return $true; 9115 } 9116 # rewind button display 9117 $xdest_but = $xdest_buttons - 3*$buttons_w/2 - 1*$delta; 9118 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9119 draw_buttons(Press_Rewind => $true, Draw_Rewind => $true); 9120 $button_press_rewind = $true; 9121 if ( $playing_music eq $false ){ return;} 9122 9123 if ($count >= 15){ $count = $count-15;} 9124 else { $count = 0; 9125 $go_back = $true; 9126 } 9127 9128 if ($files_info[$selected_row]{extension_input} ne 'cda'){ 9129 play_selection( skip => $count ); 9130 $pause = $false; 9131 return $true; 9132 } 9133 9134 if ( $cdplayer eq "cdcd" ){ 9135 my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'rew', '00:15' ); # go back 15 seconds 9136 exec_cmd_system2(@cmd); 9137 } 9138 elsif ( $cdplayer eq "gnormalize::cdplay" ){ 9139 gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1, Advance => -15); # go back 15 seconds 9140 } 9141 elsif ( $cdplayer eq "Audio::CD" ){ 9142 $audiocd->advance(0, -15); # go back 15 seconds 9143 } 9144 9145 $pause = $false; 9146 return $true; 9147 } 9148 # back button display 9149 $xdest_but = $xdest_buttons - 5*$buttons_w/2 - 2*$delta; 9150 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9151 draw_buttons(Press_Back => $true, Draw_Back => $true); 9152 $button_press_back = $true; 9153 if ( $playing_music eq $true and @rows_already_played > 0 ) { go_back(); } 9154 else { $go_back = $false; } 9155 return $true; 9156 } 9157 # volume button display ; $pixbuf_sound 9158 if ( $x >= $xdest_sound and $x <= ($xdest_sound + $sound_size_w) and $y >= $ydest_sound and $y <= ($ydest_sound + $sound_size_h) ){ 9159 if ( $cdplayer eq "Audio::CD" or $cdplayer eq "cdcd" or $cdplayer eq "gnormalize::cdplay" ){ 9160 show_buttom_volume2(); 9161 $status_bar->push($context_id, ""); 9162 } 9163 return $true; 9164 } 9165 # rand layout ? 9166 if ( $x >= $xdest_random and $x <= ($xdest_random + $random_w) and 9167 $y >= $ydest_random and $y <= ($ydest_random + $random_h) ){ 9168 $play_random ^= 1; 9169 draw_random($da,undef); 9170 if($play_random){ draw_text_scrolling( layout => (draw_layout( text => "random on" ))[0], scrolling => $false ); } 9171 else{ draw_text_scrolling( layout => (draw_layout( text => "random off" ))[0], scrolling => $false ); } 9172 9173 if ( defined($timer_wait) ){ Glib::Source->remove($timer_scroll);} # to not duplicate the MainLoop 9174 my $timer_wait = Glib::Timeout->add (700, \&show_scrolling_text); 9175 return $true; 9176 } 9177 # loop layout 9178 if ( $x >= $xdest_loop and $x <= ($xdest_loop + $loop_w) and 9179 $y >= $ydest_loop and $y <= ($ydest_loop + $loop_h) ){ 9180 $loop_tracks ^= 1; 9181 draw_loop($da,undef); 9182 if($loop_tracks){ draw_text_scrolling( layout => (draw_layout( text => "loop on" ))[0], scrolling => $false ); } 9183 else{ draw_text_scrolling( layout => (draw_layout( text => "loop off" ))[0], scrolling => $false ); } 9184 9185 if ( defined($timer_wait) ){ Glib::Source->remove($timer_scroll); } # to not duplicate the MainLoop 9186 my $timer_wait = Glib::Timeout->add (700, \&show_scrolling_text); 9187 return $true; 9188 } 9189 # time min:sec display 9190 my $dist_dig = 1; 9191 if ( $x >= $xdest_numbers and $x <= (5*($numbers_w + $dist_dig) + $xdest_numbers) and 9192 $y >= $ydest_numbers and $y <= ($ydest_numbers + $numbers_h) ){ 9193 $show_time_remaining ^= 1; 9194 if ( not $show_time_remaining){ $show_time_abs ^= 1; } 9195 show_time(); 9196 return $true; 9197 } 9198 # draw_text_scrolling ; change background color 9199 if ( $x >= $xdest and $x <= ($xdest + $scroll_w) and $y >= $ydest and $y <= ($ydest + $scroll_h) ){ 9200 cdplayer_color_selection(); 9201 sensitive_bg_color(); # cd_player bg color change 9202 return $true; 9203 } 9204 # draw_lapsed_time ; progress bar of elapsed time; 9205 if ( $x >= $xdest_posbar and $x <= ($xdest_posbar + $posbar_length) and 9206 $y >= $ydest_posbar and $y <= ($ydest_posbar + $posbar_h) ){ 9207 my $pct = number_value( sprintf ( "%.2f", ($x - $xdest_posbar + 1)/$posbar_length ) ); # 0.000 to 1.000 9208 if ($pct < 0){$pct = 0;} 9209 if ($pct > 1){$pct = 1;} 9210 #print "aqui ; x = $x ; y = $y ; pct = $pct\n"; 9211 return if not $playing_music; 9212 9213 if ($files_info[$selected_row]{extension_input} ne 'cda'){ 9214 my $total_sec = time_to_sec( $files_info[$selected_row]{length} ); 9215 $count = sprintf ('%.0f', $pct * $total_sec ); 9216 play_selection( skip => $count ); 9217 return $true; 9218 } 9219 9220 my $track = $selected_row + 1; 9221 my $startframe = $start_sector[$track-1] + 150; # for absolute frames, sum + 150 (gap) 9222 my $endframe = $start_sector[$track] + 150; 9223 my $dif = $endframe - $startframe; 9224 $startframe = int($startframe + $dif*$pct); 9225 $count = int( $dif*$pct/75 ); # relative seconds 9226 my ($hour,$min,$sec) = sec_to_time( $count ); 9227 #print "startframe = $startframe ; endframe = $endframe ; min:sec = $min:$sec\n"; 9228 9229 if ( $cdplayer eq "gnormalize::cdplay" ){ gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1, Position => $pct); } 9230 elsif ( $cdplayer eq "Audio::CD" ){ $audiocd->play_frames($startframe, $endframe); } 9231 elsif ( $cdplayer eq "cdcd" ){ 9232 # play [start track] [end track] [min:sec] 9233 my @cmd = ( $cdcd_path , '-d', $audiodevice_path, 'play', $track, $track, "$min:$sec" ); 9234 exec_cmd_system2(@cmd); 9235 } 9236 9237 return $true; 9238 } 9239 9240 } 9241 # We've handled the event, stop processing 9242 return $true; 9243} 9244 9245###--------------------------------------------------### 9246#####--------------- volume: begin ----------------##### 9247 9248# see the $pixbuf_sound 9249my $window_volume; 9250 9251sub show_buttom_volume2 { 9252 if ( not defined $window_volume ){ 9253 show_buttom_volume(); 9254 } 9255 else { 9256 $window_volume->hide; 9257 #$window_volume->destroy; 9258 $window_volume = undef; 9259 } 9260} 9261 9262sub show_buttom_volume { 9263 $window_volume = Gtk2::Window->new('popup'); 9264 $window_volume->set_decorated ($false); 9265 $window_volume->set_position ('mouse'); # none, center-always, center-on-parent , mouse 9266 9267 my ($position_x, $position_y) = $window_volume->get_position; 9268 #print "position_x = $position_x ;; position_y = $position_y\n"; 9269 if ( $position_y > 130 ){ $window_volume->move ($position_x + 72, $position_y - 120 ); } 9270 else { $window_volume->move ($position_x + 72, $position_y + 130 ); } 9271 9272 my $vbox_window_volume = Gtk2::VBox->new; 9273 my $frame_window_volume = Gtk2::Frame->new; 9274 my $vbox2_window_volume = Gtk2::VBox->new; 9275 my $label_window_volume = Gtk2::Label->new; 9276 my $hsep_window_volume = Gtk2::HSeparator->new; 9277 my $label2_window_volume = Gtk2::Label->new(" volume "); 9278 9279 # see <man Gtk2::Scale> and Gtk2::Range ;; Adjust the volume level 9280 # Gtk2::VScale->new_with_range ($min, $max, $step) 9281 $button_volume = Gtk2::VScale->new_with_range ( 0, 100, 1); 9282 $button_volume->set_digits(0); 9283 $button_volume->set_draw_value($false); 9284 $button_volume->set_inverted ($true); 9285 #$button_volume->set_value_pos ('left'); # left, right, top, bottom 9286 $button_volume->set_size_request( 40, 130 ); 9287 $button_volume->signal_connect ('value-changed', \&change_label_volume, $label_window_volume ); 9288 $button_volume->signal_connect ('value-changed', \&change_volume_level ); 9289 $button_volume->signal_connect ( 'button_release_event' => \&show_buttom_volume2 ); 9290 $button_volume->set_sensitive($true); 9291 # $button_volume->show; 9292 9293 #$button_volume->set_value ( get_volume_level($audio_cd_volume) ); 9294 # Get $audio_cd_volume value from config file $setting_file 9295 if ( $audio_cd_volume > 100 or $audio_cd_volume < 0 ){ $audio_cd_volume = 80; } 9296 $button_volume->set_value ( $audio_cd_volume ); 9297 9298 $window_volume->add($vbox_window_volume); 9299 $vbox_window_volume->add ($frame_window_volume); 9300 $frame_window_volume->add ($vbox2_window_volume); 9301 9302 $vbox2_window_volume->add ($button_volume); 9303 $vbox2_window_volume->add ($hsep_window_volume); 9304 $vbox2_window_volume->add ($label_window_volume); 9305 $vbox2_window_volume->add ($label2_window_volume); 9306 9307 #my ($width, $height) = $window_volume->get_size; 9308 #print "width = $width ;; height = $height \n"; 9309 9310 $window_volume->show_all; 9311} 9312 9313sub change_label_volume { 9314 my $widget = shift; # $button_volume = Gtk2::VScale 9315 my $label = shift; # Gtk2::Label 9316 9317 my $volume = int( $button_volume->get_value ); # 0 - 100 9318 $label->set_label( $volume."%" ); # 0 - 100%; 9319} 9320 9321# Set volume level to play audio cd. 9322sub change_volume_level { 9323 my $widget = shift; # $button_volume = Gtk2::VScale 9324 my $get_vol = defined $button_volume ? int($button_volume->get_value) : 80; 9325 9326 my $volume = shift || $get_vol; # Valid volumes: 0 - 100 9327 if ( $volume > 100 or $volume < 0 ){ $volume = 80; } 9328 $audio_cd_volume = $volume; # 0 - 100 9329 $volume = sprintf ( "%.0f", $volume * (255/100) ); # 0 - 255 9330 9331 return unless defined $files_info[$selected_row]{extension_input}; 9332 9333 if ($files_info[$selected_row]{extension_input} ne 'cda' and $amixer_path ne ""){ 9334 # amixer set PCM 90% / amixer set Master 60% ; Mixer_device 9335 my $cmd = "$amixer_path set Master $audio_cd_volume%"; 9336 exec_cmd_system($cmd); 9337 $cmd = "$amixer_path set PCM $audio_cd_volume%"; 9338 exec_cmd_system($cmd); 9339 #$cmd = "$amixer_path set Front $audio_cd_volume%"; 9340 #exec_cmd_system($cmd); 9341 return $audio_cd_volume; 9342 } 9343 9344 # Valid volumes: 0 - 255 ;; volume: front or back 9345 if ( $cdplayer eq "Audio::CD" ){ 9346 my $vol = $audiocd->get_volume; # Returns an Audio::CD::Volume object. 9347 9348 # Change the volume channels 9349 $vol->front->left ( $volume ); 9350 $vol->front->right( $volume ); 9351 $vol->back->left ( $volume ); 9352 $vol->back->right ( $volume ); 9353 # Save this changes 9354 $audiocd->set_volume ( $vol ); 9355 } 9356 elsif ( $cdplayer eq "gnormalize::cdplay" ){ 9357 gnormalize::cdplay::set_vol($volume); 9358 } 9359 elsif ( $cdplayer eq "cdcd" ){ 9360 my $cmd = "$cdcd_path -d $audiodevice_path setvol $volume"; 9361 exec_cmd_system($cmd); 9362 } 9363 return $audio_cd_volume; 9364} 9365 9366sub get_volume_level { # not used, get the volume level from config file $setting_file 9367 my $volume; 9368 # Valid volumes: 0 - 255 ;; volume: front or back 9369 if ( $cdplayer eq "Audio::CD" ){ 9370 my $vol = $audiocd->get_volume; # Returns an Audio::CD::Volume object. 9371 $volume = int ( ($vol->front->left + $vol->front->right)/2 ); 9372 } 9373 elsif ( $cdplayer eq "cdcd" ){ 9374 my $cmd = "$cdcd_path -d $audiodevice_path getvol"; 9375 my $output = exec_cmd_system($cmd); 9376 # Left Right 9377 #Front 54 54 9378 #Back 0 0 9379 while( $output =~ /Front\s+(\d+)\s+(\d+).*/g ){ 9380 $volume = int ( ($1 + $2)/2 ); 9381 } 9382 } 9383 $volume = sprintf ( "%.0f", $volume * (100/255) ); # 0 - 100 9384 return $volume; 9385} 9386 9387#####--------------- volume: final ----------------##### 9388###--------------------------------------------------### 9389 9390# to fill the empty space 9391my $label_fill = new Gtk2::Label( " " ); 9392$label_fill->set_alignment( 0.5, 0.5 ); 9393$hbox4->pack_start($label_fill, $true, $true, 0); 9394$label_fill->show(); 9395 9396# Create Dir_Selection button 9397my $button_play_more = Gtk2::Button->new; 9398$button_play_more->add( DrawIcons('gtk-add','button') ); 9399#$button_play_more->set_label("Dir / File"); 9400$tooltips->set_tip( $button_play_more, $langs{tip405} ) if $show_all_tooltips; 9401$button_play_more->signal_connect( "clicked", \&dir_selection ); 9402$button_play_more->set( 'focus-on-click' => $false, 'relief' => 'none' ); 9403$hbox4->pack_start ($button_play_more, $false, $false, 0); 9404$button_play_more->show; 9405 9406 9407#####------------- Mode :: CD display -------------##### 9408###--------------------------------------------------### 9409 9410sub show_only_cd_display { 9411 9412 if ($window->is_active) { # Hide the main $window 9413 9414 $hbox4->remove($da); 9415 $hbox4->remove($label_fill); 9416 $hbox4->remove($button_play_more); 9417 $window->hide; 9418 9419 $window_cd_player = Gtk2::Window->new('toplevel'); # 'toplevel' or 'popup' 9420 $window_cd_player->set_title( "" ); # no title 9421 $window_cd_player->set_position ('mouse'); # none, center-always, center-on-parent , mouse 9422 $window_cd_player->signal_connect( "delete_event", \&Quit ); 9423 $window_cd_player->set( 'allow-shrink' => $false, 9424 'resizable' => (not $show_cdplayer_skin), 9425 'allow-grow' => (not $show_cdplayer_skin) ); 9426 $window_cd_player->resize($window_cd_player_width, $window_cd_player_height); 9427 $window_cd_player->set_title( "gnormalize" ) if ($window_cd_player_width > 100); 9428 $show_cdplayer_keep_above ? $window_cd_player->set_keep_above($true) : $window_cd_player->set_keep_above($false); 9429 9430 $window_cd_player->add($da); 9431 $window_cd_player->set_decorated ($show_cdplayer_border); # boolean = $window->get_decorated 9432 $window_cd_player->realize; 9433 $window_cd_player->show_all; 9434 } 9435 else { # Show the main $window 9436 # 'if not defined $pixmap_mask' is the same as 'without use skin' 9437 ($window_cd_player_width, $window_cd_player_height) = $window_cd_player->get_size if not defined $pixmap_mask; 9438 $window_cd_player->remove($da); 9439 $window_cd_player->destroy; 9440 $window_cd_player = undef; 9441 9442 $hbox4->pack_start($da, $false, $false, 0); 9443 $hbox4->pack_start($label_fill, $true, $true, 0); 9444 $hbox4->pack_start ($button_play_more, $false, $false, 0); 9445 $window->set_position ('mouse'); 9446 $window->show; 9447 } 9448} 9449 9450sub motion_notify_event_cdplayer { # See /usr/share/doc/perl-Gtk2-1.080/examples/scribble.pl 9451 my ($widget, $event, @data) = @_; # $widget = $da = Gtk2::DrawingArea ; GdkEventMotion *event 9452 # Gtk2::Gdk::Event::Motion 9453 9454 my $height = $widget->allocation->height; 9455 my $width = $widget->allocation->width; 9456 9457 #return if $window_cd_player is decorated; $window->get_decorated ; 9458 my ($x, $y, $state); 9459 9460 if ($event->is_hint) { 9461 (undef, $x, $y, $state) = $event->window->get_pointer; 9462 } 9463 else { 9464 $x = $event->x; 9465 $y = $event->y; 9466 $state = $event->state; 9467 } 9468 my ( $x_root , $y_root ) = ( $event->x_root , $event->y_root ); 9469 my ($xoffset, $yoffset) = $event -> window() -> get_root_origin(); 9470 #print "x = $x ; y = $y ; x_root = $x_root ; y_root = $y_root ; xoffset = $xoffset ; yoffset = $yoffset\n"; 9471 9472 if ( $state >= "button1-mask" and defined $window_cd_player ) { 9473 if ( not $window_cd_player->get_decorated ) { 9474 # get (click_x, click_y) with button_press_event 9475 $window_cd_player->move( $x_root - $click_x , $y_root - $click_y); # move the $window_cd_player 9476 } 9477 } 9478 9479 if ( $y < $height/3 ){ return $true; } 9480 9481 my $xdest_but = $xdest_buttons - 1*$buttons_w/2 + 0*$delta; 9482 # stop button display 9483 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9484 draw_buttons(Shadow_Stop => $true, Draw_Stop => $true); 9485 } 9486 else { draw_buttons(Draw_Stop => $true); } # default color 9487 # (play || pause) buttons display 9488 $xdest_but = $xdest_buttons + 1*$buttons_w/2 + 1*$delta; 9489 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9490 draw_buttons(Shadow_Play => $true, Draw_Play => $true); 9491 } 9492 else { draw_buttons(Draw_Play => $true); } 9493 # fastforward button display 9494 $xdest_but = $xdest_buttons + 3*$buttons_w/2 + 2*$delta; 9495 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9496 draw_buttons(Shadow_Forward => $true, Draw_Forward => $true); 9497 } 9498 else { draw_buttons(Draw_Forward => $true); } 9499 # next button display 9500 $xdest_but = $xdest_buttons + 5*$buttons_w/2 + 3*$delta; 9501 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9502 draw_buttons(Shadow_Next => $true, Draw_Next => $true); 9503 } 9504 else { draw_buttons(Draw_Next => $true); } 9505 # eject button display 9506 $xdest_but = $xdest_buttons + 7*$buttons_w/2 + 4*$delta; 9507 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9508 draw_buttons(Shadow_Eject => $true, Draw_Eject => $true); 9509 } 9510 else { draw_buttons(Draw_Eject => $true); } 9511 # rewind button display 9512 $xdest_but = $xdest_buttons - 3*$buttons_w/2 - 1*$delta; 9513 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9514 draw_buttons(Shadow_Rewind => $true, Draw_Rewind => $true); 9515 } 9516 else { draw_buttons(Draw_Rewind => $true); } 9517 # back button display 9518 $xdest_but = $xdest_buttons - 5*$buttons_w/2 - 2*$delta; 9519 if ( $x >= $xdest_but and $x <= ($xdest_but + $buttons_w) and $y >= $ydest_buttons and $y <= ($ydest_buttons + $buttons_h) ){ 9520 draw_buttons(Shadow_Back => $true, Draw_Back => $true); 9521 } 9522 else { draw_buttons(Draw_Back => $true); } 9523 9524 #print "x = $x ; y = $y ; x_root = $x_root ; y_root = $y_root ; xoffset = $xoffset\n"; 9525 return $true; 9526} 9527 9528 9529#------------------------- final -----------------------# 9530###---------------------- Display --------------------### 9531 9532###---------------------- Frame6 ---------------------### 9533#--------------------------About------------------------# 9534# Construct a textview to put About 9535my $textview_about = Gtk2::TextView->new; 9536$textview_about->set ( 'editable' => $false, 9537 'cursor_visible' => $false, 9538 'left_margin' => 10, 'right_margin' => 10, 9539 'wrap-mode' => 'word'); 9540my $color_about = Gtk2::Gdk::Color->parse ("#E6EDBD"); 9541$textview_about->modify_base ('normal', $color_about); 9542$textview_about->show; 9543 9544$frame6->add($textview_about); 9545# my $container = $frame6->get_children; # see <man Gtk2::Container> 9546$textview_about->set_border_width (4); 9547my $color_textview_about = Gtk2::Gdk::Color->parse ("#A0B8A3"); 9548$textview_about->modify_bg ('normal', $color_textview_about); 9549 9550# see <man Gtk2::TextBuffer> 9551# $buffer = Gtk2::TextBuffer->new; 9552my $buffer_about = $textview_about->get_buffer; 9553$buffer_about->create_tag ("italic_about", 'foreground' => "red", # see <man Gtk2::TextTag> for more options 9554 #'background' => "yellow", 9555 justification => 'center', 9556 font => "Helvetica Italic", 9557 'size-points' => "15"); 9558$buffer_about->create_tag ("version", 'foreground' => "blue", 9559 justification => 'center', 9560 font => "Helvetica", 9561 'size-points' => "12"); 9562$buffer_about->create_tag ("descr", 'foreground' => "black", 9563 justification => 'center', 9564 font => "Sans", 9565 'size-points' => "10"); 9566 9567my $count_textview = 1; my $count_same_gif = 1; my $next_string = 1; 9568my $timer_about; 9569 9570sub tux_animation_textview { 9571 $textview_about->get_buffer->delete($textview_about->get_buffer->get_bounds); #clear 9572 my $iter_about = $buffer_about->get_iter_at_offset (0); # get start of buffer 9573 $buffer_about->insert_with_tags_by_name ($iter_about, "gnormalize", "italic_about"); 9574 $buffer_about->insert_with_tags_by_name ($iter_about, " - ", "descr"); 9575 $buffer_about->insert_with_tags_by_name ($iter_about, "version $VERSION\n", "version"); 9576 9577 # ---------------------- animation --start-------------------# 9578 # See /usr/share/doc/perl-Gtk2-1.080/gtk-demo/textview.pl 9579 my $animation = choose_random_animation(); # animation path filename 9580 my $widget_animation; 9581 eval { $widget_animation = Gtk2::Image->new_from_file ($animation); }; 9582 if ($widget_animation and -e filename_from_unicode $animation and $check_button_animation->get_active) { 9583 9584 $buffer_about->insert_with_tags_by_name ($iter_about, " ", "descr"); # to center line 9585 my $anchor = $buffer_about->create_child_anchor ($iter_about); 9586 $textview_about->add_child_at_anchor ($widget_animation, $anchor); 9587 $widget_animation->show; 9588 9589 # textmark = $buffer->create_mark ($mark_name, $where, $left_gravity) 9590 $buffer_about->create_mark ('mark', $iter_about, $true); 9591 9592 # see <man Glib::MainLoop> 9593 # integer = Glib::Timeout->add ($interval, $callback, $data=undef, $priority=G_PRIORITY_DEFAULT) 9594 if ( defined($timer_about) ){ Glib::Source->remove($timer_about);} # to not duplicate the MainLoop 9595 if ( $animation =~ /typing/i ){ $timer_about = Glib::Timeout->add (250, \&show_typing_char); } 9596 else { $timer_about = Glib::Timeout->add (20000, \&choose_textview_about); } # 15000 milliseconds = 15 seconds 9597 } 9598 # ---------------------- animation --final-------------------# 9599 else { 9600 if ( defined($timer_about) ){ Glib::Source->remove($timer_about);} # remove the MainLoop 9601 $count_textview = 1; $count_same_gif = 1; 9602 $buffer_about->insert_with_tags_by_name ($iter_about, "\n$langs{msg040}", "descr"); 9603 $buffer_about->insert_with_tags_by_name ($iter_about, "\n\n$langs{msg064}", "descr"); 9604 $buffer_about->insert_with_tags_by_name ($iter_about, "\n\n$langs{msg093}", "descr"); 9605 $buffer_about->insert_with_tags_by_name ($iter_about, "\n\n$langs{msg094}", "descr"); 9606 } 9607} 9608 9609sub choose_textview_about { 9610 my $textmark = $buffer_about->get_mark ('mark'); 9611 my $iter_mark = $buffer_about->get_iter_at_mark ($textmark); 9612 #$iter_mark = $buffer_about->get_iter_at_line ( 3 ); 9613 9614 my $iter_end = $buffer_about->get_end_iter; 9615 $textview_about->get_buffer->delete($iter_mark , $iter_end ); #clear 9616 9617 if ($count_textview == 1){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg084}", "descr"); } 9618 if ($count_textview == 2){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg085}", "descr"); } 9619 if ($count_textview == 3){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{tip429}", "descr"); } 9620 if ($count_textview == 4){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg064}", "descr"); } 9621 if ($count_textview == 5){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg093}", "descr"); } 9622 if ($count_textview == 6){ $buffer_about->insert_with_tags_by_name ($iter_mark, "\n$langs{msg094}", "descr"); $count_textview = 0; $count_same_gif += 1;} 9623 if ($count_same_gif > 2 + int(rand(8)) and $count_textview == 1 ){ 9624 $count_textview = 1; # start value 9625 $count_same_gif = 1; 9626 tux_animation_textview(); 9627 return $false; 9628 } 9629 $count_textview += 1; 9630 return $true; # # if return is $false; then stop $timer_about loop 9631} 9632 9633sub show_typing_char { 9634 my $string; 9635 if ($next_string == 1){$string = "\n$langs{msg084}";} 9636 if ($next_string == 2){$string = "\n$langs{msg085}";} 9637 if ($next_string == 3){$string = "\n$langs{tip429}";} 9638 if ($next_string == 4){$string = "\n$langs{msg064}";} 9639 if ($next_string == 5){$string = "\n$langs{msg093}";} 9640 if ($next_string == 6){$string = "\n$langs{msg094}";} 9641 if ($next_string >= 7){ 9642 $count_textview = 1; # start value 9643 $next_string = 1; 9644 tux_animation_textview(); 9645 return $false; 9646 } 9647 my $iter_mark = $buffer_about->get_iter_at_mark ( $buffer_about->get_mark ('mark') ); 9648 my $iter_end = $buffer_about->get_end_iter; 9649 $textview_about->get_buffer->delete($iter_mark , $iter_end ); #clear 9650 # substr EXPR,OFFSET,LENGTH 9651 my $new_string = substr($string, 0, $count_textview); 9652 $buffer_about->insert_with_tags_by_name ($iter_mark, $new_string , "descr"); 9653 9654 if ( length($new_string) >= length($string) ) { $count_textview = 0; $next_string += 1; } 9655 $count_textview += 1; 9656 return $true; # # if return is $false; then stop $timer_about loop 9657} 9658 9659sub choose_random_animation { 9660 my @array_animation = ( '/usr/local/share/gnormalize/animations/super_tux.gif', 9661 '/usr/local/share/gnormalize/animations/dancing_penguin.gif', 9662 '/usr/local/share/gnormalize/animations/tux_lunapaint.gif', 9663 '/usr/local/share/gnormalize/animations/penguin_computer.gif', 9664 '/usr/local/share/gnormalize/animations/penguin_and_camel.gif', 9665 '/usr/local/share/gnormalize/animations/penguin_typing.gif', 9666 '/usr/local/share/gnormalize/animations/penguin_cold.gif', 9667 '/usr/local/share/gnormalize/animations/penguin_ice.gif' 9668 ); 9669 my $count_gif = $#array_animation + 1; # Get the number of elements. 9670 my $rand = int( rand( $count_gif ) ); # pick one random element: 0 <= rand($count_gif) < $count_gif 9671 #print " rand[1---N] = $rand ; animation = $array_animation[$rand] ; count_gif = $count_gif\n"; 9672 return $array_animation[$rand]; 9673} 9674 9675tux_animation_textview(); 9676 9677######--------------------------------------------###### 9678 9679#####------------- h b o x _normalize--------------##### 9680###--------------------- start ----------------------### 9681 9682# New Button : Show Info 9683my $button_show_info = Gtk2::Button->new; 9684$button_show_info->add( DrawIcons('gtk-goto-bottom','button') ); 9685#$button_show_info->set( 'focus-on-click' => $false, 'relief' => 'none' ); 9686$button_show_info->signal_connect( clicked => \&button_with_4_phases, '1'); 9687#$button_show_info->set( 'focus-on-click' => $false, 'relief' => 'none' ); 9688$button_show_info->show; 9689 9690# New Button : Hide Info 9691my $button_hide_info = Gtk2::Button->new; 9692$button_hide_info->add( DrawIcons('gtk-goto-top','button') ); 9693$button_hide_info->signal_connect( clicked => \&button_with_4_phases, '1'); 9694$button_hide_info->show; 9695 9696# this align is a container that hold two buttons alternately 9697my $align_hold_2_buttons = Gtk2::Alignment->new(0.5, 0.5 , 0, 0); 9698$align_hold_2_buttons->add ($button_show_info); 9699$hbox_normalize->pack_start( $align_hold_2_buttons, $false, $false, 0 ); 9700$align_hold_2_buttons->show; 9701 9702#---------------------------------------# 9703 9704my $normalize_button = Gtk2::ToggleButton->new("normalize"); 9705$normalize_button->signal_connect( "toggled", \&toggle_button_normalize ); 9706#my $color_green = Gtk2::Gdk::Color->parse ("#B1C3B2"); 9707#$normalize_button->modify_bg ('normal', $color_green); 9708# a tabela ir� expandir de acordo com o tamando do hbox 9709$hbox_normalize->pack_start( $normalize_button, $true, $true, 0 ); 9710$normalize_button->show(); 9711 9712# to be implemented: Thread. See <man Thread::Queue>, 9713# <man threads::shared> and tutorial <man perlthrtut> 9714 9715my $rip_sucess = $false; # get $true if rip is completed 9716 9717##--------------------------------------------------------------## 9718# this is the brain that control all normalize processes # 9719##--------------------------------------------------------------## 9720 9721sub toggle_button_normalize { 9722 # To avoid exec the sub two times when the normalize button is pressed 9723 if ( not $normalize_button->get_active ){ return $false; } 9724 9725 if ( $extension_input eq 'other' ){ 9726 $normalize_button->set_active($false); 9727 $status_bar->push($context_id, $langs{msg003} ); 9728 return $false; 9729 } 9730 elsif ( $extension_input eq 'error' ){ 9731 $normalize_button->set_active($false); 9732 $status_bar->push($context_id, $langs{msg004} ); 9733 return $false; 9734 } 9735 9736 # Test if the $directory is writable. -w : file is writable by effective uid/gid. 9737 if ( ! -w filename_from_unicode $directory_output ){ $status_bar->push($context_id, " $directory_output ".$langs{msg012} ); return $false;} 9738 9739 # Not change the output extension frames while any encoding process 9740 $hbox1->set_sensitive($false); 9741 9742 my @array; # fill with only the files that is toggled on treeview_play. 9743 if ($normalize_button->get_active){ 9744 9745 my %treeview_play_info = get_treeview_play_informations(); 9746 @array = @{$treeview_play_info{array_checked}}; # get reference to array_checked that has files toggled. 9747 9748 if ( @array >= 1 ) { search_track_and_rip_dec(@array); } 9749 else { $status_bar->push($context_id, $langs{msg013} ); } 9750 } 9751 9752 # Show the final messages 9753 if ($extension_input eq 'cda' and @array >= 1){ 9754 if ($rip_sucess eq $true and $normalize_button->get_active){ $status_bar->push($context_id, $langs{msg014} ); } 9755 else { $status_bar->push($context_id, $langs{msg015} );} 9756 } 9757 if ($extension_input ne 'cda' and @array >= 1){ 9758 if ($norm_type eq "None"){ $status_bar->push($context_id, $langs{msg016} );} 9759 elsif ($extension_input ne $extension_output){ $status_bar->push($context_id, $langs{msg017} );} 9760 else { $status_bar->push($context_id, $langs{msg018} );} 9761 } 9762 # Return the output extension frames to original state after processes 9763 $hbox1->set_sensitive($true); 9764 9765 # After stop the process, label is changed. 9766 if ($extension_input eq 'cda'){ $normalize_button->set_label("rip + normalize + encode"); } 9767 else { $normalize_button->set_label("normalize"); } 9768 change_font_for_all_child($window_font_name,$normalize_button); 9769 9770 # before exit, set the normalize_button to false: 9771 $normalize_button->set_active($false); 9772 9773} # final of ''toggle_button_normalize'' 9774 9775sub search_track_and_rip_dec { 9776 my @files_that_is_toggled = @_; 9777 9778 for (my $file = 0; $file <= $#files_that_is_toggled ; $file++){ 9779 9780 my $row = $files_that_is_toggled[$file]; 9781 next unless $files_info[$row]{rip}; 9782 if ( $files_info[$row]{extension_input} eq 'cda' ) { $da->set_sensitive($false); stop_playing_music( change_color => $false ); } 9783 9784 # for the case when the file is deleted or changed after pressed the normalize_button 9785 if ( not -e filename_from_unicode $files_info[$row]{filepath} and $files_info[$row]{extension_input} ne 'cda' ){ 9786 print "\nsearch_track_and_rip_dec --> Can't find $files_info[$row]{filepath} file to normalize: $!\n"; 9787 $status_bar->push($context_id, " Can't find $files_info[$row]{filepath} file to normalize!"); 9788 next; 9789 } 9790 if ( $files_info[$row]{rip} and $normalize_button->get_active ){ # if the music/track is toggled, then normalize it 9791 9792 $normalize_button->set_label( $files_info[$row]{extension_input} eq 'cda' ? $langs{msg019} : "stop decoding" ); # stop ripping/decoding 9793 change_font_for_all_child($window_font_name,$normalize_button); 9794 9795 my %hash = determine_directory_and_filename_and_extension(row => $row); 9796 my $file_wav = $hash{file_wav}; 9797 #print "\nsearch_track_and_rip_dec ---> file_wav = \"$file_wav\" ;; \$row = $row\n"; 9798 # used by make_directory_final(); 9799 9800 $files_info[$row]{technical_info} ? set_tag_info($row) : get_info_from_file(%hash); # get all mp3/mp4/mpc/... info if necessary 9801 set_output_and_refresh_progress_bar(%hash); 9802 refresh_input_output_arrows(); 9803 9804 insert_msg( "$langs{msg078}: " , "purple"); # "Selected file" 9805 insert_msg( "$hash{filename}\n" , "bg_yellow"); 9806 9807 color_the_selected_tracks_and_scroll( select_color => 'playing', scroll => $true, row => $row ); 9808 9809 # ripping/decoding start here ;; $rip_sucess get $true if the rip is completed 9810 insert_msg(" --- ripping ---\n" , "small-green") if ($files_info[$row]{extension_input} eq 'cda'); 9811 insert_msg(" --- decoding ---\n", "small-green") if ($files_info[$row]{extension_input} ne 'cda' and $files_info[$row]{extension_input} ne 'wav'); 9812 9813 my $track = sprintf("%02d", $row + 1 ); # 02d : leading zero 9814 if ($files_info[$row]{extension_input} eq 'cda' and $ripper eq "cdparanoia"){ $rip_sucess = rip_audio_cdparanoia($track,$file_wav);} 9815 elsif ($files_info[$row]{extension_input} eq 'cda' and $ripper eq "cdda2wav" ){ $rip_sucess = rip_audio_cdda2wav($track,$file_wav); } 9816 9817 if ( $normalize_button->get_active ){ 9818 # decode, normalize and encode the files 9819 dec_norm_enc(%hash); # %hash have many information about the file. 9820 } 9821 color_the_selected_tracks_and_scroll( select_color => 'played', scroll => $false, row => $row); 9822 9823 last unless $normalize_button->get_active; 9824 } 9825 } # final of ''for (my $file = 0; $file <= $#files_that_is_toggled ; $file++){'' 9826 9827 if ( defined $cdcd_path or $use_audiocd eq $true or $os =~ /Linux/i ){ $da->set_sensitive($true); } 9828} 9829 9830## decode, normalize and encode - for mp3/ogg/wav files 9831sub dec_norm_enc { 9832 my %args = ( @_, # argument pair list goes here 9833 ); 9834 9835 my $file_mp3 = $args{file_mp3}; my $file_mp4 = $args{file_mp4}; my $file_mpc = $args{file_mpc}; 9836 my $file_ogg = $args{file_ogg}; my $file_ape = $args{file_ape}; my $file_flac = $args{file_flac}; 9837 my $file_cda = $args{file_cda}; my $file_wav = $args{file_wav}; 9838 my $filename = $args{filename}; my $dir = $args{directory}; my $extension_input = $args{extension_input}; 9839 my $filepath = $args{filepath}; 9840 9841 #print "\ndec_norm_enc --> (\$directory,\$file_wav) = (\"$dir\",\"$file_wav\") ;; \$extension_input = $extension_input ;; row = $args{row}\n\n"; 9842 9843 my $insensibility = $spinner_sensi->get_value; 9844 $priority = $spinner_pri->get_value; #priority 9845 9846 # decode, normalize and encode the files 9847 # decode: 9848 if ( $extension_input eq 'mp3' and $lame_path ne "" ){ decode_mp3_to_wav(%args); } 9849 elsif ( $extension_input eq 'mp4' and $faad_path ne "" ){ decode_mp4_to_wav(%args); } 9850 elsif ( $extension_input eq 'mpc' and $mpcdec_path ne "" ){ decode_mpc_to_wav(%args); } 9851 elsif ( $extension_input eq 'ogg' and $oggdec_path ne "" ){ decode_ogg_to_wav(%args); } 9852 elsif ( $extension_input eq 'ape' and $ape_path ne "" ){ decode_ape_to_wav(%args); } 9853 elsif ( $extension_input eq 'flac' and $flac_path ne "" ){ decode_flac_to_wav(%args);} 9854 elsif ( $extension_input eq 'wav' and $directory_output ne $dir ){ 9855 my @cmd = ( 'cp', '-f', $dir.'/'.$filename, $directory_output ); 9856 insert_msg("." , "small-ini"); 9857 insert_msg("@cmd" , "small"); #print on debug textview 9858 insert_msg("\n" , "small"); 9859 exec_cmd_system2(@cmd); 9860 } 9861 9862 # normalize: 9863 if ( $normalize_button->get_active ) { 9864 $normalize_button->set_label("stop normalizing"); 9865 change_font_for_all_child($window_font_name,$normalize_button); 9866 insert_msg(" --- normalizing ---\n" , "small-green"); 9867 $pbar->set_fraction(1) if ($extension_input ne 'wav'); 9868 normalize_wav(%args); 9869 } 9870 # [[$treeview_play->get_selection]] is an Gtk2::TreeSelection 9871 # $treeview_play->get_selection->unselect_all; 9872 9873 # encode: 9874 # if $check_change_properties not active and file is already normalized and has the same extension_input then make copy, otherwise the file will be encoded. 9875 if ( $normalize_button->get_active ) { 9876 9877 if ( $extension_input eq $extension_output and ( $already_normalized or abs($adjust) <= $insensibility ) and not $check_change_properties->get_active ){ 9878 # Then make a copy, don't need to encode. Note that 'cda' never satisfy this conditons 9879 same_extension_overwrite(%args); 9880 } 9881 else { # $file_cda always satisfy this conditon 9882 $normalize_button->set_label("stop encoding"); 9883 change_font_for_all_child($window_font_name,$normalize_button); 9884 insert_msg(" --- encoding ---\n" , "small-green"); 9885 9886 if ( $button_output_mp3->get_active ) { $args{file_output} = $args{file_mp3}; encode_wav_to_mp3(%args); } 9887 #if ( $button_output_mp3->get_active ) { $args{file_output} = $args{file_mp3}; encode_wav_to_wma(%args); } 9888 9889 elsif ( $button_output_mp4->get_active ) { $args{file_output} = $args{file_mp4}; encode_wav_to_mp4(%args); } 9890 elsif ( $button_output_mpc->get_active ) { $args{file_output} = $args{file_mpc}; encode_wav_to_mpc(%args); } 9891 elsif ( $button_output_ogg->get_active ) { $args{file_output} = $args{file_ogg}; encode_wav_to_ogg(%args); } 9892 elsif ( $button_output_ape->get_active ) { $args{file_output} = $args{file_ape}; encode_wav_to_ape(%args); } 9893 elsif ( $button_output_flac->get_active) { $args{file_output} = $args{file_flac}; encode_wav_to_flac(%args);} 9894 elsif ( $button_output_wav->get_active ) { $args{file_output} = $args{file_wav}; encode_wav_to_wav(%args); } # actually, don't need to encode 9895 9896 finalize_process(%args); 9897 } 9898 } 9899} 9900 9901 9902## stop a process by the pid number 9903# getppid Returns the process id of the parent process. 9904sub StopProcessing { # I see dvd2dvix3pass code with some changes 9905 my ($pid,$mesg,$file_wav) = @_; 9906 ## get lame (or normalize, ...) pid 9907 ## try to kill pid+1, else pid 9908 #print ("\n $mesg which pid = $pid\n"); 9909 if( $pid >= 0 ) # if some $pid >=0 then some process is running 9910 { 9911 ## kill the lame/normalize/... PID 9912 ++$pid; 9913 my $processeskilled = kill 9, $pid; 9914 if( $processeskilled == 0 ) 9915 { 9916 --$pid; 9917 print "STOP:: pid ".($pid+1)." failed, trying kill pid $pid \n"; 9918 $processeskilled = kill 9, $pid; 9919 if( $processeskilled == 0 ) 9920 { print "Could not $mesg : pid = $pid\n";} 9921 } 9922 } 9923 #remove wav file if button_del_wav is active and $file_wav exist 9924 if ($check_button_del_wav->get_active and -e filename_from_unicode "$directory_output/$file_wav" ){ 9925 my @cmd = ( 'rm', '-f', $directory_output.'/'.$file_wav ); 9926 exec_cmd_system2(@cmd); 9927 9928 } 9929 # In the case of stop normalize process, a file like _normAAAAAA is created, 9930 # them it will be removed, if it exist. my $file_norm =~ /^\_norm(\w){6}$/i; 9931 if ( -e filename_from_unicode "$directory_output/_normAAAAAA" ){ 9932 my @cmd = ( 'rm', '-f', $directory_output.'/_normAAAAAA' ); 9933 exec_cmd_system2(@cmd); 9934 } 9935 $status_bar->push($context_id, $mesg); 9936 insert_msg("$mesg", "small-red"); 9937 insert_msg("\n" , "small"); 9938 return -1; # set (pid = -1) assignnig to a stopped process 9939} 9940 9941sub kill_prog { # using the command "ps" ; not used 9942 my $prog = shift; 9943 my $ps_path = find_prog( Progs => "ps", Comment => "NO_COMMENT"); 9944 return if $ps_path eq ""; 9945 my $output = exec_cmd_system($ps_path); 9946 while( $output =~ /(\d+)\s+pts.*$prog/g ){ # 1874 pts/3 00:00:00 bash 9947 kill 9,$1; # print "kill pid number $1 of $prog\n"; 9948 } 9949} 9950 9951###--------------------------------------------------### 9952 9953# Create "Quit" button using the icon and text from 9954# the specified stock item, see Gtk2::Stock 9955# print ( "Stoks: ",Gtk2::Stock->list_ids ,"\n"); 9956$button_quit = Gtk2::Button->new; 9957$button_quit->add( DrawIcons('gtk-quit','button') ); 9958$tooltips->set_tip( $button_quit, $langs{tip121} ) if $show_all_tooltips; 9959$button_quit->signal_connect( "clicked", \&Quit ); 9960#$button_quit->set_size_request( 70, -1 ); 9961$hbox_normalize->pack_start( $button_quit, $false, $true, 0 ); 9962#$button_quit->modify_bg ('normal', $color_blue); 9963#$button_quit->set( 'focus-on-click' => $false, 'relief' => 'none' ); 9964$button_quit->show(); 9965 9966#####----------------T a b l e _ down--------------##### 9967###--------------------------------------------------### 9968 9969my $da_arrow_dec = Gtk2::DrawingArea->new; 9970# set a minimum size 9971$da_arrow_dec->set_size_request (78, 20); 9972$table_down->attach ($da_arrow_dec, 0, 1, 0, 1, 'fill', 'shrink', 0, 0); 9973$da_arrow_dec->signal_connect (expose_event => \&draw_arrow_dec); 9974$da_arrow_dec->show; 9975 9976$change_fonte = $true; 9977my $size_input; 9978 9979sub draw_arrow_dec { # decoder 9980 my ($widget, $event, @data) = @_; # $widget = $da = Gtk2::DrawingArea 9981 9982 # to expose this event 9983 if ( $extension_input eq 'other' ){ draw_input_output($da_arrow_dec,undef,"mp3","wav"); } # default 9984 else { draw_input_output($da_arrow_dec,undef,("$extension_input","wav")); } 9985 9986 return $true; 9987} 9988 9989my $width_lay; my $height_lay; # to determine the font size 9990 9991sub draw_input_output { 9992 my ($widget, $event, @data) = @_; # $widget = $da = Gtk2::DrawingArea 9993 9994 my $height = $widget->allocation->height; # height of $widget $da 9995 my $width = $widget->allocation->width ; 9996 9997 my $gc = Gtk2::Gdk::GC->new ($widget->window); # ($widget->window) = Gtk2::Gdk::Drawable 9998 my $color = Gtk2::Gdk::Color->new (184*256, 211*256, 193*256); # #B8D3C1 = 184 211 193 (RGB) 9999 $gc->set_rgb_fg_color ($color); 10000 my $gc1 = Gtk2::Gdk::GC->new ($widget->window); # ($widget->window) = Gtk2::Gdk::Drawable 10001 my $color1 = Gtk2::Gdk::Color->new (100*256, 100*256, 200*256); #RGB = 85 90 190 10002 $gc1->set_rgb_fg_color ($color1); 10003 my $purple = Gtk2::Gdk::Color->parse ('purple'); 10004 my $blue = Gtk2::Gdk::Color->parse ('blue'); 10005 my $color3 = Gtk2::Gdk::Color->parse ('#E6EDBD'); 10006 10007 $widget->window->draw_rectangle ($gc, $true, 0, 0, $width, $height); 10008 10009 my $border = 5; 10010 my $width_a = $height - 2*$border; 10011 # arrow 10012 $widget->window->draw_rectangle ($gc1, $true, $width/2 - 7, $height/2 - 2, 8, 4); 10013 $widget->window->draw_polygon ($gc1, $true, 10014 $width/2, $height - $border, 10015 $width/2, $border, 10016 $width/2 + $width_a, $height/2 ); 10017 10018 my $layout = $widget->create_pango_layout (""); 10019 my $context = $layout->get_context; 10020 my $fontdesc = $context->get_font_description; 10021 $fontdesc->set_family ("Sans"); 10022 10023 if ( $change_fonte eq $true ){ # find the nice size and change the font only one time 10024 my $min_width = 20; 10025 $width_lay = $min_width; 10026 $size_input = 2; 10027 while ( $width_lay <= $min_width ){ # to determine the minimum size 10028 $fontdesc->set_size ( $size_input * PANGO_SCALE ); 10029 $layout->set_text ("wav"); # only to get its width and height 10030 ($width_lay, $height_lay) = $layout->get_pixel_size; 10031 $size_input += 1 if ($width_lay <= $min_width) ; 10032 } 10033 $change_fonte = $false; 10034 } 10035 else{ $fontdesc->set_size ( $size_input * PANGO_SCALE ); } 10036 10037 #print " input = $data[0] ;; output = $data[1] ;; size = ",$size_input-1,"\n"; 10038 10039 $layout->set_text ($data[0]); # $data = "mp3" 10040 ($width_lay, $height_lay) = $layout->get_pixel_size; 10041 $widget->window->draw_layout_with_colors ($gc1, 2, $height/2 - $height_lay/2, $layout, $blue, $color); 10042 10043 $layout->set_text ($data[1]); # $data = "wav" 10044 ($width_lay, $height_lay) = $layout->get_pixel_size; 10045 $widget->window->draw_layout_with_colors ($gc1, $width - $width_lay - 2, $height/2 - $height_lay/2, $layout, $blue, $color); 10046 10047 return $true; 10048} 10049 10050########-------------Progress-Bar----------------####### 10051 10052# Create the Gtk2::ProgressBar to decode 10053$pbar = Gtk2::ProgressBar->new; 10054#$table_down->attach_defaults ($pbar, 1, 4, 0, 1); 10055$table_down->attach($pbar, 1, 4, 0, 1, ['expand','fill'], 'shrink', 0, 0); 10056$pbar->set_size_request( 420, 24 ); # width, height 10057#$pbar->set_text($file_mp3); 10058$pbar->set_orientation('left_to_right'); 10059$pbar->show; 10060 10061 10062my $da_norm = Gtk2::DrawingArea->new; 10063# set a minimum size 10064$da_norm->set_size_request (76, 20); 10065$table_down->attach ($da_norm, 0, 1, 1, 2, 'fill', 'shrink', 0, 0); 10066$da_norm->signal_connect (expose_event => \&draw_norm); 10067$da_norm->show; 10068 10069$change_fonte_norm = $true; 10070my $size_norm; 10071 10072sub draw_norm { 10073 my ($widget, $event, @data) = @_; # $widget = $da = Gtk2::DrawingArea 10074 10075 my $height = $widget->allocation->height; # height of $widget $da 10076 my $width = $widget->allocation->width ; 10077 10078 my $gc = Gtk2::Gdk::GC->new ($widget->window); # ($widget->window) = Gtk2::Gdk::Drawable 10079 my $color = Gtk2::Gdk::Color->new (184*256, 211*256, 193*256); # #B8D3C1 = 184 211 193 (RGB) 10080 $gc->set_rgb_fg_color ($color); 10081 my $gc1 = Gtk2::Gdk::GC->new ($widget->window); # ($widget->window) = Gtk2::Gdk::Drawable 10082 my $color1 = Gtk2::Gdk::Color->new (100*256, 100*256, 200*256); #RGB = 100 100 200 10083 $gc1->set_rgb_fg_color ($color1); 10084 my $purple = Gtk2::Gdk::Color->parse ('purple'); 10085 my $blue = Gtk2::Gdk::Color->parse ('blue'); 10086 my $color3 = Gtk2::Gdk::Color->parse ('#E6EDBD'); 10087 10088 $widget->window->draw_rectangle ($gc, $true, 0, 0, $width, $height); 10089 10090 my $border = 5; 10091 my $width_a = 10; 10092 # arrow 10093 $widget->window->draw_rectangle ($gc1, $true, $width/2 - 6, $height/2 - 2, 8, 4); 10094 $widget->window->draw_polygon ($gc1, $true, 10095 $width/2 - $width_a/2 +5, $height - $border, 10096 $width/2 - $width_a/2 +5, $border, 10097 $width/2 + $width_a/2 +5, $height/2 ); 10098 10099 my $layout = $widget->create_pango_layout (""); 10100 my $context = $layout->get_context; 10101 my $fontdesc = $context->get_font_description; 10102 $fontdesc->set_family ("Sans"); 10103 10104 if ( $change_fonte_norm eq $true ){ # find the nice size and change the font only one time 10105 my $min_width = 60; 10106 $width_lay = $min_width; 10107 $size_norm = 2; 10108 while ( $width_lay <= $min_width ){ # to determine the minimum size 10109 $fontdesc->set_size ( $size_norm * PANGO_SCALE ); 10110 $layout->set_text ("normalize"); # only to get its width and height 10111 ($width_lay, $height_lay) = $layout->get_pixel_size; 10112 $size_norm = $size_norm + 1; 10113 } 10114 $change_fonte_norm = $false; 10115 } 10116 else{ $fontdesc->set_size ( ($size_norm - 1) * PANGO_SCALE ); } 10117 10118 $layout->set_text ("normalize"); 10119 ($width_lay, $height_lay) = $layout->get_pixel_size; 10120 $widget->window->draw_layout_with_colors ($gc1, $width/2 - $width_lay/2, $height/2 - $height_lay/2, $layout, $blue, $color); 10121 10122 return $true; 10123} 10124 10125 10126# Create the Gtk2::ProgressBar to normalize 10127$pbar_n = Gtk2::ProgressBar->new; 10128$pbar_n->set_size_request( 420, 24 ); # width, height 10129#$table_down->attach_defaults ($pbar_n, 1, 4, 1, 2); 10130$table_down->attach($pbar_n, 1, 4, 1, 2, ['expand','fill'], 'shrink', 0, 0); 10131$pbar_n->set_orientation('left_to_right'); 10132$pbar_n->show; 10133 10134my $da_arrow_enc = Gtk2::DrawingArea->new; 10135# set a minimum size 10136$da_arrow_enc->set_size_request (76, 20); 10137$table_down->attach ($da_arrow_enc, 0, 1, 2, 3, 'fill', 'shrink', 0, 0); 10138$da_arrow_enc->signal_connect (expose_event => \&draw_arrow_enc); 10139$da_arrow_enc->show; 10140 10141sub draw_arrow_enc { 10142 my ($widget, $event, @data) = @_; # $widget = $da = Gtk2::DrawingArea 10143 10144 # to expose this event 10145 draw_input_output($da_arrow_enc,undef,("wav","$extension_output")); 10146 10147 return $true; 10148} 10149 10150# Create the Gtk2::ProgressBar to encode 10151$pbar_encode = Gtk2::ProgressBar->new; 10152$pbar_encode->set_size_request( 420, 24 ); # width, height 10153#$table_down->attach_defaults ($pbar_encode, 1, 4, 2, 3); 10154$table_down->attach($pbar_encode, 1, 4, 2, 3, ['expand','fill'], 'shrink', 0, 0); 10155$pbar_encode->set_orientation('left_to_right'); 10156$pbar_encode->show; 10157 10158 10159##-----------------------------------------------------## 10160## ----------------- hbox + TextView ----------------- ## 10161# output command : debug textview 10162$vbox_text = new Gtk2::VBox; 10163$frame_debug->add( $vbox_text ); 10164$vbox_text->set_border_width(2); 10165$vbox_text->show; 10166 10167# on hbox we put a button_clear_debug 10168$hbox_text = new Gtk2::HBox; 10169$vbox_text->pack_start( $hbox_text, $false, $false, 0 ); 10170$hbox_text->show; 10171 10172# Create a centering alignment object; 10173$align = Gtk2::Alignment->new(0.0, 0.5, 0, 0); 10174$hbox_text->add($align); 10175$align->show; 10176 10177# debug clear button 10178$button_clear = Gtk2::Button->new; 10179$button_clear->add( DrawIcons('gtk-clear','button') ); 10180$tooltips->set_tip( $button_clear, $langs{tip122} ) if $show_all_tooltips; 10181$button_clear->signal_connect( "clicked", \&textview_clear); 10182$button_clear->set( 'focus-on-click' => $false, 'relief' => 'none' ); 10183$align->add($button_clear); 10184$button_clear->show; 10185 10186sub textview_clear { 10187 my $buffer = $textview->get_buffer; 10188 # delete buffer - $buffer->delete ($start, $end) 10189 # " (start, end) = $buffer->get_bounds - Retrieves the first and 10190 # last iterators in the buffer, i.e. the entire buffer lies within 10191 # the range (start,end). " 10192 $textview->get_buffer->delete( $buffer->get_bounds ); 10193 # $iter = $buffer->get_iter_at_offset (0); # get start of buffer 10194} 10195 10196##--------------------TextView-------------------------## 10197 10198# Construct an command output text 10199$textview = new Gtk2::TextView; 10200$textview->set_wrap_mode('char'); # 'none', char, word 10201# or $textview->set_editable($false); 10202$textview->set (editable => $false, cursor_visible => $false); 10203$textview->show; 10204 10205$scrolled = new Gtk2::ScrolledWindow( undef, undef ); 10206$scrolled->set_policy( 'automatic', 'always' ); # 'never', 'automatic' 10207$scrolled->set_size_request( -1, 130 ); 10208$scrolled->add($textview); 10209$scrolled->set_shadow_type('GTK_SHADOW_IN'); # 'in' , 'GTK_SHADOW_IN' 10210 10211$vbox_text->add($scrolled); 10212$scrolled->show; 10213 10214# see <man Gtk2::TextBuffer> 10215# $buffer = Gtk2::TextBuffer->new; 10216$buffer = $textview->get_buffer; 10217$buffer->create_tag ("italic", 'foreground' => "red", 10218 #'background' => "yellow", 10219 justification => 'center', 10220 style => 'italic'); 10221$buffer->create_tag ("small", 'foreground' => "blue", 10222 'size-points' => "10"); 10223$buffer->create_tag ("small-green", 'foreground' => "green", 10224 justification => 'center', 10225 'size-points' => "10"); 10226$buffer->create_tag ("small-black", 'foreground' => "black", 10227 justification => 'center', 10228 'size-points' => "10"); 10229$buffer->create_tag ("black", 'foreground' => "black", 10230 justification => 'left', 10231 'size-points' => "10"); 10232$buffer->create_tag ("purple", 'foreground' => "purple", 10233 justification => 'left', 10234 'size-points' => "10"); 10235$buffer->create_tag ("red", 'foreground' => "red", 10236 justification => 'left', 10237 'size-points' => "11"); 10238$buffer->create_tag ("small-red", 'foreground' => "red", 10239 justification => 'center', 10240 'size-points' => "10"); 10241$buffer->create_tag ("bg_yellow", 'foreground' => "blue", 10242 'background' => "yellow", 10243 'size-points' => "11"); 10244$buffer->create_tag ("small-ini", 'foreground' => "red", 10245 justification => 'left', 10246 'size-points' => "20"); 10247 10248# "get start of buffer; each insertion will revalidate the 10249# iterator to point to just after the inserted text." 10250$iter = $buffer->get_iter_at_offset (0); 10251$buffer->insert_with_tags_by_name ($iter, "gnormalize", "italic"); 10252$buffer->insert_with_tags_by_name ($iter, " $VERSION \n\n" , "small"); 10253#$buffer->insert ($iter , " - author: $AUTHOR"); 10254 10255# see /usr/share/doc/perl-Gtk2-1.054/examples/thread_usage.pl 10256# see <man Gtk2::TextIter>, <man Gtk2::Gdk::Threads> 10257 10258sub insert_msg { # scrolls down the text in the textboxes 10259 my $msg = shift; 10260 my $tag_name = shift; 10261 # (start, end) = $buffer->get_bounds 10262 $buffer = $textview->get_buffer; 10263 $iter = $buffer->get_end_iter; # or $iter = $buffer->get_bounds; 10264 # $iter = $textview->get_buffer->get_end_iter; 10265 if ($tag_name) { 10266 $buffer->insert_with_tags_by_name($iter, $msg, $tag_name);} 10267 else { $buffer->insert($iter, $msg);} # if don't have tag 10268 10269 return if ( $button_info_type != 2 ); # if debug button is not active, return 10270 #$text_view->scroll_to_iter ($iter, $within_margin,$use_align, $xalign, $yalign) 10271 $textview->scroll_to_iter($iter, 0.0, $true, 0.00, 1.00) if $iter; 10272 while (Gtk2->events_pending()) { Gtk2->main_iteration()}; # to update 10273} 10274 10275# only for illustration 10276sub get_text { 10277 my $buffer = shift->get_buffer; 10278 $buffer->get_text ($buffer->get_start_iter, $buffer->get_end_iter, $true); 10279 # print (get_text($textview) ); 10280} 10281 10282#####--------------------------------------------------##### 10283#####------------------ Subroutines -------------------##### 10284 10285sub button_with_4_phases { 10286 my ( $self, $adjust ) = @_; 10287 10288 $button_info_type += $adjust; # set the new value; $adjust = 0 or 1. 10289 #print "button_info_type = $button_info_type ; adjust = $adjust\n"; 10290 10291 $align_hold_2_buttons->remove ($align_hold_2_buttons->child); # always remove one button 10292 10293 if ( $button_info_type == 1 ){ 10294 $frame_prog_bar->show; # show the Progress_Bar Frame 10295 $align_hold_2_buttons->add ($button_show_info); 10296 $tooltips->set_tip( $button_show_info, $langs{tip119} ) if $show_all_tooltips; 10297 } 10298 elsif ( $button_info_type == 2 ){ # $frame_debug->show; 10299 $align_hold_2_buttons->add ($button_hide_info); 10300 $tooltips->set_tip( $button_hide_info, $langs{tip120} ) if $show_all_tooltips; 10301 resize_window(); 10302 } 10303 elsif ( $button_info_type == 3 ){ 10304 $align_hold_2_buttons->add ($button_hide_info); 10305 $tooltips->set_tip( $button_hide_info, $langs{tip118} ) if $show_all_tooltips; 10306 resize_window(); 10307 } 10308 elsif ( $button_info_type == 4 or $button_info_type == 0 ){ 10309 $frame_prog_bar->hide; 10310 $align_hold_2_buttons->add ($button_show_info); 10311 $tooltips->set_tip( $button_show_info, $langs{tip117} ) if $show_all_tooltips; 10312 $button_info_type = 0; # return to inicial value 10313 } 10314} 10315button_with_4_phases(0,0); # '0' to not change the $button_info_type value 10316 10317 10318# Show or hide the frame_debug that show some output commands, 10319# and hold the notebook size constant without shrink. 10320sub resize_window { 10321 my $width = $window->allocation->width; # get main window width 10322 my $height = $window->allocation->height; # get main window height 10323 10324 # get $frame_debug height ; for the first time, always '$frame_debug->allocation->height < 10' is true 10325 my $height_fd = $frame_debug->allocation->height; 10326 $height_fd = $frame_debug->allocation->height < 10 ? 177 : $height_fd; # 177 pixel is the minimum size 10327 10328 #$vpaned->child1_resize ($false); # "child1_resize" determines whether the first child should expand when $paned is resized. 10329 #print "\nfora: width = $width ; height = $height ; height_fd = ",$frame_debug->allocation->height,"\n"; 10330 10331 if ( $button_info_type == 2 ){ 10332 my $pos = $vpaned->get_position; 10333 $window->resize ( $width, $height + $height_fd ); # ($width, $height) 10334 $frame_debug->show; 10335 $vpaned->set_position ($pos); 10336 #print "-->ativo: width = $width ; height = ",$height + $height_fd," ; height_fd = $height_fd\n"; 10337 } 10338 elsif ( $button_info_type == 3 ){ 10339 $frame_debug->hide; 10340 return if $frame_debug->allocation->height < 10; 10341 $window->resize ( $width, $height - $height_fd ); 10342 #print "desativo: width = $width ; height = ",$height - $height_fd," ; height_fd = ",$frame_debug->allocation->height,"\n"; 10343 #$vpaned->set_position ($height); 10344 } 10345 #$vpaned->compute_position ($allocation, $child1_req, $child2_req); 10346 $vpaned->compute_position (0, $vbox_up->allocation->height, $vbox_down->allocation->height); 10347 #$vpaned->child1_resize ($true); 10348 10349 # boolean = $widget->get_child_visible 10350 #if ($frame_debug->get_child_visible){print "oooi\n";} 10351} 10352 10353####----------------------------------------------------#### 10354 10355#####---------------- Programs Path -------------------##### 10356 10357# sub inspirated from normalize 10358sub find_prog { # Find a valid path for the program 10359 10360 # See Perl Cookbook, 2nd Edition, Ch. 10.7 10361 my %args = ( # default value 10362 Progs => undef, # array with program name: name1::name2::name3:: ... = (name1,name2,name3,...) 10363 Comment => "", # show one message/comment 10364 @_, # argument pair list goes here 10365 ); 10366 my @progs = split(/::/, $args{Progs}); # an Array for elements in hash // Odd number of elements in hash assignment 10367 my $path = undef; 10368 my $fullpath; 10369 my $prog; 10370 #foreach $prog (@progs){ print "\$prog = $prog\n"; } 10371 10372 @_ = split(/:/, $ENV{PATH}); # get the system executable paths 10373 10374 LOOP:foreach $prog (@progs){ 10375 for (@_) { # $_ is an element of @_ 10376 ($_ .= "/") unless (/\/$/); # put a "/" at the end of path 10377 # print " S = $_ \n"; 10378 $fullpath = $_.$prog; 10379 if (-x $fullpath) { # if (-x file) : file is executable by effective uid/gid. 10380 $path = $fullpath; 10381 last LOOP; # abandon the 'foreach' LOOP 10382 } 10383 } 10384 } 10385 if ( $args{Comment} eq "NO_COMMENT" ) { return $path; } 10386 10387 foreach $prog (@progs){ 10388 if ( not defined $path ) { 10389 insert_msg( $langs{msg023}, "black"); 10390 insert_msg("$prog" , "red"); 10391 insert_msg( $langs{msg024}." $args{Comment}\n" , "black"); 10392 } 10393 } 10394 return $path; 10395} 10396 10397 10398sub verify_all_paths { 10399 $os = exec_cmd_system( 'uname -s' ); # operational system name: $os = Linux 10400 10401 # see <man Gtk2::version> 10402 # the GtkFileChooser, new in gtk+ 2.6.0 and first supported in 10403 # Gtk2-Perl at 1.100, is available. 10404 my $Gtk2_version_boolean = Gtk2->CHECK_VERSION (2, 6, 0); # boolean 10405 my ($Gtk2_version_MAJOR, $Gtk2_version_MINOR, $Gtk2_version_MICRO) = Gtk2->GET_VERSION_INFO; 10406 my $Gtk2_version = $Gtk2_version_MAJOR.".".$Gtk2_version_MINOR.".".$Gtk2_version_MICRO; 10407 my $Gtk2_Perl_version = $Gtk2::VERSION; 10408 10409 if ( $Gtk2_Perl_version < 1.100 or not $Gtk2_version_boolean ) { 10410 insert_msg( "Found Gtk2 (version = $Gtk2_version) and Gtk2_Perl (version = $Gtk2_Perl_version).", "black"); 10411 insert_msg( "\n$langs{msg079}\n" , "red"); 10412 insert_msg( " Gtk2 version >= 2.6.0 ; Gtk2_Perl version >= 1.100\n\n", "red"); 10413 } 10414 10415 $lame_path = find_prog( Progs => 'lame', Comment => $langs{msg025} ); 10416 #print " lame_path = $lame_path \n"; 10417 unless ($lame_path) { $button_output_mp3->set_sensitive($false); } 10418 10419 $oggenc_path = find_prog( Progs => "oggenc", Comment => $langs{msg026} ); 10420 #print " oggenc_path = $oggenc_path \n"; 10421 unless ($oggenc_path) { $button_output_ogg->set_sensitive($false); } 10422 10423 $mpcenc_path = find_prog( Progs => "mppenc", Comment => $langs{msg027} ); 10424 unless ($mpcenc_path) { $button_output_mpc->set_sensitive($false);} 10425 10426 $ape_path = find_prog( Progs => "mac", Comment => $langs{msg028} ); 10427 unless ($ape_path) { $button_output_ape->set_sensitive($false); } 10428 10429 $flac_path = find_prog( Progs => "flac", Comment => $langs{msg029} ); 10430 unless ($flac_path) { $button_output_flac->set_sensitive($false);} 10431 10432 $faac_path = find_prog( Progs => "faac", Comment => $langs{msg030} ); 10433 unless ($faac_path) { $button_output_mp4->set_sensitive($false);} 10434 10435 if (not defined $lame_path and $extension_output eq 'mp3') {$extension_output = 'ogg'; } 10436 if (not defined $oggenc_path and $extension_output eq 'ogg') {$extension_output = 'mpc'; } 10437 if (not defined $mpcenc_path and $extension_output eq 'mpc') {$extension_output = 'ape'; } 10438 if (not defined $ape_path and $extension_output eq 'ape') {$extension_output = 'flac';} 10439 if (not defined $flac_path and $extension_output eq 'flac'){$extension_output = 'mp4'; } 10440 if (not defined $faac_path and $extension_output eq 'mp4') {$extension_output = 'wav'; } 10441 10442 if ($extension_output eq 'mp3' and $lame_path ) {$button_output_mp3->set_active( $true ); } #padr�o - ativo 10443 elsif ($extension_output eq 'ogg' and $oggenc_path ) {$button_output_ogg->set_active( $true ); } 10444 elsif ($extension_output eq 'mpc' and $mpcenc_path ) {$button_output_mpc->set_active( $true ); } 10445 elsif ($extension_output eq 'ape' and $ape_path ) {$button_output_ape->set_active( $true ); } 10446 elsif ($extension_output eq 'flac' and $flac_path ) {$button_output_flac->set_active( $true );} 10447 elsif ($extension_output eq 'mp4' and $faac_path ) {$button_output_mp4->set_active( $true ); } 10448 elsif ($extension_output eq 'wav') {$button_output_wav->set_active( $true );} 10449 else {$normalize_button->set_sensitive($false);} # do nothing!! 10450 10451 $metaflac_path = find_prog( Progs => "metaflac"); 10452 10453 # 'normalize-audio' is a link used on Ubuntu Linux to 'normalize' 10454 # $normalize_path = find_prog( Progs => 'normalize::normalize-audio', Comment => $langs{msg031} ); 10455 10456 # 'gnormalize-wavegain' is a link used on Suse Linux to 'wavegain' 10457 $wavegain_path = find_prog( Progs => 'wavegain::gnormalize-wavegain', Comment => $langs{msg031} ); 10458 unless ($wavegain_path) { 10459 $norm_type = "None"; 10460 $ComboBox_Norm_Type->set_active(2); # 2 set to "None" 10461 $ComboBox_Norm_Type->set_sensitive($false); 10462 $spinner->set_sensitive($false); 10463 } 10464 10465 $oggdec_path = find_prog( Progs => "oggdec", Comment => $langs{msg032} ); 10466 10467 $mpcdec_path = find_prog( Progs => "mppdec", Comment => $langs{msg033} ); 10468 10469 $faad_path = find_prog( Progs => "faad", Comment => $langs{msg034} ); 10470 10471 $cdparanoia_path = find_prog( Progs => "cdparanoia"); 10472 unless ($cdparanoia_path) { 10473 $ripper = "cdda2wav"; 10474 ComboBox_select_this_text(\$ComboBox_rip,\@rippers,\$ripper); 10475 $ComboBox_rip->set_sensitive($false); 10476 } 10477 $cdda2wav_path = find_prog( Progs => "cdda2wav", Comment => "NO_COMMENT" ); 10478 unless ($cdda2wav_path) { 10479 $ripper = "cdparanoia"; 10480 ComboBox_select_this_text(\$ComboBox_rip,\@rippers,\$ripper); 10481 $ComboBox_rip->set_sensitive($false); 10482 } 10483 10484 $vorbiscomment_path = find_prog( Progs => "vorbiscomment"); 10485 10486 if (not $use_external_cddbget){ insert_msg( "$langs{msg082}\n", "black"); } 10487 if (not $use_external_MP3Info){ insert_msg( "$langs{msg083}\n", "black"); } 10488 10489 #---- mp3 players ----# ; 10490 $madplay_path = find_prog( Progs => "madplay", Comment => "NO_COMMENT" ); 10491 $mpg123_path = find_prog( Progs => "mpg123", Comment => "NO_COMMENT" ); 10492 $mpg321_path = find_prog( Progs => "mpg321", Comment => "NO_COMMENT" ); 10493 $mplayer_path = find_prog( Progs => "mplayer", Comment => "NO_COMMENT" ); 10494 10495 $all_mp3_player{"mpg321"} = $true if $mpg321_path; 10496 $all_mp3_player{"mpg123"} = $true if $mpg123_path; 10497 $all_mp3_player{"madplay"} = $true if $madplay_path; 10498 $all_mp3_player{"mplayer"} = $true if $mplayer_path; 10499 10500 foreach my $key (sort keys %all_mp3_player) { 10501 $player_mp3 = $key if ( not $all_mp3_player{"$player_mp3"} ); 10502 #print "The value of <$key> is <$all_mp3_player{$key}> ;; player_mp3 = $player_mp3\n"; 10503 } 10504 10505 if ( not %all_mp3_player ){ # no mp3 player was found 10506 find_prog( Progs => "mpg123::mpg321::madplay::mplayer", Comment => "MP3 files can't be played!" ); 10507 } 10508 10509 #---- mp4 players ----# 10510 $all_mp4_player{"mplayer"} = $true if $mplayer_path; 10511 10512 foreach my $key (sort keys %all_mp4_player) { 10513 $player_mp4 = $key if ( not $all_mp4_player{"$player_mp4"} ); 10514 } 10515 10516 #---- mpc players ----# 10517 $all_mpc_player{"mplayer"} = $true if $mplayer_path; 10518 $all_mpc_player{"mpcdec"} = $true if $mpcdec_path; 10519 10520 foreach my $key (sort keys %all_mpc_player) { 10521 $player_mpc = $key if ( not $all_mpc_player{"$player_mpc"} ); 10522 } 10523 10524 if ( not %all_mpc_player ){ # no mpc player was found 10525 find_prog( Progs => "mpcdec::mplayer", Comment => "MPC files can't be played!" ); 10526 } 10527 10528 #---- ogg players ----# ; 10529 $ogg123_path = find_prog( Progs => "ogg123", Comment => "NO_COMMENT" ); 10530 10531 $all_ogg_player{"mplayer"} = $true if $mplayer_path; 10532 $all_ogg_player{"ogg123"} = $true if $ogg123_path; 10533 10534 foreach my $key (keys %all_ogg_player) { 10535 $player_ogg = $key if ( not $all_ogg_player{"$player_ogg"} ); 10536 } 10537 10538 if ( not %all_ogg_player ){ # no ogg player was found 10539 find_prog( Progs => "ogg123::mplayer", Comment => "OGG files can't be played!" ); 10540 } 10541 10542 #---- ape players ----# 10543 $play_path = find_prog( Progs => "play", Comment => "NO_COMMENT" ); # play from sox 10544 $aplay_path = find_prog( Progs => "aplay", Comment => "NO_COMMENT" ); 10545 10546 $all_ape_player{"mplayer"} = $true if $mplayer_path; 10547 $all_ape_player{"mac"} = $true if ($ape_path and $play_path); 10548 $all_ape_player{"aplay"} = $true if ($ape_path and $aplay_path); 10549 10550 foreach my $key (keys %all_ape_player) { 10551 $player_ape = $key if ( not $all_ape_player{"$player_ape"} ); 10552 } 10553 10554 unless ( %all_ape_player ){ # no ape player was found 10555 find_prog( Progs => "mac::play::aplay::mplayer", Comment => "APE files can't be played!" ); 10556 } 10557 10558 #---- flac players ----# 10559 $flac123_path = find_prog( Progs => "flac123", Comment => "NO_COMMENT" ); 10560 10561 $all_flac_player{"mplayer"} = $true if $mplayer_path; 10562 $all_flac_player{"flac123"} = $true if $flac123_path; 10563 10564 foreach my $key (sort keys %all_flac_player) { 10565 $player_flac = $key if ( not $all_flac_player{"$player_flac"} ); 10566 } 10567 10568 if ( not %all_flac_player ){ # no flac player was found 10569 find_prog( Progs => "flac123::mplayer", Comment => "FLAC files can't be played!" ); 10570 } 10571 10572 #---- wav players ----# 10573 $all_wav_player{"mplayer"} = $true if $mplayer_path; 10574 $all_wav_player{"aplay"} = $true if $aplay_path; 10575 $all_wav_player{"play"} = $true if $play_path; 10576 10577 foreach my $key (sort keys %all_wav_player) { 10578 $player_wav = $key if ( not $all_wav_player{"$player_wav"} ); 10579 } 10580 10581 if ( not %all_wav_player ){ # no wav player was found 10582 find_prog( Progs => "mplayer::aplay::play", Comment => "WAV files can't be played!" ); 10583 } 10584 10585 #---- ----------- ----# 10586 10587 $amixer_path = find_prog( Progs => "amixer", Comment => "Can not set volume level!" ); 10588 $nice_path = find_prog( Progs => "nice", Comment => "Can not modify scheduling priority!" ); 10589} 10590 10591sub cdplayer_available { # Audio CD player uses gnormalize::cdplay or Audio::CD or cdcd. 10592 my @cdplayers = (); 10593 $cdcd_path = find_prog( Progs => "cdcd", Comment => "NO_COMMENT" ); 10594 10595 if ( $cdcd_path and not -e filename_from_unicode "$home/.cdcdrc" ){ 10596 insert_msg( "\n$langs{msg036}\n" , "black"); 10597 insert_msg( "$langs{msg037}\n" , "black"); 10598 } 10599 if ( $use_audiocd eq $false and not defined $cdcd_path and $os !~ /Linux/i ){ 10600 insert_msg( $langs{msg038} , "black"); 10601 insert_msg("Audio::CD" , "red"); 10602 insert_msg("\".\n" , "black"); 10603 $cdcd_path = find_prog( Progs => "cdcd", Comment => $langs{msg035} ); 10604 } 10605 10606 # $cdplayer = "Audio::CD" or "cdcd" or "gnormalize::cdplay" 10607 if ($os =~ /Linux/i ) { push @cdplayers, "gnormalize::cdplay";} 10608 if ($use_audiocd eq $true ) { push @cdplayers, "Audio::CD"; } 10609 if ($cdcd_path ) { push @cdplayers, "cdcd"; } 10610 10611 return @cdplayers; 10612} 10613 10614verify_all_paths(); 10615@all_cdplayer = cdplayer_available(); 10616Make_ComboBox_cdplayer(); 10617 10618 10619#####-------------- Output Directory Selection --------------##### 10620#####------------------------ start -------------------------##### 10621 10622my $file_dialog_output; 10623sub dir_selection_output { 10624 # repair the standard cancel label 10625 my @items = ( { stock_id => "gtk-cancel", label => "_Cancel" } ); 10626 Gtk2::Stock->add (@items); # Register our stock items 10627 10628 $file_dialog_output = Gtk2::FileChooserDialog->new( "Choose the Output Directory" , 10629 undef, 'open', 10630 'gtk-cancel' => 'cancel', 10631 'gtk-ok' => 'ok'); 10632 10633 # On Unix, the assumption of GLib and GTK+ by default is that filenames on 10634 # the filesystem are encoded in UTF-8 rather than the encoding of the locale; (Release notes for GTK+ 2.6) 10635 # Output = gtk_func->set_text(Input), Output and Input should be in unicode on the perl level. 10636 10637 # filename_to_unicode : convert local encoding --> unicode. 10638 # filename_from_unicode: convert unicode --> local encoding. 10639 10640 # filename_display_name is used with filename that need to display in gtk+ and guaranteed 10641 # to return valid utf8, but the conversion is not necessary reversible. See 'man Glib'. 10642 10643 #_utf8_on($directory_output); # Turn on the UTF8 flag so Perl don't try to convert the some "$string1$string2" to utf8. 10644 10645 #print "\n dir_selection_output --> 1\$directory_output = ", $directory_output,"\n"; 10646 #$directory_output = encode('utf8',$directory_output); 10647 my $current_folder = $entry_dir_output->get_text; # '$entry_dir_output->get_text' are in unicode reversible 10648 $current_folder = $home if not -d filename_from_unicode $current_folder; 10649 10650 # "you first need to convert filename from the local encoding to unicode." (see <man Glib>) 10651 $file_dialog_output->set_current_folder( filename_from_unicode $current_folder ); #abrir no lacal espec�fico 10652 10653 # Gtk2::FileChooserAction : 'select-folder', 'open', 10654 $file_dialog_output->set_action ('select-folder'); # directory selection only 10655 if ($file_dialog_output->run eq 'ok') { 10656 10657 $directory_output = $file_dialog_output->get_filename; # '$file_dialog_output->get_filename' are in unicode reversible 10658 eval { $directory_output = filename_to_unicode $directory_output; }; # To remove Wide character 10659 10660 verify_writable_dir( $directory_output ); 10661 10662 $entry_dir_output->set_text( $directory_output ); 10663 $tooltips->set_tip( $entry_dir_output, $directory_output ) if $show_all_tooltips; 10664 10665 #print "\n dir_selection_output --> 2\$directory_output = ", $directory_output,"\n"; 10666 insert_msg("\n dir_selection_output --> \$directory_output = $directory_output\n" , "small"); #print on debug textview 10667 }; 10668 $file_dialog_output->destroy; 10669} 10670 10671sub verify_writable_dir { 10672 my $dir = shift; 10673 10674 if ( not -w filename_from_unicode $dir ){ 10675 $status_bar->push($context_id, " $dir ".$langs{msg012} ); 10676 $directory_output = $home; 10677 $entry_dir_output->set_text( $directory_output ); 10678 $tooltips->set_tip( $entry_dir_output, $directory_output ) if $show_all_tooltips; 10679 } 10680 else{ $status_bar->push($context_id, " " ); } 10681} 10682 10683#####------------------------ final -------------------------##### 10684#####-------------- Output Directory Selection --------------##### 10685 10686 10687#####------------------- Directory Selection ----------------##### 10688#####------------------------ start -------------------------##### 10689 10690sub dir_selection { 10691 10692 # repair the standard cancel label 10693 my @items = ( { stock_id => "gtk-cancel", label => "_Cancel" } ); 10694 Gtk2::Stock->add (@items); # Register our stock items 10695 10696 my $fd_msg = $langs{msg087}; 10697 10698 # Create a new file selection widget 10699 # See file:///usr/share/gtk-doc/html/gtk/GtkFileChooserDialog.html, 10700 # /usr/share/doc/perl-Gtk2-1.080/examples/file_chooser.pl 10701 # or <man Gtk2::FileChooserDialog> and <man Gtk2::FileChooser> 10702 # clicking the 'gtk-cancel' button will emit the "response" signal with the given response_id. 10703 $file_dialog = Gtk2::FileChooserDialog->new( $fd_msg , 10704 undef, 'open', 10705 'gtk-cancel' => 'cancel', 10706 'gtk-ok' => 'ok'); 10707 10708 ###----------------------- Filters -----------------------### 10709 # Unfortunately Gtk2::FileFilter don't have the 'insensitive case' option!!! 10710 10711 my $filter_all = Gtk2::FileFilter->new; 10712 $filter_all->set_name ('All files'); 10713 $filter_all->add_pattern ('*'); 10714 $file_dialog->add_filter ($filter_all); 10715 10716 my $filter_mp3 = Gtk2::FileFilter->new; 10717 $filter_mp3->set_name ('.mp3'); # 2 ** 2 = 4 combinations 10718 $filter_mp3->add_pattern ('*.mp3'); $filter_mp3->add_pattern ('*.mP3'); 10719 $filter_mp3->add_pattern ('*.Mp3'); $filter_mp3->add_pattern ('*.MP3'); 10720 $file_dialog->add_filter ($filter_mp3); 10721 10722 my $filter_mp4 = Gtk2::FileFilter->new; 10723 $filter_mp4->set_name ('.mp4'); # All 2 ** 2 = 4 combinations for mp4 10724 $filter_mp4->add_pattern ('*.mp4'); $filter_mp4->add_pattern ('*.mP4'); 10725 $filter_mp4->add_pattern ('*.Mp4'); $filter_mp4->add_pattern ('*.MP4'); 10726 $filter_mp4->add_pattern ('*.M4A'); $filter_mp4->add_pattern ('*.m4a'); # for m4a 10727 $filter_mp4->add_pattern ('*.M4a'); $filter_mp4->add_pattern ('*.m4A'); 10728 $filter_mp4->add_pattern ('*.aac'); $filter_mp4->add_pattern ('*.AAC'); # for aac 10729 $file_dialog->add_filter ($filter_mp4); 10730 10731 my $filter_mpc = Gtk2::FileFilter->new; 10732 $filter_mpc->set_name ('.mpc'); 10733 $filter_mpc->add_pattern ('*.mpc'); $filter_mpc->add_pattern ('*.MPC'); 10734 $filter_mpc->add_pattern ('*.mpp'); $filter_mpc->add_pattern ('*.MPP'); 10735 $filter_mpc->add_pattern ('*.mp+'); $filter_mpc->add_pattern ('*.MP+'); 10736 $file_dialog->add_filter ($filter_mpc); 10737 10738 my $filter_ogg = Gtk2::FileFilter->new; 10739 $filter_ogg->set_name ('.ogg'); # All 2 ** 3 = 8 combinations 10740 $filter_ogg->add_pattern ('*.ogg'); $filter_ogg->add_pattern ('*.Ogg'); 10741 $filter_ogg->add_pattern ('*.oGg'); $filter_ogg->add_pattern ('*.ogG'); 10742 $filter_ogg->add_pattern ('*.OGg'); $filter_ogg->add_pattern ('*.OgG'); 10743 $filter_ogg->add_pattern ('*.oGG'); $filter_ogg->add_pattern ('*.OGG'); 10744 $file_dialog->add_filter ($filter_ogg); 10745 10746 my $filter_ape = Gtk2::FileFilter->new; 10747 $filter_ape->set_name ('.ape'); # There are 2 ** 3 = 8 combinations 10748 $filter_ape->add_pattern ('*.ape'); $filter_ape->add_pattern ('*.APE'); 10749 $filter_ape->add_pattern ('*.Ape'); $filter_ape->add_pattern ('*.aPe'); 10750 $filter_ape->add_pattern ('*.apE'); $filter_ape->add_pattern ('*.APe'); 10751 $filter_ape->add_pattern ('*.aPE'); $filter_ape->add_pattern ('*.aPe'); 10752 $file_dialog->add_filter ($filter_ape); 10753 10754 my $filter_flac = Gtk2::FileFilter->new; 10755 $filter_flac->set_name ('.flac'); # There are 2 ** 4 = 16 combinations 10756 $filter_flac->add_pattern ('*.flac'); $filter_flac->add_pattern ('*.FLAC'); 10757 $filter_flac->add_pattern ('*.Flac'); $filter_flac->add_pattern ('*.fLac'); 10758 $filter_flac->add_pattern ('*.flAc'); $filter_flac->add_pattern ('*.flaC'); 10759 $filter_flac->add_pattern ('*.FLac'); $filter_flac->add_pattern ('*.FlAc'); 10760 $filter_flac->add_pattern ('*.FlaC'); $filter_flac->add_pattern ('*.fLAc'); 10761 $filter_flac->add_pattern ('*.fLaC'); $filter_flac->add_pattern ('*.flAC'); 10762 $filter_flac->add_pattern ('*.FLAc'); $filter_flac->add_pattern ('*.FLaC'); 10763 $filter_flac->add_pattern ('*.FlAC'); $filter_flac->add_pattern ('*.fLAC'); 10764 10765 $file_dialog->add_filter ($filter_flac); 10766 10767 my $filter_wav = Gtk2::FileFilter->new; 10768 $filter_wav->set_name ('.wav'); # There are 2 ** 3 = 8 combinations 10769 $filter_wav->add_pattern ('*.wav'); $filter_wav->add_pattern ('*.WAV'); 10770 $filter_wav->add_pattern ('*.Wav'); $filter_wav->add_pattern ('*.waV'); 10771 $filter_wav->add_pattern ('*.wAv'); $filter_wav->add_pattern ('*.WAv'); 10772 $filter_wav->add_pattern ('*.WaV'); $filter_wav->add_pattern ('*.wAV'); 10773 $file_dialog->add_filter ($filter_wav); 10774 10775 ###----------------------- Filters -----------------------### 10776 my $current_folder = $entry_dir_input->get_text; # '$entry_dir_output->get_text' are in unicode reversible 10777 $current_folder = $home if not -d filename_from_unicode $current_folder; 10778 10779 $file_dialog->set_current_folder( filename_from_unicode $current_folder ); # to open at specific local 10780 10781 # Gtk2::FileChooserAction : 'select-folder', 'open', 10782 $file_dialog->set_action ('select-folder'); # directory selection only 10783 10784 $check_button_recursively = Gtk2::CheckButton->new ( $langs{name008} ); #16jun2008 10785 $check_button_recursively->set_active($recursively); 10786 $check_button_recursively->signal_connect( "clicked", sub { $recursively = $check_button_recursively->get_active? 1 : 0 ; } ); 10787 $tooltips->set_tip( $check_button_recursively, $langs{tip107} ) if $show_all_tooltips; 10788 $check_button_recursively->show; 10789 10790 # Create the label for "set_extra_widget". 10791 $label_pct = Gtk2::Label->new("0.0%"); 10792 $label_pct->show; 10793 10794 # Create the Gtk2::ProgressBar to read file info for "set_extra_widget". 10795 $progbar_files_info = Gtk2::ProgressBar->new; 10796 $progbar_files_info->set_text( $directory_base ); 10797 $progbar_files_info->set_orientation('left_to_right'); 10798 $progbar_files_info->show; 10799 10800 # Add $label_pct and $progbar_files_info into $vbox_extra_widget 10801 my $vbox_extra_widget = Gtk2::VBox->new( $false, 8 ); 10802 $vbox_extra_widget->add($check_button_recursively); 10803 $vbox_extra_widget->add($label_pct); 10804 $vbox_extra_widget->add($progbar_files_info); 10805 $vbox_extra_widget->show; 10806 10807 # Add $vbox_extra_widget into $file_dialog 10808 $file_dialog->set_extra_widget ($vbox_extra_widget); 10809 10810 $file_dialog->signal_connect( "selection-changed", sub { 10811 my $selected_dir = $file_dialog->get_filename; # '$file_dialog->get_filename' is in local encoding ?? 10812 eval { $selected_dir = filename_to_unicode $selected_dir; }; 10813 10814 $file_dialog->set_show_hidden ($false); 10815 # $file_dialog->set('use-preview-label' => $true ); 10816 10817 $entry_dir_input->set_text($selected_dir); 10818 $progbar_files_info->set_text( $selected_dir ); 10819 $tooltips->set_tip( $entry_dir_input, $selected_dir) if $show_all_tooltips; 10820 # print "\$selected_dir = $selected_dir\n"; 10821 }); 10822 10823 if ( $file_dialog->run eq 'ok' ) { 10824 10825 # $directory_base is used to find 'directory_ramain' with remove_directory_base() 10826 $directory_base = $file_dialog->get_filename; # '$file_dialog_output->get_filename' are in unicode reversible 10827 eval { $directory_base = filename_to_unicode $directory_base; }; # To remove Wide character 10828 10829 my $msg = ($check_button_recursively->get_active) ? $langs{msg086}: $langs{msg088}; 10830 insert_msg( "\n$msg: $directory_base\n\n" , "small"); 10831 10832 #print "\n dir_selection --> \$directory_base = $directory_base\n"; 10833 fill_with_all_informations($directory_base); 10834 }; 10835 $file_dialog->destroy; 10836} 10837 10838#####------------------------ final -------------------------##### 10839#####------------------- Directory Selection ----------------##### 10840 10841sub fill_with_all_informations { 10842 my $dir_path = shift; # directory 10843 10844 make_array_of_files($dir_path); # make an array of files with only supported extensions: *.mp3 , *.mp4*, *.mpc, *.ogg ... 10845 if (@array_of_files <= 0){ 10846 $tooltips->set_tip( $entry_f, $langs{msg063} ) if $show_all_tooltips; # entry at beginning 10847 return; 10848 } 10849 #for (@array_of_files) { print "$_\n"; } 10850 fill_treeview_files_to_be_played(); 10851 10852 $normalize_button->set_label("normalize"); 10853 change_font_for_all_child($window_font_name,$normalize_button); 10854} 10855 10856sub determine_directory_and_filename_and_extension { # filepath = (directory/)(filename) 10857 10858 my %args = ( @_, # argument pair list goes here 10859 ); 10860 my $row = $args{row}; 10861 my $filepath = defined $row ? $files_info[$row]{filepath} : $args{filepath} ; 10862 10863 return unless defined $filepath; 10864 10865 $filepath =~ s/\/{2,}/\//g; # change two or more '//' character for one '/' 10866 (my $filename = $filepath) =~ s/.*\/(.*)/$1/g; # (path/)(filename): copy and get the (filename) 10867 (my $dir = $filepath) =~ s/(.*\/).*/$1/g; # (path/)(filename): copy and get the (path/) 10868 $dir =~ s/(\/.+)\/{1,}$/$1/; # remove the '/' character from final, if it exists, unless '/'. 10869 10870 # determine the directory and file ;; see 'man File::Basename' and 'fileparse' 10871 10872 # determine the input/extension ;; example: $filename = 'Music.MP3' or 'Music.flac' 10873 10874 if ( $filename =~ /\.mp3$/i ){ $extension_input = 'mp3'; } # for files like: music.Mp3, music.MP3 or music.mP3 10875 elsif ( $filename =~ /\.(mp4|m4a|aac)$/i ){ $extension_input = 'mp4'; } 10876 elsif ( $filename =~ /\.(mpc|mpp|mp\+)$/i ){ $extension_input = 'mpc'; } # for files like: music.mpc, .mpp, MPC, MPp ... 10877 elsif ( $filename =~ /\.ogg$/i ){ $extension_input = 'ogg'; } # for files like: music.OGG, music.OgG or music.oGG or ... 10878 elsif ( $filename =~ /\.ape$/i ){ $extension_input = 'ape'; } 10879 elsif ( $filename =~ /\.flac$/i ){ $extension_input = 'flac'; } 10880 elsif ( $filename =~ /\.cda$/i ){ $extension_input = 'cda'; } 10881 elsif ( $filename =~ /\.wav$/i ){ $extension_input = 'wav' } 10882 else { $extension_input = 'other';} 10883 10884 # get all file extensions from original filename 10885 10886 (my $file_mp3 = $filename) =~ s/\.((.){3}|flac)$/.mp3/i; # to obtain the filename with appropriate extension_input 10887 (my $file_mp4 = $filename) =~ s/\.((.){3}|flac)$/.mp4/i; # '(.){3}' is the same as '...' 10888 (my $file_ogg = $filename) =~ s/\.((.){3}|flac)$/.ogg/i; 10889 (my $file_mpc = $filename) =~ s/\.(...|flac)$/.mpc/i; 10890 (my $file_ape = $filename) =~ s/\.(...|flac)$/.ape/i; 10891 (my $file_flac = $filename) =~ s/\.(...|flac)$/.flac/i; 10892 (my $file_cda = $filename) =~ s/\.(...|flac)$/.cda/i; 10893 (my $file_wav = $filename) =~ s/\.(...|flac)$/.wav/i; 10894 10895 # return to the real extension_input name; for that cases *.mP3, Mp3, ... 10896 if ( $extension_input eq 'mp3' ){ $file_mp3 = $filename; } 10897 elsif ( $extension_input eq 'mp4' ){ $file_mp4 = $filename; } 10898 elsif ( $extension_input eq 'mpc' ){ $file_mpc = $filename; } 10899 elsif ( $extension_input eq 'ogg' ){ $file_ogg = $filename; } # return to original extension_input 10900 elsif ( $extension_input eq 'ape' ){ $file_ape = $filename; } 10901 elsif ( $extension_input eq 'flac'){ $file_flac = $filename; } 10902 elsif ( $extension_input eq 'cda' ){ $file_cda = $filename; } 10903 elsif ( $extension_input eq 'wav' ){ $file_wav = $filename; } 10904 10905 $entry_f->set_text( $filename ); # refresh file to normalize 10906 $tooltips->set_tip( $entry_f, $filename) if $show_all_tooltips; 10907 $entry_dir_input->set_text( $dir ); 10908 $tooltips->set_tip( $entry_dir_input, "$dir") if $show_all_tooltips; 10909 10910 return ( row => $row, extension_input => $extension_input, 10911 filename => $filename, directory => $dir, 10912 filepath => $dir . '/' . $filename, 10913 10914 file_mp3 => $file_mp3, file_mp4 => $file_mp4, file_mpc => $file_mpc, 10915 file_ogg => $file_ogg, file_ape => $file_ape, file_flac => $file_flac, 10916 file_cda => $file_cda, file_wav => $file_wav, 10917 ); 10918} 10919 10920sub make_directory_final { # when normalizing recursively or not. 10921 my %args = ( @_ ); 10922 my $file_wav = $args{file_wav}; my $dir = $args{directory}; my $row = $args{row}; 10923 10924 $directory_final = "$directory_output/$files_info[$row]{directory_remain}"; # where all the files will be saved 10925 $directory_final =~ s/\/{2,}/\//g; # change the '//' character for '/' 10926 $directory_final =~ s/\/{1,}$//; # remove the '/' character from final if it exists. 10927 10928 if ( not -d filename_from_unicode $directory_final ){ 10929 my @cmd = ( 'mkdir', '-p', $directory_final ); 10930 insert_msg("\n@cmd\n" , "small"); #print on debug textview 10931 exec_cmd_system2(@cmd); 10932 } 10933 #print " make_directory_final --> directory = $dir \ndirectory_base = $directory_base\n"; 10934 #print " make_directory_final --> directory_remain = $args{directory_remain} \ndirectory_final = $directory_final\n\n"; 10935} 10936 10937sub refresh_input_output_arrows { # draw arrows 10938 10939 if ( $extension_input eq 'mp4' ){ draw_input_output($da_arrow_dec,undef,("mp4","wav")); } 10940 elsif ( $extension_input eq 'mpc' ){ draw_input_output($da_arrow_dec,undef,("mpc","wav")); } 10941 elsif ( $extension_input eq 'ogg' ){ draw_input_output($da_arrow_dec,undef,("ogg","wav")); } 10942 elsif ( $extension_input eq 'ape' ){ draw_input_output($da_arrow_dec,undef,("ape","wav")); } 10943 elsif ( $extension_input eq 'flac'){ draw_input_output($da_arrow_dec,undef,("flac","wav"));} 10944 elsif ( $extension_input eq 'wav' ){ draw_input_output($da_arrow_dec,undef,("wav","wav")); } 10945 elsif ( $extension_input eq 'cda' ){ draw_input_output($da_arrow_dec,undef,("cda","wav")); } 10946 else { draw_input_output($da_arrow_dec,undef,("mp3","wav")); } # default 10947 10948 if ( $extension_input eq 'mp3' or $extension_input eq 'mpc' or 10949 $extension_input eq 'ape' or $extension_input eq 'flac' or 10950 $extension_input eq 'wav' or ($extension_input eq 'ogg' and $vorbiscomment_path ne "") ) { 10951 10952 $status_bar->push($context_id, " $extension_input ".$langs{msg066} ); 10953 } 10954} 10955 10956####--------------------------------------------------#### 10957 10958sub set_extension_output { 10959 10960 if ($button_output_mp3->get_active) { $extension_output = 'mp3'; } 10961 if ($button_output_mp4->get_active) { $extension_output = 'mp4'; } 10962 if ($button_output_mpc->get_active) { $extension_output = 'mpc'; } 10963 if ($button_output_ogg->get_active) { $extension_output = 'ogg'; } 10964 if ($button_output_ape->get_active) { $extension_output = 'ape'; } 10965 if ($button_output_flac->get_active){ $extension_output = 'flac';} 10966 if ($button_output_wav->get_active) { $extension_output = 'wav'; } 10967 10968 encode_choice_sensitive(); 10969 10970 my $row = $files_info[0]{get_selection_row} || 0; 10971 my %hash = determine_directory_and_filename_and_extension(row => $row); 10972 set_output_and_refresh_progress_bar(%hash); 10973 #print "\$extension_output = $extension_output ; \$row = $row\n"; 10974} 10975 10976sub set_output_and_refresh_progress_bar { 10977 my %args = ( @_, # argument pair list goes here 10978 ); 10979 my $extension_input = $args{extension_input}; 10980 my $row = $args{row}; 10981 10982 return if ( not defined $extension_input or $extension_input eq 'other' ); 10983 10984 my $file_mp3 = $args{file_mp3}; my $file_mp4 = $args{file_mp4}; my $file_mpc = $args{file_mpc}; 10985 my $file_ogg = $args{file_ogg}; my $file_ape = $args{file_ape}; my $file_flac= $args{file_flac}; 10986 my $file_cda = $args{file_cda}; my $file_wav = $args{file_wav}; 10987 10988 $pbar->set_fraction(0); 10989 $pbar_n->set_fraction(0); 10990 $pbar_encode->set_fraction(0); 10991 10992 if ( $extension_input eq 'wav' ){ $pbar->set_text(" "); } 10993 else { $pbar->set_text(reduce_length_size($file_wav)); } 10994 10995 10996 $pbar_n->set_text(reduce_length_size($file_wav)); 10997 draw_input_output($da_arrow_enc,undef,("wav",$extension_output)); 10998 10999 if ($button_output_mp3->get_active) { 11000 $frame21->set_label("lame ".$langs{msg077}); 11001 ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_mp3); 11002 ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_mp3,\$encode_type{$extension_output}); # recover the last encode_type value 11003 $pbar_encode->set_text(reduce_length_size($file_mp3)); 11004 } 11005 if ($button_output_mp4->get_active) { 11006 $frame21->set_label("faac ".$langs{msg077}); 11007 ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_mp4); 11008 ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_mp4,\$encode_type{$extension_output}); 11009 $pbar_encode->set_text(reduce_length_size($file_mp4)); 11010 } 11011 if ($button_output_mpc->get_active) { 11012 $frame21->set_label("mppenc ".$langs{msg077}); 11013 ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_mpc); 11014 ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_mpc,\$encode_type{$extension_output}); 11015 $pbar_encode->set_text(reduce_length_size($file_mpc)); 11016 } 11017 if ($button_output_ogg->get_active) { 11018 $frame21->set_label("oggenc ".$langs{msg077}); 11019 ComboBox_set_popdown_strings($ComboBox_encode_type,@encode_type_ogg); 11020 ComboBox_select_this_text(\$ComboBox_encode_type,\@encode_type_ogg,\$encode_type{$extension_output}); 11021 $pbar_encode->set_text(reduce_length_size($file_ogg)); 11022 } 11023 if ($button_output_ape->get_active) { 11024 $frame21->set_label("ape ".$langs{msg077}); 11025 $pbar_encode->set_text(reduce_length_size($file_ape)); 11026 } 11027 if ($button_output_flac->get_active) { 11028 $frame21->set_label("flac ".$langs{msg077}); 11029 $pbar_encode->set_text(reduce_length_size($file_flac)); 11030 } 11031 if ($button_output_wav->get_active) { 11032 $frame21->set_label("wav ".$langs{msg077}); 11033 $pbar_encode->set_text(" "); 11034 } 11035 11036 $status_bar->push($context_id, " "); 11037} 11038 11039#####------------------------------------------##### 11040# calcule the space to be reduced to obtain a standard string'size 11041# we note that the char numbers are widthest than letters for Sans font type. 11042# substr string, pos, [n, replacement] 11043# Extracts and returns a substring n characters long, starting at character 11044# position pos, from a given string. 11045sub reduce_length_size{ 11046 my $string = shift; 11047 my $max_length = shift || 160; 11048 my $length = length( $string ); 11049 my $sub = $length - $max_length; 11050 #print("\n add = $add\n"); 11051 if ($sub < 0 ){$sub = 0 ;} 11052 $string = substr($string, $sub); # cut, remove $sub bytes 11053 #print("\n string = $string\n"); 11054 return $string; 11055} 11056 11057 11058#####-------------vetor-com-arquivos--------------##### 11059#####----- array of mp3, mp4, mpc, ... files -----##### 11060 11061sub eval_to_unicode { 11062 my $filepath_local = shift; 11063 my $filepath_unicode = undef; 11064 11065 #my $filepath = filename_from_unicode $filepath if( ! -e $filepath ); 11066 11067 eval { $filepath_unicode = filename_to_unicode $filepath_local; }; # All input data MUST be convertted to unicode reversible 11068 if ($@) { #$filepath_unicode = filename_display_name $filepath_local; # 'filename_display_name' convert to unicode not reversible! 11069 #$filepath_unicode = $filepath_local; # change nothing! 11070 warn "\nTry to read the file <$filepath_local>, maybe some Wide character: $!"; 11071 } 11072 return $filepath_unicode; 11073} 11074 11075sub eval_from_unicode { # not used 11076 my %args = ( row => undef, 11077 filepath => undef, 11078 @_, # argument pair list goes here 11079 ); 11080 my $row = $args{row}; my $filepath = $args{filepath}; 11081 11082 my $filepath_local = filename_from_unicode $filepath; # convert filename_from_unicode to local encoding 11083 if( ! -e $filepath_local ) { $filepath_local = $files_info[ $row ]{filepath_local}; } # get original filename encoding 11084 11085 return $filepath_local; 11086} 11087 11088# Find recursively all files. See <man perlfunc> and Recipe 9.7 from Perl Cookbook, 2nd Edition. 11089sub make_array_of_files { 11090 my $directories = shift; # $directories could be an array @directories 11091 # no warnings; 11092 my @all_filepath = (); 11093 11094 #print "\n make_array_of_files --> \$directories = $directories\n"; 11095 11096 # use File::Find; # see <man File::Find> 11097 # $File::Find::dir is the current directory name, 11098 # $_ is the current filename within that directory 11099 # $File::Find::name is the complete pathname to the file. 11100 # $File::Find::prune = 1; # prune to true to tell find not to descending into the directory. 11101 11102 find { 11103 #no_chdir => 1, # stops find from descending into directory during processing 11104 #bydepth => 1, # to visit all files beneath a directoty before the directory itself 11105 #no_chdir => $check_button_recursively->get_active ? $false : $true, 11106 11107 wanted => sub { 11108 my $filepath = $File::Find::name; 11109 11110 if ( $File::Find::dir ne $directories and not $check_button_recursively->get_active ){ return; } # not find recursively 11111 11112 if ( not -r $filepath ){ return; } # -r : File is readable by effective uid/gid. 11113 if ( -d $filepath ){ return; } # -d : File is a directory 11114 11115 push @all_filepath, eval_to_unicode($filepath); 11116 #push @all_filepath, $filepath; 11117 } 11118 } => filename_from_unicode $directories; # convert $directories from unicode to local encoding 11119 11120 # Directory Selection with some Filter 11121 my $filter; 11122 eval { $filter = $file_dialog->get_filter->get_name; }; 11123 if (defined $filter){ 11124 $filter = undef if ( $filter !~ /^\.(mp3|mp4|mpc|ogg|ape|flac|wav)$/i ); # 'All files' have undef filter 11125 } 11126 11127 @array_of_files = (); # empty , reset the array of files 11128 for (my $i = 0; $i <= $#all_filepath; $i++){ 11129 #print_local ("filename[$i] = $all_filepath[$i] \n"); 11130 #print "filter = $filter ; filename[$i] = $all_filepath[$i] \n"; 11131 my $file = $all_filepath[$i]; 11132 next unless defined $file; 11133 11134 if (defined $filter){ 11135 if ( $filter eq '.mp4' and $file =~ /\.(mp4|m4a|aac)$/i ){ push @array_of_files, $file; } 11136 elsif ( $filter eq '.mpc' and $file =~ /\.(mpc|mpp|mp\+)$/i ){ push @array_of_files, $file; } 11137 elsif ( $file =~ /$filter$/i ){ push @array_of_files, $file; } 11138 } 11139 #/i option: case-insensitive search ;; get all supported files 11140 elsif ( $file =~ /\.mp3$/i or $file =~ /\.ogg$/i or $file =~ /\.ape$/i or $file =~ /\.flac$/i or 11141 $file =~ /\.wav$/i or $file =~ /\.(mp4|m4a|aac)$/i or $file =~ /\.(mpc|mpp|mp\+)$/i ){ 11142 push @array_of_files, $file; 11143 } 11144 } 11145 11146 @array_of_files = sort_full_path_names(@array_of_files); 11147 11148 if ( @array_of_files <= 0 ){ # There is no supported file! 11149 insert_msg( "$langs{msg090}\n", "small-red"); 11150 $status_bar->push($context_id, $langs{msg090} ); 11151 return $false; 11152 } 11153 11154 if ( $check_button_recursively->get_active ){ 11155 insert_msg( "$langs{msg001}\n" , "small-black");} 11156 else { insert_msg( "$langs{msg002}\n" , "small-black");} 11157 11158 for (my $i=1;$i<=@array_of_files;$i++){ # @array_of_files is the size of array @array_of_files 11159 $i = sprintf ("%02d", $i); 11160 # print on debug textview 11161 insert_msg( "($i): $array_of_files[$i-1] \n", "small") if ($i % 2 == 1); # alternating colors 11162 insert_msg( "($i): $array_of_files[$i-1] \n", "purple") if ($i % 2 == 0); 11163 } 11164 insert_msg("-----*****-----\n" , "small-black"); 11165 11166 return @array_of_files; 11167} 11168 11169###----------- add files to treeview --------------### 11170###------------------- start ----------------------### 11171 11172# The selected file is always the first array element if supported 11173sub put_selected_file_to_first_position { # not used! 11174 my $file = shift; # selected_file 11175 11176 unless ( $file =~ /\.mp3$/i or $file =~ /\.ogg$/i or $file =~ /\.ape$/i or $file =~ /\.flac$/i or 11177 $file =~ /\.wav$/i or $file =~ /\.(mp4|m4a|aac)$/i or $file =~ /\.(mpc|mpp|mp\+)$/i ){ 11178 return; 11179 } 11180 # unshift ARRAY,LIST : "Prepends list to the front of the array, and returns the new number of elements in the array". 11181 unshift @array_of_files, $file; 11182} 11183 11184 11185sub fill_treeview_files_to_be_played { 11186 11187 #my $model = $treeview_play->get_model; #get the old model from Gtk2::TreeView 11188 #$model->clear; # clear the old model - see <man Gtk2::ListStore> 11189 11190 my $model = create_model_files_to_be_played(); # add new files to tree model 11191 11192 #print "\nfill_treeview_files_to_be_played --> 1 \n"; 11193 11194 $treeview_play->set_model($model); # add the new model 11195 count_artists_and_album_already_played(update_model_artist => $false, update_model_album => $false); 11196 add_columns( show_play => $true); # add columns to the treeview_play 11197 make_artist_and_album_treeview_column( make_artist_column => $true, make_album_column => $true, array_with_tracks => \@files_info ); 11198 11199 $button_unselec->set_sensitive($true); 11200 $button_selec->set_sensitive($true); 11201 $da->set_sensitive($true); 11202 @rows_already_played = (); 11203 11204 #get_selection_tree(); # select the first file and get info from file 11205 11206 return unless $playing_music; 11207 color_the_selected_tracks_and_scroll( select_color => 'playing' ); 11208} 11209 11210fill_treeview_files_to_be_played(); 11211 11212###------------------- final ----------------------### 11213###----------- add files to treeview --------------### 11214 11215sub sort_full_path_names{ 11216 my @array = @_; 11217 # For example: 11218 # $array[0] = '/tmp/teste/teste4/mus.mp3' 11219 # $array[1] = '/tmp/teste/teste2/teste4/mus.mp3' 11220 # $array[2] = '/tmp/mus.mp3' 11221 # First, sort this array in ascending order by number of '/' character. 11222 # Then, sort in case-insensitively mode. 11223 11224 # sort case-insensitively : @articles = sort {uc($a) cmp uc($b)} @files; (see man perlfunc) 11225 # multiple comparisons in the routine and separate them with ||. 11226 # See Perl Cookbook, 2nd Edition. Chap. 4.16; 10.18 for help; 11227 #my $teste = '/tmp/teste/teste2/teste4/mus.mp3'; $teste =~ s/[^\/]//g; print "teste = $teste\n"; # output: teste = ///// 11228 # first compare the number of directory character '/'. 11229 11230 sub compare_dir { 11231 (my $temp1 = $a) =~ s/[^\/]//g; # remove all character but '/' 11232 (my $temp2 = $b) =~ s/[^\/]//g; 11233 #if ( $temp1 eq $temp2 ){return $false;} # print "temp1 = $temp1 ;; temp2 = $temp2\n"; 11234 $temp1 cmp $temp2 # sort them in ascending order by number of '/' character. 11235 } 11236 @array = sort { compare_dir() || uc($a) cmp uc($b) } @array; 11237 return @array; 11238} 11239 11240#####----------- get and show mp3/mp4/ogg ... info --------##### 11241 11242sub get_info_from_file { 11243 my %args = ( show_tag => $true, 11244 @_, # argument pair list goes here 11245 ); 11246 my $extension_input = $args{extension_input}; 11247 my $filepath = $args{filepath}; 11248 my $row = $args{row}; 11249 return if ($extension_input eq 'other' or $extension_input eq 'cda'); 11250 11251 #print "get_info_from_file --> \$row = $row ;; \$extension_input = $extension_input ;; \$filepath = $filepath\n"; 11252 11253 #my $fh = encode("utf8",$file_mp3); 11254 #print ("fh = $fh\n"); 11255 #my $fh2 = decode("utf8",$fh); 11256 #print ("fh2 = $fh2\n"); 11257 11258 %metadata = (); # clear all tags and technical informations (metadata) 11259 11260 # set init value "" for all 8 tags 11261 $metadata{title} = ""; 11262 $metadata{artist} = ""; 11263 $metadata{album} = ""; 11264 $metadata{comment} = ""; 11265 $metadata{genre} = ""; 11266 $metadata{track} = ""; 11267 $metadata{total_track} = ""; 11268 $metadata{year} = ""; 11269 11270 # set init value for all 7 technical informations: 11271 $metadata{technical_info} = "MPEG"; 11272 $metadata{bitrate} = 160; 11273 $metadata{bitrate_nominal} = 160 if ( $extension_input eq 'ogg' ); 11274 $metadata{bitrate_average} = $true; 11275 $metadata{frequency} = 0; 11276 $metadata{mode} = ""; 11277 $metadata{length} = "" if ( $extension_input ne 'cda' ); 11278 $metadata{fileSize} = 0; 11279 11280 #------------------------mp3--------------------------# 11281 # Only show the mp3 info for a file whose extension_input is .mp3 11282 if ( $files_info[$row]{extension_input} eq 'mp3' ){ 11283 #read_ID3v1_mp3_tag($file_mp3); 11284 #$bitrate_average = read_Xing_mp3_tag($file_mp3); 11285 read_mp3_info_tag(%args); 11286 } 11287 #------------------------mp4--------------------------# 11288 # Only show the mp4 info for a file whose extension_input is .mp4 11289 elsif ( $files_info[$row]{extension_input} eq 'mp4' ){ 11290 get_mp4_info_from_file(%args); 11291 } 11292 #------------------------mpc--------------------------# 11293 # Only show the mpc info for a file whose extension_input is .mpc 11294 elsif ( $files_info[$row]{extension_input} eq 'mpc' ){ 11295 show_APE_tag(%args); 11296 show_mpc_info(%args); 11297 } 11298 #------------------------ogg--------------------------# 11299 # Only show the ogg info for a file whose extension_input is .ogg 11300 elsif ( $files_info[$row]{extension_input} eq 'ogg' ){ 11301 show_ogg_tag(%args); 11302 show_ogg_info(%args); 11303 #get_ogg_info_from_file(); 11304 } 11305 #------------------------ape--------------------------# 11306 # Only show the ape info for a file whose extension_input is .ape 11307 elsif ( $files_info[$row]{extension_input} eq 'ape' ){ 11308 show_APE_tag(%args); 11309 show_ape_info(%args); 11310 } 11311 #------------------------flac-------------------------# 11312 # Only show the flac info for a file whose extension_input is .flac 11313 elsif ( $files_info[$row]{extension_input} eq 'flac' ){ 11314 show_flac_info(%args); 11315 } 11316 #------------------------wav--------------------------# 11317 elsif ( $files_info[$row]{extension_input} eq 'wav' ){ 11318 show_APE_tag(%args); 11319 show_wav_info(%args); 11320 } 11321 11322 #---------- update the all info for one $row ---------# 11323 11324 # get all technical informations: 11325 $files_info[$row]{technical_info} = $metadata{technical_info}; 11326 $files_info[$row]{bitrate} = $metadata{bitrate}; # more precise value 11327 $files_info[$row]{bitrate_nominal} = $metadata{bitrate_nominal} if ( $extension_input eq 'ogg' ); 11328 $files_info[$row]{bitrate_average} = $metadata{bitrate_average}; 11329 $files_info[$row]{frequency} = $metadata{frequency}; 11330 $files_info[$row]{mode} = $metadata{mode}; 11331 $files_info[$row]{length} = $metadata{length} if ( $extension_input ne 'cda' ); 11332 #$files_info[$row]{cda_total_time} = $metadata{cda_total_time} if ( $extension_input eq 'cda' ); 11333 $files_info[$row]{fileSize} = $metadata{fileSize}; 11334 11335 # get the 8 tags 11336 $files_info[$row]{title} = $metadata{title}; 11337 $files_info[$row]{artist} = $metadata{artist}; 11338 $files_info[$row]{album} = $metadata{album}; 11339 $files_info[$row]{comment} = $metadata{comment}; 11340 $files_info[$row]{year} = $metadata{year}; 11341 $files_info[$row]{genre} = $metadata{genre}; 11342 $files_info[$row]{track} = $metadata{track}; # track = track_number 11343 $files_info[$row]{total_track} = $metadata{total_track}; 11344 11345 #print "\n get_info_from_file --> title = $files_info[$row]{title} ;; bitrate = $metadata{bitrate} ;; bitrate_average = $metadata{bitrate_average} ;; \$row = $row\n"; 11346 11347 set_tag_info($row) if $args{show_tag}; 11348 11349 # remove the decimals numbers: 146.5 --> 146 11350 $files_info[$row]{bitrate} = sprintf("%.0f", number_value( $metadata{bitrate} ) ); #Kbitrate 11351} 11352 11353sub set_tag_info { 11354 my $row = shift; 11355 return unless defined $row; 11356 11357 #print " set_tag_info -->1 row = $row ;; title = $files_info[$row]{title} ;; track = $files_info[$row]{track}\n"; 11358 11359 # Set all 7 technical informations on the tab entries: 11360 $frame31->set_label ( uc($files_info[$row]{extension_input}) . " Info" ); 11361 $label_mpeg->set_label ( $files_info[$row]{technical_info} ); 11362 $label_freq->set_label ( $files_info[$row]{frequency} ? "$langs{name041}: $files_info[$row]{frequency} Hz" : "$langs{name041}:" ); 11363 $label_mode->set_label ( ($files_info[$row]{extension_input} eq 'mp3' ? $langs{name031} : $langs{name043}) . ": $files_info[$row]{mode}" ); 11364 $label_time->set_label ( $files_info[$row]{extension_input} ne 'cda' ? "$langs{name042}: $files_info[$row]{length}" : "$langs{name042}: $files_info[$row]{length} ($files_info[$row]{cda_total_time})" ); 11365 $label_size->set_label ( $files_info[$row]{fileSize} ? "$langs{name048}: $files_info[$row]{fileSize} MB" : "$langs{name048}:" ); 11366 11367 if ( $files_info[$row]{extension_input} eq 'mp3' and $files_info[$row]{bitrate} ){ 11368 $label_kbps->set_label ( ($files_info[$row]{bitrate_average} ? 'Variable' : 'Constant') . "\nBitrate: $files_info[$row]{bitrate} Kb/s"); 11369 } 11370 elsif ( $files_info[$row]{extension_input} eq 'ogg' ){ 11371 $label_kbps->set_label ("Bitrate: $files_info[$row]{bitrate} Kb/s\nNominal : $files_info[$row]{bitrate_nominal} Kb/s"); 11372 } 11373 elsif ( $files_info[$row]{extension_input} eq 'cda' ){ 11374 $label_kbps->set_label ( $files_info[$row]{bitrate} ? "Bitrate: 1411.2 Kb/s" : "Bitrate:" ); 11375 } 11376 else { 11377 $label_kbps->set_label ( $files_info[$row]{bitrate} ? "Bitrate: $files_info[$row]{bitrate} Kb/s" : "Bitrate:" ); 11378 } 11379 11380 # To not execute the 'sub change_tag' 11381 $abandon_change_tag = $true; # if '$abandon_change_tag eq $true' then force to abandon the 'sub change_tag' 11382 11383 # Set all 8 tags on the tab entries: 11384 $entry_title->set_text( $files_info[$row]{title} ) if defined $files_info[$row]{title}; 11385 #$entry_title->set_text( filename_from_unicode $files_info[$row]{title} ) if defined $files_info[$row]{title}; 11386 $entry_artist->set_text( $files_info[$row]{artist} ) if defined $files_info[$row]{artist}; 11387 $entry_album->set_text( $files_info[$row]{album} ) if defined $files_info[$row]{album}; 11388 $entry_year->set_text( $files_info[$row]{year} ) if defined $files_info[$row]{year}; 11389 $entry_tn->set_text( $files_info[$row]{track} ) if defined $files_info[$row]{track}; 11390 $entry_tt->set_text( $files_info[$row]{total_track} ) if defined $files_info[$row]{total_track}; 11391 $entry_comment->set_text( $files_info[$row]{comment} ) if defined $files_info[$row]{comment}; 11392 $ComboBoxEntry_genre->child->set_text( $files_info[$row]{genre} ) if defined $files_info[$row]{genre}; 11393 11394 $abandon_change_tag = $false; # if '$abandon_change_tag eq $true' then force to abandon the 'sub change_tag' 11395 11396 #print " set_tag_info -->2 row = $row ;; title = $files_info[$row]{title} ;; track = $files_info[$row]{track}\n"; 11397 $button_save_tag->set_sensitive($false); 11398} 11399 11400# Perl in a Nutshell - OReilly - By Ellen Siever, Stephen Spainhour & Nathan Patwardhan 11401# See too: <man perlfunc> 11402 11403 # read (filehandle, $var, length [,offset]); 11404 # "Attempts to read length bytes of data into variable $var from the specified filehandle. 11405 # The offset, if specified, says where in the variable $var to start putting bytes, 11406 # so that you can do a read into the middle of a string." 11407 11408 # unpack ("template", string); 11409 # "Takes a string representing a data structure and expands it into a list value, 11410 # returning the list value. (unpack does the reverse of pack.) In a scalar context, 11411 # it can be used to unpack a single value. The template ... specifies the order and 11412 # type of the values to be unpacked. " 11413 11414 # pack ("template", list); 11415 # "Takes a list of values and packs it into a binary structure, returning the string 11416 # containing the structure. The template is a sequence of characters that give the 11417 # order and type of values, as follows: 11418 # C : An unsigned char value 11419 # x : A null byte 11420 # Each character may optionally be followed by a number that gives a repeat count. 11421 # Field specifiers may be separated by whitespace, which will be ignored." 11422 11423 # This i a example of content of mp3 file: 11424 # ID3 11425 # 11426 # 11427 # 11428 11429 # GripTYER 11430 # 11431 11432 11433sub show_mpc_info { 11434 my %args = ( @_ ); 11435 my $extension_input = $args{extension_input}; my $filepath = $args{filepath}; my $row = $args{row}; 11436 return unless $extension_input eq 'mpc'; 11437 11438 my $header; 11439 my $Streamversion; 11440 my $buffer; 11441 11442 use constant MPCHEADERFLAG => 'MP+'; 11443 11444 my @profileNames = ( 11445 'na', "Unstable/Experimental", 'na', 'na', 11446 'na', "below Telephone", "below Telephone", "Telephone", 11447 "Thumb", "Radio", "Standard", "Xtreme", 11448 "Insane", "BrainDead", "above BrainDead", "above BrainDead" 11449 ); 11450 11451 my @samplFreq = qw(44100 48000 37800 32000); 11452 11453 open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 11454 11455 binmode IN; 11456 $fileSize = -s filename_from_unicode $filepath; 11457 11458 # Read musepack header. 11459 read (IN, $header, 3); # 3 byte for 'MP+' 11460 11461 if ($header ne MPCHEADERFLAG) { return $false; } 11462 11463 # read one byte 11464 read IN, $Streamversion, 1; 11465 $Streamversion = unpack "C", $Streamversion; 11466 #print "Streamversion = $Streamversion\n"; 11467 if ( $Streamversion < 7 ){ return; } # Musepack SV version supported 11468 11469 # read 4 byte 11470 read IN, $buffer, 4; 11471 my $frame_count = unpack "L", $buffer; 11472 # print "frame_count = $frame_count\n"; 11473 11474 read IN, $buffer, 4; # for Stream Flags ;; 4 bytes = 4 * 8 bits = 32 bits 11475 11476 my $StreamFlags = reverse unpack "b32", $buffer; # 'b' : A bit string (ascending bit order inside each byte) 11477 #print "StreamFlags = $StreamFlags\n"; 11478 11479 my $profile = bin2dec(substr($StreamFlags, 8, 4)); # get the profile number 11480 #print "profile = $profile ;; bin = ",substr($StreamFlags, 8, 4),"\n"; 11481 $Frequency = $samplFreq[bin2dec(substr($StreamFlags, 14, 2))]; 11482 11483 read IN, $buffer, 12; 11484 11485 $buffer = unpack "L", substr($buffer,8); # remove 8 byte, remain 4 byte 11486 $buffer = sprintf( "%032b", $buffer ); # convert $StreamFlags to binary base with 32 digits 11487 11488 my $lastValidSamples = bin2dec(substr($buffer, 1, 11)); 11489 #print "profile = $profile ;; samplFreq = $Frequency ;; lastValidSamples = $lastValidSamples \n"; 11490 11491 my $totalSamples = ($frame_count - 1)*32*36 + $lastValidSamples; 11492 my $totalSeconds = $totalSamples/$Frequency; 11493 11494 my $bitrate = 8 * $fileSize / $totalSeconds; # 8*$filesize = size in bit 11495 11496 $totalSeconds = sprintf("%.0f",$totalSeconds); 11497 # convert x seconds to hour:min:sec format 11498 my ($hour,$min,$sec) = sec_to_time($totalSeconds); # return ($hour,$min,$sec); 11499 11500 #print "bitrate = $bitrate ;; time = $hour:$min:$sec ;; totalSeconds = $totalSeconds\n"; 11501 11502 close(IN); 11503 11504 # if $bitrate > 500 kp/s 11505 if ($bitrate> 500000){$profile = 15;} # correct the bug of mppenc whem q = 10.0 11506 $profile = $profileNames[$profile]; 11507 11508 $Streamversion = sprintf("%0.1f",$Streamversion); 11509 $Technical_Info = "Stream: v$Streamversion\nProfile: '$profile'"; 11510 $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ; 11511 $bitrate_original = sprintf("%0.1f",$bitrate/1000); 11512 $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes 11513 $Frequency = sprintf("%.0f",$Frequency); 11514 11515 11516 $encode = 'average'; 11517 $bitrate_average = $true; 11518 $mode_channel = 2; 11519 11520 # get all technical informations: 11521 $metadata{technical_info} = $Technical_Info; 11522 $metadata{bitrate} = $bitrate_original; 11523 $metadata{bitrate_nominal} = 160; # only for ogg 11524 $metadata{bitrate_average} = $bitrate_average; # $true or $false 11525 $metadata{frequency} = $Frequency; 11526 $metadata{mode} = $mode_channel; 11527 $metadata{length} = $Time_Min_Sec if ( $extension_input ne 'cda' ); 11528 $metadata{fileSize} = $fileSize; 11529 11530 11531 # SV 7.0 Header - Item Size ( 1 byte = 8 bit ) 11532 # Preample 3 bytes 'MP+' 11533 11534 # Streamversion 1 byte 11535 11536 # StreamMinorVersion 4 bits 11537 # StreamMajorVersion 4 bits 11538 # sum = 8 bits = 1 byte 11539 # FrameCount 4 bytes 11540 11541 # Stream Flags 4 bytes 11542 11543 # IntensityStereo 1 bit 11544 # MidSideStereo 1 bit 11545 # MaxBand 6 bits 11546 # Profile 4 bits 11547 # Link 2 bits 11548 # SampleFreq 2 bits 11549 # MaxLevel 16 bits 11550 # sum = 32 bits = 4 bytes 11551 # TitleGain 2 bytes 11552 # TitlePeak 2 bytes 11553 # AlbumGain 2 bytes 11554 # AlbumPeak 2 bytes 11555 # 11556 # TrueGapless 1 bit 11557 # LastFrameLength 11 bits 11558 # ... 11559 11560 # tell Returns the current position in bytes for FILEHANDLE, 11561 # sysread FILEHANDLE,SCALAR,LENGTH,OFFSET ;; Returns the number of bytes actually read 11562 # syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET 11563 # substr EXPR,OFFSET,LENGTH,REPLACEMENT ;; Extracts a substring out of EXPR and returns it. 11564} 11565 11566sub show_ape_info { 11567 my %args = ( @_ ); 11568 my $extension_input = $args{extension_input}; my $filepath = $args{filepath}; my $row = $args{row}; 11569 return unless $extension_input eq 'ape'; 11570 11571 my $header; 11572 my $buffer; 11573 11574 my $CompressionLevel; my $Channels; my $HeaderBytes; 11575 my $TerminatingBytes; my $TotalFrames; my $FinalFrameBlocks; 11576 my $BlocksPerFrame; my $BitsPerSample; 11577 11578 use constant APEHEADERFLAG => 'MAC '; 11579 11580 use constant COMPRESSION_LEVEL_FAST => '1000'; 11581 use constant COMPRESSION_LEVEL_NORMAL => '2000'; 11582 use constant COMPRESSION_LEVEL_HIGH => '3000'; 11583 use constant COMPRESSION_LEVEL_EXTRA_HIGH => '4000'; 11584 use constant COMPRESSION_LEVEL_INSANE_HIGH => '5000'; 11585 use constant COMPRESSION_LEVEL_BRAINDEAD_HIGH => '6000'; 11586 11587 my @CompLevel = ( 'n', 'Fast', 'Normal', 'High', 'Extra High', 11588 'Insane', 'BrainDead' ); 11589 11590 open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 11591 11592 binmode IN; 11593 $fileSize = -s filename_from_unicode $filepath; 11594 #print "fileSize = $fileSize bytes\n"; 11595 11596 # Read ape header. 11597 read (IN, $header, 4); # 4 byte for 'MAC ' 11598 11599 if ($header ne APEHEADERFLAG) { return $false; } 11600 11601 read IN, my $version, 2; # 2 byte for version 11602 $version = unpack "S", $version; 11603 $version = sprintf( "%.2f", $version/1000 ); 11604 $version = number_value($version); 11605 #print "version = $version\n"; 11606 11607 if ( $version < 3.98 ) { # old header format for APE 11608 11609 read IN, $CompressionLevel, 2; # 2 byte for CompressionLevel 11610 $CompressionLevel = unpack "S", $CompressionLevel; 11611 #print "CompressionLevel = $CompressionLevel\n"; 11612 11613 read IN, $Channels, 4; # 2 byte = 16 bits, for Channels 11614 $Channels = unpack "S", substr($Channels, 2, 2); # don't read flags not used 11615 #print "Channels = $Channels\n"; 11616 11617 read IN, $Frequency, 4; # 4 byte for SampleRate 11618 $Frequency = unpack "L", $Frequency; 11619 #print "Samples per second(Frequency):= $Frequency\n"; 11620 11621 read IN, $HeaderBytes, 4; # 4 byte for HeaderBytes 11622 $HeaderBytes = unpack "L", $HeaderBytes; 11623 #print "HeaderBytes = $HeaderBytes\n"; 11624 11625 read IN, $TerminatingBytes, 4; # 4 byte for TerminatingBytes 11626 $TerminatingBytes = unpack "L", $TerminatingBytes; 11627 #print "TerminatingBytes = $TerminatingBytes\n"; 11628 11629 read IN, $TotalFrames, 4; # 4 byte for TotalFrames 11630 $TotalFrames = unpack "L", $TotalFrames; 11631 #print "TotalFrames = $TotalFrames\n"; 11632 11633 read IN, $FinalFrameBlocks, 4; # 4 byte for FinalFrameBlocks 11634 $FinalFrameBlocks = unpack "L", $FinalFrameBlocks; 11635 #print "FinalFrameBlocks = $FinalFrameBlocks\n"; 11636 11637 } 11638 11639 $BlocksPerFrame = (($version >= 3.90) || (($version >= 3.80) && ($CompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH))) ? 0x12000 : 0x02400; 11640 if ($version >= 3.95){$BlocksPerFrame = 0x48000; } # 0x48000 (hex) = 294912 (decimal) 11641 11642 if ( $version >= 3.98 ) { # current header format for APE files 11643 11644 # 8 bytes = 4 bytes for 'MAC ' + 4 bytes for version 11645 #$APE_DESCRIPTOR, 44; # 4*7 + 16 (MD5) = 44 bytes 11646 # total = 52 bytes = 8 + 44 11647 seek(IN, 8 + 4, 0); 11648 11649 read IN, $HeaderBytes, 4; # 4 byte for HeaderBytes 11650 $HeaderBytes = unpack "L", $HeaderBytes; 11651 #print "HeaderBytes = $HeaderBytes\n"; 11652 11653 # total = 52 bytes = 8 + 44 11654 seek(IN, 52, 0); 11655 11656 read IN, $CompressionLevel, 2; # 2 byte for CompressionLevel 11657 $CompressionLevel = unpack "S", $CompressionLevel; 11658 #print "CompressionLevel = $CompressionLevel\n"; 11659 11660 read IN, my $FormatFlags, 2; # 2 byte for FormatFlags (not used) 11661 11662 read IN, $BlocksPerFrame, 4; # 4 byte for BlocksPerFrame 11663 $BlocksPerFrame = unpack "L", $BlocksPerFrame; 11664 #print "BlocksPerFrame = $BlocksPerFrame\n"; 11665 11666 read IN, $FinalFrameBlocks, 4; 11667 $FinalFrameBlocks = unpack "L", $FinalFrameBlocks; 11668 #print "FinalFrameBlocks = $FinalFrameBlocks\n"; 11669 11670 read IN, $TotalFrames, 4; 11671 $TotalFrames = unpack "L", $TotalFrames; 11672 #print "TotalFrames = $TotalFrames\n"; 11673 11674 read IN, $BitsPerSample, 2; # 2 byte for BitsPerSample 11675 $BitsPerSample = unpack "S", $BitsPerSample; 11676 #print "BitsPerSample = $BitsPerSample\n"; 11677 11678 read IN, $Channels, 2; # 2 byte for Channels 11679 $Channels = unpack "S", $Channels; 11680 #print "Channels = $Channels\n"; 11681 11682 read IN, $Frequency, 4; # 4 byte for SampleRate 11683 $Frequency = unpack "L", $Frequency; 11684 #print "Samples per second(Frequency):= $Frequency\n"; 11685 11686 } 11687 11688 close(IN); 11689 11690 # from src/MACLib/APEHeader.cpp ;; Total Samples = $TotalBlocks 11691 my $TotalBlocks = ($TotalFrames == 0) ? 0 : ($TotalFrames - 1) * $BlocksPerFrame + $FinalFrameBlocks ; 11692 my $totalSeconds = $TotalBlocks/$Frequency; 11693 11694 my $bitrate = ($totalSeconds <= 0) ? 0 : ($fileSize - $HeaderBytes) * 8 / $totalSeconds; # 8*$filesize = size in bit 11695 $bitrate = sprintf("%.1f",$bitrate/1000); 11696 11697 $totalSeconds = sprintf("%.0f",$totalSeconds); 11698 # convert x seconds to hour:min:sec format 11699 my ($hour,$min,$sec) = sec_to_time($totalSeconds); # return ($hour,$min,$sec); 11700 11701 #print "Kbitrate = $bitrate ;; time = $hour:$min:$sec ;; totalSeconds = $totalSeconds\n"; 11702 11703 $Frequency = sprintf("%.0f", $Frequency ); 11704 #my $Compression_ratio = sprintf("%.0f", ($bitrate/1411.2) * 100 ); # approximate value 11705 $Technical_Info = "MAC version: $version\nComp: " . $CompLevel[$CompressionLevel/1000] ; # . "\nCompression:~ $Compression_ratio%"; 11706 $mode_channel = $Channels; 11707 $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ; 11708 $bitrate_original = $bitrate; 11709 $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes 11710 11711 11712 $encode = 'average'; 11713 $bitrate_average = $true; 11714 11715 # get all technical informations: 11716 $metadata{technical_info} = $Technical_Info; 11717 $metadata{bitrate} = $bitrate_original; 11718 $metadata{bitrate_nominal} = 160; # only for ogg 11719 $metadata{bitrate_average} = $bitrate_average; # $true or $false 11720 $metadata{frequency} = $Frequency; 11721 $metadata{mode} = $mode_channel; 11722 $metadata{length} = $Time_Min_Sec if ( $extension_input ne 'cda' ); 11723 $metadata{fileSize} = $fileSize; 11724 11725 #----------------------------OLD APE files-----------------------------# 11726 11727 # APE header structure for old APE files (version <= 3.97) : APEHeader.h and APEHeader.cpp 11728 11729 # APE Header - Item Size ( 1 byte = 8 bits ) - Type - Total 32 bytes - see <man perlfunc> 11730 # Preample 4 bytes 'MAC ' char c 11731 # version 2 bytes 'S' unsigned int16 # version number * 1000 (3.81 = 3810) 11732 # CompressionLevel 2 bytes int16 11733 # FormatFlags 2 bytes int16 # any format flags (for future use) 11734 # Channels 2 bytes int16 # the number of channels (1 or 2) 11735 # SampleRate 4 bytes 'L' unsigned int32 # the sample rate (typically 44100) 11736 # HeaderBytes 4 bytes int32 # the bytes after the MAC header that compose the WAV header 11737 # TerminatingBytes 4 bytes int32 # the bytes after that raw data (for extended info) 11738 # TotalFrames 4 bytes int32 # the number of frames in the file 11739 # FinalFrameBlocks 4 bytes int32 # the number of samples in the final frame 11740 11741 11742 #----------------------------NEW APE files-----------------------------# 11743 11744 # APE header structure for new APE files (version >= 3.98) : from src/MACLib/MACLib.h 11745 11746 #JUNK - any amount of "junk" before the APE_DESCRIPTOR (so people that put ID3v2 tags on the files aren't hosed) 11747 #APE_DESCRIPTOR - defines the sizes (and offsets) of all the pieces, as well as the MD5 checksum 11748 #APE_HEADER - describes all of the necessary information about the APE file 11749 11750 #APE_DESCRIPTOR structure (file header that describes lengths, offsets, etc.) 11751 # char cID[4]; // should equal 'MAC ' 11752 # uint16 nVersion; // version number * 1000 (3.81 = 3810) 11753 # uint32 nDescriptorBytes; // the number of descriptor bytes (allows later expansion of this header) 11754 # uint32 nHeaderBytes; // the number of header APE_HEADER bytes 11755 # uint32 nSeekTableBytes; // the number of bytes of the seek table 11756 # uint32 nHeaderDataBytes; // the number of header data bytes (from original file) 11757 # uint32 nAPEFrameDataBytes; // the number of bytes of APE frame data 11758 # uint32 nAPEFrameDataBytesHigh; // the high order number of APE frame data bytes 11759 # uint32 nTerminatingDataBytes; // the terminating data of the file (not including tag data) 11760 # uint8 cFileMD5[16]; // the MD5 hash of the file (see notes for usage... it's a littly tricky) 11761 11762 #APE_HEADER structure (describes the format, duration, etc. of the APE file) 11763 # uint16 nCompressionLevel; // the compression level (see defines I.E. COMPRESSION_LEVEL_FAST) 11764 # uint16 nFormatFlags; // any format flags (for future use) 11765 # uint32 nBlocksPerFrame; // the number of audio blocks in one frame 11766 # uint32 nFinalFrameBlocks; // the number of audio blocks in the final frame 11767 # uint32 nTotalFrames; // the total number of frames 11768 # uint16 nBitsPerSample; // the bits per sample (typically 16) 11769 # uint16 nChannels; // the number of channels (1 or 2) 11770 # uint32 nSampleRate; // the sample rate (typically 44100) 11771 11772 11773 #-------------------------------INFO----------------------------------# 11774 11775 # fill the APE info structure (see APE_3.96b8_Source.tar.bz2 : Monkey/Source/MACLib/APEInfo.cpp) 11776 #m_APEFileInfo.nBlocksPerFrame = ((APEHeader.nVersion >= 3900) || ((APEHeader.nVersion >= 3800) && (APEHeader.nCompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH))) ? 0x12000 : 0x02400; 11777 # if ((APEHeader.nVersion >= 3950)) m_APEFileInfo.nBlocksPerFrame = 0x48000; 11778 #m_APEFileInfo.nBitsPerSample = (m_APEFileInfo.nFormatFlags & MAC_FORMAT_FLAG_8_BIT) ? 8 : ((m_APEFileInfo.nFormatFlags & MAC_FORMAT_FLAG_24_BIT) ? 24 : 16); 11779 #m_APEFileInfo.nBytesPerSample = m_APEFileInfo.nBitsPerSample / 8; 11780 #m_APEFileInfo.nBlockAlign = m_APEFileInfo.nBytesPerSample * m_APEFileInfo.nChannels; 11781 #m_APEFileInfo.nTotalBlocks = (APEHeader.nTotalFrames == 0) ? 0 : ((APEHeader.nTotalFrames - 1) * m_APEFileInfo.nBlocksPerFrame) + APEHeader.nFinalFrameBlocks; 11782 #m_APEFileInfo.nWAVHeaderBytes = (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER) ? sizeof(WAVE_HEADER) : APEHeader.nHeaderBytes; 11783 #m_APEFileInfo.nWAVTerminatingBytes = int(APEHeader.nTerminatingBytes); 11784 #m_APEFileInfo.nWAVDataBytes = m_APEFileInfo.nTotalBlocks * m_APEFileInfo.nBlockAlign; 11785 #m_APEFileInfo.nWAVTotalBytes = m_APEFileInfo.nWAVDataBytes + m_APEFileInfo.nWAVHeaderBytes + m_APEFileInfo.nWAVTerminatingBytes; 11786 #m_APEFileInfo.nLengthMS = int((double(m_APEFileInfo.nTotalBlocks) * double(1000)) / double(m_APEFileInfo.nSampleRate)); 11787 #m_APEFileInfo.nAverageBitrate = (m_APEFileInfo.nLengthMS <= 0) ? 0 : int((double(m_APEFileInfo.nAPETotalBytes) * double(8)) / double(m_APEFileInfo.nLengthMS)); 11788 #m_APEFileInfo.nDecompressedBitrate = (m_APEFileInfo.nBlockAlign * m_APEFileInfo.nSampleRate * 8) / 1000; 11789} 11790 11791 11792sub show_flac_info { 11793 my %args = ( @_ ); 11794 my $extension_input = $args{extension_input}; my $filepath = $args{filepath}; my $row = $args{row}; 11795 return unless $extension_input eq 'flac'; 11796 11797 my $header; 11798 my $buffer; 11799 11800 use constant FLACHEADERFLAG => 'fLaC'; # FLAC__STREAM_SYNC_STRING 11801 11802 my @block_type = ( 'STREAMINFO', 'PADDING', 'APPLICATION', 'SEEKTABLE', 11803 'VORBIS_COMMENT', 'CUESHEET', 'reserved' ); 11804 11805 open(IN, filename_from_unicode $filepath ) or die "Can't open <$filepath>: $!, stopped"; 11806 11807 binmode IN; 11808 $fileSize = -s filename_from_unicode $filepath; 11809 11810 # Read flac header. 11811 read (IN, $header, 4); # 4 byte for 'fLaC' 11812 11813 if ($header ne FLACHEADERFLAG) { return $false; } 11814 11815 # METADATA_BLOCK_HEADER (4 bytes) 11816 # A block header that specifies the type and size of the metadata block data. 11817 11818 #-------------------------------------------------# 11819 my $vorbis_comment; 11820 my $flag = 0; 11821 my $it = 0; # to avoid infinite loop 11822 11823 while ( $flag == 0 and $it < 9 ) # Search for vorbis_comment 11824 { 11825 # METADATA_BLOCK_HEADER (4 bytes) 11826 # A block header that specifies the type and size of the metadata block data. 11827 read IN, $buffer, 4; # 4 byte (=32 bits) 11828 $buffer = unpack "B32", $buffer; 11829 $flag = bin2dec(substr($buffer, 0, 1)); # flag: = 1 if last metadata, 0 otherwise 11830 $buffer = substr($buffer, 1); # remove the first 1 bit 11831 #print "flag = $flag\n"; 11832 11833 my $b_type = bin2dec(substr($buffer, 0, 7)); 11834 $buffer = substr($buffer, 7); # remove the first 7 bits, remain 24 bits 11835 #print "block_type = $block_type[$b_type]\n"; 11836 11837 my $block_size = bin2dec($buffer); 11838 #print "block_size = $block_size bytes\n"; 11839 11840 # METADATA_BLOCK PADDING or APPLICATION or SEEKTABLE or VORBIS_COMMENT 11841 read IN, $buffer, $block_size; # read $block_size bytes to buffer 11842 11843 if ( $block_type[$b_type] eq 'VORBIS_COMMENT' ){ 11844 $vorbis_comment = $buffer; 11845 #print "vorbis = $buffer\n"; 11846 read_vorbis_comment_tag($vorbis_comment,$extension_input); 11847 } 11848 $it = $it +1; 11849 } 11850 #-------------------------------------------------# 11851 11852 # 8 bytes = 4 bytes for ''fLaC' + 4 bytes for first block_header 11853 seek(IN, 4 + 4, 0); 11854 11855 # METADATA_BLOCK_STREAMINFO (34 bytes) 11856 # b A bit string (ascending bit order inside each byte, like vec()). 11857 # B A bit string (descending bit order inside each byte). - see <man perlfunc> 11858 11859 read IN, my $min_blocksize, 2; # 2 bytes = 16 bits for min_blocksize 11860 $min_blocksize = bin2dec(unpack "B16", $min_blocksize); 11861 #print "min_blocksize = $min_blocksize\n"; 11862 11863 read IN, my $max_blocksize, 2; # 2 bytes for max_blocksize 11864 $max_blocksize = bin2dec(unpack "B16", $max_blocksize); 11865 #print "max_blocksize = $max_blocksize\n"; 11866 11867 read IN, my $min_framesize, 3; # 3 bytes = 24 bits for min_framesize 11868 $min_framesize = unpack "B24", $min_framesize; 11869 $min_framesize = bin2dec($min_framesize); 11870 #print "min_framesize = $min_framesize\n"; 11871 11872 read IN, my $max_framesize, 3; # 3 bytes = 24 bits for max_framesize 11873 $max_framesize = unpack "B24", $max_framesize; 11874 $max_framesize = bin2dec($max_framesize); 11875 #print "max_framesize = $max_framesize\n"; 11876 11877 read IN, $buffer, 8; # 8 bytes = (20+3+5+36) bits = 64 bits 11878 $buffer = unpack "B64", $buffer; 11879 $Frequency = bin2dec(substr($buffer, 0, 20)); #SampleRate frequency 11880 $buffer = substr($buffer, 20); # remove the first 20 bits 11881 #print "sample_rate = $Frequency\n"; 11882 11883 my $Channels = 1 + bin2dec(substr($buffer, 0, 3)); 11884 $buffer = substr($buffer, 3); # remove the first 3 bits 11885 #print "Channels = $Channels\n"; 11886 11887 my $bits_per_sample = 1 + bin2dec(substr($buffer, 0, 5)); 11888 $buffer = substr($buffer, 5); # remove the first 5 bits 11889 #print "bits_per_sample = $bits_per_sample\n"; 11890 11891 my $Total_samples = bin2dec(substr($buffer, 0, 36)); 11892 #print "Total_samples = $Total_samples\n"; 11893 11894 read IN, $buffer, 16; # 16 bytes for MD5 signature 11895 11896 close(IN); 11897 11898 my $totalSeconds = $Total_samples/$Frequency; 11899 my $bitrate = ($totalSeconds <= 0) ? 0 : $fileSize * 8 / $totalSeconds; 11900 $bitrate = sprintf("%.1f",$bitrate/1000); 11901 my $Compression_ratio = 100 * $fileSize / ($bits_per_sample / 8 * $Channels * $Total_samples); 11902 $Compression_ratio = sprintf("%.2f",$Compression_ratio); 11903 11904 $totalSeconds = sprintf("%0.0f",$totalSeconds); 11905 # convert x seconds to hour:min:sec format 11906 my ($hour,$min,$sec) = sec_to_time($totalSeconds); # return ($hour,$min,$sec); 11907 11908 #print "bitrate = $bitrate ;; time = $hour:$min:$sec ;; totalSeconds = $totalSeconds\n"; 11909 #print "Compression_ratio = $Compression_ratio\n"; 11910 11911 $Frequency = sprintf("%.0f", $Frequency ); 11912 $Technical_Info = "Compression: $Compression_ratio%"; 11913 $mode_channel = $Channels; 11914 $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ; 11915 $bitrate_original = $bitrate; 11916 $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes 11917 11918 $encode = 'average'; 11919 $bitrate_average = $true; 11920 11921 # get all technical informations: 11922 $metadata{technical_info} = $Technical_Info; 11923 $metadata{bitrate} = $bitrate_original; 11924 $metadata{bitrate_nominal} = 160; # only for ogg 11925 $metadata{bitrate_average} = $bitrate_average; # $true or $false 11926 $metadata{frequency} = $Frequency; 11927 $metadata{mode} = $mode_channel; 11928 $metadata{length} = $Time_Min_Sec if ( $extension_input ne 'cda' ); 11929 $metadata{fileSize} = $fileSize; 11930 11931 11932# See flac-1.1.2/doc/html/format.html#metadata_block_streaminfo 11933 11934# FLAC Header - Size ( 1 byte = 8 bits ) - Type - Total 4 bytes 11935 # Preample 4 bytes 'fLaC char c 11936 11937# METADATA_BLOCK_HEADER Size Type - Total 4 bytes 11938 # Flags (1 byte) 11939 # 1 bit #'1' if this block is the last metadata block before the audio blocks, '0' otherwise. 11940 # + 7 bits # 0 : STREAMINFO ;; 1 : PADDING ;; 2 : APPLICATION ;; 3 : SEEKTABLE ;; 4 : VORBIS_COMMENT 11941 # = 8 bits = 1 byte B8 11942 # Length 3 bytes B24 # Length (in bytes) of metadata to follow (does not include the size of the METADATA_BLOCK_HEADER) 11943 11944# METADATA_BLOCK_STREAMINFO Size Type - Total 34 bytes 11945 11946 # min_blocksize 2 bytes B16 # The minimum block size (in samples) used in the stream. 11947 # min_blocksize 2 bytes B16 # (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream. 11948 # 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. 11949 # max_framesize 3 bytes B24 11950 # 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. 11951 # Channels 3 bits B3 # (number of channels) - 1. FLAC supports from 1 to 8 channels 11952 # 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. 11953 # 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. 11954 # MD5 signature 16 bytes 11955 11956## NOTES: FLAC specifies a minimum block size of 16 and a maximum block size of 65535, meaning 11957## the bit patterns corresponding to the numbers 0-15 in the minimum blocksize and maximum blocksize fields are invalid. 11958 11959} 11960 11961sub read_vorbis_comment_tag { # to 'ogg' and 'flac' files 11962 my ($vorbis_comment, $extension_input) = @_; 11963 11964 my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 11965 my $Total_Track = ""; my $Genre=""; 11966 11967 # field_name = field_value, field_value_length 11968 11969 # from vorbis-tools-1.1.1/ogginfo/ogginfo2.c 11970 # "Xiphophorus libVorbis I 20000508", "1.0 beta 1 or beta 2" 11971 # "Xiphophorus libVorbis I 20001031", "1.0 beta 3" 11972 # "Xiphophorus libVorbis I 20010225", "1.0 beta 4" 11973 # "Xiphophorus libVorbis I 20010615", "1.0 rc1" 11974 # "Xiphophorus libVorbis I 20010813", "1.0 rc2" 11975 # "Xiphophorus libVorbis I 20011217", "1.0 rc3" 11976 # "Xiphophorus libVorbis I 20011231", "1.0 rc3" 11977 # "Xiph.Org libVorbis I 20020717", "1.0" 11978 # "Xiph.Org libVorbis I 20030909", "1.0.1" 11979 # "Xiph.Org libVorbis I 20040629", "1.1.0 rc1" 11980 # "Xiph.Org libVorbis I 20070622", "1.2.0" 11981 11982 11983 # The first thing in the comment is the vendor ID size, followed by a UTF8 string with the vendor ID. 11984 my $vendor_size = substr($vorbis_comment,0,4); # 4 bytes = 32 bits 11985 $vendor_size = unpack "L",$vendor_size; 11986 #print "vendor_size = $vendor_size\n"; 11987 my $vendor = substr($vorbis_comment, 4, $vendor_size + 4); # read the vendor 11988 #print "vendor = $vendor \n"; 11989 $vorbis_comment = substr($vorbis_comment, $vendor_size + 4); # cut, remove 11990 11991 if ( $vendor =~ /20010615/ ){ $vendor = '1.0rc1'; } 11992 elsif ( $vendor =~ /20010813/ ){ $vendor = '1.0rc2'; } 11993 elsif ( $vendor =~ /20011217/ or $vendor =~ /20011231/ ){ $vendor = '1.0rc3'; } 11994 elsif ( $vendor =~ /20020717/ ){ $vendor = '1.0'; } 11995 elsif ( $vendor =~ /20030909/ ){ $vendor = '1.0.1'; } 11996 elsif ( $vendor =~ /20040629/ ){ $vendor = '1.1.0rc1'; } 11997 elsif ( $vendor =~ /20050304/ ){ $vendor = '1.1.1'; } 11998 elsif ( $vendor =~ /20070622/ ){ $vendor = '1.2.0'; } 11999 else { $vendor =""; } 12000 if ( $extension_input eq 'ogg' ) { $Technical_Info = "OGG Vorbis $vendor"; $metadata{technical_info} = $Technical_Info; } 12001 12002 # Next the number of fields in the comment vector. 12003 my $item_count = substr($vorbis_comment,0,4); 12004 $item_count = unpack "L",$item_count; 12005 #print "item_count = $item_count\n"; 12006 $vorbis_comment = substr($vorbis_comment, 4); # cut, remove 12007 12008 # Each comment field is in the format "key=value" in a UTF8 string and has 12009 # 4 bytes before the text starts that gives the length. 12010 my $tagLen; 12011 my ($tag_key, $tag_val); 12012 my %taghash = (); 12013 12014 for (my $i=0;$i<$item_count;$i++) 12015 { 12016 $tagLen = substr($vorbis_comment,0,4); # read 4 bytes for size/length 12017 $tagLen = unpack "L",$tagLen; 12018 #print "tagLen = $tagLen\n"; 12019 $vorbis_comment = substr($vorbis_comment,4); # cut, remove 4 bytes 12020 12021 my $comment = substr($vorbis_comment,0,$tagLen); # read $tagLen bytes 12022 $vorbis_comment = substr($vorbis_comment,$tagLen); # cut, remove $tagLen bytes 12023 12024 if ($comment =~ /^(.*?)=/) { $tag_key = $1; } # = separation 12025 #$tag_key =~ tr/A-Z/a-z/; #lower case 12026 $tag_key = lc($tag_key); #lower case 12027 $comment =~ s/^.*?=//; 12028 12029 $tag_val = decode("utf8",$comment); 12030 12031 #print "tag_key = $tag_key ;; tag_val = $tag_val ;; vorbis_comment = $vorbis_comment\n"; 12032 # Fill the hash 12033 $taghash{$tag_key} = $tag_val; 12034 if ( length($vorbis_comment) <= 0 ){last;} 12035 } 12036 # framing bit or framing_flag 12037 #my $framing_bit = bin2dec( unpack "B8",substr($vorbis_comment,0,1) ); # read 1 byte = 8 bits 12038 #print "framing_bit = $framing_bit ;;\n"; 12039 12040 if ( defined($taghash{date}) ){ $Year = $taghash{date}; } 12041 if ( defined($taghash{artist}) ){ $Artist = $taghash{artist}; } 12042 if ( defined($taghash{title}) ){ $Title = $taghash{title}; } 12043 if ( defined($taghash{genre}) ){ $Genre = $taghash{genre}; } 12044 if ( defined($taghash{album}) ){ $Album = $taghash{album}; } 12045 12046 if ( defined($taghash{tracknumber}) ){ $Track_Number = $taghash{tracknumber}; } 12047 if ( $Track_Number =~ /(\d+)\/(\d+)/ ){ $Track_Number = $1 ; $Total_Track = $2 ; } 12048 12049 if ( defined($taghash{description}) ){ $Comment = $taghash{description}; } 12050 if ( defined($taghash{comment}) and not defined($taghash{description}) ){ $Comment = $taghash{comment}; } 12051 12052 $Track_Number = remove_change_10_chars($Track_Number); 12053 $Total_Track = remove_change_10_chars($Total_Track); 12054 12055 # get all the 8 tags 12056 $metadata{title} = remove_change_10_chars($Title); 12057 $metadata{artist} = remove_change_10_chars($Artist); 12058 $metadata{album} = remove_change_10_chars($Album); 12059 $metadata{comment} = remove_change_10_chars($Comment); 12060 $metadata{genre} = remove_change_10_chars($Genre); 12061 $metadata{track} = $Track_Number =~ /^\d+$/ ? sprintf("%02d", $Track_Number ) : "" ; # "%02d": leading zero 12062 $metadata{total_track} = $Total_Track =~ /^\d+$/ ? sprintf("%02d", $Total_Track ) : "" ; 12063 $metadata{year} = $Year =~ /^\d{1,4}$/ ? sprintf("%04d", $Year ) : "" ; 12064 12065# See: file:///usr/share/doc/libvorbis0-devel-1.1.0/Vorbis_I_spec.html 12066# The comment header: 12067# 1) [vendor_length] = read an unsigned integer of 32 bits (= 4 bytes) 12068# 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets 12069# 3) [user_comment_list_length] = read an unsigned integer of 32 bits 12070# 4) iterate [user_comment_list_length] times { 12071# 5) [length] = read an unsigned integer of 32 bits 12072# 6) this iteration's user comment = read a UTF-8 vector as [length] octets 12073# } 12074# 7) [framing_bit] = read a single bit as boolean 12075# 8) if ( [framing_bit] unset or end-of-packet ) then ERROR 12076# 9) done. 12077 12078} 12079 12080sub show_ogg_info { 12081 my %args = ( @_ ); 12082 my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath}; 12083 12084 return unless $extension_input eq 'ogg'; 12085 12086 my $header; 12087 my $buffer; 12088 12089 use constant OGGHEADERFLAG => 'OggS'; 12090 12091 my @block_type = ( 'STREAMINFO', 'PADDING', 'APPLICATION', 'SEEKTABLE', 12092 'VORBIS_COMMENT', 'CUESHEET', 'reserved' ); 12093 12094 open(OGG, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 12095 12096 binmode OGG; 12097 $fileSize = -s filename_from_unicode $filepath; 12098 12099 # Read ogg header. 12100 read (OGG, $header, 4); # 4 byte for 'OggS' 12101 12102 if ($header ne OGGHEADERFLAG) { return $false; } 12103 12104 ##------------------------## 12105 # Search for the first header containing Identification header ( $header_type_flag == 1 ). 12106 my $byte = 25; # at least equal to 28 bytes 12107 my $string = ""; 12108 my $myseek = sub { 12109 my $n = $_[0] || 6; # read 6 bytes for one loop to search for 'vorbis' string 12110 $byte += $_[1] || 1; # advance 1 byte for one loop 12111 seek OGG, $byte, 0; 12112 read OGG, $string, $n; 12113 }; 12114 while ($string ne 'vorbis') { 12115 &$myseek(6,1); 12116 if ($byte > 8*1024) { return $false; } 12117 } 12118 #print "byte = $byte\n"; 12119 ##------------------------## 12120 my $first_frame_size = $byte - 1; # 28 is the more likely value. 12121 12122 seek OGG, $first_frame_size, 0; # set read to $first_frame_size ( at least equal to 28 bytes). 12123 12124 # Identification header (type = 1) 12125 read (OGG, my $header_type, 1); # read 1 byte 12126 $header_type = bin2dec(unpack "B8",$header_type); # header_type = 1 indicates the Identification header. 12127 #print "header_type = $header_type\n"; 12128 if ($header_type != 1){return;} 12129 12130 read (OGG, $header, 6); # read + 6 bytes for 'vorbis' 12131 12132 read (OGG, my $vorbis_version, 4); # read 4 bytes = 32 bits 12133 $vorbis_version = unpack "L",$vorbis_version; 12134 if ($vorbis_version != 0){return $false;} 12135 #print "vorbis_version = $vorbis_version\n"; 12136 12137 read (OGG, my $audio_channels, 1); # read 1 byte = 8 bits 12138 $audio_channels = bin2dec(unpack "B8",$audio_channels); 12139 if ($audio_channels < 1){return $false;} 12140 #print "audio_channels = $audio_channels\n"; 12141 12142 read (OGG, $Frequency, 4); # read 4 bytes 12143 $Frequency = unpack "L",$Frequency; 12144 if ($Frequency < 1){return $false;} 12145 #print "Frequency = $Frequency\n"; 12146 12147 read (OGG, my $bitrate_maximum, 4); # read 4 bytes 12148 $bitrate_maximum = unpack "L",$bitrate_maximum; 12149 #print "bitrate_maximum = $bitrate_maximum\n"; 12150 12151 read (OGG, $bitrate_nominal, 4); # read 4 bytes 12152 $bitrate_nominal = unpack "L",$bitrate_nominal; 12153 if ($bitrate_nominal <= 0){return $false;} 12154 #print "bitrate_nominal = $bitrate_nominal\n"; 12155 12156 read (OGG, my $bitrate_minimum, 4); # read 4 bytes 12157 $bitrate_minimum = unpack "L",$bitrate_minimum; 12158 #print "bitrate_minimum = $bitrate_minimum\n"; 12159 12160 read (OGG, my $blocksize, 1); # read 1 byte = 8 bits = (4 + 4) bits 12161 12162 $blocksize = unpack "B8",$blocksize; 12163 #print "blocksize = $blocksize \n"; 12164 12165 # "1 << x" is equal to "2 exponent to x = 2 ** x" valid for x=2^n, n=0,1,2,... . 12166 #my $exp0 = bin2dec(substr($blocksize, 4, 4)); 12167 #my $exp1 = bin2dec(substr($blocksize, 0, 4)); 12168 #my $blocksize_0 = 1 << $exp0; # read the first 4 bits 12169 #my $blocksize_1 = 1 << $exp1; # read the last 4 bits 12170 12171 #print "exp0 = $exp0 ;; exp1 = $exp1 ;; blocksize_0 = $blocksize_0 ;; blocksize_1 = $blocksize_1\n"; 12172 #if ($blocksize_0 < 8){return $false;} 12173 #if ($blocksize_1 < $blocksize_0){return $false;} 12174 12175 # See /usr/share/doc/libvorbis0-devel-1.1.0/Vorbis_I_spec.html 12176 # Seek for the last header complete: 12177 # -The granule position of the first pages containing only headers is zero. 12178 # -The granule position of pages containing Vorbis audio is in units of PCM audio samples (per channel; 12179 # a stereo stream's granule position does not increment at twice the speed of a mono stream). 12180 # -The granule position of a page represents the end PCM sample position of the last packet completed 12181 # on that page. A page that is entirely spanned by a single packet (that completes on a subsequent page) 12182 # has no granule position, and the granule position is set to '-1'. 12183 12184 # To find the length of the file see http://wiki.xiph.org/VorbisStreamLength/ 12185 # Seek for the first header containing Vorbis audio. 12186 12187 my $firstGranulePosition = 0; 12188 12189 my $header_type_flag = 0; 12190 my $complete = 0; # init value 12191 $string = ""; 12192 $byte = -1; 12193 $myseek = sub { 12194 my $n = $_[0] || 4; # read 4 bytes for one loop 12195 $byte += $_[1] || 1; # advance 1 byte for one loop 12196 seek OGG, $byte, 0; 12197 read OGG, $string, $n; 12198 }; 12199 # Search for the first header containing Vorbis audio ( $header_type_flag == 1 ). 12200 # This occur when $firstGranulePosition != 0 12201 while ( $complete <= 8 and $firstGranulePosition == 0 ){ 12202 while ($string ne 'OggS') { 12203 &$myseek(4,1); 12204 if ($byte > 32*1024) { return $false; } 12205 } 12206 $string = ""; 12207 $byte += 1; 12208 $complete += 1; 12209 12210 read (OGG, my $stream_structure_version, 1); 12211 read (OGG, $header_type_flag, 1); 12212 # first page of logical bitstream (bos) when $header_type_flag = 3 12213 $header_type_flag = bin2dec(unpack "B8",$header_type_flag); 12214 12215 read (OGG, $firstGranulePosition, 8); # 8 bytes = 64 bits 12216 $firstGranulePosition = unpack "L2",$firstGranulePosition; 12217 #print "firstGranulePosition = $firstGranulePosition; "; 12218 #print "header_type_flag = $header_type_flag ; complete = $complete ; byte = $byte\n"; 12219 12220 #read (OGG, my $stream_serial_number, 4); # 4 bytes 12221 #read (OGG, my $page_sequence_no, 4); # 4 bytes 12222 #$page_sequence_no = unpack "L",$page_sequence_no; 12223 #print "page_sequence_no = $page_sequence_no\n"; 12224 } 12225 # remove the bytes of the first n headers without Vorbis audio. 12226 my $total_data_length = $fileSize - $byte + 1; 12227 12228 $complete = 0; 12229 $string = ""; 12230 $byte = 3; 12231 $myseek = sub { 12232 my $n = $_[0] || 4; # read 4 bytes for one loop 12233 $byte += $_[1] || 1; # advance 1 byte for one loop 12234 seek OGG, -$byte, 2; # Set FileHandle $byte bytes from the end of file 12235 read OGG, $string, $n; 12236 }; 12237 # Search for the last header OggS containing Vorbis audio 12238 while ( $complete <= 0 ){ # 0: last header OggS 12239 while ($string ne 'OggS') { 12240 &$myseek(4,1); 12241 if ($byte > 32*1024) { return $false; } 12242 } 12243 #print "complete = $complete ;; byte = $byte\n"; 12244 $string = ""; 12245 $byte += 1; 12246 $complete += 1; 12247 } 12248 my $current_position = tell OGG; 12249 #print "byte = $byte ;; current_position = $current_position\n"; 12250 12251 read (OGG, my $stream_structure_version, 1); 12252 $stream_structure_version = bin2dec(unpack "B8",$stream_structure_version); 12253 read (OGG, $header_type_flag, 1); 12254 # last page of logical bitstream (eos) when $header_type_flag = 5. 12255 $header_type_flag = bin2dec(unpack "B8",$header_type_flag); 12256 #print "header_type_flag = $header_type_flag\n"; 12257 12258 12259 # 0x12 0x34 0x56 0x78 # big-endian 4 bytes 12260 # 0x78 0x56 0x34 0x12 # little-endian 12261 read (OGG, my $lastGranulePosition, 8); # 8 bytes = 64 bits 12262 $lastGranulePosition = unpack "L2",$lastGranulePosition; 12263 #print "lastGranulePosition = $lastGranulePosition\n"; 12264 12265 my $Total_Samples = $lastGranulePosition ; # - $firstGranulePosition; 12266 if ($Total_Samples < 1){return $false;} 12267 12268 my $totalSeconds = $Total_Samples / $Frequency; 12269 $bitrate_original = ( $total_data_length * 8 ) / $totalSeconds; 12270 #print "totalSeconds = $totalSeconds ;; Kbitrate_original = $bitrate_original ;; total_data_length = $total_data_length\n"; 12271 $totalSeconds = sprintf("%0.0f",$totalSeconds); 12272 # convert x seconds to hour:min:sec format 12273 my ($hour,$min,$sec) = sec_to_time($totalSeconds); # return ($hour,$min,$sec); 12274 12275 $Frequency = sprintf("%.0f", $Frequency ); 12276 $mode_channel = $audio_channels; 12277 $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ; 12278 $bitrate_original = sprintf("%.1f", $bitrate_original/1000 ); #Kbitrate 12279 $bitrate_nominal = sprintf("%.0f", $bitrate_nominal/1000 ); #Kbitrate 12280 $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes ; 2**10 = 1024 12281 #print "fileSize = $fileSize MB \n"; 12282 12283 close(OGG); 12284 12285 #$Technical_Info = "OGG Vorbis"; 12286 $bitrate_average = $true; 12287 12288 # get all technical informations: 12289 # $metadata{technical_info} = $Technical_Info; see 'sub read_vorbis_comment_tag' 12290 $metadata{bitrate} = $bitrate_original; 12291 $metadata{bitrate_nominal} = $bitrate_nominal; # only for ogg 12292 $metadata{bitrate_average} = $bitrate_average; # $true or $false 12293 $metadata{frequency} = $Frequency; 12294 $metadata{mode} = $mode_channel; 12295 $metadata{length} = $Time_Min_Sec if ( $extension_input ne 'cda' ); 12296 $metadata{fileSize} = $fileSize; 12297 12298 return $true; 12299 12300# See: file:///usr/share/doc/libvorbis0-devel-1.0.1/Vorbis_I_spec.html 12301 12302# file:///usr/share/doc/libogg-1.1.2/framing.html 12303# byte value: byte value: 12304# 0 0x4f 'O' capture_pattern 18 0xXX LSB page sequence no 12305# 1 0x67 'g' 19 0xXX 12306# 2 0x67 'g' 20 0xXX 12307# 3 0x53 'S' 21 0xXX MSB 12308# 4 0x00 stream_structure_version 22 0xXX LSB page checksum 12309# 5 bitflags header_type_flag 23 0xXX 12310# 6 0xXX LSB absolute granule position 24 0xXX 12311# 7 0xXX 25 0xXX MSB 12312# 8 0xXX 26 0x00-0xff page_segments 12313# 9 0xXX 27 0x00-0xff (0-255) segment_table (containing packet lacing values) 12314# 10 0xXX 12315# 11 0xXX 12316# 12 0xXX 12317# 13 0xXX MSB 12318# 14 0xXX LSB stream serial number 12319# 15 0xXX 12320# 16 0xXX 12321# 17 0xXX MSB 12322 12323# absolute granule position: The position specified is the total samples encoded. 12324 12325# 5 bitflags: 0x01: unset = fresh packet 12326# set = continued packet 12327# 0x02: unset = not first page of logical bitstream 12328# set = first page of logical bitstream (bos) 12329# 0x04: unset = not last page of logical bitstream 12330# set = last page of logical bitstream (eos) 12331 12332# A Vorbis bitstream begins with three header packets. The header packets are, in order, 12333# the identification header, the comments header, and the setup header. 12334 12335# Each header packet begins with the same header fields. 12336# 1) [packet_type] : 8 bit value = 1 byte 12337# 2) 0x76, 0x6f, 0x72, 0x62, 0x69, 0x73: the characters 'v','o','r','b','i','s' as six octets 12338# Identification header is type 1, the comment header type 3 and the setup header type 5 (these types 12339# are all odd as a packet with a leading single bit of '0' is an audio packet). The packets must occur 12340# in the order of identification, comment, setup. 12341 12342# Identification header (header_type = 1) L: An unsigned long value (32 bits). 12343# 1) [vorbis_version] = read 32 bits as unsigned integer 12344# 2) [audio_channels] = read 8 bit integer as unsigned 12345# 3) [audio_sample_rate] = read 32 bits as unsigned integer 12346# 4) [bitrate_maximum] = read 32 bits as signed integer 12347# 5) [bitrate_nominal] = read 32 bits as signed integer 12348# 6) [bitrate_minimum] = read 32 bits as signed integer 12349# 7) [blocksize_0] = 2 exponent (read 4 bits as unsigned integer) 12350# 8) [blocksize_1] = 2 exponent (read 4 bits as unsigned integer) 12351# 9) [framing_flag] = read one bit 12352 12353# The comment header (header_type = 3): 12354# The setup header (header_type = 5): 12355 12356} 12357 12358sub show_ogg_tag { 12359 my %args = ( @_ ); 12360 my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath}; 12361 return unless $extension_input eq 'ogg'; 12362 12363 open(VORBIS, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 12364 binmode VORBIS; 12365 12366 # To find the second 'vorbis' that contain comment header (header_type = 3) 12367 # and the third 'vorbis' to get the size of comment header. 12368 my $header_type = 0; 12369 my $find_comment_header = $false; 12370 my $vorbis_comment_size = 0; 12371 my $loop = 0; # init value 12372 my $string = ""; 12373 my $byte = -1; 12374 my $myseek = sub { 12375 my $n = $_[0] || 6; # read 6 bytes for one loop 12376 $byte += $_[1] || 1; # advance 1 byte for one loop 12377 seek VORBIS, $byte, 0; 12378 read VORBIS, $string, $n; 12379 }; 12380 while ( $loop <= 2 and $header_type != 5 ){ 12381 while ($string ne 'vorbis') { 12382 &$myseek(6,1); 12383 if ($byte > 8*1024) { return $false; } 12384 } 12385 # The comment header (header_type = 3): 12386 seek VORBIS, $byte -1, 0; # goes back one byte of string 'vorbis' to read [packet_type] 12387 read (VORBIS, $header_type, 1); # read 1 byte 12388 $header_type = bin2dec(unpack "B8",$header_type); 12389 #print "header_type = $header_type ;; byte = $byte ;; loop = $loop\n"; 12390 12391 # $header_type == 1 for the first 'vorbis' that contain Identification header vorbis 12392 if ($header_type == 3){ # header_type = 3 indicates comment header. 12393 $find_comment_header = $true; 12394 $vorbis_comment_size = $byte; # get the start position of comment header 12395 } 12396 $string = ""; 12397 $byte += 1; 12398 $loop += 1; 12399 } 12400 if ($find_comment_header eq $false){return $false;} 12401 seek VORBIS, $vorbis_comment_size, 0; 12402 # remove 1 (because '$byte += 1;') and 1 (packet_type) and 6 (because 'vorbis') 12403 $vorbis_comment_size = ($byte - 1 - 1 - 6 ) - $vorbis_comment_size; 12404 if ($vorbis_comment_size <= 0){return $false;} 12405 #print "vorbis_comment_size = $vorbis_comment_size \n"; 12406 12407 read (VORBIS, my $header, 6); # read + 6 bytes for 'vorbis' 12408 #print "VORBIS = $header ;; header_type = $header_type\n"; 12409 12410 # read $vorbis_comment whose length is $vorbis_comment_size. 12411 read (VORBIS, my $vorbis_comment, $vorbis_comment_size ); 12412 read_vorbis_comment_tag($vorbis_comment,$extension_input); 12413 #print "vorbis_comment = $vorbis_comment;;"; 12414 12415 close(VORBIS); 12416 return $true; 12417} 12418 12419 12420# only obtain info from ogg files 12421sub get_ogg_info_from_file { # not more used 12422 my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 12423 my $Total_Track = ""; my $Genre=""; my $Frequency = 0; my $mode_channel = ""; my $Time_Min_Sec = ""; 12424 my $bitrate_average = $true; my $bitrate_original = 160; my $fileSize = 0; 12425 12426 my $ogginfo_path = '/usr/bin/ogginfo'; 12427 12428 if ($ogginfo_path eq "") { 12429 insert_msg("None informations about \"ogg\" format because can't find \"" , "black"); 12430 insert_msg("ogginfo" , "red"); 12431 insert_msg("\" in executable path.\n\n" , "black"); 12432 return $false; 12433 } 12434 12435 my $cmd; # command 12436 12437 $cmd = "$ogginfo_path -v \"$directory/$file_ogg\" "; 12438 12439 my $res = open (OGGINFO, filename_from_unicode "$cmd 2>&1 |" ) ; 12440 12441 ## pid process of ogginfo 12442 if( !defined($res) ) { 12443 $status_bar->push($context_id, " Could not find ogginfo!"); 12444 return $false; 12445 } 12446 12447 $/="\r"; ## start of loop 12448 while(<OGGINFO>){ 12449 12450 #New logical stream (#1, serial: 424f22ae): type vorbis 12451 #Vorbis headers parsed for stream 1, information follows... 12452 #Version: 0 12453 #Vendor: Xiph.Org libVorbis I 20030909 (1.0.1) 12454 #Channels: 2 12455 #Rate: 44100 12456 12457 #Nominal bitrate: 112.001000 Kb/s or Nominal bitrate: 112,001000 Kb/s 12458 #Upper bitrate: 0.320000 Kb/s 12459 #Lower bitrate: 0.064000 Kb/s 12460 #User comments section follows... 12461 # comment=gnormalize Fix value=30 12462 # title=Vinheta do Capeta 12463 # artist=Almir Sater 12464 # genre=Folk 12465 # date=1885 12466 # album=Instrumental 12467 # tracknumber=3 12468 #Vorbis stream 1: 12469 # Total data length: 814983 bytes 12470 # Playback length: 0m:56s 12471 # Average bitrate: 115.015600 kbps 12472 #Logical stream 1 ended 12473 12474 # discover if the bitrate of mp3 file is variable 12475 12476 if( $_ =~ /Channels?:\s+(\d+)\n/i ){ $mode_channel = $1;} 12477 if( $_ =~ /Rate:\s+(\d+)\n/i ){ 12478 my $fq = sprintf("%0.0f", $1 ); 12479 $Frequency = $fq; } 12480 if( $_ =~ /Nominal\sbitrate:\s+(\d+[\.,]\d+)\s.*\n/i ){ 12481 my $br = sprintf("%0.0f",number_value($1) ); 12482 $br = number_value($br); 12483 #print (" br = $br ;; 1 = $1\n"); 12484 $bitrate_original = $br; } 12485 if( $_ =~ /\s+Playback\slength:\s+(.*)\n/i ){ $Time_Min_Sec = $1 ; } 12486 $Time_Min_Sec =~ s/[hms]//ig; 12487 if( $_ =~ /\s+genre=(.*)\n/i ) { $Genre = $1 ; } 12488 if( $_ =~ /\s+title=(.*)\n/i ) { $Title = $1 ; } 12489 if( $_ =~ /\s+artist=(.*)\n/i ){ $Artist = $1 ; } 12490 if( $_ =~ /\s+album=(.*)\n/i ) { $Album = $1 ; } 12491 if( $_ =~ /\s+(date|year)=(.*)\n/i ){ $Year = $2 ; } 12492 if( $_ =~ /\s+tracknumber=\s*(\d+)\/?(\d+)?\n/i ){ $Track_Number = $1 ; } 12493 if( $_ =~ /\s+tracknumber=\s*(\d+)\/(\d+)\n/i ){ $Total_Track = $2 } 12494 if( $_ =~ /\s+comment=(.*)\n/i ){ $Comment = $1 ; } 12495 $Technical_Info = "OGG Vorbis"; 12496 $bitrate_average = $true; 12497 } 12498 $/="\n"; ## final of loop 12499 close(OGGINFO); 12500} 12501 12502sub show_wav_info { 12503 my %args = ( @_ ); 12504 my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath}; 12505 return unless $extension_input eq 'wav'; 12506 12507 my $header; 12508 my $buffer; 12509 12510 use constant WAVHEADERFLAG => 'RIFF'; 12511 12512 open(WAV, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 12513 12514 binmode WAV; 12515 12516 $fileSize = -s filename_from_unicode $filepath; # $fileSize = $FileLength + 8 = $DataLength + 44 12517 #print "fileSize = $fileSize\n"; 12518 12519 # Read WAV header. 12520 read (WAV, $header, 4); # 4 byte for 'RIFF' 12521 12522 if ($header ne WAVHEADERFLAG) { return $false; } 12523 12524 read (WAV, my $FileLength, 4); # read 4 bytes = 32 bits 12525 $FileLength = unpack "L",$FileLength; 12526 #print "FileLength = $FileLength\n"; # $FileLength = $DataLength + 36 12527 12528 read (WAV, my $FormatTag, 8); # read 8 bytes 12529 #print "FormatTag = $FormatTag\n"; 12530 if ($FormatTag ne 'WAVEfmt '){ return $false;} 12531 12532 read (WAV, my $FormatLength, 4); # read 4 bytes = 32 bits 12533 $FormatLength = unpack "L",$FormatLength; 12534 #print "FormatLength = $FormatLength\n"; 12535 12536 read (WAV, my $DataFormat, 2); # read 2 byte = 16 bits 12537 12538 read (WAV, my $Channels, 2); # read 2 byte = 16 bits 12539 $Channels = unpack "S",$Channels; # 00000010 00000000 12540 #$Channels = ( bin2dec(unpack "B16",$Channels) ) >> 8 ; 12541 #$Channels = bin2dec( substr ( (unpack "B16",$Channels) , 0 , 8 ) ) ; 12542 #print "NumChannels = $Channels\n"; 12543 12544 read (WAV, $Frequency, 4); # read 4 bytes 12545 $Frequency = unpack "L",$Frequency; 12546 #print "Frequency = $Frequency\n"; 12547 $Frequency = sprintf("%.0f", $Frequency ); #Kbitrate 12548 12549 read (WAV, my $BytesPerSecond, 4); # read 4 bytes 12550 $BytesPerSecond = unpack "L",$BytesPerSecond; 12551 #print "BytesPerSecond = $BytesPerSecond\n"; 12552 $bitrate_original = sprintf("%.1f", ($BytesPerSecond * 8)/1000 ); #Kbitrate 12553 12554 read (WAV, my $BlockAlignment, 2); # read 2 byte = 16 bits 12555 12556 read (WAV, my $BitsPerSample, 2); # read 2 byte = 16 bits 12557 $BitsPerSample = unpack "S",$BitsPerSample; # Sample Size 12558 12559 $mode_channel = "$Channels\n($BitsPerSample bits)"; 12560 12561 read (WAV, my $char, 4); # read 4 bytes 12562 #print "char = $char\n"; 12563 if ($char ne 'data'){ return $false;} 12564 12565 read (WAV, my $DataLength, 4); # read 4 bytes 12566 $DataLength = unpack "L",$DataLength; 12567 # 2352 = bytes per frame, "raw" mode ;; 1 sec have 75 frames = 75 * 2352 bytes = 176400 bytes 12568 #print "DataLength = $DataLength\n"; 12569 12570 my $totalSeconds = int($DataLength / $BytesPerSecond) ; 12571 #my $totalSeconds2 = sprintf("%0.3f",$DataLength / $BytesPerSecond); print "\n\$totalSeconds2 = $totalSeconds2 \n"; 12572 12573 # convert x seconds to hour:min:sec format 12574 my ($hour,$min,$sec) = sec_to_time($totalSeconds); # return ($hour,$min,$sec); 12575 $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ; 12576 $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes ; 2**10 = 1024 12577 12578 $Technical_Info = "WAV"; 12579 $encode = 'average'; 12580 $bitrate_average = $true; 12581 12582 # get all technical informations: 12583 $metadata{technical_info} = $Technical_Info; 12584 $metadata{bitrate} = $bitrate_original; 12585 $metadata{bitrate_nominal} = 160; # only for ogg 12586 $metadata{bitrate_average} = $bitrate_average; # $true or $false 12587 $metadata{frequency} = $Frequency; 12588 $metadata{mode} = $mode_channel; 12589 $metadata{length} = $Time_Min_Sec if ( $extension_input ne 'cda' ); 12590 $metadata{fileSize} = $fileSize; 12591 12592# See Linux::CDROM::Cookbook and http://www.sonicspot.com/guide/wavefiles.html 12593# ------------ WAV header ----------- # 12594# total size = 44 bytes 12595#struct { 12596# char RiffTag[4]; // 'RIFF' 12597# int32_t FileLength; // Filesize - 8 12598# char FormatTag[8]; // 'WAVEfmt ' 12599# int32_t FormatLength; // 16 for PCM 12600# int16_t DataFormat; // Compression Code: (1) for PCM/uncompressed raw sample values ;; (2) for Microsoft ADPCM ; ... 12601# int16_t NumChannels; // Mono = 1, Stereo = 2 etc. 12602# int32_t SampleRate; // 8000, 44100 etc. 12603# int32_t BytesPerSecond; // == SampleRate * BlockAlignment 12604# int16_t BlockAlignment; // == NumChannels * BitsPerSample/8 12605# int16_t BitsPerSample; // 8 bits, 16 bits, ... This value specifies the number of bits used to define each sample. 12606# char DataTag[4]; // 'data' 12607# int32_t DataLength; // == NumSamples * NumChannels * BitsPerSample/8. This is the number of bytes in the data. 12608#} header = { 12609# "RIFF", 0, "WAVEfmt ", 12610# 16, 1, 2, 44100, 176400, 4, 16, 12611# "data", 0 12612#}; 12613# ------------ WAV header ----------- # 12614 12615# $totalSeconds = $DataLength / $BytesPerSecond; 12616# $totalSamples = $Frequency * $totalSeconds; 12617 12618} 12619 12620 12621sub read_ID3v1_mp3_tag { # not used 12622 my $fname = shift; 12623 my $filepath = $directory."/".$fname; 12624 my $buffer; 12625 12626 my ($title, $artist, $album, $year, $comment, $tracknum, $genre); 12627 12628 if ($filepath !~ /\.mp3$/i) { return $false;} 12629 12630 open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 12631 12632 binmode IN; 12633 $fileSize = -s filename_from_unicode $filepath; 12634 12635 seek(IN,-128, 2); # Set FileHandle 128 byte from the end of file 12636 read(IN, $buffer, 128, 0); # read 128 byte to $buffer 12637 12638 my $preamble = substr($buffer,0,3); # read 3 byte 12639 return unless $preamble eq 'TAG'; 12640 $buffer = substr($buffer, 3); # remove 3 byte 12641 12642 $tracknum = unpack "C", substr($buffer, 123, 1); 12643 12644 # get TAG to variables 12645 if ( defined($tracknum) ){ 12646 ( $title, $artist, $album, $year, $comment, $tracknum, $genre ) = unpack "a30a30a30a4a28xCC", $buffer;} 12647 else { ( $title, $artist, $album, $year, $comment, $genre ) = unpack "a30a30a30a4a30C", $buffer; 12648 $tracknum = ""; 12649 } 12650 print "title = $title ;; artist = $artist ;; album = $album ;; year = $year ;; comment = $comment \n"; 12651 print "track number = $tracknum ;; genre = $genre ;; fileSize = $fileSize\n"; 12652 return ($title, $artist, $album, $year, $comment, $tracknum, $genre); 12653} 12654 12655sub save_ID3v1_mp3_tag { 12656 my ( $filepath, $title, $artist, $album, $year, $comment, $tracknum, $genre) = @_; 12657 my $buffer; my $ID3v1 = ""; 12658 12659 12660 # see 'sub eval_to_unicode' 12661 $filepath = filename_from_unicode $filepath; # convert filename_from_unicode to local encoding 12662 #if( ! -e $filepath ) { $filepath = $files_info[$row]{filepath_local}; } # get original filename encoding 12663 12664 12665 12666 my $char = $id3tag_character; # encode could be 'iso-8859-1' or 'utf8'. 12667 12668 $genre = get_genre_number($genre) || '12'; # 12 Other : default 12669 #print "genre_number = $genre_number ;; Genre = $Genre\n"; 12670 12671 $title = encode($char,$title); $artist = encode($char,$artist); 12672 $album = encode($char,$album); $comment = encode($char,$comment); 12673 $genre = encode($char,$genre); 12674 if ( not ($year =~ /^\d+$/ or $year eq "") ){return;} 12675 12676 # See 'man perlopentut' for "+<" to specify both read and write access 12677 #open(IN, '+<', filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 12678 open(IN, '+<', $filepath ) || die "Can't open <$filepath>: $!, stopped"; 12679 12680 binmode IN; 12681 seek(IN,-128, 2); # Set FileHandle 128 byte from the end of filepath 12682 read(IN, $buffer, 128, 0); # read 128 byte to $buffer 12683 12684 my $preamble = substr($buffer,0,3); # read 3 byte 12685 if ( $preamble ne 'TAG' ){ seek(IN, 0, 2); } # go to the end of filepath 12686 else{ seek(IN,-128, 2);} #overwrite, clobber 12687 12688 # save TAG to filepath, overwrite if it exist 12689 if ( $tracknum =~ /^\d+$/ ) { 12690 $tracknum = $tracknum > 255 ? 255 : $tracknum; # must be an integer from 1 and 255 12691 $ID3v1 = pack "a3a30a30a30a4a28xCC", 'TAG', $title, $artist, $album, $year, $comment, $tracknum, $genre; } 12692 else { 12693 $ID3v1 = pack "a3a30a30a30a4a30C", 'TAG', $title, $artist, $album, $year, $comment, $genre; 12694 } 12695 syswrite ( IN, $ID3v1, 128 ); 12696 close(IN); 12697} 12698 12699 12700sub read_Xing_mp3_tag { # Not used 12701 my $fname = shift; 12702 my $filepath = $directory."/".$fname; 12703 my $buffer; 12704 my $off = -1; my $byte = "" ; my $try_harder = 4096; 12705 my $frames = 0; $fileSize = 0; 12706 12707 if ($filepath !~ /\.mp3$/i) { return $false;} 12708 12709 open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 12710 12711 binmode IN; 12712 12713 # check first three bytes for 'ID3' 12714 seek IN, 0, 0; 12715 read IN, $buffer, 3; 12716 12717 if ($buffer eq 'ID3'){ 12718 # get ID3v2 tag length from bytes 7-10 12719 my $tag_size = 10; # include ID3v2 header size 12720 seek IN, 6, 0; 12721 read IN, $buffer, 4; 12722 $tag_size += ID3_GET_SIZE28($buffer); 12723 print "tagsize = $tag_size\n"; 12724 $off = $tag_size; 12725 } 12726 # For Xing headers, see "http://home.pcisys.net/~melanson/codecs/mp3extensions.txt" 12727 # Xing headers are often added to VBR (variable bit rate) MP3 12728 12729 my $myseek = sub { 12730 my $n = $_[0] || 4; # read 4 bytes for one loop 12731 $off += $_[1] || 1; # advance 1 byte for one loop 12732 seek IN, $off, 0; 12733 read IN, $byte, $n; 12734 }; 12735 while ($byte ne 'Xing') { 12736 &$myseek; 12737 if ($off > $try_harder) { return $false; } 12738 #print "byte = $byte ;; off = $off\n"; 12739 } 12740 print "preamble_xing = $byte ;; off = $off\n"; 12741 12742 &$myseek(4,4); 12743 my $flags = unpack_head($byte); 12744 12745 if ($flags & 1) { 12746 &$myseek(4,4); 12747 $frames = unpack_head($byte); 12748 } 12749 if ($flags & 2) { 12750 &$myseek(4,4); 12751 $fileSize = unpack_head($byte); 12752 } 12753 12754 print "frames = $frames ;; fileSize = $fileSize\n"; 12755 $Frequency = 48000; 12756 12757 my $timePerFrame = 32*36; #32*36 = 1152 12758 my $totalSamples = $frames * $timePerFrame; 12759 my $totalSeconds = $totalSamples/$Frequency; 12760 my $bitrate = 8 * $fileSize / $totalSeconds; # 8*$filesize = size in bit 12761 12762 $totalSeconds = sprintf("%0.0f",$totalSeconds); 12763 # convert x seconds to hour:min:sec format 12764 my ($hour,$min,$sec) = sec_to_time($totalSeconds); # return ($hour,$min,$sec); 12765 12766 $bitrate = sprintf("%0.0f",$bitrate/1000); 12767 print "Kbitrate = $bitrate ;; time = $hour:$min:$sec ;; totalSeconds = $totalSeconds\n"; 12768 12769 return $true; 12770} 12771 12772# from MPEG::MP3Info 12773sub unpack_head { unpack('l', pack('L', unpack('N', $_[0]))); } 12774 12775# from MP3::Info 12776sub read_mp3_info_tag { 12777 my %args = ( @_ ); 12778 my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath}; 12779 return unless $extension_input eq 'mp3'; 12780 12781 my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 12782 my $Total_Track = ""; my $Genre=""; my $Frequency = 0; my $mode_channel = ""; my $Time_Min_Sec = ""; 12783 my $bitrate_average = $true; my $bitrate_original = 160; my $fileSize = 0; 12784 12785 $filepath = filename_from_unicode $filepath; 12786 12787 # see 'sub eval_to_unicode' 12788 #my $filepath = filename_from_unicode $files_info[$row]{filepath}; # convert filename_from_unicode to local encoding 12789 #if( ! -e $filepath ) { $filepath = $files_info[$row]{filepath_local}; } # get original filename encoding 12790 #$filepath = eval_from_unicode( row => $row , filepath => $args{filepath} ); 12791 12792 12793 12794 ## MP3::Info - Copyright (c) 1998-2005 Chris Nandor. 12795 my $mp3; 12796 12797 if ( $use_external_MP3Info ) { # use external MP3::Info 12798 $mp3 = MP3::Info->new($filepath); 12799 get_mp3tag($filepath); 12800 get_mp3info ($filepath); # The conversion to unicode will be made bellow. 12801 use_mp3_utf8($false); # Force MP3::Info to NOT return TAG info in UTF-8. 12802 } 12803 else { # use internal MP3::Info 12804 $mp3 = MP3::Info::Internal->new($filepath); 12805 MP3::Info::Internal::get_mp3tag($filepath); 12806 MP3::Info::Internal::get_mp3info ($filepath); 12807 MP3::Info::Internal::use_mp3_utf8($false); # Force MP3::Info to NOT return TAG info in UTF-8. 12808 MP3::Info::Internal::use_winamp_genres(); 12809 } 12810 12811 # eval : see <man perlfunc> 12812 eval { $mp3->title; }; if ($@){warn "\n$filepath: $@";} else{$Title = $mp3->title if (defined $mp3->title);} 12813 eval { $mp3->artist; }; unless ($@){$Artist = $mp3->artist if (defined $mp3->artist);} 12814 eval { $mp3->album; }; unless ($@){$Album = $mp3->album if (defined $mp3->album);} 12815 eval { $mp3->year; }; unless ($@){$Year = $mp3->year if (defined $mp3->year);} 12816 eval { $mp3->comment; }; unless ($@){$Comment = $mp3->comment if (defined $mp3->comment);} 12817 eval { $mp3->genre; }; unless ($@){$Genre = $mp3->genre if (defined $mp3->genre);} 12818 eval { $mp3->tracknum;}; unless ($@){$Track_Number = $mp3->tracknum if (defined $mp3->tracknum);} 12819 12820 12821 # %tag_v2 is a hash with id3v2 mp3 tag 12822 my $tag_v2 = get_mp3tag($filepath, 2, 2) if $use_external_MP3Info; # get_mp3tag (FILE, tag VERSION, RAW_V2) 12823 #for (sort keys %$tag_v2){ 12824 # next unless (defined $tag_v2->{$_} and defined $MP3::Info::v2_tag_names{$_}); 12825 # printf "=== %4s (%s): %s\n", $_, $MP3::Info::v2_tag_names{$_}, $tag_v2->{$_}; 12826 # $metadata{$_} = "$tag_v2->{$_}"; 12827 #} 12828 # %metadata is a hash with metadata (tag) and technical information 12829 # "\0XXX\0Some Lyrics\0" such that XXX is the Language ( print chr($Lyric) ); and remove the last NULL(s). 12830 ($metadata{'Lyrics'} = "$tag_v2->{'USLT'}") =~ s/\0+$// if (defined $tag_v2->{'USLT'}); 12831 $metadata{'Encoded by'} = "$tag_v2->{'TENC'}" if (defined $tag_v2->{'TENC'}); 12832 $metadata{'Composer'} = "$tag_v2->{'TCOM'}" if (defined $tag_v2->{'TCOM'}); 12833 $metadata{'Length'} = "$tag_v2->{'TLEN'}" if (defined $tag_v2->{'TLEN'}); 12834 12835 12836 if( $Track_Number =~ /(\d+)\/(\d+)/ ){ $Track_Number = $1 ; $Total_Track = $2 ; } 12837 12838 if ($Genre =~ /(\d+)/){ $Genre = $1; } # if <genre = name (number)> --> get <genre = number> 12839 12840 # if $Genre is a number, get its reference name 12841 if ($Genre =~ /^\d+$/){ $Genre = $genre_hash{"$Genre"}; } # $genre_hash{"32"} 12842 12843 #($Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Genre) = read_ID3v1_mp3_tag($file_mp3); 12844 12845 eval { $bitrate_average = $mp3->vbr; }; unless ($@){$bitrate_average = $mp3->vbr if (defined $mp3->vbr); } 12846 eval { $Frequency = $mp3->frequency; }; unless ($@){$Frequency = $mp3->frequency if (defined $mp3->frequency); } 12847 $Frequency = sprintf("%.0f", 1000*$Frequency ); 12848 if ($Frequency < 1000){warn "\nCould not read the Frequency from file: $filepath";} 12849 12850 my @channel_mode = ('stereo','joint stereo','dual channels','mono'); # mono = single channel 12851 my $mode = 0; # (0 = stereo, 1 = joint stereo, 2 = dual channel, 3 = single channel) 12852 eval { $mode = $mp3->mode; }; 12853 $mode_channel = $@ ? print "Error!" : $channel_mode[$mode]; 12854 12855 eval { $mp3->time; }; unless ($@){$Time_Min_Sec = $mp3->time if (defined $mp3->time);} 12856 eval { $mp3->bitrate; }; unless ($@){$bitrate_original = $mp3->bitrate if (defined $mp3->bitrate);} 12857 12858 $fileSize = -s $filepath; 12859 $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes 12860 12861 my $version = ""; my $layer = " Error"; 12862 eval { $version = $mp3->version }; unless ($@){$version = $mp3->version if (defined $mp3->version);} 12863 eval { $layer = $mp3->layer }; unless ($@){$layer = $mp3->layer if (defined $mp3->layer);} 12864 12865 # Must convert all input data to unicode. 12866 if (1){ 12867 foreach ( $Title, $Artist, $Album, $Comment, $Genre, $Year, $Track_Number, $Total_Track, 12868 $metadata{'Lyrics'}, $metadata{'Encoded by'}, $metadata{'Composer'}, $metadata{'Length'} ){ 12869 12870 if ( not utf8::is_utf8($_) and defined $_ and $_ ne "" ) { 12871 #print "Is not utf8: \"$_\".\n"; 12872 eval { $_ = filename_to_unicode $_; } ; # convert to unicode and remove Wide character 12873 } 12874 #if ( utf8::is_utf8($_) and defined $_ and $_ ne "" ) { print "Is utf8: \"$_\".\n"; } 12875 } 12876 } 12877 12878 $Technical_Info = "MPEG$version/layer$layer"; 12879 12880 $Track_Number = remove_change_10_chars($Track_Number); 12881 $Total_Track = remove_change_10_chars($Total_Track); 12882 12883 # get all the 8 tags 12884 $metadata{title} = remove_change_10_chars($Title); 12885 $metadata{artist} = remove_change_10_chars($Artist); 12886 $metadata{album} = remove_change_10_chars($Album); 12887 $metadata{comment} = remove_change_10_chars($Comment); 12888 $metadata{genre} = remove_change_10_chars($Genre); 12889 $metadata{track} = $Track_Number =~ /^\d+$/ ? sprintf("%02d", $Track_Number ) : "" ; # "%02d": leading zero 12890 $metadata{total_track} = $Total_Track =~ /^\d+$/ ? sprintf("%02d", $Total_Track ) : "" ; 12891 $metadata{year} = $Year =~ /^\d{1,4}$/ ? sprintf("%04d", $Year ) : "" ; 12892 12893 # get all 7 technical informations: 12894 $metadata{technical_info} = $Technical_Info; 12895 $metadata{bitrate} = $bitrate_original; 12896 #$metadata{bitrate_nominal} = 160; # only for ogg 12897 $metadata{bitrate_average} = $bitrate_average; # $true or $false 12898 $metadata{frequency} = $Frequency; 12899 $metadata{mode} = $mode_channel; 12900 $metadata{length} = $Time_Min_Sec if ( $extension_input ne 'cda' ); 12901 $metadata{fileSize} = $fileSize; 12902 12903 #print "\n read_mp3_info_tag --> \$bitrate_average = $bitrate_average\n"; 12904} 12905 12906sub get_mp4_info_from_file { 12907 my %args = ( @_ ); 12908 my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath}; 12909 return unless $extension_input eq 'mp4'; 12910 12911 my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 12912 my $Total_Track = ""; my $Genre=""; my $Frequency = 0; my $mode_channel = ""; my $Time_Min_Sec = ""; 12913 my $bitrate_average = $true; my $bitrate_original = 160; my $fileSize = 0; 12914 12915 if ($faad_path eq "") { 12916 insert_msg("None informations about \"mp4\" format because can't find \"" , "black"); 12917 insert_msg("faad" , "red"); 12918 insert_msg("\" in executable path.\n\n" , "black"); 12919 return $false; 12920 } 12921 my $totalSeconds = 0; 12922 $bitrate_original = 0; 12923 $bitrate_average = $true; 12924 12925 $fileSize = -s filename_from_unicode $filepath; 12926 12927 (my $filepath2 = $filepath ) =~ s/"/\\"/g; # change all " characters by \" 12928 # Use 'filename_from_unicode' to convert from unicode to local encoding. 12929 $filepath2 = filename_from_unicode $filepath2; 12930 _utf8_on($filepath2); # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'. 12931 12932 my $cmd = "$faad_path -i \"$filepath2\" "; 12933 12934 my $res = open (INFO, "$cmd 2>&1 |" ) or die "Can't get info $cmd: $!"; 12935 12936 while(<INFO>){ 12937 # LC AAC 106.939 secs, 2 ch, 44100 Hz 12938 # or 'MAIN AAC 114.966 secs, 2 ch, 44100 Hz' 12939 # or 'ADTS, 315.815 sec, 125 kbps, 44100 Hz' for AAC format 12940 12941 #tool: FAAC 1.24 beta (Jun 8 2004) UNSTABLE 12942 #artist: Johann Sebastian Bach nome bem grand�o m�ximo teste 12943 #title: Prelude (Suite n.1) � � 12944 #album: Suites para violoncelo n.1 e n.2 12945 #track: 3 12946 #totaltracks: 12 12947 #date: 2005 12948 #genre: Bossa Nova 12949 #comment: gnormalize Fix value=30 12950 12951 if( $_ =~ /AAC\s+(\d+[\.,]\d+)\ssecs?,\s(\d+)\sch,\s+(\d+)\sHz\n/i ){ 12952 $Time_Min_Sec = $1; # total seconds 12953 $mode_channel = $2; 12954 my $fq = sprintf("%.0f", $3 ); 12955 $Frequency = $fq; 12956 $Technical_Info = "MPEG4 MP4/M4A"; 12957 } 12958 if( $_ =~ /ADTS,\s+(\d+[\.,]\d+)\ssecs?,\s(\d+)\skbps,\s+(\d+)\sHz\n/i ){ 12959 $Time_Min_Sec = $1; # total seconds 12960 $bitrate_original = $2; 12961 $mode_channel = '2'; 12962 my $fq = sprintf("%.0f", $3 ); 12963 $Frequency = $fq; 12964 $Technical_Info = "MPEG2 AAC"; 12965 } 12966 if( $_ =~ /^artist:\s+(.*)$/mi ){ $Artist = $1 ; } # //m: '.' matches any character except "\n". See <man perlretut> 12967 if( $_ =~ /^title:\s+(.*)$/mi ){ $Title = $1 ; } 12968 if( $_ =~ /^album:\s+(.*)$/mi ){ $Album = $1 ; } 12969 if( $_ =~ /^track:\s+(\d+)$/mi ){ $Track_Number = $1 ; } 12970 if( $_ =~ /^totaltracks:\s+(\d+)$/mi ){ $Total_Track = $1 } 12971 if( $_ =~ /^(date|year):\s+(\d+)$/mi ){ $Year = $2 ; } 12972 if( $_ =~ /^genre:\s+(.*)$/mi ){ $Genre = $1 ; } 12973 if( $_ =~ /^comment:\s+(.*)$/mi ){ $Comment = $1 ; } 12974 } 12975 close(INFO); 12976 12977 my $bitrate = ($Time_Min_Sec <= 0) ? 0 : ($fileSize * 8) / ($Time_Min_Sec * 1000); 12978 $fileSize = sprintf("%.1f", $fileSize/(1024 * 1024) ); # MBytes 12979 $bitrate_original = ($bitrate_original > 0) ? $bitrate_original : $bitrate; 12980 $bitrate_original = sprintf("%.0f",$bitrate_original); 12981 12982 my $TotalSeconds = sprintf("%.0f",$Time_Min_Sec); 12983 my ($hour,$min,$sec) = sec_to_time($TotalSeconds); # return ($hour,$min,$sec); 12984 $Time_Min_Sec = $hour > 0 ? "$hour:$min:$sec" : "$min:$sec" ; 12985 12986 12987 # Must convert all input data to unicode. 12988 if (1){ 12989 foreach ( $Title, $Artist, $Album, $Comment, $Genre, $Year, $Track_Number, $Total_Track ){ 12990 12991 if ( not utf8::is_utf8($_) and defined $_ and $_ ne "" ) { 12992 #print "Is not utf8: \"$_\".\n"; 12993 eval { $_ = filename_to_unicode $_; } ; # convert to unicode and remove Wide character 12994 } 12995 #if ( utf8::is_utf8($_) and defined $_ and $_ ne "" ) { print "Is utf8: \"$_\".\n"; } 12996 } 12997 } 12998 12999 $Track_Number = remove_change_10_chars($Track_Number); 13000 $Total_Track = remove_change_10_chars($Total_Track); 13001 13002 # get all the 8 tags 13003 $metadata{title} = remove_change_10_chars($Title); 13004 $metadata{artist} = remove_change_10_chars($Artist); 13005 $metadata{album} = remove_change_10_chars($Album); 13006 $metadata{comment} = remove_change_10_chars($Comment); 13007 $metadata{genre} = remove_change_10_chars($Genre); 13008 $metadata{track} = $Track_Number =~ /^\d+$/ ? sprintf("%02d", $Track_Number ) : "" ; # "%02d": leading zero 13009 $metadata{total_track} = $Total_Track =~ /^\d+$/ ? sprintf("%02d", $Total_Track ) : "" ; 13010 $metadata{year} = $Year =~ /^\d{1,4}$/ ? sprintf("%04d", $Year ) : "" ; 13011 13012 # get all technical informations: 13013 $metadata{technical_info} = $Technical_Info; 13014 $metadata{bitrate} = $bitrate_original; 13015 $metadata{bitrate_nominal} = 160; # only for ogg 13016 $metadata{bitrate_average} = $bitrate_average; # $true or $false 13017 $metadata{frequency} = $Frequency; 13018 $metadata{mode} = $mode_channel; 13019 $metadata{length} = $Time_Min_Sec if ( $extension_input ne 'cda' ); 13020 $metadata{fileSize} = $fileSize; 13021} 13022 13023$buffer->create_tag ("id3tag", 'foreground' => 'blue', # see <man Gtk2::TextTag> for more options 13024 'background' => '#B8D3C1', # #B8D3C1 = 184 211 193 (RGB) 13025 'justification' => 'center', 13026 left_margin => 0, 13027 style => 'normal', 13028 wrap_mode => 'word', 13029 scale => '1', 13030 family => 'Courier', 13031 # family => 'Terminal', 13032 # family => 'Fixed', 13033 'size-points' => '11'); 13034 13035 13036sub save_ID3v2_mp3_tag { 13037 my ( $filepath, $title, $artist, $album, $year, $comment, $track, $Total_Track, $genre) = @_; 13038 my $tmpfile; my $copy; my $ID3v2 = ""; 13039 my $buf_size = 2048*1024; # the bigger the faster 13040 my $need_rewrite_file = $false; # to avoid rewriting the entire file 13041 13042 use constant MP3HEADERFLAG => 'ID3'; 13043 13044 my $unsync = 0; my $ext_header = 0; my $experimental = 0; my $footer = 0; 13045 # Masks for TAGS FLAGS 13046 use constant ID3FLAG_USYNC => '10000000'; # Unsynchronisation - (10000000) binary (bite 7) (the first bit) 13047 use constant ID3FLAG_EXT => '01000000'; # Extended header - (01000000) binary (bite 6) (the second bit) 13048 use constant ID3FLAG_EXP => '00100000'; # Experimental indicator - (00100000) binary (bite 5) (the third bit) 13049 use constant ID3FLAG_FOOT => '00010000'; # Footer present - (00010000) binary (bite 4) 13050 13051 if ( $Total_Track ne "" and $Total_Track =~ /^\d+$/ and $Total_Track >= $track ){ $track = $track."/".$Total_Track; } 13052 13053 #my $genre_number = get_genre_number($genre); 13054 # $genre .= " [$genre_number]" if (defined $genre_number); 13055 13056 my $enc_title = $title; 13057 my $enc_artist = $artist; 13058 my $enc_album = $album; 13059 my $enc_comment = $comment; 13060 my $enc_genre = $genre; 13061 my $enc_track = $track; 13062 my $enc_year = $year; 13063 13064 my $enc_Encoded = $metadata{'Encoded by'} if ($metadata{'Encoded by'}); 13065 my $enc_Lyrics = $metadata{'Lyrics'} if ($metadata{'Lyrics'}); 13066 my $enc_Composer = $metadata{'Composer'} if ($metadata{'Composer'}); 13067 my $enc_Length = $metadata{'Length'} if ($metadata{'Length'}); 13068 13069 my $char = $id3tag_character; # encode could be 'iso-8859-1' or 'utf8'. 13070 13071 if ( 1 ) { 13072 13073 $enc_title = encode($char,$title); 13074 $enc_artist = encode($char,$artist); 13075 $enc_album = encode($char,$album); 13076 $enc_comment = encode($char,$comment); 13077 $enc_genre = encode($char,$genre); 13078 $enc_track = encode($char,$track); 13079 $enc_year = encode($char,$year); 13080 13081 $enc_Encoded = encode($char,$metadata{'Encoded by'}) if ($metadata{'Encoded by'}); 13082 $enc_Lyrics = encode($char,$metadata{'Lyrics'}) if ($metadata{'Lyrics'}); 13083 $enc_Composer = encode($char,$metadata{'Composer'}) if ($metadata{'Composer'}); 13084 $enc_Length = encode($char,$metadata{'Length'}) if ($metadata{'Length'}); 13085 } 13086 13087 my $sz_tit = length($enc_title); # get size in byte 13088 my $sz_art = length($enc_artist); 13089 my $sz_alb = length($enc_album); 13090 my $sz_com = length($enc_comment); 13091 my $sz_gen = length($enc_genre); 13092 my $sz_tra = length($enc_track); 13093 my $sz_yea = length($enc_year); 13094 13095 my $sz_enc = length($enc_Encoded) if ($metadata{'Encoded by'}); 13096 my $sz_lyr = length($enc_Lyrics) if ($metadata{'Lyrics'}); 13097 my $sz_cps = length($enc_Composer) if ($metadata{'Composer'}); 13098 my $sz_len = length($enc_Length) if ($metadata{'Length'}); 13099 13100 my $tagSize = 0; 13101 do { 13102 use bytes; 13103 if ($year ne ""){ $tagSize += 10 + 1 + $sz_yea; } # More 10 (= header frame size) + 1 null 13104 if ($track ne ""){ $tagSize += 11 + $sz_tra; } 13105 if ($genre ne ""){ $tagSize += 11 + $sz_gen; } 13106 if ($artist ne ""){ $tagSize += 11 + $sz_art; } 13107 if ($album ne ""){ $tagSize += 11 + $sz_alb; } 13108 if ($title ne ""){ $tagSize += 11 + $sz_tit; } 13109 if ($metadata{'Encoded by'}){ $tagSize += 11 + $sz_enc; } 13110 if ($metadata{'Composer'} ){ $tagSize += 11 + $sz_cps; } 13111 if ($metadata{'Length'} ){ $tagSize += 11 + $sz_len; } 13112 if ($comment ne "" ){ $tagSize += 10 + 1 + 3 + 1 + $sz_com; } # 5 for <nul>XXX<nul>$comment, Language = 'XXX' 13113 if ($metadata{'Lyrics'} ){ $tagSize += 10 + 1 + 3 + 1 + $sz_lyr; } # 5 for <nul>XXX<nul>$Lyric, such that Language = 'XXX' 13114 }; 13115 13116 # 4.11. Comments (see id3v2.3.0.txt) 13117 # <Header for 'Comment', ID: "COMM"> 13118 # Text encoding $xx 13119 # Language $xx xx xx 13120 # Short content descrip. <text string according to encoding> $00 (00) 13121 # The actual text <full text string according to encoding> 13122 13123 # ID3v2.3.0 tags: 13124 # 'TIT2' => 'TITLE' ;; 'TPE1' => 'ARTIST', 13125 # 'TALB' => 'ALBUM' ;; 'TYER' => 'YEAR', 13126 # 'COMM' => 'COMMENT' ;; 'TRCK' => 'TRACKNUM', 13127 # 'TCON' => 'GENRE' ;; 'USLT' => 'Unsychronized lyric/text transcription' 13128 # TENC Encoded by 13129 # TSSE Software/Hardware and settings used for encoding 13130 # TLEN Length - The 'Length' frame contains the length of the audiofile in milliseconds, 13131 # TDAT Date - The 'Date' frame is a numeric string in the DDMM format containing the date for the recording. 13132 13133 # see <man perlopentut> 13134 open(FILE, '+<', filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 13135 13136 binmode FILE; 13137 seek(FILE, 0 , 0); 13138 13139 read FILE, my $header, 3; 13140 if ( $header ne MP3HEADERFLAG ){ $need_rewrite_file = $true; } 13141 13142 read FILE, my $bytes, 2; 13143 my ($major_version, $minor_version) = unpack 'c c', $bytes; 13144 # print " vers�o ID3v2.$major_version.$minor_version\n"; 13145 13146 read FILE, my $flag, 1; # flag has 1 byte = 8 bits 13147 my @bits = split //, unpack 'b8', $flag; 13148 if ($major_version >= 3) { # for ID3v2.3 or ID3v2.4 ... 13149 $unsync = $bits[7]; # my $buffer = unpack 'b8', $flag; $unsync = substr($buffer, 7, 1); 13150 $ext_header = $bits[6]; 13151 $experimental = $bits[5]; 13152 $footer = $bits[4] if $major_version == 4; 13153 } 13154 #print "unsync = $unsync ;; ext_head = $ext_header;; exp = $experimental;; footer = $footer \n"; 13155 13156 read FILE, my $original_sz, 4; 13157 $original_sz = $need_rewrite_file ? 512 : ID3_GET_SIZE28($original_sz); # if don't have ID3 tag 13158 #print "original size = $original_sz ;; tagSize = $tagSize\n"; 13159 13160# Overall tag ID3v2.4.0 - version structure: 13161 13162# +-----------------------------+ 13163# | Header (10 bytes) | 13164# +-----------------------------+ 13165# | Extended Header | 13166# | (variable length, OPTIONAL) | 13167# +-----------------------------+ The size is excluding the frame header ('total frame size' - 10 bytes) 13168# | Frames (variable length) | and stored as a 32 bit synchsafe integer only if version >= ID3v2.4.0 13169# +-----------------------------+ 13170# | Padding | Use padding where possible to avoid rewriting the entire 13171# | (variable length, OPTIONAL) | file if the metadata size changes. Paddings are null bytes. 13172# +-----------------------------+ 13173# | Footer (10 bytes, OPTIONAL) | Padding and a footer together are not allowed by the specifications. 13174# +-----------------------------+ 13175 13176# ID3v2 header - The ID3v2 tag header, which should be the first information in the file, is 10 bytes as follows: 13177# ID3v2/file identifier "ID3" 13178# ID3v2 version $03 00 13179# ID3v2 flags %abcd0000 13180# ID3v2 size 4 * %0xxxxxxx 13181 13182# The ID3v2 tag size is the sum of the byte length of the extended header, the padding and the frames after unsynchronisation. 13183# If a footer is present this equals to ('total size' - 20) bytes, otherwise ('total size' - 10) bytes. 13184# The ID3v2 tag size is stored as a 32 bit synchsafe integer, making a total of 28 effective bits (representing up to 256MB). 13185# Synchsafe integers are integers that keep its highest bit (bit 7) zeroed, making seven bits out of eight available. 13186# Thus a 32 bit synchsafe integer can store 28 bits of information. 13187# Example: 255 (%11111111) encoded as a 16 bit synchsafe integer is 383 (%00000001 01111111). 13188 13189# Since the ID3v2 tag doesn't contain a valid syncsignal, no software will attempt to play the tag. If, for any 13190# reason, coincidence make a syncsignal appear within the tag it will be taken care of by the 'unsynchronisation scheme'. 13191# Only 28 bits are used in the size description to avoid the introducuction of 'false syncsignals'. 13192 13193# ID3v2 flags %abcd0000 13194# a - Unsynchronisation (bit 7) 13195# b - Extended header (bit 6) 13196# c - Experimental indicator (bit 5) 13197# d - Footer present (bit 4) 13198 13199 # Dont't use synchsafe integer for frame size with ID3v2.3.0!!! 13200 #my $sz_tit_pack = ID3_SET_SIZE28( $sz_tit + 1); 13201 my $sz_yea_pack = reverse pack 'L', ( $sz_yea + 1); # The size is excluding the frame header ('total frame size' - 10 bytes) 13202 my $sz_tra_pack = reverse pack 'L', ( $sz_tra + 1); # If the frame size >= 128, then (length != length_sync) 13203 my $sz_gen_pack = reverse pack 'L', ( $sz_gen + 1); 13204 my $sz_art_pack = reverse pack 'L', ( $sz_art + 1); 13205 my $sz_alb_pack = reverse pack 'L', ( $sz_alb + 1); # + 1 null 13206 my $sz_tit_pack = reverse pack 'L', ( $sz_tit + 1); 13207 my $sz_enc_pack = reverse pack 'L', ( $sz_enc + 1) if (defined $sz_enc); 13208 my $sz_cps_pack = reverse pack 'L', ( $sz_cps + 1) if (defined $sz_cps); 13209 my $sz_len_pack = reverse pack 'L', ( $sz_len + 1) if (defined $sz_len); 13210 my $sz_com_pack = reverse pack 'L', ( $sz_com + 1 + 4); # 4 for XXX<nul> 13211 my $sz_lyr_pack = reverse pack 'L', ( $sz_lyr + 1 + 4) if (defined $sz_lyr); # 4 for XXX<nul> 13212 13213 # see <man perlfunc> 13214 # b: A bit string (ascending bit order inside each byte) 13215 # B: A bit string (descending bit order inside each byte). 13216 my $tagVersion = pack('C C', 3, 0 ); # version ID3v2.3.0 (for more compatibility) 13217 #my $tagFlags = pack('B8', ID3FLAG_FOOT ); # has a footer - optional -- 13218 my $tagFlags = pack('B8', 0 ); 13219 my $tagFlagsFrame = pack('B8 B8', 0, 0 ); 13220 my $min_size = maximum($tagSize,$original_sz); # print "-->min_size = $min_size\n"; 13221 if ( $original_sz < $tagSize ){ # my personal choice, min_size multiple of 512 13222 $need_rewrite_file = $true; 13223 $min_size = int($tagSize/512) * 512 + 512; # print "min_size = $min_size ;; tagSize = $tagSize\n"; 13224 } 13225 my $padding = $min_size - $tagSize; # print "padding = $padding\n"; # note that, always $padding >= 1 . 13226 my $tagSize_pack = ID3_SET_SIZE28($min_size); # $tagSize = n * 512 for n = 1,2,3,... 13227 my $total_size = $min_size + 10; # + 10 (if header) + 10 (if footer) 13228 13229 $ID3v2 = pack "a3a2a1a4", 'ID3', $tagVersion, $tagFlags, $tagSize_pack; #Header 13230 $ID3v2 .= pack "a4a4a2x1a${sz_tit}", 'TIT2', $sz_tit_pack, $tagFlagsFrame, ,$enc_title if ($title ne ""); 13231 $ID3v2 .= pack "a4a4a2x1a${sz_art}", 'TPE1', $sz_art_pack, $tagFlagsFrame, ,$enc_artist if ($artist ne ""); 13232 $ID3v2 .= pack "a4a4a2x1a${sz_alb}", 'TALB', $sz_alb_pack, $tagFlagsFrame, ,$enc_album if ($album ne ""); 13233 $ID3v2 .= pack "a4a4a2x1a${sz_gen}", 'TCON', $sz_gen_pack, $tagFlagsFrame, ,$enc_genre if ($genre ne ""); 13234 $ID3v2 .= pack "a4a4a2x1a${sz_yea}", 'TYER', $sz_yea_pack, $tagFlagsFrame, ,$enc_year if ($year ne ""); 13235 $ID3v2 .= pack "a4a4a2x1a${sz_tra}", 'TRCK', $sz_tra_pack, $tagFlagsFrame, ,$enc_track if ($track ne ""); 13236 $ID3v2 .= pack "a4a4a2x1a${sz_enc}", 'TENC', $sz_enc_pack, $tagFlagsFrame, ,$enc_Encoded if ($metadata{'Encoded by'}); 13237 $ID3v2 .= pack "a4a4a2x1a${sz_cps}", 'TCOM', $sz_cps_pack, $tagFlagsFrame, ,$enc_Composer if ($metadata{'Composer'}); 13238 $ID3v2 .= pack "a4a4a2x1a${sz_len}", 'TLEN', $sz_len_pack, $tagFlagsFrame, ,$enc_Length if ($metadata{'Length'}); 13239 $ID3v2 .= pack "a4a4a2x1a3x1a${sz_com}", 'COMM', $sz_com_pack, $tagFlagsFrame, ,'XXX', ,$enc_comment if ($comment ne ""); 13240 $ID3v2 .= pack "a4a4a2x1a3x1a${sz_lyr}", 'USLT', $sz_lyr_pack, $tagFlagsFrame, ,'XXX', ,$enc_Lyrics if ($metadata{'Lyrics'}); 13241 $ID3v2 .= pack "x${padding}"; 13242 #$ID3v2 .= pack "a3a2a1a4", '3DI', $tagVersion, $tagFlags, $tagSize_pack; #Footer is optional 13243 13244 # ID3 13245 13246 if ( $need_rewrite_file eq $true ){ 13247 my $n = $$; 13248 while (1) { # make one temp file 13249 13250 my $dir = -d filename_from_unicode $directory_output ? $directory_output : $home ; 13251 $tmpfile = "$dir/gnormalize-".$n.".temp"; 13252 13253 if ( open(TEMP, ">", filename_from_unicode $tmpfile ) ) { last; } 13254 if ( not -w filename_from_unicode $tmpfile ){ $status_bar->push($context_id, " $tmpfile ".$langs{msg012} ); die " $tmpfile ".$langs{msg012}; } 13255 $n++; 13256 } 13257 syswrite(TEMP, $ID3v2, $total_size ); 13258 13259 if ( $header ne MP3HEADERFLAG ){ seek(FILE, 0, 0); } # go to begining of file 13260 else { seek(FILE, $original_sz + 10, 0); } # to ignore the old ID3tagv2 at begining of file 13261 13262 # sysread FILEHANDLE,SCALAR,LENGTH,OFFSET -- Returns the number of bytes actually read, 0 at end of file, 13263 while ( my $ret = sysread(FILE, $copy, $buf_size) ) { 13264 syswrite(TEMP, $copy, $ret ); # make copy from FILE and paste to TEMP file 13265 } 13266 close(FILE); 13267 close(TEMP); 13268 13269 # To delete a file, use unlink : unlink ( "$filepath" ) or die "Can't delete $filepath: $!\n"; 13270 # Don't use rename (see man perlfunc) because rename c funtion fails on diferent mounted file systems. 13271 # rename($tmpfile, $filepath) || die "Can't rename temp file, leaving in $tmpfile, stopped"; 13272 my @cmd = ( 'mv', '-f', $tmpfile, $filepath ); # move (overwrite) the filepath 13273 exec_cmd_system2(@cmd); 13274 #print "use the temp file ; total size = $total_size ; original_sz = $original_sz\n"; 13275 } 13276 else{ 13277 seek(FILE, 0 , 0); # go to begining of filepath 13278 syswrite ( FILE, $ID3v2, $total_size ); # syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET 13279 close(FILE); 13280 #print "total size = $total_size\n"; 13281 } 13282 13283 #####-------------Print-Beautiful-Tag-------------##### 13284 print_beautiful_tag( Intro => "ID3v2.3.0 MP3 Tag (encode: $char)", 13285 filepath => $filepath, Title => $title, Artist => $artist, 13286 Album => $album, Year => $year, Comment => $comment, 13287 Genre => $genre, Track => $track, 13288 ); 13289} 13290 13291sub print_beautiful_tag { 13292 my %args = ( @_, # argument pair list goes here 13293 ); 13294 my $intro = $args{Intro}; my $title = $args{Title}; my $artist = $args{Artist}; 13295 my $album = $args{Album}; my $year = $args{Year}; my $comment = $args{Comment}; 13296 my $genre = $args{Genre}; my $track = $args{Track}; my $filepath = $args{filepath}; 13297 13298 insert_msg("\n$intro" , "small-black"); 13299 13300 $title = "Title : \"$title\" "; $artist = "Artist : \"$artist\""; 13301 $album = "Album : \"$album\" "; $comment = "Comment : \"$comment\""; 13302 $genre = "Genre : \"$genre\" "; $year = "Year : \"$year\""; 13303 13304 ###----------------------------------------------### 13305 # floor() and fmod() - See 'man POSIX' 13306 my $Total = maximum( 50 , floor( $window->allocation->width / 10 ) ) ; # max horizontal value 13307 $Total -= 1 if ( fmod($Total,2) != 0 ); # choose $Total always an even number. 13308 13309 # get length 13310 my $l_tit = length( $title ); my $l_art = length( $artist ); 13311 my $l_alb = length( $album ); my $l_com = length( $comment ); 13312 my $l_gen = length( $genre ); my $l_yea = length( $year ); 13313 13314 # get maximum from left and right side. 13315 my $max_left = maximum ($l_tit, $l_alb); my $max_right = maximum ($l_art, $l_com); 13316 $max_left = maximum ($max_left, $l_gen); $max_right = maximum ($max_right, $l_yea); 13317 13318 # if ($max_left + $max_right) is an odd number, then add +1 and make it an even number. 13319 $max_left += 1 if ( fmod( $max_left + $max_right, 2 ) != 0 and $max_left < $max_right ); 13320 $max_right += 1 if ( fmod( $max_left + $max_right, 2 ) != 0 and $max_left > $max_right ); 13321 13322 $Total = maximum ( $Total, $max_left + $max_right ); # $Total is always an even number. 13323 13324 my $dif_left = $max_left - floor($Total/2); my $dif_right = $max_right - floor($Total/2); 13325 #print "\$Total = $Total ; \$max_left = $max_left ; \$max_right = $max_right ; \$dif_left = $dif_left ; \$dif_right = $dif_right\n"; 13326 13327 my $size_left = floor($Total/2); # initial value that can be changed 13328 my $size_right = floor($Total/2); 13329 13330 if ( $dif_left > 0 and $dif_right < 0 ) { $size_left += $dif_left ; $size_right -= $dif_left ; } 13331 if ( $dif_left < 0 and $dif_right > 0 ) { $size_left -= $dif_right ; $size_right += $dif_right ; } 13332 13333 ###----------------------------------------------### 13334 13335 my $Intro = "File : \""; # has size equal to 9 spaces 13336 my $filep = $filepath . "\" (Track : $track)"; 13337 my $l_path = length( $filep ); 13338 13339 # set "..." like ".../file/path/for/long/filepath" if necessary. 13340 my $cut_file = $l_path > $Total - 9 ? "..." . reduce_length_size($filep, $Total - 9 - 3) : $filep ; 13341 $Intro .= $cut_file; 13342 13343 ###----------------------------------------------### 13344 13345 my $Intro2 = sprintf ("%-${Total}s", $Intro ); # s: spaces, see perlfunc - sprintf. 13346 my $title2 = sprintf ("%-${size_left}s", $title ); my $artist2 = sprintf ("%-${size_right}s", $artist ); 13347 my $album2 = sprintf ("%-${size_left}s", $album ); my $comment2 = sprintf ("%-${size_right}s", $comment ); 13348 my $track2 = sprintf ("%-${size_left}s", $genre ); my $year2 = sprintf ("%-${size_right}s", $year ); 13349 13350 insert_msg("\n$Intro2\n", "id3tag"); #print on debug textview 13351 insert_msg("${title2}${artist2}\n", "id3tag"); # 50 + 2 + 50 = 102 spaces 13352 insert_msg("${album2}${comment2}\n","id3tag"); 13353 insert_msg("${track2}${year2}", "id3tag"); 13354 insert_msg("\n", "small"); 13355} 13356 13357# For 32 bit synchsafe integer - The Synchsafe integers are integers that keep 13358# its highest bit (bit 7) zeroed, making seven bits out of eight available. 13359sub ID3_SET_SIZE28 { # 32 bit synchsafe. See <man perlop> 13360 my $size = shift; 13361 my ($a, $b, $c, $d); 13362 # Example1: 255 (%11111111) encoded as a 16 bit synchsafe integer is 383 (%00000001 01111111). 13363 # Example2: 128 (%10000000) encoded as a 16 bit synchsafe integer is 256 (%00000001 00000000). 13364 # The bit-shift operators (<< and >>) : 16 >> 1 = 8 , that is: 16 = (10000) in binary goes to 8 = (01000) 13365 # 255 >> 1 is equal to 127, because : 255 = (11111111) goes to 127 = (01111111) 13366 # $x >> 1 : every bit of the value stored in $x is shifted one place to the right. 13367 # $x & $y : - The values are converted to an integer, if necessary; 13368 # - Each bit of the left operand is compared to the corresponding bit of the right operand; 13369 # - If a pair of corresponding bits both have the value 1, the correponding bit of the 13370 # result is set to 1. Otherwise, the corresponding bit of the result is set to 0. 13371 13372 $d = $size & 0x7f; 13373 $c = ( $size >> 7 ) & 0x7f; # 0x7f (hexadecinal, base 16) = 127 (decimal, base 10) = 01111111 (binary, base 2) 13374 $b = ( $size >> 14 ) & 0x7f; # 0x7f = 127 = 01111111 13375 $a = ( $size >> 21 ) & 0x7f; 13376 13377 $size = pack "C C C C", $a, $b, $c, $d; # $a, $b, $c and $d are in decimal base. 13378 13379 #$a = sprintf( "%08b", $a ); # convert to binary base with 8 digits 13380 #$b = sprintf( "%08b", $b ); # convert to binary base with 8 digits 13381 #$c = sprintf( "%08b", $c ); # convert to binary base with 8 digits 13382 #$d = sprintf( "%08b", $d ); # convert to binary base with 8 digits 13383 #my $temp = "$a"."$b"."$c"."$d"; # binary with 32 digits 13384 #print "decimal = ",oct( "0b$temp" ),"\n"; 13385 #print "binary (32 bits) = $a $b $c $d \n"; 13386 13387 return $size; 13388} 13389# ID3_SET_SIZE28(2**13 + 2**14 + 2**15); # for test 13390 13391sub ID3_GET_SIZE28 { 13392 my ($x1, $x2, $x3, $x4) = unpack("C C C C", shift ); 13393 my $size = ($x4 & 0x7f) + ( ($x3 & 0x7f) << 7 ) + ( ($x2 & 0x7f) << 14 ) + ( ($x1 & 0x7f) << 21 ); 13394 # my $size = $x4 + ($x3 << 7) + ($x2 << 14) + ($x1 << 21); 13395 # if $x3 = 00000001 then $x3 << 7 = 10000000 (binary) = 128 (decimal) 13396 13397 #the same result with: 13398 #my @array = reverse unpack 'C4', shift; 13399 #foreach my $i (0 .. 3) { $size += $array[$i] * 128 ** $i; } 13400 13401 #print "x1 = $x1 ;; x2 = $x2 ;; x3 = $x3 ;; x4 = $x4 ;; size = $size\n"; 13402 return $size; 13403} 13404 13405sub remove_ID3v2_mp3_tag{ #not used 13406 my $fh; my $tag_size; my $file; 13407 13408 my $buf ||= 4096*1024; # the bigger the faster 13409 seek $fh, 0, 2; 13410 my $eof = tell $fh; 13411 my $off = $tag_size; 13412 13413 while ($off < $eof) { 13414 seek $fh, $off, 0; 13415 read $fh, my($bytes), $buf; 13416 seek $fh, $off - $tag_size, 0; 13417 print $fh $bytes; 13418 $off += $buf; 13419 } 13420 truncate $fh, $eof - $tag_size or die "Can't truncate '$file': $!"; 13421} 13422 13423 13424sub show_APE_tag { 13425 my %args = ( @_ ); 13426 my $extension_input = $args{extension_input}; my $row = $args{row}; my $filepath = $args{filepath}; 13427 #return if (not $extension_input eq 'ape' and not $extension_input eq 'mpc' and not $extension_input eq 'wav' ); 13428 return unless ( $extension_input =~ /(mpc|ape|wav)/i ); 13429 13430 my $Title=""; my $Artist=""; my $Album=""; my $Year=""; my $Comment=""; my $Track_Number=""; 13431 my $Total_Track = ""; my $Genre=""; 13432 13433 my $APEtag; my $APEtag_footer; my $Preample; 13434 my $version; my $tag_size; my $item_count; 13435 my $tag_flags; 13436 13437 open(IN, filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 13438 13439 # read APETAGEX footer, if it exist 13440 # split /PATTERN/,EXPR,LIMIT 13441 # seek FILEHANDLE,POSITION,WHENCE 13442 seek(IN,-32, 2); # read ( 8 + 4 * 4 + 8 ) = 32 byte from the end of file 13443 read(IN, $APEtag_footer, 32, 0); 13444 13445 $Preample = substr($APEtag_footer,0,8); 13446 if ( $Preample ne 'APETAGEX' ){ return $false; } 13447 #print "Preample = $Preample\n"; 13448 $APEtag_footer = substr($APEtag_footer, 8 ); 13449 13450 $version = substr($APEtag_footer,0,4); 13451 $version = unpack "L",$version; 13452 #print "version = $version\n"; 13453 $APEtag_footer = substr($APEtag_footer,4); 13454 13455 $tag_size = substr($APEtag_footer,0,4); 13456 $tag_size = unpack "L",$tag_size; 13457 #print "tag_size = $tag_size bytes\n"; 13458 $APEtag_footer = substr($APEtag_footer,4); 13459 13460 $item_count = substr($APEtag_footer,0,4); 13461 $item_count = unpack "L",$item_count; 13462 #print "item_count = $item_count\n"; 13463 $APEtag_footer = substr($APEtag_footer,4); 13464 13465 $tag_flags = substr($APEtag_footer,0,4); 13466 13467 my @bits = split //, unpack 'b32', $tag_flags; 13468 my $Contains_Header = $bits[31]; # @bits is an array ;; the first bit is $bits[0] 13469 my $Contains_Footer = $bits[30]; 13470 my $Is_Header = $bits[29]; 13471 13472 #print "Contains_Header = $Contains_Header ;; Contains_Footer = $Contains_Footer ;; Is_Header = $Is_Header\n"; 13473 13474 seek(IN,-$tag_size, 2); # set $tag_size bytes from the end of file 13475 read(IN, $APEtag, $tag_size - 32 , 0); # don't read the last 32 bytes 13476 13477 close(IN); 13478 13479 my $tagLen; 13480 my ($tag_key, $tag_val); 13481 my %taghash = (); 13482 my $tag_copy = $APEtag; 13483 13484 for (my $i=0;$i<$item_count;$i++){ 13485 $tagLen = substr($APEtag,0,4); 13486 $tagLen = unpack "L",$tagLen; 13487 $APEtag = substr($APEtag,8); 13488 #print "tagLen = $tagLen ;; APEtag = $APEtag\n"; 13489 13490 if ($APEtag =~ /^(.*?)\0/) { $tag_key = $1; } # \0 = 13491 #$tag_key =~ tr/A-Z/a-z/; #lower case 13492 $tag_key = lc($tag_key); #lower case 13493 $APEtag =~ s/^.*?\0//; #remove tag_key\0 13494 13495 $tag_val = substr $APEtag, 0, $tagLen; # read 13496 $tag_val = decode("utf8",$tag_val); 13497 $APEtag = substr $APEtag, $tagLen; # cut, remove 13498 13499 #print "tag_key = $tag_key ;; tag_val = $tag_val \n"; 13500 $taghash{$tag_key} = $tag_val; # Fill the hash 13501 if ( length($APEtag) <= 0 ){last;} 13502 } 13503 #print "Album = ",$taghash{Album},"\n\n"; 13504 #for my $key (keys %taghash) { print "$key => $taghash{$key}\n"; } 13505 13506 if ( defined($taghash{year}) ){ $Year = $taghash{year}; } 13507 if ( defined($taghash{artist}) ){ $Artist = $taghash{artist}; } 13508 if ( defined($taghash{title}) ){ $Title = $taghash{title}; } 13509 if ( defined($taghash{comment}) ){ $Comment = $taghash{comment}; } 13510 if ( defined($taghash{genre}) ){ $Genre = $taghash{genre}; } 13511 if ( defined($taghash{album}) ){ $Album = $taghash{album}; } 13512 if ( defined($taghash{track}) ){ $Track_Number = $taghash{track}; } 13513 13514 if ( defined($taghash{'encoded by'}) ){ $metadata{'Encoded by'} = $taghash{'encoded by'}; } 13515 if ( defined($taghash{'lyrics'}) ){ $metadata{'Lyrics'} = $taghash{'lyrics'}; } 13516 if ( defined($taghash{'composer'}) ){ $metadata{'Composer'} = $taghash{'composer'}; } 13517 13518 if( $Track_Number =~ /(\d+)\/(\d+)/ ){ $Track_Number = $1 ; $Total_Track = $2 ; } 13519 13520 $Track_Number = remove_change_10_chars($Track_Number); 13521 $Total_Track = remove_change_10_chars($Total_Track); 13522 13523 # get all the 8 tags 13524 $metadata{title} = remove_change_10_chars($Title); 13525 $metadata{artist} = remove_change_10_chars($Artist); 13526 $metadata{album} = remove_change_10_chars($Album); 13527 $metadata{comment} = remove_change_10_chars($Comment); 13528 $metadata{genre} = remove_change_10_chars($Genre); 13529 $metadata{track} = $Track_Number =~ /^\d+$/ ? sprintf("%02d", $Track_Number ) : "" ; # "%02d": leading zero 13530 $metadata{total_track} = $Total_Track =~ /^\d+$/ ? sprintf("%02d", $Total_Track ) : "" ; 13531 $metadata{year} = $Year =~ /^\d{1,4}$/ ? sprintf("%04d", $Year ) : "" ; 13532} 13533 13534 13535sub remove_apetag { 13536 my %args = ( @_ ); 13537 my $row = $args{row}; my $filepath = $args{filepath}; 13538 13539 my $Title = $files_info[$row]{title}; 13540 my $Artist = $files_info[$row]{artist}; 13541 my $Comment = $files_info[$row]{comment}; 13542 my $Album = $files_info[$row]{album}; 13543 my $Genre = $files_info[$row]{genre}; 13544 my $Year = $files_info[$row]{year}; 13545 my $Track_Number = $files_info[$row]{track}; 13546 my $Total_Track = $files_info[$row]{total_track}; 13547 13548 my $tag_size; my $tag_flags; my $APEfooter; my $preamble; 13549 13550 print "remove_apetag --> Could not find the file: \"$filepath\"\n" if( ! -e filename_from_unicode $filepath ); 13551 if (not -s filename_from_unicode $filepath) { $@ = "File is empty"; return undef; } 13552 13553 # see <man perlopentut> 13554 open(APE, "+<", filename_from_unicode $filepath ) || die "Can't open <$filepath>: $!, stopped"; 13555 13556 binmode APE; 13557 13558 seek(APE,-32, 2); # Set FileHandle 32 byte from the end of file 13559 read(APE, $APEfooter, 32, 0); # read 32 byte to $APEfooter 13560 13561 $preamble = substr($APEfooter,0,8); 13562 $preamble = unpack "a8",$preamble; 13563 if ( $preamble ne 'APETAGEX' ){ return; } 13564 #print "preamble = $preamble\n"; 13565 $APEfooter = substr($APEfooter,8 + 4); # + 4 byte (version) 13566 13567 $tag_size = substr($APEfooter,0,4); 13568 $tag_size = unpack "L",$tag_size; 13569 $APEfooter = substr($APEfooter,4 + 4); # + 4 byte (Item Counts) 13570 #print "tag_size = $tag_size\n"; 13571 13572 $tag_flags = substr($APEfooter,0,4); 13573 13574 my @bits = split //, unpack 'b32', $tag_flags; 13575 my $Contains_Header = $bits[31]; # @bits is an array ;; the first bit is $bits[0] 13576 my $Contains_Footer = $bits[30]; 13577 my $Is_Header = $bits[29]; 13578 13579 #print "Contains_Header = $Contains_Header ;; Contains_Footer = $Contains_Footer ;; Is_Header = $Is_Header\n"; 13580 13581 if ($Contains_Header){ $tag_size = $tag_size + 32; } # 32 bytes of headear 13582 13583 seek (APE, -$tag_size, 2); 13584 my $file_size = tell APE; # file_size - APEtag_size : get the current position 13585 13586 #read(APE, $APEfooter, $tag_size, 0); 13587 #print "tell = $file_size ;; APEtag = $APEfooter\n"; 13588 13589 truncate APE, $file_size or warn "Can't truncate \"$filepath\": $!"; 13590 13591 close(APE); 13592 13593 # see <man perlfunc> 13594 # tell Returns the current position in bytes for FILEHANDLE, 13595 # truncate FH,LENGTH : Truncates the file opened on FILEHANDLE to the specified length. 13596 # sysread FILEHANDLE,SCALAR,LENGTH,OFFSET ;; Returns the number of bytes actually read 13597 # syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET 13598 13599 #print "\n ---> remove_apetag ;; \$row = $row ;; \$filepath = $filepath ;; \$Title = $Title\n"; 13600} 13601 13602sub write_apetag { # 18Mai2008 13603 my %args = ( @_ ); 13604 my $row = $args{row}; my $filepath = $args{filepath}; 13605 13606 my $Title = $files_info[$row]{title}; 13607 my $Artist = $files_info[$row]{artist}; 13608 my $Comment = $files_info[$row]{comment}; 13609 my $Album = $files_info[$row]{album}; 13610 my $Genre = $files_info[$row]{genre}; 13611 my $Year = $files_info[$row]{year}; 13612 my $Track_Number = $files_info[$row]{track}; 13613 my $Total_Track = $files_info[$row]{total_track}; 13614 13615 my $Track; 13616 if ( $Total_Track ne "" and $Total_Track =~ /^\d+$/ and $Total_Track >= $Track_Number ){ $Track = $Track_Number."/".$Total_Track; } 13617 else { $Track = $Track_Number; } 13618 13619 my $char = 'utf8'; # encode to utf8 13620 13621 my $enc_Title = encode($char,$Title); 13622 my $enc_Artist = encode($char,$Artist); 13623 my $enc_Album = encode($char,$Album); 13624 my $enc_Comment = encode($char,$Comment); 13625 my $enc_Genre = encode($char,$Genre); 13626 my $enc_Track = encode($char,$Track); 13627 my $enc_Year = encode($char,$Year); 13628 13629 my $enc_Composer = encode($char,$metadata{'Composer'}) if ($metadata{'Composer'}); 13630 my $enc_Encoded = encode($char,$metadata{'Encoded by'}) if ($metadata{'Encoded by'}); 13631 my $enc_Length = encode($char,$metadata{'Length'}) if ($metadata{'Length'}); 13632 my $enc_Lyrics = encode($char,$metadata{'Lyrics'}) if ($metadata{'Lyrics'}); 13633 13634 my $tail; my $tag; my $tag_size; 13635 13636 # Masks for TAGS FLAGS 13637 use constant Contains_Header => 0x80000000; # hexdecimal 0x80 = 128 decimal = (10000000) binary (bite 8) 13638 use constant Contains_Footer => 0x40000000; # hexdecimal 0x40 = 64 decimal = (01000000) binary (bite 7) 13639 use constant Is_Header => 0x20000000; # hexdecimal 0x20 = 32 decimal = (00100000) binary (bite 6) 13640 13641 print "write_apetag --> Could not find the file: \"$filepath\"\n" if( ! -e filename_from_unicode $filepath ); 13642 if (not -s filename_from_unicode $filepath ) { print "File <$filepath> is empty: $@"; return undef; } 13643 13644 open(APETAG, ">>", filename_from_unicode $filepath ) or die "Can't open <$filepath>: $!, stopped"; 13645 binmode APETAG; 13646 13647 seek APETAG, 0, 2; # go to end of file : 2 to set it to EOF (End Of File) 13648 13649 my $sz_tit = length($enc_Title); # get size in byte 13650 my $sz_art = length($enc_Artist); 13651 my $sz_alb = length($enc_Album); 13652 my $sz_com = length($enc_Comment); 13653 my $sz_gen = length($enc_Genre); 13654 my $sz_tra = length($enc_Track); 13655 my $sz_yea = length($enc_Year); 13656 13657 my $sz_cps = length($enc_Composer) if ($metadata{'Composer'}); 13658 my $sz_enc = length($enc_Encoded) if ($metadata{'Encoded by'}); 13659 my $sz_len = length($enc_Length) if ($metadata{'Length'}); 13660 my $sz_lyr = length($enc_Lyrics) if ($metadata{'Lyrics'}); 13661 13662 my $tagTotalSize = 32; # + 32 bytes (Footer) 13663 my $items = 0; 13664 do { 13665 use bytes; 13666 if ($enc_Title ne ""){ $items ++; $tagTotalSize += 8 + length('Title') + 1 + $sz_tit; } 13667 if ($enc_Artist ne ""){ $items ++; $tagTotalSize += length('Artist') + $sz_art + 9; } 13668 if ($enc_Album ne ""){ $items ++; $tagTotalSize += length('Album') + $sz_alb + 9; } 13669 if ($enc_Comment ne ""){ $items ++; $tagTotalSize += length('Comment') + $sz_com + 9; } 13670 if ($enc_Genre ne ""){ $items ++; $tagTotalSize += length('Genre') + $sz_gen + 9; } 13671 if ($enc_Track ne ""){ $items ++; $tagTotalSize += length('Track') + $sz_tra + 9; } 13672 if ($enc_Year ne ""){ $items ++; $tagTotalSize += length('Year') + $sz_yea + 9; } 13673 13674 if ($metadata{'Composer'} ){ $items ++; $tagTotalSize += length('Composer') + $sz_cps + 9; } 13675 if ($metadata{'Encoded by'}){ $items ++; $tagTotalSize += length('Encoded by') + $sz_enc + 9; } 13676 if ($metadata{'Length'} ){ $items ++; $tagTotalSize += length('Length') + $sz_len + 9; } 13677 if ($metadata{'Lyrics'} ){ $items ++; $tagTotalSize += length('Lyrics') + $sz_lyr + 9; } 13678 }; 13679 13680 # L: An unsigned long value. --- see <man perlfunc> 13681 my $tagVersion = pack('L', 2000 ); # 2000: version 13682 $tagTotalSize = pack('L', $tagTotalSize ); # footer + all tag items 13683 my $tagTotalItems = pack('L', $items ); # 7 items : year,track,artist,...,comment 13684 my $tagGlobalFlags = pack('L', Is_Header + Contains_Header + Contains_Footer ); 13685 my $tagGlobalFlags2 = pack('L', Contains_Header + Contains_Footer ); 13686 13687 # initial - header 13688 # APETAGEX� 13689 13690 print APETAG pack "a8a4a4a4a4x8", 'APETAGEX', $tagVersion, $tagTotalSize, $tagTotalItems, $tagGlobalFlags; 13691 13692 if ($enc_Title ne ""){ print APETAG pack "a8a6a${sz_tit}", pack('L', $sz_tit ), 'Title', $enc_Title; } 13693 if ($enc_Artist ne ""){ print APETAG pack "a8a7a${sz_art}", pack('L', $sz_art ), 'Artist', $enc_Artist; } 13694 if ($enc_Album ne ""){ print APETAG pack "a8a6a${sz_alb}", pack('L', $sz_alb ), 'Album', $enc_Album; } 13695 if ($enc_Comment ne ""){ print APETAG pack "a8a8a${sz_com}", pack('L', $sz_com ), 'Comment', $enc_Comment; } 13696 if ($enc_Genre ne ""){ print APETAG pack "a8a6a${sz_gen}", pack('L', $sz_gen ), 'Genre', $enc_Genre; } 13697 if ($enc_Track ne ""){ print APETAG pack "a8a6a${sz_tra}", pack('L', $sz_tra ), 'Track', $enc_Track; } 13698 if ($enc_Year ne ""){ print APETAG pack "a8a5a${sz_yea}", pack('L', $sz_yea ), 'Year', $enc_Year; } 13699 13700 if ($metadata{'Composer'} ){ print APETAG pack "a8a9a${sz_cps}", pack('L', $sz_com ), 'Composer', $enc_Composer;} 13701 if ($metadata{'Encoded by'}){ print APETAG pack "a8a11a${sz_enc}",pack('L', $sz_enc ), 'Encoded by', $enc_Encoded; } 13702 if ($metadata{'Length'} ){ print APETAG pack "a8a7a${sz_len}", pack('L', $sz_len ), 'Length', $enc_Length; } 13703 if ($metadata{'Lyrics'} ){ print APETAG pack "a8a7a${sz_lyr}", pack('L', $sz_lyr ), 'Lyrics', $enc_Lyrics; } 13704 13705 print APETAG pack "a8a4a4a4a4x8", 'APETAGEX', $tagVersion, $tagTotalSize, $tagTotalItems, $tagGlobalFlags2; 13706 13707 # final - footer 13708 #APETAGEX� 13709 13710# from taglib-1.3.1: taglib/ape/ape-tag-format.txt --- Member of APE Tag 2.0 13711# http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html 13712#/===========================================================================\ 13713#| Preamble | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' } | 13714#|----------------|---------|------------------------------------------------| 13715#| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000 | 13716#|----------------|---------|------------------------------------------------| 13717#| Tag Size | 4 bytes | Tag size in bytes including footer and all tag | 13718#| | | items excluding the header (for 1.000 | 13719#| | | compatibility) | 13720#|----------------|---------|------------------------------------------------| 13721#| Item Count | 4 bytes | Number of items in the tag | 13722#|----------------|---------|------------------------------------------------| 13723#| Tag Flags | 4 bytes | Global flags | 13724#|----------------|---------|------------------------------------------------| 13725#| Reserved | 8 bytes | Must be zeroed | 13726#\===========================================================================/ 13727 13728 13729# APE Tag Flags 13730#/=================================================================\ 13731#| Contains Header | Bit 31 | 1 - has header | 0 - no header | 13732#|-----------------|-------------|---------------------------------| 13733#| Contains Footer | Bit 30 | 1 - has footer | 0 - no footer | 13734#|-----------------|-------------|---------------------------------| 13735#| Is Header | Bit 29 | 1 - is header | 0 - is footer | 13736#|-----------------|-------------|---------------------------------| 13737#| Undefined | Bits 28 - 3 | Undefined, must be zeroed | 13738#|-----------------|-------------|---------------------------------| 13739#| Encoding | Bits 2 - 1 | 00 - UTF-8 | 13740#| | | 01 - Binary Data * | 13741#| | | 10 - External Reference ** | 13742#| | | 11 - Reserved | 13743#|-----------------|-------------|---------------------------------| 13744#| Read Only | Bit 0 | 1 - read only | 0 - read/write | 13745#\=================================================================/ 13746 13747# http://www.hydrogenaudio.org/musepack/klemm/www.personal.uni-jena.de/%7Epfk/mpp/sv8/apevalue.html 13748# APE Tags Header 32 byte 13749# APE Tag Item 1 10 byte : APE tags items should be sorted ascending by size. 13750# APE Tag Item 2 10 byte 13751# ... 13752# APE Tag Item n 10 byte 13753# APE Tags Footer 32 byte 13754 13755 13756# Item: length key value 13757# APE Tag Item: 4 byte : Length len of the assigned value in bytes 13758# 4 byte : Item flags 13759# m byte : Item key, can contain ASCII characters from 0x20 (Space) up to 0x7E (Tilde) 13760# 1 byte : Item key terminator 0x00 13761# len byte : Item value, can be binary data or UTF-8 string 13762 13763 close(APETAG); 13764 #print "size = ",bin2dec(unpack('B32', '' )),"\n"; #219 13765 #print "genre = $Genre ;; size = $sz_gen \n"; 13766 #$tagGlobalFlags2 = bin2dec( unpack('B32', '�' ) ); 13767 #$tagGlobalFlags2 = pack('L', TF_HAS_HEADER ); 13768 #$tagGlobalFlags2 = bin2dec( unpack('B32', $tagGlobalFlags2 ) ); 13769 #print "tagGlobalFlags2 = $tagGlobalFlags2 ;;\n"; 13770 13771 #print "\n ---> write_apetag ;; \$row = $row ;; \$filepath = $filepath ;; \$Title = $Title ;; \$Album = $Album\n"; 13772 13773 #####-------------Print-Beautiful-Tag-------------##### 13774 print_beautiful_tag( Intro => "APE Tag 2.0 (encode: utf8)", 13775 filepath => $filepath, Year => $Year, 13776 Title => $Title, Artist => $Artist, 13777 Album => $Album, Comment => $Comment, 13778 Genre => $Genre, Track => $Track, 13779 ); # if ( $extension_input !~ /(wav)/ ); 13780} 13781 13782sub bin2dec { 13783 # see <man perlfunc> 13784 return unpack ('N', pack ('B32', substr(0 x 32 . shift, -32))); 13785} 13786 13787 13788sub get_genre_number{ 13789 my $genre = shift; 13790 my $genre_number; # 12 Other : default 13791 13792 if ( $genre =~ /^\d+$/ ){ # if $Genre is a number 13793 $genre_number = $genre; 13794 } 13795 else{ # if $genre is a reference name, get its number 13796 for my $key (keys %genre_hash) { 13797 # print "$key => $genre_hash{$key}\n"; 13798 if ( uc($genre_hash{$key}) eq uc($genre) ){ 13799 $genre_number = $key; 13800 last; 13801 } 13802 } 13803 } 13804 return $genre_number; 13805} 13806 13807 13808sub ppaths{ # print all selected paths 13809 my $tree_selection = $treeview_play->get_selection; 13810 my $model = $treeview_play->get_model; 13811 my @paths = $tree_selection->get_selected_rows; # sel = Gtk2::TreePath 13812 13813 foreach my $path (@paths) { 13814 $iter = $model->get_iter($path); 13815 next unless $iter; 13816 13817 my $selected = $model->get_value($iter,COLUMN_FILE); # track number 13818 my $row = $selected - 1; # $track-1; 13819 my $filepath = $files_info[$row]{filepath}; 13820 my $extension_input = $files_info[$row]{extension_input}; 13821 my $title = $files_info[$row]{title}; 13822 print "\$filepath = $filepath ; \$extension_input = $extension_input ; \$title = $title\n"; 13823 } 13824} 13825 13826# save_tag button of table31 13827sub save_tag { # sub cell_edited { 13828 13829 # get selected row from 'sub get_selection_tree' that will be used by 'sub change_tag' and 'sub save_tag' 13830 my $row = $files_info[0]{get_selection_row}; 13831 13832 return unless defined $row; 13833 13834 my $filepath = $files_info[$row]{filepath}; 13835 my $extension_input = $files_info[$row]{extension_input}; 13836 my %hash = determine_directory_and_filename_and_extension(row => $row); 13837 13838 my $cmd; 13839 13840 # the hash %temp_tags has temporary variables only used on 'sub change_tag'. 13841 $files_info[$row]{title} = $temp_tags{title}; 13842 $files_info[$row]{artist} = $temp_tags{artist}; 13843 $files_info[$row]{album} = $temp_tags{album}; 13844 $files_info[$row]{comment} = $temp_tags{comment}; 13845 $files_info[$row]{genre} = $temp_tags{genre}; 13846 $files_info[$row]{track} = $temp_tags{track}; 13847 $files_info[$row]{total_track} = $temp_tags{total_track}; 13848 $files_info[$row]{year} = $temp_tags{year}; 13849 13850 Set_this_changes_on_Treeview($filepath,$row) if ($files_info[$row]{extension_input} ne 'cda'); 13851 Set_this_changes_on_Treeview_cda($filepath,$row) if ($files_info[$row]{extension_input} eq 'cda'); 13852 13853 my $Title = $temp_tags{title}; 13854 my $Artist = $temp_tags{artist}; 13855 my $Comment = $temp_tags{comment}; 13856 my $Album = $temp_tags{album}; 13857 my $Genre = $temp_tags{genre}; 13858 my $Year = $temp_tags{year}; 13859 my $Track_Number = $temp_tags{track}; 13860 my $Total_Track = $temp_tags{total_track}; 13861 13862 #print "\n sub save_tag --->1 \$row = $row \$filepath = $filepath ;; \$Title = $Title ;; \$Album = $Album\n"; 13863 13864 #verify if the choosed file is valid 13865 if ( $extension_input eq 'mp3' ){ 13866 13867 save_ID3v2_mp3_tag($filepath, $Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Total_Track, $Genre ); 13868 13869 save_ID3v1_mp3_tag($filepath, $Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Genre ); 13870 } 13871 if ( $extension_input eq 'ogg' ){ 13872 if ($vorbiscomment_path eq "") { 13873 $status_bar->push($context_id, " vorbiscomment can't be found!"); 13874 return $false; 13875 } 13876 my @cmd_tag = ( $vorbiscomment_path, '--raw', '-t', "title=$Title", '-t', "artist=$Artist" ); 13877 push @cmd_tag, ( '-t', "genre=$Genre", '-t', "date=$Year", '-t', "album=$Album" ); 13878 if ( $Total_Track ne "" and $Total_Track >= $Track_Number ) { 13879 push @cmd_tag, ( '-t', "tracknumber=$Track_Number/$Total_Track" ); } 13880 else { push @cmd_tag, ( '-t', "tracknumber=$Track_Number" ); } 13881 push @cmd_tag, ( '-t', "description=$Comment", '-t', "comment=$Comment", '-w', filename_from_unicode $filepath ); 13882 13883 exec_cmd_system3(@cmd_tag); 13884 } 13885 if ( $extension_input eq 'flac' ){ 13886 if ($metaflac_path eq "") { 13887 $status_bar->push($context_id, " metaflac can't be found!"); 13888 return $false; 13889 } 13890 exec_cmd_system2( $metaflac_path, '--remove-all-tags', $filepath ); 13891 13892 # tag commands -- to see the entries: metaflac --list music.flac 13893 # obsolete, deprecated: --show-vc-field=Title ;; --set-vc-field=Title= 13894 # --no-utf8-convert decode("utf8",$1) 13895 13896 my @cmd = ( $metaflac_path, '--no-utf8-convert', "--set-tag=Title=$Title", "--set-tag=Artist=$Artist" ); 13897 push @cmd, ( "--set-tag=Album=$Album", "--set-tag=Date=$Year", "--set-tag=Description=$Comment", "--set-tag=Comment=$Comment" ); 13898 if ($Total_Track ne "" and $Total_Track >= $Track_Number){ 13899 push @cmd, ( "--set-tag=Tracknumber=$Track_Number/$Total_Track" ); } 13900 else { push @cmd, ( "--set-tag=Tracknumber=$Track_Number" ); } 13901 push @cmd, ( "--set-tag=Genre=$Genre", filename_from_unicode $filepath ); 13902 13903 exec_cmd_system3(@cmd); 13904 #print "\n save_tag --> \@cmd = @cmd\n"; 13905 } 13906 if ( $extension_input =~ /(mpc|ape|wav)/ ){ 13907 remove_apetag (%hash); 13908 write_apetag (%hash); 13909 } 13910 13911 my $info_cddb = ""; 13912 if ( $extension_input eq 'cda' ){ 13913 $info_cddb = save_cddb_info_to_home($row); # save info to "$home/.cddb/ ($dir/) $cddbid" 13914 $status_bar->push($context_id, " Saved tag to $info_cddb"); 13915 } 13916 else{ $status_bar->push($context_id, " $extension_input".$langs{msg062} ); } 13917 13918 $button_save_tag->set_sensitive($false); 13919 13920 #print "\n sub save_tag --->2 \$row = $row \$filepath = $filepath ;; \$Title = $Title ;; \$Album = $Album\n"; 13921} 13922 13923sub Set_this_changes_on_Treeview { 13924 my ($filepath,$row) = @_; 13925 my $model = $treeview_play->get_model; 13926 13927 my $Title = $files_info[$row]{title}; 13928 my $Artist = $files_info[$row]{artist}; 13929 my $Comment = $files_info[$row]{comment}; 13930 my $Album = $files_info[$row]{album}; 13931 my $Genre = $files_info[$row]{genre}; 13932 my $Year = $files_info[$row]{year}; 13933 my $Track_Number = $files_info[$row]{track}; 13934 my $Total_Track = $files_info[$row]{total_track}; 13935 13936 my @rows_with_same_files = (); 13937 for (my $row2 = 0; $row2 <= $#files_info; $row2++){ 13938 if ($filepath eq $files_info[$row2]{filepath}){ push @rows_with_same_files, $row2; } 13939 } 13940 # print "\@rows_with_same_files = @rows_with_same_files ; \$filepath = $filepath\n"; 13941 13942 foreach my $row2 (@rows_with_same_files){ 13943 my ($iter, $path) = get_iter_path_given_track_art_alb ( value => $row2 + 1, treeview => 'treeview_play', column => COLUMN_FILE ); 13944 13945 # set all the new 8 entries: 13946 $files_info[$row2]{title} = $Title; 13947 $files_info[$row2]{artist} = $Artist; 13948 $files_info[$row2]{album} = $Album; 13949 $files_info[$row2]{genre} = $Genre; 13950 $files_info[$row2]{comment} = $Comment; 13951 $files_info[$row2]{year} = $Year; 13952 $files_info[$row2]{track} = $Track_Number; 13953 $files_info[$row2]{total_track} = $Total_Track; 13954 13955 $model->set ($iter, COLUMN_ARTIST, $files_info[$row2]{artist}, # set value on model 13956 COLUMN_TITLE, $files_info[$row2]{title}, 13957 COLUMN_ALBUM, $files_info[$row2]{album}, 13958 COLUMN_TRACK, $files_info[$row2]{track}, # $Track_Number, 13959 COLUMN_YEAR, $files_info[$row2]{year}, 13960 ) if $iter; 13961 } 13962} 13963 13964sub Set_this_changes_on_Treeview_cda { 13965 my ($filepath,$row) = @_; 13966 my $model = $treeview_play->get_model; 13967 13968 my $Title = $files_info[$row]{title}; 13969 my $Artist = $files_info[$row]{artist}; 13970 my $Comment = $files_info[$row]{comment}; 13971 my $Album = $files_info[$row]{album}; 13972 my $Genre = $files_info[$row]{genre}; 13973 my $Year = $files_info[$row]{year}; 13974 my $Track_Number = $files_info[$row]{track}; 13975 my $Total_Track = $files_info[$row]{total_track}; 13976 13977 #print "\n Set_this_changes_on_Treeview_cda -->1 \$Title = $Title ;; \$Artist = $Artist ;; \$Album = $Album\n"; 13978 13979 # initial values 13980 if ( $Artist eq "" or not defined $Artist ) { $Artist = "artist"; } 13981 if ( $Album eq "" or not defined $Album ) { $Album = "album"; } 13982 if ( $Genre eq "" or not defined $Genre ) { $Genre = "Other"; } 13983 if ( $Year eq "" or not defined $Year ) { $Year = ""; } 13984 13985 for (my $row2 = 0; $row2 <= $#files_info; $row2++){ 13986 if ($files_info[$row2]{extension_input} ne 'cda'){last;} 13987 my ($iter, $path) = get_iter_path_given_track_art_alb ( value => $row2 + 1, treeview => 'treeview_play', column => COLUMN_FILE ); 13988 13989 # set all the new 8 entries: 13990 $files_info[$row2]{title} = $Title if ( $row2 == $row ); # change only the selected row 13991 $files_info[$row2]{artist} = $Artist if ( $row2 == $row or $files_info[$row2]{artist} eq 'artist' ); 13992 $files_info[$row2]{album} = $Album; 13993 $files_info[$row2]{genre} = $Genre; 13994 $files_info[$row2]{comment} = $Comment; 13995 $files_info[$row2]{year} = $Year; 13996 #$files_info[$row2]{track} = $Track_Number; 13997 #$files_info[$row2]{total_track} = $Total_Track; 13998 13999 $model->set ($iter, COLUMN_ARTIST, $files_info[$row2]{artist}, # set value on model 14000 COLUMN_TITLE, $files_info[$row2]{title}, 14001 COLUMN_ALBUM, $files_info[$row2]{album}, 14002 #COLUMN_TRACK, $files_info[$row2]{track}, # $Track_Number, 14003 COLUMN_YEAR, $files_info[$row2]{year}, 14004 ) if $iter; 14005 } 14006 #print "\n Set_this_changes_on_Treeview_cda -->2 \$Title = $Title ;; \$Artist = $Artist ;; \$Album = $Album\n"; 14007} 14008 14009#####-----------------------------------------------##### 14010 14011# get_info_from_entries from entry "Tag" of gnormalize for wave files 14012sub get_info_from_entries { # no more used! 14013 # get mp3/mp4 ... info to be saved on normalized file 14014 $Title = $entry_title->get_text; 14015 $Artist = $entry_artist->get_text; 14016 $Album = $entry_album->get_text; 14017 $Year = $entry_year->get_text; 14018 14019 $Track_Number = ""; $Total_Track = ""; 14020 if ( $entry_tn->get_text =~ /(\d+)/ ) { $Track_Number = $1; } 14021 if ( $entry_tt->get_text =~ /(\d+)/ ) { $Total_Track = $1; } 14022 14023 #print " tn = $Track_Number ;; Total_Track = $Total_Track \n"; 14024 $Comment = $entry_comment->get_text; 14025 $Genre = $ComboBoxEntry_genre->child->get_text; 14026} 14027 14028#####-----------------------------------------------##### 14029 14030##--------------------- Character ---------------------## 14031 14032# substitute the command <system()> by this sub routine <exec_cmd_system()> 14033# see man Encode. utf8, PerlIO, perlrun, ... 14034sub exec_cmd_system { # need capture the output 14035 my $cmd = shift; # $cmd is a string 14036 my $output; 14037 14038 open (CM, filename_from_unicode "$cmd 2>&1 |" ) or die "couldn't execute \"$cmd\": $!"; 14039 $/="\r"; ## start of loop 14040 while(<CM>){ $output = $_; } # $_ is the output of command 14041 $/="\n"; ## final of loop 14042 close(CM); 14043 return $output; 14044} 14045 14046sub exec_cmd_system2 { 14047 my @exec_argv = @_; 14048 14049 #$SIG{CHLD} = \&REAPER; # To reap/eliminate dead children ; see perlipc 14050 # see man perlfunc, perlfork, perlipc ; Learning Perl 14.6, 3a Ed. ; Perl Cookbook 16.10, 2a. Ed 14051 my $child_pid = fork(); 14052 die "fork() failed: $!" unless defined $child_pid; 14053 14054 # convert to local encoding 14055 for (my $i = 0; $i <= $#exec_argv ; $i++){ $exec_argv[$i] = filename_from_unicode $exec_argv[$i]; } 14056 14057 if( $child_pid == 0 ){ 14058 #Child process is here ; child process has a zero value 14059 open \*STDIN, '>/dev/null'; # see man perlopentut 14060 open \*STDOUT,'>/dev/null'; 14061 open \*STDERR,'>/dev/null'; 14062 exec @exec_argv; # see perlfunc 14063 die "cannot execute $exec_argv[0]: $!\n"; 14064 } 14065 #Parent process is here ; parent process has a nonzero value 14066 #print "\n exec_cmd_system2 --> \$child_pid = $child_pid ;; \@exec_argv = @exec_argv\n"; 14067 return; 14068} 14069 14070sub exec_cmd_system3 { # used by vorbiscomment and metaflac 14071 my @exec_argv = @_; 14072 my $child_pid = fork(); 14073 die "fork() failed: $!" unless defined $child_pid; 14074 14075 if( $child_pid == 0 ){ 14076 #Child process is here ; child process has a zero value 14077 open \*STDIN, '>/dev/null'; # see man perlopentut 14078 open \*STDOUT,'>/dev/null'; 14079 open \*STDERR,'>/dev/null'; 14080 exec @exec_argv; # see perlfunc 14081 die "cannot execute $exec_argv[0]: $!\n"; 14082 } 14083 return; 14084} 14085 14086# change, for exemple, '0,49' to '0.49'. 14087sub number_value{ 14088 my $nvalue = shift; 14089 $nvalue =~ s/,/./g; 14090 return $nvalue; 14091} 14092 14093sub print_local { 14094 print filename_from_unicode shift; 14095} 14096 14097#####-----------------------------------------------##### 14098 14099sub minimum { 14100 my $v1 = shift; 14101 my $v2 = shift; 14102 my $min = $v1 < $v2 ? $v1 : $v2 ; 14103 return $min; 14104} 14105 14106sub maximum { 14107 my $v1 = shift; 14108 my $v2 = shift; 14109 my $max = $v1 < $v2 ? $v2 : $v1; 14110 return $max; 14111} 14112 14113 14114# if ( the extension_input eq extension_output and $check_change_properties is not active 14115# and $check_button_overwrite is not active then make copy. 14116sub same_extension_overwrite { 14117 my %args = ( @_ ); 14118 my $filepath = $args{filepath}; my $file_wav = $args{file_wav}; 14119 my $directory = $args{directory}; 14120 14121 my @cmd; 14122 14123 #remove wav file if button_del_wav is active and $file_wav exist 14124 if ($check_button_del_wav->get_active and -e filename_from_unicode "$directory_output/$file_wav" ){ 14125 @cmd = ( 'rm', '-f', $directory_output.'/'.$file_wav ); 14126 14127 insert_msg("@cmd" , "small"); #print on debug textview 14128 insert_msg("\n" , "small"); 14129 14130 exec_cmd_system2(@cmd); 14131 } 14132 # if overwrite is active, don't need copy file 14133 if ( not $check_button_overwrite->get_active and (filename_from_unicode $directory ne filename_from_unicode $directory_final) ){ 14134 14135 # copy the mp3/mp4/ogg ... files (that don't need to normalize) to $directory_final 14136 @cmd = ( 'cp', '-f', $filepath, $directory_final ); 14137 14138 insert_msg("@cmd\n" , "small"); #print on debug textview 14139 insert_msg( $langs{msg056} , "small-red"); 14140 insert_msg("\n" , "small"); 14141 14142 exec_cmd_system2(@cmd); 14143 } 14144 if ( not $already_normalized ) { 14145 $pbar_n->set_fraction(0) ; 14146 my $sb = $spinner_sensi->get_value; 14147 14148 if ( abs($adjust) <= $sb and $norm_type ne "None" ){ 14149 14150 $sb = sprintf("%0.2f", $spinner_sensi->get_value); 14151 $sb = number_value($sb); # For example, change '0,57' by '0.57'. 14152 14153 $pbar_n->set_text( $langs{msg042} ); 14154 insert_msg( $langs{msg043} , "small"); 14155 insert_msg("|$adjust| <= $sb" , "small-red"); 14156 insert_msg( $langs{msg044} , "small"); 14157 insert_msg("\n-----*****-----" , "small-black"); 14158 insert_msg("\n", "small"); 14159 } 14160 else { $pbar_n->set_text( $langs{msg045} );} # for type = None 14161 } 14162 $pbar_encode->set_fraction(0) ; 14163 $pbar_encode->set_text( $langs{msg046} ); 14164 $status_bar->push($context_id, " "); 14165} 14166 14167sub finalize_process { #01May2008 14168 my %args = ( @_ ); 14169 my $row = $args{row}; 14170 my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; my $directory = $args{directory}; 14171 my $file_input = $args{filename}; 14172 my $file_output = $args{file_output}; 14173 14174 my @cmd; 14175 #print "\n finalize_process --> \$file_input = $file_input ;; \$file_output = $file_output ;; \$directory = $directory ;; \$directory_final = $directory_final\n"; 14176 14177 #remove wav file_input if button_del_wav is active and $file_wav exist and ... 14178 if ( $check_button_del_wav->get_active and -e filename_from_unicode "$directory_output/$file_wav" and 14179 (( not $button_output_wav->get_active ) or ( $button_output_wav->get_active and $directory_output ne $directory_final )) ) { 14180 14181 @cmd = ( 'rm', '-f', $directory_output.'/'.$file_wav ); 14182 14183 insert_msg( "\n$langs{msg089}\n" , "small-red"); # "Removing temporary file:" 14184 insert_msg("@cmd" , "small"); 14185 insert_msg("\n" , "small"); 14186 14187 exec_cmd_system2(@cmd); 14188 } 14189 # overwrite: yes or not? That is the question. 14190 # overwrite only if the encoding process have finished, that is, $normalize_button is active 14191 if ( $normalize_button->get_active and $check_button_overwrite->get_active and 14192 -w filename_from_unicode "$directory_final/$file_output" and 14193 ((-w filename_from_unicode $directory and $extension_input ne $extension_output) or (-w filename_from_unicode $directory.'/'.$file_input and $extension_input eq $extension_output)) and 14194 $directory_final ne $directory ){ 14195 14196 @cmd = ( 'mv', '-f', $directory_final.'/'.$file_output, $directory.'/'.$file_input ) if ($extension_input eq $extension_output); 14197 @cmd = ( 'mv', '-f', $directory_final.'/'.$file_output, $directory ) if ($extension_input ne $extension_output); 14198 14199 exec_cmd_system2(@cmd); # overwrite 14200 insert_msg("\n$langs{msg005}:", "small-red"); 14201 insert_msg("\n@cmd\n", "small"); 14202 14203 @cmd = ( 'rmdir', $directory_final ); # 'rmdir' fail if on different mounted file systems. 14204 exec_cmd_system2(@cmd); # remove the directory_final 14205 insert_msg("@cmd", "small"); 14206 insert_msg("\n", "small"); 14207 } 14208 14209 if ( $normalize_button->get_active and $check_button_overwrite->get_active and 14210 -w filename_from_unicode "$directory_final/$file_output" and 14211 not ((-w filename_from_unicode $directory and $extension_input ne $extension_output) or (-w filename_from_unicode $directory.'/'.$file_input and $extension_input eq $extension_output)) and 14212 $directory_final ne $directory and $extension_input ne 'cda' ){ 14213 14214 my $msg; 14215 $msg = "mv: cannot move \"$directory_final/$file_output\" to \"$directory/$file_output\": Permission denied" if ($extension_input eq $extension_output); 14216 $msg = "mv: cannot move \"$directory_final/$file_output\" to \"$directory/\": Permission denied" if ($extension_input ne $extension_output); 14217 14218 insert_msg("\n$msg", "small-red"); 14219 insert_msg("\n", "small"); 14220 } 14221 14222 ## set encoding on the final of process 14223 if ( $normalize_button->get_active ) { # the normalize button is active 14224 insert_msg("-----*****-----\n" , "small-green"); 14225 if ($button_output_wav->get_active){ $pbar_encode->set_fraction( 0 ); } 14226 else { $pbar_encode->set_fraction( 1 ); } 14227 } 14228 elsif ( -e filename_from_unicode "$directory_final/$file_output" ) { # if the file exists 14229 #remove normalized file not finished 14230 exec_cmd_system2( 'rm', '-f', $directory_final.'/'.$file_output ); 14231 } 14232} 14233 14234 14235# determine the values of 6 encode variables: ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) 14236# Don't need to determine $quality 14237 14238sub encode_settings { 14239 my %args = ( @_ ); 14240 my $row = $args{row}; my $extension_input = $args{extension_input}; 14241 14242 # get some technical informations: 14243 my $bitrate_original = $files_info[$row]{bitrate}; 14244 my $Frequency = $files_info[$row]{frequency}; 14245 my $bitrate_average = $files_info[$row]{bitrate_average}; 14246 my $mode_channel = $files_info[$row]{mode}; 14247 14248 my ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max); 14249 14250 # button "change properties" active 14251 if ( $check_change_properties->get_active ){ 14252 $mode = $ComboBox_mode->get_active_text; 14253 $encode = $ComboBox_encode_type->get_active_text; # refresh value 14254 if ( $extension_output eq 'mp3' ) { $bitrate = $spinner_bitrate_mp3->get_value_as_int(); }# for $encode = "average" 14255 elsif ( $extension_output eq 'mp4' ) { $bitrate = $spinner_bitrate_mp4->get_value_as_int(); }# for $encode = "average" 14256 elsif ( $extension_output eq 'ogg' ) { $bitrate = $spinner_bitrate_ogg->get_value_as_int(); }# for $encode = "average" 14257 $freq = number_value($ComboBox_freq->get_active_text); 14258 # for mp3 constant $bitrate is obtainned from $ComboBox_const_bitrate 14259 if ( $encode eq "constant" and $extension_output eq 'mp3' ) { $bitrate = $bitrate_constant;} 14260 $V = $spinner_V->get_value_as_int; # Vmp3 14261 $Vmp4 = $spinner_Vmp4->get_value; 14262 $Vogg = $spinner_Vogg->get_value; 14263 $Vmpc = $spinner_Vmpc->get_value; 14264 } 14265 # button "change properties" not active 14266 # decide if the bitrate of normalized files will be preserved 14267 else { 14268 $bitrate = $bitrate_original; # copy the value of original bitrate 14269 $freq = $Frequency; 14270 $encode = $bitrate_average ? "average" : "constant" ; # only this two possibility when button "change properties" is not active 14271 14272 if ( $extension_output eq 'mpc' ){ 14273 # estimating a fuction to find $Vmpc from $bitrate: $Vmpc = f($bitrate) 14274 my $x = number_value($bitrate_original); 14275 my $adjustm = 0.15*exp(-( ($x-160)^2 )/8000) ; 14276 $Vmpc = sprintf("%0.2f", ($x/29)*(1 - $adjustm) - 0.2 ); 14277 $Vmpc = number_value($Vmpc); 14278 #print("bitrate = $x; ajust = $adjustm; Vmpc = $Vmpc \n"); 14279 } 14280 if ( $extension_input =~ /(wav|cda|ape|flac)/ ){ 14281 $bitrate = 160; 14282 $freq = 44100; 14283 $Vogg = $V = 4.0; 14284 $Vmpc = 5.0; 14285 $Vmp4 = 200; 14286 $encode = "average"; 14287 } 14288 if ( $extension_input eq 'mp3' and defined $mode_channel ){ $mode = $mode_channel; } 14289 else { $mode = 'joint stereo'; } # $mode is only used by encode_wav_to_mp3() 14290 } 14291 $Vogg = sprintf("%0.1f", $Vogg ); $Vogg = number_value($Vogg); # only one digit 14292 $Vmpc = sprintf("%0.1f", $Vmpc ); $Vmpc = number_value($Vmpc); 14293 14294 $vb_Max = $ComboBox_Max->get_active_text; #refresh value 14295 $vb_Min = $ComboBox_Min->get_active_text; 14296 14297 # for MPEG-2 layer III sample frequencies (kHz): 16 24 22.05 14298 # bitrates (kbps): 8 16 24 32 40 48 56 64 80 96 112 128 144 160 14299 if ( $freq <= 24000 and $extension_output eq 'mp3') { 14300 $vb_Min = minimum($vb_Min, 160); 14301 $vb_Max = minimum($vb_Max, 160); 14302 $bitrate = minimum($bitrate, 160); 14303 } 14304 return ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max); 14305} 14306 14307##-----------------------CDDB--------------------------## 14308# See to <man CDDB_get> 14309# Read the Album, Artist and Track Titles 14310 14311sub get_cddb_info_from_internet { #26Abr2008 14312 14313 my %config; 14314 my $CDDB_server = $entry_CDDB_server->get_text; 14315 my $cddb_port = $spinner_cddb_port->get_value; 14316 my $cddb_transport = $ComboBox_cddb_transport->get_active_text; 14317 my %cd; 14318 14319 # following variables just need to be declared if different from defaults 14320 $config{CDDB_HOST}=$CDDB_server; # set cddb host ;; default = "freedb.freedb.org" 14321 $config{CDDB_PORT}=$cddb_port; # set cddb port 14322 $config{CDDB_MODE}=$cddb_transport; # set cddb mode: cddb or http 14323 $config{CD_DEVICE}="$audiodevice_path"; # set cd device 14324 14325 my $cddbid = $use_external_cddbget ? get_discids($audiodevice_path)->[0] : CDDB_get::Internal::get_discids($audiodevice_path)->[0]; 14326 $cddbid = sprintf("%08x", $cddbid); 14327 #print "\n\n get_cddb_info_from_internet --> \$cddbid = $cddbid\n\n "; 14328 14329 # user interaction welcome? 14330 $config{input}=0; # 1: ask user if more than one possibility 14331 # 0: no user interaction 14332 14333 my $info_cddb = ""; 14334 my $msg; 14335 14336 # ($Title,$Artist,$Album,$Comment,$Year,$Track_Number,$Total_Track,$Genre) ARE NOT Global variables 14337 # all the 8 tags 14338 my $Title = ""; 14339 my $Artist = "artist"; 14340 my $Album = "album"; 14341 my $Genre = "Other"; 14342 my $Comment = ""; 14343 my $Year = ""; 14344 my $Track_Number = ""; 14345 my $Total_Track = ""; 14346 14347 $info_cddb = get_cddb_info_from_home(); # return the cddb filename 14348 if ( $info_cddb ne "" and not $check_button_overwrite_cddb->get_active ){ 14349 $msg = $langs{msg020} . $info_cddb; 14350 return ( msg => $msg ); # not overwrite 14351 } 14352 else{ 14353 eval {%cd = $use_external_cddbget ? get_cddb(\%config) : CDDB_get::Internal::get_cddb(\%config);}; # get info from internet 14354 if($@) { 14355 if ( $info_cddb ne "" ) { $msg = $langs{msg071} . "$info_cddb."; } 14356 else { $msg = $langs{msg072}; } # " cddb: can't connect to internet!"; 14357 return ( msg => $msg ); # not overwrite 14358 } 14359 } 14360 $Artist = $cd{artist}; $Artist = remove_change_10_chars($Artist); 14361 $Album = $cd{title}; $Album = remove_change_10_chars($Album); 14362 $Genre = $cd{genre}; $Genre = remove_change_10_chars($Genre); 14363 $Year = $cd{year}; $Year = remove_change_10_chars($Year); 14364 $Total_Track = $cd{tno}; $Total_Track = remove_change_10_chars($Total_Track); 14365 14366 # initial values 14367 if ( $Artist eq "" or not defined $Artist ) { $Artist = "artist"; } 14368 if ( $Album eq "" or not defined $Album ) { $Album = "album"; } 14369 if ( $Genre eq "" or not defined $Genre ) { $Genre = "Other"; } 14370 if ( $Year eq "" or not defined $Year ) { $Year = ""; } 14371 14372 my $model = $treeview_play->get_model; 14373 14374 for (my $row=0; $row<=$Total_Track; $row++){ 14375 14376 my $track = sprintf("%02d", $row+1); 14377 my $titulo = $cd{track}->[$row]; # foreach my $titulo ( @{$cd{track}} ) { 14378 $titulo = remove_change_10_chars($titulo); 14379 14380 my $iter = $model->get_iter_from_string ("$row"); 14381 14382 # set all the new 8 entries: 14383 14384 eval { $titulo = filename_to_unicode $titulo; }; 14385 $files_info[$row]{title} = $titulo; 14386 14387 eval { $Artist = filename_to_unicode $Artist; }; 14388 $files_info[$row]{artist} = $Artist; 14389 14390 eval { $Album = filename_to_unicode $Album; }; 14391 $files_info[$row]{album} = $Album; 14392 14393 eval { $Genre = filename_to_unicode $Genre; }; 14394 $files_info[$row]{genre} = $Genre; 14395 14396 #$files_info[$row]{comment} = $Comment; 14397 $files_info[$row]{year} = $Year; 14398 #$files_info[$row]{track} = $Track_Number; 14399 #$files_info[$row]{total_track} = $Total_Track; 14400 14401 $model->set ($iter, COLUMN_ARTIST, $files_info[$row]{artist}, # set value on model 14402 COLUMN_TITLE, $files_info[$row]{title}, 14403 COLUMN_ALBUM, $files_info[$row]{album}, 14404 #COLUMN_TRACK, $files_info[$row]{track}, # $Track_Number, 14405 COLUMN_YEAR, $files_info[$row]{year}, 14406 ) if $iter; 14407 } 14408 save_cddb_info_to_home(0); # save info to "$home/.cddb/ ($dir/) $cddbid" 14409} 14410 14411 14412##-----------------------------------------------------## 14413 14414sub save_cddb_info_to_home { #26jan2008 14415 my $row = shift; 14416 return if ($files_info[$row]{extension_input} ne 'cda'); 14417 14418 my $Title = $files_info[$row]{title}; 14419 my $Artist = $files_info[$row]{artist}; 14420 my $Comment = $files_info[$row]{comment}; 14421 my $Album = $files_info[$row]{album}; 14422 my $Genre = $files_info[$row]{genre}; 14423 my $Year = $files_info[$row]{year}; 14424 my $Track_Number = $files_info[$row]{track}; 14425 my $Total_Track = $files_info[$row]{total_track}; 14426 14427 my $info_cddb = undef; #filename of $info_cddb saved at $home 14428 14429 # Get ID number of CD. 14430 my $cddbid = $use_external_cddbget ? get_discids($audiodevice_path)->[0] : CDDB_get::Internal::get_discids($audiodevice_path)->[0]; 14431 $cddbid = sprintf("%08x", $cddbid); 14432 14433 #print "\n\n save_cddb_info_to_home --> \$cddbid = $cddbid\n\n "; 14434 14435 # -d : if file is a directory 14436 if ( -d filename_from_unicode "$home/.cddb" ){ 14437 opendir(DIR, filename_from_unicode "$home/.cddb" ) or die "couldn't execute opendir: $!\n";; #search for $home/.cddb/$Genre/ directory 14438 while (my $direct = readdir(DIR)) { 14439 next if $direct eq "."; 14440 next if $direct eq ".."; 14441 if ( -e filename_from_unicode "$home/.cddb/$direct/$cddbid" ){ 14442 $info_cddb = "$home/.cddb/$direct/$cddbid"; 14443 last; 14444 } 14445 } 14446 closedir(DIR); 14447 } 14448 # make the directory "$home/.cddb/$Genre" if it not exist 14449 # if the file "$home/.cddb/$direct/$cddbid" don't exist, make the file "$home/.cddb/$Genre/$cddbid". 14450 if ( not defined $info_cddb ){ 14451 my @cmd = ( 'mkdir', '-p', $home.'/.cddb/'.$Genre ); # create the directory .cddb/$Genre 14452 exec_cmd_system2(@cmd); 14453 14454 $info_cddb = "$home/.cddb/$Genre/$cddbid"; 14455 insert_msg("Saved cddb file to $info_cddb", "small"); 14456 insert_msg("\n", "small"); 14457 } 14458 14459 my $first_artist = $files_info[0]{artist}; 14460 my $DiscArtist = $first_artist; 14461 my $multi_artist = $false; 14462 14463 for (my $row=0; $row <= $#files_info ; $row++){ # determine if the CD is multi artist 14464 if ($files_info[$row]{extension_input} ne 'cda' ){last;} 14465 if ($files_info[$row]{artist} eq 'artist'){next;} 14466 if ( uc($first_artist) ne uc($files_info[$row]{artist}) ){$multi_artist = $true;} 14467 } 14468 14469 # See 'man perlopentut' for '+>' to specify both read and write access 14470 open( CDDB, '+>', "$info_cddb" ) or die "Can not write to $info_cddb: $!"; 14471 print CDDB "# created by gnormalize - version $VERSION\n"; 14472 print CDDB "# homepage: $HOMEPAGE\n\n"; 14473 print CDDB "DISCID=$cddbid\n"; 14474 print CDDB "DTITLE=$DiscArtist / $Album\n"; 14475 print CDDB "DYEAR=$Year\n"; 14476 print CDDB "DGENRE=$Genre\n"; 14477 14478 # fill the music titles and artist name 14479 for (my $row=0; $row <= $#files_info ; $row++){ 14480 if ($files_info[$row]{extension_input} ne 'cda'){last;} 14481 print CDDB "TTITLE$row=$files_info[$row]{title}\n"; 14482 print CDDB "TARTIST$row=$files_info[$row]{artist}\n" if $multi_artist; 14483 } 14484 close CDDB; 14485 14486 # some programs search for cddbid at "$home/.cddb/$cddbid", then make a symbolic link. 14487 # symlink OLDFILE,NEWFILE ;; see perlfunc 14488 my $symlink_exists = eval { symlink( $info_cddb,"$home/.cddb/$cddbid" ); 1 }; 14489 if ( $symlink_exists != 1 ){ link $info_cddb,"$home/.cddb/$cddbid"; } 14490 14491 my $model = $treeview_play->get_model; 14492 for (my $row=0; $row<=$#files_info;$row++){ 14493 next if ($files_info[$row]{extension_input} ne 'cda'); 14494 my $iter = $model->get_iter_from_string ("$row"); 14495 14496 $files_info[$row]{filepath} = make_filepath_format_for_cda($row); 14497 $files_info[$row]{filename} = make_filename_format_for_cda($row); 14498 $files_info[$row]{directory_remain} = remove_directory_base($audiodevice_path,$files_info[$row]{filepath}); # mar2008 14499 14500 $model->set ($iter, COLUMN_FILEPATH, $files_info[$row]{filepath}, 14501 COLUMN_FILENAME, $files_info[$row]{filename}, 14502 ) if $iter; 14503 } 14504 14505 my %hash = determine_directory_and_filename_and_extension(row => $row); 14506 set_output_and_refresh_progress_bar(%hash); 14507 14508 show_scrolling_text(); # Display the "Artist - Title - Album ..." 14509 make_artist_and_album_treeview_column( make_artist_column => $true, make_album_column => $true, array_with_tracks => \@files_info ); 14510 14511 #print "\n save_cddb_info_to_home --> \$DiscArtist = $DiscArtist ;; \$Album = $Album\n"; 14512 14513 return $info_cddb; # the filename 14514} 14515 14516##-----------------------------------------------------## 14517 14518# Get cddb info and return the cddb filename 14519sub get_cddb_info_from_home { 14520 my $model = $treeview_play->get_model; 14521 my $info_cddb = ""; #filename 14522 14523 # Get ID number and track number of CD. 14524 my $cddbid = $use_external_cddbget ? get_discids($audiodevice_path)->[0] : CDDB_get::Internal::get_discids($audiodevice_path)->[0]; 14525 $cddbid = sprintf("%08x", $cddbid); 14526 my $tracks = $use_external_cddbget ? get_discids($audiodevice_path)->[1] : CDDB_get::Internal::get_discids($audiodevice_path)->[1]; 14527 #print "cddbid = $cddbid ;; tracks = $tracks ;; home - $home \n"; 14528 14529 # -d : if file is a directory 14530 if ( -d "$home/.cddb" ){ 14531 opendir(DIR, "$home/.cddb" ) or die "couldn't execute opendir: $!\n"; #search for $genre/$cddbid file 14532 while (my $dir = readdir(DIR)) { 14533 next if $dir eq "."; 14534 next if $dir eq ".."; 14535 if ( -e filename_from_unicode "$home/.cddb/$dir/$cddbid" ){ 14536 $info_cddb = "$home/.cddb/$dir/$cddbid"; 14537 #print "-->dir = $dir ;; info_cddb = $info_cddb\n"; 14538 last; 14539 } 14540 #print "dir = $dir ;; info_cddb = $info_cddb\n"; 14541 } 14542 closedir(DIR); 14543 } 14544 14545 # the file "$home/.cddb/$cddbid" have less preference than "$home/.cddb/$dir/$cddbid" 14546 if ( -e filename_from_unicode "$home/.cddb/$cddbid" and $info_cddb eq "" ){$info_cddb = "$home/.cddb/$cddbid";} 14547 if ( $info_cddb eq "" ){ return $info_cddb;} # no file found 14548 #print "\$info_cddb = $info_cddb\n"; 14549 14550 #input: 14551 #DISCID=29107b14 14552 #DTITLE=Alceu Valenca / Focus 14553 #DYEAR=1999 14554 #DGENRE=unknown 14555 #DID3=12 14556 #TTITLE0=Estacao da luz 14557 #TARTIST0=Claudio # if have multi artist 14558 #TTITLE1=petalas 14559 #TARTIST1=Alceu 14560 #TTITLE2=leque moleque 14561 #TARTIST2=Jo�o 14562 14563 # ($Title,$Artist,$Album,$Comment,$Year,$Track_Number,$Total_Track,$Genre) ARE NOT Global variables 14564 # all the 8 tags 14565 my $Title = ""; 14566 my $Artist = "artist"; 14567 my $Album = "album"; 14568 my $Genre = "Other"; 14569 my $Comment = ""; 14570 my $Year = ""; 14571 my $Track_Number = ""; 14572 my $Total_Track = ""; 14573 14574 my @ttitle; my @tartist; 14575 14576 ## 26jan2008 14577 open( INFOCDDA, "<", $info_cddb ) or die "Can't open <$info_cddb>: $!, stopped"; # read from file 14578 while( <INFOCDDA> ) # Get Artist/Album/Year/Genre/title info. 14579 { 14580 if ($_ =~ /DTITLE=\s*(.*)\s*\/\s*(.*)\s*\n/gi){ 14581 $Artist = remove_whitespace_character($1); 14582 $Album = remove_whitespace_character($2); } 14583 if ($_ =~ /DYEAR=(\d{4})\n/i){ $Year = $1; } 14584 if ($_ =~ /DGENRE=(.*)\n/i){ $Genre = $1; } 14585 if ($_ =~ /TITLE(\d+)=(.*)\n/i){ $ttitle[$1] = remove_whitespace_character($2); } 14586 if ($_ =~ /ARTIST(\d+)=(.*)\n/i){ $tartist[$1] = remove_whitespace_character($2); } #multi artist 14587 } 14588 close(INFOCDDA); 14589 14590 # initial values 14591 if ( $Artist eq "" or not defined $Artist ) { $Artist = "artist"; } 14592 if ( $Album eq "" or not defined $Album ) { $Album = "album"; } 14593 if ( $Genre eq "" or not defined $Genre ) { $Genre = "Other"; } 14594 if ( $Year eq "" or not defined $Year ) { $Year = ""; } 14595 14596 $Artist = remove_change_10_chars($Artist); 14597 $Album = remove_change_10_chars($Album); 14598 $Genre = remove_change_10_chars($Genre); 14599 $Year = remove_change_10_chars($Year); 14600 14601 eval { $Album = filename_to_unicode $Album; }; 14602 eval { $Genre = filename_to_unicode $Genre; }; 14603 14604 for (my $row=0; $row<=$#files_info;$row++){ 14605 14606 next if ($files_info[$row]{extension_input} ne 'cda'); 14607 my $iter = $model->get_iter_from_string ("$row"); 14608 14609 $files_info[$row]{comment} = ""; 14610 $files_info[$row]{genre} = $Genre; 14611 $files_info[$row]{total_track} = $#files_info + 1; # $Total_Track 14612 14613 my $art = defined $tartist[$row] ? $tartist[$row] : $Artist; 14614 $art = remove_change_10_chars($art); 14615 eval { $art = filename_to_unicode $art; }; 14616 $files_info[$row]{artist} = $art; 14617 $model->set ($iter, COLUMN_ARTIST, $files_info[$row]{artist}); 14618 14619 if ( defined $ttitle[$row] ){ 14620 $ttitle[$row] = remove_change_10_chars( $ttitle[$row] ); 14621 eval { $ttitle[$row] = filename_to_unicode $ttitle[$row]; }; 14622 $files_info[$row]{title} = $ttitle[$row]; 14623 $model->set ($iter, COLUMN_TITLE, $files_info[$row]{title}); 14624 } 14625 14626 $files_info[$row]{album} = $Album; 14627 $model->set ($iter, COLUMN_ALBUM, $files_info[$row]{album}); 14628 14629 $files_info[$row]{year} = $Year; 14630 $model->set ($iter, COLUMN_YEAR, $files_info[$row]{year}); 14631 } 14632 for (my $row=0; $row<=$#files_info;$row++){ 14633 if ($files_info[$row]{extension_input} ne 'cda'){next;} 14634 14635 my $iter = $model->get_iter_from_string ("$row"); 14636 14637 $files_info[$row]{filepath} = make_filepath_format_for_cda($row); 14638 $files_info[$row]{filename} = make_filename_format_for_cda($row); 14639 $files_info[$row]{directory_remain} = remove_directory_base($audiodevice_path,$files_info[$row]{filepath}); # mar2008 14640 14641 $model->set ($iter, COLUMN_FILEPATH, $files_info[$row]{filepath}, 14642 COLUMN_FILENAME, $files_info[$row]{filename}, 14643 ) if $iter; 14644 } 14645 return $info_cddb; 14646} 14647 14648sub remove_whitespace_character { 14649 my $char = shift; 14650 $char =~ s/^\s*//; # remove the \s whitespace character at the first position. 14651 $char =~ s/\s*$//; # remove the \s whitespace character at the end position. 14652 $char =~ s/\s+/ /g; # replace more than one \s whitespace character by only one. 14653 return $char; 14654} 14655 14656##-----------------------------------------------------## 14657 14658# cda --> wav ; rip audio cd with cdparanoia 14659 14660sub refresh_cda { 14661 $audiodevice_path = $entry_cda->get_text; # /dev/hdc or /dev/cdrom or ... 14662 stop_playing_music(); 14663 14664 # make 3 arrays with frames of audio cd and return $total_frames number. 14665 # The 3 arrays are @length, @music_sector and @start_sector. 14666 my %hash = length_music_sector(); 14667 my $total_frames = $hash{total_frames} if $hash{total_frames}; 14668 my $msg = $hash{msg} if $hash{msg}; 14669 14670 print filename_from_unicode "\n\n ---> \$msg = $msg\n\n" if $msg; 14671 #print "\n\$ ---> total_frames = $total_frames\n\n" if $total_frames; 14672 14673 # get the old model from Gtk2::TreeView 14674 # clear the old model - see <man Gtk2::ListStore> 14675 $treeview_play->get_model->clear; 14676 $treeview_album->get_model->clear; 14677 $treeview_artist->get_model->clear; 14678 14679 #print "\n refresh_cda ---> aqui\n"; 14680 14681 # create the new tree model 14682 my $model = create_model_audio_cd(@length); # and fill the @files_info 14683 14684 # refresh tree view 14685 $treeview_play->set_model($model); 14686 count_artists_and_album_already_played(update_model_artist => $false, update_model_album => $false); 14687 14688 # add columns to the tree view 14689 add_columns(show_file => $false, show_play => $false); 14690 14691 if ( defined $files_info[0]{filepath} and $total_frames > 0 ){ # exist, at least, one audiocd track 14692 $force_unselect_all_tracks = $false; # to select all tracks 14693 unselect_cda(); # subroutine that select all tracks 14694 $button_unselec->set_sensitive($true); 14695 $button_selec->set_sensitive($true); 14696 if ( defined $cdcd_path or $use_audiocd eq $true or $os =~ /Linux/i ){ 14697 $da->set_sensitive($true); 14698 @rows_already_played = (); 14699 $go_forward = $false; 14700 $go_back = $false; 14701 $have_current_track = audio_cd_have_current_track($audiodevice_path) 14702 if ($use_audiocd and $cdplayer eq "Audio::CD"); 14703 } 14704 $normalize_button->set_label("rip + normalize + encode"); 14705 change_font_for_all_child($window_font_name,$normalize_button); 14706 14707 $button_save_tag->set_sensitive($false); 14708 14709 my %hash_cddb; 14710 14711 if ( $check_button_cddb->get_active ){ 14712 $status_bar->push($context_id, $langs{msg068} ); # " Getting information from cddb ..."; 14713 while (Gtk2->events_pending()) { Gtk2->main_iteration()}; 14714 %hash_cddb = get_cddb_info_from_internet(); 14715 $msg = $hash_cddb{msg}; 14716 } 14717 else { $msg = $langs{msg069}; } 14718 14719 get_selection_tree(); # select the first file and get info from file 14720 14721 print_cdparanoia_output($total_frames); 14722 show_scrolling_text(); # Display the "Artist - Title - Album ..." 14723 } 14724 else { entry_cda_change(); } 14725 14726 make_artist_and_album_treeview_column( make_artist_column => $true, make_album_column => $true, array_with_tracks => \@files_info ); 14727 14728 # verify if some ripper is available. 14729 if ( $ripper eq "cdparanoia" and not $cdparanoia_path ){ 14730 $status_bar->push($context_id, $langs{msg073} ); 14731 $extension_input = 'error'; 14732 return $false; 14733 } 14734 elsif ( $ripper eq "cdda2wav" and not $cdda2wav_path ){ 14735 $status_bar->push($context_id, $langs{msg074} ); 14736 $extension_input = 'error'; 14737 return $false; 14738 } 14739 # show final msg 14740 $status_bar->push($context_id, $msg ) if $msg; 14741} 14742 14743sub entry_cda_change { 14744 $button_selec->set_sensitive($false); 14745 $button_unselec->set_sensitive($false); 14746 $da->set_sensitive($false); 14747 $extension_input = 'error'; # rip audio cd is not possible 14748 stop_playing_music(); 14749 #if ( defined($timer) ){ Glib::Source->remove($timer);} # quit loop, see <man Glib::MainLoop> 14750 14751 # erase all info 14752 14753 # clear the old model - see <man Gtk2::ListStore> 14754 $treeview_play->get_model->clear; 14755 $treeview_album->get_model->clear; 14756 $treeview_artist->get_model->clear; 14757 14758 my $row = 0; 14759 14760 # erase all technical informations: 14761 $files_info[$row]{extension_input} = 'mp3'; 14762 $files_info[$row]{technical_info} = "MPEG"; # standard value 14763 $files_info[$row]{bitrate_original} = 160; # standard value if "change properties" is not active 14764 $files_info[$row]{bitrate_average} = $true; # $true or $false 14765 $files_info[$row]{mode} = ''; 14766 $files_info[$row]{length} = ''; 14767 $files_info[$row]{bitrate} = undef; 14768 $files_info[$row]{frequency} = undef; 14769 $files_info[$row]{fileSize} = undef; 14770 14771 # erase all the 8 tags 14772 $files_info[$row]{title} = ""; 14773 $files_info[$row]{artist} = ""; 14774 $files_info[$row]{album} = ""; 14775 $files_info[$row]{track} = ""; # track = track_number 14776 $files_info[$row]{total_track} = ""; 14777 $files_info[$row]{comment} = ""; 14778 $files_info[$row]{year} = ""; 14779 $files_info[$row]{genre} = ""; 14780 14781 set_tag_info($row); 14782 14783 # erase progress bar names 14784 $pbar->set_text(" "); $pbar->set_fraction(0); 14785 $pbar_n->set_text(" "); $pbar_n->set_fraction(0); 14786 $pbar_encode->set_text(" "); $pbar_encode->set_fraction(0); 14787 14788 my %hash = determine_directory_and_filename_and_extension(row => $row); 14789 refresh_input_output_arrows(); 14790 $status_bar->push($context_id, "" ); 14791 14792 $normalize_button->set_label("normalize"); 14793 14794 @files_info = (); # reset the array 14795 %albums_already_played = (); # reset the hash whose key is only the played album name 14796 %artists_already_played = (); # reset the hash whose key is only the played artist name 14797 @length = (); # array of music length 14798 @music_sector = (); # array of relative frames 14799 @start_sector = (); # absolute frames - 150 (offset) 14800 $selected_row = 0; 14801} 14802 14803sub length_music_sector { # make this 3 arrays 14804 @length = (); # array of music length 14805 @music_sector = (); # array of relative frames 14806 @start_sector = (); # absolute frames - 150 14807 my $total_frames = 0; 14808 my $msg; 14809 my $channel; 14810 14811 if ($os =~ /Linux/i) { 14812 $toc_audiocd = gnormalize::cdplay::read_toc($cdplayer); # toc of audiocd, array of reference 14813 if ( not $toc_audiocd ){ # can't read the cdrom drive 14814 $button_selec->set_sensitive($false); 14815 $da->set_sensitive($false); 14816 $msg = $langs{msg067}."$audiodevice_path."; 14817 return ( total_frames => $total_frames, msg => $msg ); 14818 } 14819 my $total_track = $toc_audiocd->[0]->{total_track}; 14820 $channel = 2; 14821 for (my $i = 1; $i <= $total_track; $i++) { 14822 my $min = $toc_audiocd->[$i]->{min}; 14823 my $sec = $toc_audiocd->[$i]->{sec}; 14824 push @length ,"$min:$sec" ; 14825 push @music_sector ,$toc_audiocd->[$i]->{frames}; # for relative frames 14826 push @start_sector ,$toc_audiocd->[$i]->{begin_frames}; # for absolute frames - 150 (gap) 14827 } 14828 $total_frames = $toc_audiocd->[0]->{total_frames}; 14829 } 14830 elsif ( defined $cdparanoia_path ){ # use cdparanoia for other operational system 14831 14832 #my $cdparanoia_path = '/usr/bin/cdparanoia'; 14833 14834 # cdda2wav dev=/dev/hdc -J -v toc 14835 # $cdda2wav_path dev=$audiodevice_path -J -v toc 14836 14837 $status_bar->push($context_id, $langs{msg021} ); 14838 while (Gtk2->events_pending()) { Gtk2->main_iteration()}; 14839 14840 $priority = $spinner_pri->get_value; 14841 14842 # -Q --query Perform CDROM drive autosense, query and print the CDROM table 14843 # of contents, then quit. 14844 14845 my $cmd = "$nice_path -n $priority $cdparanoia_path -Q -d $audiodevice_path "; 14846 14847 my $list = exec_cmd_system($cmd); 14848 14849 if ( $list =~ /Unable\sto\sopen\sdisc/is or $list =~ /Unable\sto\sopen\scdrom\sdrive/is ){ 14850 $button_selec->set_sensitive($false); 14851 $da->set_sensitive($false); 14852 $msg = $langs{msg067}."$audiodevice_path."; 14853 return ( total_frames => $total_frames, msg => $msg ); 14854 } 14855 #output: 14856 # Table of contents (audio tracks only): 14857 #track length begin copy pre ch 14858 #=========================================================== 14859 # 1. 11900 [02:38.50] 0 [00:00.00] no no 2 14860 # 2. 21945 [04:52.45] 11900 [02:38.50] no no 2 14861 # 3. 18505 [04:06.55] 33845 [07:31.20] no no 2 14862 # 18. 15580 [03:27.55] 259607 [57:41.32] no no 2 14863 # <man perlrequick or man perlretut> 14864 14865 # @length is an array with length of the songs 14866 while( $list =~ /\s*\d+\.\s+(\d+)\s+\[(.*):(\d+\.\d+)\]\s+(\d+)\s+\[.*\]\s+\w+\s+\w+\s+(\d+)/g ) 14867 { 14868 my $sec = number_value(sprintf("%02d", $3 )); # 02d: leading zero 14869 push @length ,"$2:$sec" ; 14870 push @music_sector , $1; 14871 push @start_sector , $4; 14872 $channel = $5; 14873 } 14874 # Audio CD Total Time 14875 # 23. 18012 [04:00.12] 322529 [71:40.29] no no 2 14876 #TOTAL 340541 [75:40.41] (audio only) 14877 while( $list =~ /TOTAL\s+(\d+)\s+\[(\d+):(\d+\.\d+)\]\s+/g ) { 14878 $total_frames = $1; 14879 } 14880 } # cdparanoia , final 14881 14882 # Get the $fileSize 14883 my $totalbytes = $total_frames * 2352 ; 14884 push @start_sector, $total_frames; 14885 $audio_cd_fileSize = sprintf("%.1f", $totalbytes/(1024*1024) ); 14886 $audio_cd_channel = $channel; 14887 14888 # Audio CD size 14889 # see /usr/include/linux/cdrom.h 14890 # CD_FRAMES 75 /* frames per second */ 14891 # CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */ 14892 # 1 second have 75 frames, that have 75*2352 bytes = 75*2352*8 bits = 1 411 200 bits = 1411.2 kbits 14893 # So, the bitrate of an audio cd is equal to 1411.2 kb/s . 14894 14895 my $minTot = $total_frames / (60 * 75); 14896 my $secTot = ($total_frames / 75) % 60; 14897 $minTot = sprintf ( "%02d", $minTot); 14898 $secTot = sprintf ( "%02d", $secTot); 14899 $audio_cd_total_time = "$minTot:$secTot"; 14900 $audio_cd_total_time = time_to_sec($audio_cd_total_time); 14901 14902 # convert x seconds to hour:min:sec format 14903 my ($hourT,$minT,$secT) = sec_to_time($audio_cd_total_time); # return ($hour,$min,$sec); 14904 14905 $audio_cd_total_time = $hourT > 0 ? "$hourT:$minT:$secT" : "$minT:$secT" ; 14906 14907 #for (my $i=0;$i<@length;$i++){ print "i=$i ; length=$length[$i] ; $music_sector[$i] ; $start_sector[$i] \n"; } 14908 return ( total_frames => $total_frames, msg => $msg ); 14909} 14910 14911$buffer->create_tag ("paranoia", 'foreground' => 'blue', # see <man Gtk2::TextTag> for more options 14912 'background' => '#B8D3C1', # #B8D3C1 = 184 211 193 (RGB) 14913 'justification' => 'center', 14914 left_margin => 0, 14915 style => 'normal', 14916 wrap_mode => 'word', 14917 scale => '1.1', 14918 family => 'Courier', 14919 # family => 'Terminal', 14920 # family => 'Fixed', 14921 'size-points' => '11'); 14922 14923sub print_cdparanoia_output { 14924 my $total_frames = shift || 0; 14925 14926 my $art = $files_info[0]{artist}; # [0] is the first artist 14927 my $alb = $files_info[0]{album}; 14928 14929 insert_msg("\n$art / $alb" , "small-black"); 14930 14931 insert_msg("\nTable of contents (audio tracks only): \n" , "paranoia"); 14932 insert_msg("track length begin \n" , "paranoia"); 14933 insert_msg("============================================\n" , "paranoia"); 14934 14935 for (my $track = 1; $track <= @music_sector; $track++) { 14936 my $frames = $music_sector[$track-1]; # for relative frames 14937 my $begin_frames = $start_sector[$track-1]; # for absolute frames - 150 (gap) 14938 14939 my $minf = sprintf ( "%02d", $frames / (60 * 75) ); 14940 my $secf = sprintf ( "%02d", ($frames / 75) % 60 ); 14941 my $fraf = sprintf ( "%02d", $frames % 75 ); 14942 14943 my $minb = sprintf ( "%02d", $begin_frames / (60 * 75) ); 14944 my $secb = sprintf ( "%02d", ($begin_frames / 75) % 60 ); 14945 my $frab = sprintf ( "%02d", $begin_frames % 75 ); 14946 14947 # $track = " " x ( 3 - length($track) ) . $track; # the same result 14948 $track = sprintf ("%3s", $track ); # s: spaces, see perlfunc. 14949 $frames = sprintf ("%7s", $frames ); 14950 $begin_frames = sprintf ("%7s", $begin_frames ); 14951 14952 insert_msg("$track. $frames [$minf:$secf.$fraf] $begin_frames [$minb:$secb.$frab]\n" , "paranoia"); 14953 } 14954 my $mint = sprintf ( "%02d", $total_frames / (60 * 75) ); 14955 my $sect = sprintf ( "%02d", ($total_frames / 75) % 60 ); 14956 my $frat = sprintf ( "%02d", $total_frames % 75 ); 14957 $total_frames = sprintf ("%7s", $total_frames ); 14958 14959 insert_msg("TOTAL $total_frames [$mint:$sect.$frat] (audio only) \n", "paranoia"); 14960 14961 # like 'cdparanoia -Q' 14962 #printf "%3d. %7ld [%02d:%02d.%02d] %7ld [%02d:%02d.%02d]\n", $track, 14963 # $frames, ($frames / (60 * 75)), (($frames/75)%60), ($frames % 75), 14964 # $begin_frames, ($begin_frames/(60*75)), (($begin_frames/75)%60), ($begin_frames % 75); 14965} 14966 14967sub add_columns { 14968 my %args = ( show_filepath => $column_show_filepath, 14969 show_filename => $column_show_filename, 14970 show_rip => $false, 14971 show_play => $false, 14972 show_file => $column_show_file, 14973 show_artist => $column_show_artist, 14974 show_album => $column_show_album, 14975 show_track => $column_show_track, 14976 show_bitrate => $column_show_bitrate, 14977 show_year => $column_show_year, 14978 show_frequency => $column_show_frequency, 14979 show_extension => $column_show_extension, 14980 treeview => $treeview_play, 14981 @_, # argument pair list goes here 14982 ); 14983 my $treeview = $args{treeview}; 14984 my @all_columns = $treeview->get_columns; # Retuns an array of columns. 14985 foreach my $col (@all_columns){ $treeview->remove_column($col); } 14986 14987 14988 # column for fixed toggles 14989 my $renderer_rip = Gtk2::CellRendererToggle->new; 14990 $renderer_rip->signal_connect (toggled => \&fixed_toggled); 14991 $renderer_rip->set_data (column => COLUMN_RIP); 14992 14993 my $column_rip = Gtk2::TreeViewColumn->new_with_attributes ("rip", $renderer_rip, active => COLUMN_RIP, 14994 'cell-background-gdk' => COLUMN_COLOR); 14995 # set this column to a fixed sizing (of 40 pixels) ; 14996 # $column_rip->set_sizing ('fixed'); $column_rip->set_fixed_width (40); 14997 $column_rip->set_resizable ($true); 14998 $column_rip->set_min_width (34); 14999 $column_rip->set (alignment => 0.5, 'clickable' => $true); # 'clickable' : Whether the header can be clicked 15000 $column_rip->signal_connect ( clicked => \&unselect_cda); 15001 15002 my $all_track_is_cda = $true; 15003 for (my $row = 0; $row <= $#files_info ; $row++){ 15004 last if (not defined $files_info[0]{extension_input}); 15005 if ($files_info[$row]{extension_input} ne 'cda' ){ $all_track_is_cda = $false; last; }; 15006 }; 15007 $column_rip->set_title( $all_track_is_cda ? "rip" : $langs{name065} ); 15008 $treeview->insert_column ($column_rip, COLUMN_RIP); 15009 15010 15011 if ( $args{show_file} ){ 15012 # file column 15013 my $renderer_file = Gtk2::CellRendererText->new; 15014 $renderer_file->set ('font' => $window_font_name, 'xalign' => 0.5); 15015 $renderer_file->set_data (column => COLUMN_FILE); 15016 15017 my $column_file = Gtk2::TreeViewColumn->new_with_attributes ($langs{name007}, $renderer_file, text => COLUMN_FILE, 15018 'cell-background-gdk' => COLUMN_COLOR); 15019 $column_file->set_min_width (40); 15020 $column_file->set_resizable ($true); 15021 $column_file->set (alignment => 0.5); # Alignment of the column header text 15022 $column_file->set_sort_column_id (COLUMN_FILE); 15023 $treeview->insert_column ($column_file, COLUMN_FILE); 15024 } 15025 15026 if ( $args{show_artist} ){ 15027 # artist column 15028 $renderer_artist = Gtk2::CellRendererText->new; 15029 #$renderer_artist->signal_connect (edited => \&cell_edited); 15030 $renderer_artist->set_data (column => COLUMN_ARTIST); 15031 $renderer_artist->set ('font' => $window_font_name, style => 'italic', scale => '0.9'); 15032 15033 my $column_artist = Gtk2::TreeViewColumn->new_with_attributes ($langs{name046}, $renderer_artist, text => COLUMN_ARTIST, 15034 #editable => $true, 15035 'cell-background-gdk' => COLUMN_COLOR); 15036 $column_artist->set_resizable ($true); 15037 $column_artist->set_expand ($true); # this column expand to max width 15038 #$column_artist->set_sizing ('fixed'); $column_artist->set_fixed_width (300); 15039 $column_artist->set (alignment => 0.0); # Alignment of the column header text 15040 $column_artist->set_sort_column_id (COLUMN_ARTIST); 15041 $treeview->insert_column ($column_artist, COLUMN_ARTIST); 15042 } 15043 15044 # title column 15045 $renderer_title = Gtk2::CellRendererText->new; 15046 #$renderer_title->signal_connect (edited => \&cell_edited); 15047 $renderer_title->set_data (column => COLUMN_TITLE); 15048 $renderer_title->set ('font' => $window_font_name, style => 'italic', scale => '0.9'); 15049 15050 my $column_title = Gtk2::TreeViewColumn->new_with_attributes ($langs{name047}, $renderer_title, text => COLUMN_TITLE, 15051 #editable => $true , 15052 'cell-background-gdk' => COLUMN_COLOR); 15053 $column_title->set_resizable ($true); 15054 #$column_title->set_min_width (220); 15055 $column_title->set (alignment => 0.0); 15056 $column_title->set_expand ($true); # this column expand to max width 15057 #$column_title->set_sizing ('fixed'); $column_title->set_fixed_width (300); 15058 $column_title->set_sort_column_id (COLUMN_TITLE); 15059 $treeview->insert_column ($column_title, COLUMN_TITLE); 15060 15061 if ( $args{show_album} ){ 15062 # album column 15063 $renderer_album = Gtk2::CellRendererText->new; 15064 $renderer_album->set_data (column => COLUMN_ALBUM); 15065 $renderer_album->set ('font' => $window_font_name, style => 'italic', scale => '0.9'); 15066 15067 my $column_album = Gtk2::TreeViewColumn->new_with_attributes ($langs{name053}, $renderer_album, text => COLUMN_ALBUM, 15068 'cell-background-gdk' => COLUMN_COLOR); 15069 $column_album->set_resizable ($true); 15070 #$column_album->set_min_width (100); 15071 $column_album->set (alignment => 0.0); # Alignment of the column header text 15072 $column_album->set_expand ($true); # this column expand to max width 15073 $column_album->set_sort_column_id (COLUMN_ALBUM); 15074 $treeview->insert_column ($column_album, COLUMN_ALBUM); 15075 } 15076 15077 if ( $args{show_track} ){ 15078 # column for tracks 15079 $renderer_track = Gtk2::CellRendererText->new; 15080 $renderer_track->set ('font' => $window_font_name, 'xalign' => 0.5); 15081 $renderer_track->set_data (column => COLUMN_TRACK); 15082 15083 my $column_track = Gtk2::TreeViewColumn->new_with_attributes ($langs{name045}, $renderer_track, text => COLUMN_TRACK, 15084 'cell-background-gdk' => COLUMN_COLOR); 15085 $column_track->set_min_width (40); 15086 $column_track->set_resizable ($true); 15087 $column_track->set (alignment => 0.5); # Alignment of the column header text 15088 $column_track->set_sort_column_id (COLUMN_TRACK); 15089 #$column_track->set_expand ($true); 15090 $treeview->insert_column ($column_track, COLUMN_TRACK); 15091 } 15092 15093 # length column 15094 $renderer_length = Gtk2::CellRendererText->new; 15095 $renderer_length->set ('font' => $window_font_name, 'xalign' => 0.5); 15096 my $column_length = Gtk2::TreeViewColumn->new_with_attributes ($langs{name044}, $renderer_length, text => COLUMN_LENGTH, 15097 'cell-background-gdk' => COLUMN_COLOR); 15098 $column_length->set_min_width (50); 15099 $column_length->set_resizable ($true); 15100 $column_length->set (alignment => 0.5); # Alignment of the column header text 15101 $column_length->set_sort_column_id (COLUMN_LENGTH); 15102 $treeview->insert_column ($column_length, COLUMN_LENGTH); 15103 15104 if ( $args{show_bitrate} ){ 15105 # bitrate column 15106 my $renderer_bitrate = Gtk2::CellRendererText->new; 15107 $renderer_bitrate->set_data (column => COLUMN_BITRATE); 15108 $renderer_bitrate->set ('font' => $window_font_name, 'xalign' => 0.5); 15109 15110 my $column_bitrate = Gtk2::TreeViewColumn->new_with_attributes ("Bitrate", $renderer_bitrate, text => COLUMN_BITRATE, 15111 'cell-background-gdk' => COLUMN_COLOR); 15112 $column_bitrate->set_min_width (50); 15113 $column_bitrate->set_resizable ($true); 15114 $column_bitrate->set_expand ($false); 15115 $column_bitrate->set (alignment => 0.5); # Alignment of the column header text 15116 $column_bitrate->set_sort_column_id (COLUMN_BITRATE); 15117 $treeview->insert_column ($column_bitrate, COLUMN_BITRATE); 15118 } 15119 if ( $args{show_year} ){ 15120 my $renderer_year = Gtk2::CellRendererText->new; 15121 $renderer_year->set_data (column => COLUMN_YEAR); 15122 $renderer_year->set ('font' => $window_font_name, 'xalign' => 0.5); 15123 15124 my $column_year = Gtk2::TreeViewColumn->new_with_attributes ($langs{name049}, $renderer_year, text => COLUMN_YEAR, 15125 'cell-background-gdk' => COLUMN_COLOR); 15126 $column_year->set_resizable ($true); 15127 $column_year->set (alignment => 0.5); # Alignment of the column header text 15128 $column_year->set_min_width (50); 15129 $column_year->set_sort_column_id (COLUMN_YEAR); 15130 $treeview->insert_column ($column_year, COLUMN_YEAR); 15131 } 15132 if ( $args{show_frequency} ){ 15133 my $renderer_frequency = Gtk2::CellRendererText->new; 15134 $renderer_frequency->set_data (column => COLUMN_FREQUENCY); 15135 $renderer_frequency->set ('font' => $window_font_name, 'xalign' => 0.5); 15136 15137 my $column_frequency = Gtk2::TreeViewColumn->new_with_attributes ($langs{name041}, $renderer_frequency, text => COLUMN_FREQUENCY, 15138 'cell-background-gdk' => COLUMN_COLOR); 15139 $column_frequency->set_resizable ($true); 15140 $column_frequency->set (alignment => 0.5); # Alignment of the column header text 15141 $column_frequency->set_min_width (50); 15142 $column_frequency->set_sort_column_id (COLUMN_FREQUENCY); 15143 $treeview->insert_column ($column_frequency, COLUMN_FREQUENCY); 15144 } 15145 if ( $args{show_filepath} ){ 15146 # filename column 15147 my $renderer_filepath = Gtk2::CellRendererText->new; 15148 $renderer_filepath->set_data (column => COLUMN_FILEPATH); 15149 $renderer_filepath->set ('font' => $window_font_name, scale => '0.9'); 15150 15151 my $column_filepath = Gtk2::TreeViewColumn->new_with_attributes ($langs{name050}, $renderer_filepath, text => COLUMN_FILEPATH, 15152 'cell-background-gdk' => COLUMN_COLOR); 15153 $column_filepath->set_resizable ($true); 15154 $column_filepath->set (alignment => 0.0); # Alignment of the column header text 15155 $column_filepath->set_expand ($false); # this column expand to max width 15156 $column_filepath->set_sort_column_id (COLUMN_FILEPATH); 15157 $treeview->insert_column ($column_filepath, COLUMN_FILEPATH); 15158 } 15159 if ( $args{show_filename} ){ 15160 my $renderer_filename = Gtk2::CellRendererText->new; 15161 $renderer_filename->set_data (column => COLUMN_FILENAME); 15162 $renderer_filename->set ('font' => $window_font_name, scale => '0.9'); 15163 15164 my $column_filename = Gtk2::TreeViewColumn->new_with_attributes ($langs{name056}, $renderer_filename, text => COLUMN_FILENAME, 15165 'cell-background-gdk' => COLUMN_COLOR); 15166 $column_filename->set_resizable ($true); 15167 $column_filename->set (alignment => 0.0); # Alignment of the column header text 15168 $column_filename->set_expand ($false); # this column expand to max width 15169 $column_filename->set_sort_column_id (COLUMN_FILENAME); 15170 $treeview->insert_column ($column_filename, COLUMN_FILENAME); 15171 } 15172 if ( $args{show_extension} ){ 15173 # extension column 15174 my $renderer_extension = Gtk2::CellRendererText->new; 15175 $renderer_extension->set_data (column => COLUMN_EXTENSION); 15176 $renderer_extension->set ('font' => $window_font_name, 'xalign' => '0.5'); 15177 15178 my $column_extension = Gtk2::TreeViewColumn->new_with_attributes ($langs{name051}, $renderer_extension, text => COLUMN_EXTENSION, 15179 'cell-background-gdk' => COLUMN_COLOR); 15180 $column_extension->set_resizable ($true); 15181 $column_extension->set_min_width (40); 15182 $column_extension->set (alignment => 0.5); # Alignment of the column header text 15183 $column_extension->set_sort_column_id (COLUMN_EXTENSION); 15184 $treeview->insert_column ($column_extension, COLUMN_EXTENSION); 15185 } 15186} 15187 15188sub add_columns_album_artist { #08Jun2008 15189 my %args = ( column_show_play_count => $column_show_play_count, 15190 @_, # argument pair list goes here 15191 ); 15192 my $treeview = $treeview_artist; # COLUMN_PLAY_COUNT = 13, but has column position = 1 15193 my $treeviewcolumn = $treeview->get_column(1); # treeviewcolumn = $tree_view->get_column ($n) 15194 # my $position = $treeviewcolumn->get_sort_column_id; 15195 #print "COLUMN_PLAY_COUNT = ",COLUMN_PLAY_COUNT," \$treeviewcolumn = $treeviewcolumn\n"; 15196 $treeview->remove_column($treeviewcolumn) if $treeviewcolumn; 15197 15198 if ( $args{column_show_play_count} ){ 15199 # artist play count 15200 $renderer_artist_play_count = Gtk2::CellRendererText->new; 15201 $renderer_artist_play_count->set_data (column => COLUMN_PLAY_COUNT); 15202 $renderer_artist_play_count->set ('font' => $window_font_name, 'xalign' => 0.5, style => 'italic', scale => '0.9'); 15203 15204 my $column_artist_play_count = Gtk2::TreeViewColumn->new_with_attributes ($langs{name054}, $renderer_artist_play_count, text => COLUMN_PLAY_COUNT, 15205 'cell-background-gdk' => COLUMN_COLOR); 15206 $column_artist_play_count->set_resizable ($true); 15207 $column_artist_play_count->set (alignment => 0.0); # Alignment of the column header text 15208 $column_artist_play_count->set_expand ($false); # this column expand to max width 15209 $column_artist_play_count->set_min_width (50); 15210 $column_artist_play_count->set (alignment => 0.5); # Alignment of the column header text 15211 $column_artist_play_count->set_sort_column_id (COLUMN_PLAY_COUNT); 15212 $treeview->insert_column ($column_artist_play_count, COLUMN_PLAY_COUNT); 15213 } 15214 15215 $treeview = $treeview_album; # COLUMN_PLAY_COUNT = 13, but has column position = 1 15216 $treeviewcolumn = $treeview->get_column(1); # treeviewcolumn = $tree_view->get_column ($n) 15217 $treeview->remove_column($treeviewcolumn) if $treeviewcolumn; 15218 15219 if ( $args{column_show_play_count} ){ 15220 # album play count 15221 $renderer_album_play_count = Gtk2::CellRendererText->new; 15222 $renderer_album_play_count->set_data (column => COLUMN_PLAY_COUNT); 15223 $renderer_album_play_count->set ('font' => $window_font_name, 'xalign' => 0.5, style => 'italic', scale => '0.9'); 15224 15225 my $column_album_play_count = Gtk2::TreeViewColumn->new_with_attributes ($langs{name054}, $renderer_album_play_count, text => COLUMN_PLAY_COUNT, 15226 'cell-background-gdk' => COLUMN_COLOR); 15227 $column_album_play_count->set_resizable ($true); 15228 $column_album_play_count->set (alignment => 0.0); # Alignment of the column header text 15229 $column_album_play_count->set_expand ($false); # this column expand to max width 15230 $column_album_play_count->set_min_width (50); 15231 $column_album_play_count->set (alignment => 0.5); # Alignment of the column header text 15232 $column_album_play_count->set_sort_column_id (COLUMN_PLAY_COUNT); 15233 $treeview_album->insert_column ($column_album_play_count, COLUMN_PLAY_COUNT); 15234 } 15235} 15236 15237sub fixed_toggled { 15238 my ($cell, $path_string) = @_; 15239 my $path = Gtk2::TreePath->new ($path_string); # $path_string is the row number 15240 15241 #my $path = $treeview_play->get_path_at_pos ($path_string); 15242 15243 # this is necessary when the column Track or Length is reordenable or altered. 15244 my $model = $treeview_play->get_model; 15245 my $iter = $model->get_iter($path); 15246 #print ("model = ",$model->get ($iter)," \n"); 15247 my $file = $model->get_value($iter,COLUMN_FILE); 15248 15249 #my $row = ($path->get_indices)[0]; 15250 my $row = $file-1; 15251 15252 # change the boolean value 15253 $files_info[$row]{rip} ^= 1; # set new value 15254 $model->set ($iter, COLUMN_RIP, $files_info[$row]{rip}); 15255} 15256 15257sub cell_edited { # not more used 15Apr2008 15258 my ($cell, $path_string, $new_text) = @_; 15259 # $path_string is the row number 15260 #print (" path_string = $path_string \n"); 15261 my $path = Gtk2::TreePath->new_from_string ($path_string); 15262 15263 my $column = $cell->get_data ("column"); #column number = 2 for title 15264 my $model = $treeview_play->get_model; 15265 my $iter = $model->get_iter ($path); 15266 15267 my $track = $model->get_value($iter,COLUMN_FILE); # track number 15268 #my $track2 = $files_info[$row]{track}; # Note that this don't work 15269 my $row = $track-1; 15270 #my $row = ($path->get_indices)[0]; 15271 15272 my $filepath = $files_info[$row]->{filepath}; 15273 if ( not -w filename_from_unicode $filepath and $files_info[$row]->{extension_input} ne 'cda' ){ 15274 $status_bar->push($context_id, " $filepath ".$langs{msg012} ); 15275 return; 15276 } 15277 if ($column == COLUMN_ARTIST) { $entry_artist->set_text( $new_text ); } # this change active sub change_tag 15278 if ($column == COLUMN_TITLE ) { $entry_title->set_text( $new_text ); } 15279 15280 $model->set ($iter, $column, $new_text); 15281 save_tag(); 15282 15283 #$status_bar->push($context_id, $langs{msg070} ); 15284 $status_bar->push($context_id, "Changes Saved." ); 15285} 15286 15287sub unselect_cda { # unselect all tracks; See man Gtk2::ListStore, Gtk2::TreeModel 15288 my $model = $treeview_play->get_model; 15289 my $path; my $iter; 15290 15291 if ( @files_info <= 0 ){ return $false; } 15292 my $val = $force_unselect_all_tracks ? $false : $true; 15293 15294 $model->foreach( sub{ # model is a $ListStore 15295 my($ListStore,$path,$iter,$val) = @_; 15296 my $file = $ListStore->get_value($iter,COLUMN_FILE); 15297 $files_info[$file-1]{rip} = $val; 15298 $ListStore->set ($iter, COLUMN_RIP, $val); 15299 return $false; # to don't abandon the loop 15300 }, $val); 15301 15302 $align_selec->remove ($align_selec->child); 15303 15304 if ( $force_unselect_all_tracks eq $false ){ $align_selec->add ($button_unselec); } 15305 else { $align_selec->add ($button_selec); } 15306 15307 $force_unselect_all_tracks ^= 1; # change boolean variable 15308} 15309 15310 15311# get treeview_play selection/playing/first_row_toggled/first_row files 15312sub get_selection_tree { 15313 return if ( $normalize_button->get_active ); 15314 15315 my $selected = undef; my $row_playing = undef; my $first_row_toggled = undef; 15316 my $first_row = undef; my $row = undef; 15317 15318 my $tree_selection = $treeview_play->get_selection; # $treeview_play->get_selection is an Gtk2::TreeSelection 15319 my $model = $treeview_play->get_model; 15320 15321 my @paths = $tree_selection->get_selected_rows; # sel = Gtk2::TreePath 15322 #my @sel_rows = map $_->to_string, @paths; 15323 #print "\n s_tree: \@sel_rows = @sel_rows ; np = ",$#paths+1; 15324 15325 if (@paths_button > 0){ # to select the last clicked cell 15326 foreach my $p (@paths_button){$tree_selection->select_path ($p);} 15327 } 15328 my $path = $paths[0]; # get the first selected path only 15329 my $iter = $model->get_iter($path) if $path; 15330 $selected = ($model->get_value($iter,COLUMN_FILE) - 1) if $iter; 15331 15332 my %treeview_play_info = get_treeview_play_informations(); 15333 #my @array = @{$treeview_play_info{array_checked}}; # get array_with_files_checked 15334 $first_row_toggled = $treeview_play_info{array_checked}->[0]; 15335 $row_playing = $treeview_play_info{row_playing}; 15336 $first_row = $treeview_play_info{first_row}; 15337 15338 # show info with preference order: $selected -> $row_playing -> $first_row_toggled -> $first_row 15339 15340 $row = undef; 15341 $row = $selected if (defined $selected); 15342 $row = $row_playing if (defined $row_playing and not defined $row); 15343 $row = $first_row_toggled if (defined $first_row_toggled and not defined $row); 15344 $row = $first_row if (defined $first_row and not defined $row); 15345 15346 # only for print purpose! 15347 $selected = 'none' if not defined $selected; 15348 $row_playing = 'none' if not defined $row_playing; 15349 $first_row_toggled = 'none' if not defined $first_row_toggled; 15350 $first_row = 'none' if not defined $first_row; 15351 $row = 'none' if not defined $row; 15352 #print "\n \$selected = $selected \n \$row_playing = $row_playing \n \$first_row_toggled = $first_row_toggled "; 15353 #print "\n \$first_row = $first_row \n ------------> \$row = $row\n"; 15354 15355 return if $row eq 'none'; 15356 15357 my $filepath = $files_info[$row]{filepath}; 15358 return unless $filepath; 15359 15360 # save this value that will be used by 'sub change_tag' and 'sub save_tag' 15361 $files_info[0]{get_selection_row} = $row; 15362 my %hash = determine_directory_and_filename_and_extension(row => $row); 15363 15364 # update info 15365 get_info_from_file(%hash) if ( $files_info[$row]{extension_input} ne 'cda' ); # get mp3/mp4/mpc/... info and set_tag_info 15366 set_tag_info($row) if ( $files_info[$row]{extension_input} eq 'cda' ); 15367 set_output_and_refresh_progress_bar(%hash); 15368 refresh_input_output_arrows(); 15369} 15370 15371sub get_treeview_play_informations { # 08Abr2008 15372 my $model = $treeview_play->get_model; 15373 my @array_with_files_checked; 15374 my @array_with_files_unchecked; 15375 my $row_playing = undef; 15376 my $first_row = undef; 15377 15378 $model->foreach( sub{ # model is a $ListStore 15379 my($ListStore,$path,$iter,$val) = @_; 15380 my $row = $ListStore->get_value($iter,COLUMN_FILE) - 1; 15381 15382 # if the row is toggled, then push it into array 15383 if ($files_info[$row]{rip} eq $true){ push @array_with_files_checked, $row; } 15384 else { push @array_with_files_unchecked, $row; } 15385 15386 if ($files_info[$row]{playing}){ $row_playing = $row; } 15387 15388 $first_row = $row if not defined $first_row; 15389 15390 return $false; # to don't abandon the loop 15391 }); 15392 15393 return ( array_checked => \@array_with_files_checked, # ref to array 15394 array_unchecked => \@array_with_files_unchecked, # ref to array 15395 row_playing => $row_playing, 15396 first_row => $first_row, 15397 ); 15398} 15399 15400sub set_no_color_for_all { # all tracks are unselected 15401 my $model = $treeview_play->get_model; 15402 $model->foreach( sub{ # model is a $ListStore 15403 my ($ListStore,$path,$iter,$val) = @_; 15404 my $file = $ListStore->get_value($iter,COLUMN_FILE); 15405 my $row = $file - 1; 15406 $files_info[$row]{played} = 0; 15407 $files_info[$row]{playing} = $false; 15408 $model->set ($iter, COLUMN_COLOR, undef) if $iter; # 'untaggle' the played music 15409 return $false; # to don't abandon the loop 15410 }); 15411 15412 $model = $treeview_artist->get_model; 15413 $model->foreach( sub{ # model is a $ListStore 15414 my ($ListStore,$path,$iter,$val) = @_; 15415 my $artist = $ListStore->get_value($iter,COLUMN_ARTIST); 15416 #$artists_already_played{uc($artist)} = 0; # Set False to the artist already played 15417 $model->set ($iter, COLUMN_COLOR, undef) if $iter; # 'untaggle' the played music 15418 return $false; # to don't abandon the loop 15419 }); 15420 15421 $model = $treeview_album->get_model; 15422 $model->foreach( sub{ # model is a $ListStore 15423 my ($ListStore,$path,$iter,$val) = @_; 15424 my $album = $ListStore->get_value($iter,COLUMN_ALBUM); 15425 #$albums_already_played{uc($album)} = 0; # Set False to the album already played 15426 $model->set ($iter, COLUMN_COLOR, undef) if $iter; # 'untaggle' the played music 15427 return $false; # to don't abandon the loop 15428 }); 15429} 15430 15431sub color_the_selected_tracks_and_scroll { # color the selected track, artist and album 15432 15433 my %args = ( select_color => 'playing', # ('no_color','playing','played') 15434 scroll => $true, 15435 color_artist => $true, 15436 color_album => $true, 15437 set_rip => $true, 15438 row => $selected_row, 15439 @_, # argument pair list goes here 15440 ); 15441 my ($iter,$path,$color,$model); 15442 #while (Gtk2->events_pending()) {Gtk2->main_iteration()}; # to update 15443 15444 if ( $args{color_artist} ){ # color the compound artist name 'art1 & art2' and scroll only to the first artist name 15445 $model = $treeview_artist->get_model; 15446 my @artists = return_artist_name($files_info[$args{row}]); # 'art1 & art2' return (art1,art2) 15447 15448 my $art_playcount_min = $artists[0]; # first artist 15449 foreach my $artist ( @artists ){ 15450 last unless defined $artists_already_played{ uc($artist) }; 15451 $art_playcount_min = $artist if ( $artists_already_played{ uc($artist) } < $artists_already_played{ uc($art_playcount_min) } ); 15452 } 15453 15454 foreach my $artist ( @artists ){ 15455 15456 if ( $args{select_color} eq 'no_color' and not $artists_already_played{ uc($artist) } ){ $color = undef; } 15457 elsif ( $args{select_color} eq 'playing' ){ $color = $color_row_playing; } 15458 #elsif ( $args{select_color} eq 'played' and $artists_already_played{ uc($artist) } >= 1 ){ $color = $color_row_already_played; } 15459 else { $color = $color_row_already_played; } 15460 15461 ($iter, $path) = get_iter_path_given_track_art_alb ( value => $artist, treeview => 'treeview_artist', column => COLUMN_ARTIST ); 15462 $model->set ( $iter, COLUMN_COLOR, $color ) if $iter; # to color the selected artist line 15463 15464 next if ( uc($artist) ne uc($art_playcount_min) ); # only scroll to the artist with minimum play_count or to the first artist. 15465 $treeview_artist->scroll_to_cell($path, undef, $true ,0.50, 0.50) if ($path and $args{scroll}); 15466 } 15467 } 15468 15469 if ( $args{color_album} ){ 15470 $model = $treeview_album->get_model; 15471 my $album = return_album_name( $files_info[$args{row}] ); # if no album name, create a guess name from filepath 15472 15473 if ( $args{select_color} eq 'no_color' and not $albums_already_played{ uc($album) } ){ $color = undef; } 15474 elsif ( $args{select_color} eq 'playing' ){ $color = $color_row_playing; } 15475 #elsif ( $args{select_color} eq 'played' ){ $color = $color_row_already_played; } 15476 else { $color = $color_row_already_played; } 15477 15478 ($iter, $path) = get_iter_path_given_track_art_alb ( value => $album, treeview => 'treeview_album', column => COLUMN_ALBUM ); 15479 15480 # Now, scroll to the selected album: 15481 $model->set ( $iter, COLUMN_COLOR, $color ) if $iter; # to color the selected album line 15482 $treeview_album->scroll_to_cell($path, undef, $true ,0.50, 0.50) if ($path and $args{scroll}); 15483 } 15484 15485 $model = $treeview_play->get_model; 15486 ($iter, $path) = get_iter_path_given_track_art_alb ( value => $args{row} + 1, treeview => 'treeview_play', column => COLUMN_FILE ); 15487 15488 $treeview_play->scroll_to_cell($path, undef, $true ,0.50, 0.50) if ($path and $args{scroll}); 15489 15490 if ( $args{select_color} eq 'no_color' ){ 15491 $files_info[$args{row}]{rip} = $true if $args{set_rip}; # change the boolean value 15492 $files_info[$args{row}]{played} = 0; 15493 $files_info[$args{row}]{playing} = $false; 15494 $color = undef; 15495 $treeview_play->set_drag_dest_row ($path, 'into-or-before') if $path; # select the last played track 15496 } 15497 elsif ( $args{select_color} eq 'playing' ){ 15498 $files_info[$args{row}]{rip} = $true; 15499 $files_info[$args{row}]{played} = 0; 15500 $files_info[$args{row}]{playing} = $true; 15501 $color = $color_row_playing; 15502 } 15503 elsif ( $args{select_color} eq 'played' ){ 15504 $files_info[$args{row}]{rip} = $false; 15505 $files_info[$args{row}]{played} = 1; 15506 $files_info[$args{row}]{playing} = $false; 15507 $color = $color_row_already_played; 15508 $treeview_play->set_drag_dest_row ($path, 'into-or-before') if $path; # select the last played track 15509 } 15510 15511 $model->set ($iter, COLUMN_RIP, $files_info[$args{row}]{rip}, #'untaggle' the played music 15512 COLUMN_COLOR, $color) if $iter; # color the $selected_row 15513 #print "file = ",$args{row}," ; select_color = $args{select_color} ; scroll = $args{scroll} \n"; 15514 15515 #print "\n\n color_the_selected_tracks_and_scroll --> row = $args{row} ;; select_color = $args{select_color}\n"; 15516 15517 $treeview_play->get_selection->unselect_all; # [[$treeview_play->get_selection]] is an Gtk2::TreeSelection 15518 get_selection_tree() if ($args{select_color} eq 'playing'); 15519 15520 #count_artists_and_album_already_played() if ($args{select_color} eq 'playing'); 15521} 15522 15523#my ($iter, $path) = get_iter_path_given_track_art_alb ( value => $track, treeview => 'treeview_play', column => COLUMN_FILE ); 15524 15525sub get_iter_path_given_track_art_alb { # 14Jun2008 - See man Gtk2::ListStore, Gtk2::TreeModel - Without Loops 15526 my %args = ( treeview => 'treeview_play', # default value 15527 value => $selected_row + 1, # value can be track/artist/album/. 15528 column => COLUMN_FILE, 15529 @_, # argument pair list goes here 15530 ); 15531 return unless defined $args{treeview}; 15532 my ($model, $path, $iter, $row, $value, $value_cmp); 15533 my $debug = $false; # to print messages 15534 15535 print "--> \$value = $args{value} in $args{treeview}.\n" if $debug; 15536 $value = uc( $args{value} ); # value can be track/artist/album/. 15537 15538 if ($args{treeview} eq 'treeview_play' ) { $model = $treeview_play->get_model; $row = $treeview_play_rows { $value - 1 }; } # row = track - 1 15539 elsif ($args{treeview} eq 'treeview_artist') { $model = $treeview_artist->get_model; $row = $treeview_artist_rows{ $value }; } 15540 elsif ($args{treeview} eq 'treeview_album' ) { $model = $treeview_album->get_model; $row = $treeview_album_rows { $value }; } 15541 15542 #$path = Gtk2::TreePath->new ( $row ); # get $path given/knowing the row number 15543 $path = Gtk2::TreePath->new_from_string ($row) if defined $row; 15544 $iter = $model->get_iter ($path) if defined $path; # See 'man Gtk2::TreeModel' 15545 15546 # Now, test the results. If not equal, then use Brute-Force search! 15547 $value_cmp = defined $iter ? $model->get_value($iter,$args{column}) : 'undef_iter'; 15548 15549 if ( $value ne uc($value_cmp) or not defined $iter ) { # search_iter_path_using_brute_force 15550 print " Error: \$value = $value not equal to \$value_cmp = $value_cmp in $args{treeview}. Use Brute-Force search!\n" if $debug; 15551 #($iter,$path) = search_iter_path_for_some_element($full_row + 1,$treeview_play,COLUMN_FILE); 15552 ($iter,$path) = search_iter_path_using_brute_force( value => $value, treeview => $args{treeview}, column => $args{column} ); 15553 } 15554 print " --- *** ---\n" if ( $args{treeview} eq 'treeview_play' and $debug ); 15555 return ( $iter, $path ); 15556} 15557 15558#($iter,$path) = search_iter_path_using_brute_force( value => $artist, treeview => 'treeview_artist', column => COLUMN_ARTIST ); 15559 15560# Find $iter and $path associeted to some file 15561# This is necessary when the columns Track/Artist/Album/Play Count/ ... are reordenable or altered 15562 15563sub search_iter_path_using_brute_force { # 14Jun2008 - See man Gtk2::ListStore, Gtk2::TreeModel - Using Loop '$model->foreach(' 15564 my %args = ( treeview => 'treeview_play', # default value 15565 value => $selected_row + 1, # value can be track/artist/album/. 15566 column => COLUMN_FILE, 15567 @_, # argument pair list goes here 15568 ); 15569 return unless defined $args{treeview}; 15570 my ($model, $path, $iter); 15571 15572 if ($args{treeview} eq 'treeview_play' ) { $model = $treeview_play->get_model; %treeview_play_rows = (); } 15573 elsif ($args{treeview} eq 'treeview_artist') { $model = $treeview_artist->get_model; %treeview_artist_rows = () ;} 15574 elsif ($args{treeview} eq 'treeview_album' ) { $model = $treeview_album->get_model; %treeview_album_rows = () ;} 15575 15576 my $row = 0; 15577 15578 $model->foreach( sub{ # Brute-Force search 15579 my($ListStore,$path2,$iter2) = @_; # model is a $ListStore 15580 my $value_found = $ListStore->get_value($iter2,$args{column}); 15581 #my $rrow = ($path2->get_indices)[0]; 15582 15583 if ( uc($args{value}) eq uc($value_found) ){ # if the values are equals, the $iter is right 15584 $path = Gtk2::TreePath->new ($row); 15585 $iter = $model->get_iter($path); 15586 #print "row = $row ; value = $args{value} ; value_found = $value_found ; column = $args{column}\n"; 15587 #return $true; # abandon the loop 'foreach' 15588 } 15589 15590 # Fill with the new values before to alter some column. 15591 if ( $args{treeview} eq 'treeview_play' ) { $treeview_play_rows { $value_found - 1 } = $row; } # $value_found is track = row + 1 15592 elsif ( $args{treeview} eq 'treeview_artist' ) { $treeview_artist_rows{ uc( $value_found ) } = $row; } 15593 elsif ( $args{treeview} eq 'treeview_album' ) { $treeview_album_rows { uc( $value_found ) } = $row; } 15594 15595 #if ( $args{treeview} eq 'treeview_artist' ) { print "\$treeview_artist_rows{ $value_found } = $treeview_artist_rows{ uc( $value_found ) } \n"; } 15596 #elsif ( $args{treeview} eq 'treeview_album' ) { print "\$treeview_album_rows{ $value_found } = $treeview_album_rows{ uc( $value_found ) } \n"; } 15597 15598 $row += 1; 15599 return $false; # to don't abandon the loop 15600 } ); 15601 15602 return ($iter,$path); 15603} 15604 15605sub search_iter_path_for_some_element { # See man Gtk2::ListStore, Gtk2::TreeModel - Not more used 15606 my ($value,$treeview,$column) = @_; # value can be track/artist/album/... 15607 my $iter; my $path; 15608 my $model = $treeview->get_model; 15609 15610 my $row = 0; 15611 15612 $model->foreach( sub{ # Brute-Force search 15613 my($ListStore,$path2,$iter2) = @_; # model is a $ListStore 15614 my $value_found = $ListStore->get_value($iter2,$column); 15615 15616 # $value can be a number or character 15617 if ( uc($value) eq uc($value_found) ){ # if the values are equals, the $iter is right 15618 $path = Gtk2::TreePath->new ($row); 15619 $iter = $model->get_iter($path); 15620 #print "row = $row ; value = $value ; value_found = $value_found ; column = $column\n"; 15621 return $true; # abandon the loop 'foreach' 15622 } 15623 15624 $row += 1; 15625 return $false; # to don't abandon the loop 15626 } ); 15627 return ($iter,$path); 15628} 15629 15630 15631sub REAPER { # To reap/eliminate dead children ; see perlipc; Programming Perl, 3a Ed., Chap.16 15632 # If a second child dies while in the signal handler caused by the 15633 # first death, we won't get another signal. So must loop here else 15634 # we will leave the unreaped child as a zombie. And the next time 15635 # two children die we get another zombie. And so on. 15636 while ( waitpid(-1,WNOHANG) > 0 ){} # waitpid return "-1" if there is no such child process. 15637 $SIG{CHLD} = \&REAPER; # still loathe sysV 15638} 15639 15640my $selected_row_last_value = -10; #some absurd value 15641my $extension_last_value = ""; 15642 15643sub play_selection { # stop and play 15644 my %args = ( go_back => $false, # default value 15645 skip => undef, 15646 @_, # argument pair list goes here 15647 ); 15648 $extension_last_value = $files_info[$selected_row]{extension_input}; 15649 stop_playing_music(); 15650 $status_bar->push($context_id, ""); 15651 15652 if ( not defined $args{skip} ) { 15653 # when go_back, the selected_row is already known from @rows_already_played 15654 if ( not $args{go_back} ){ 15655 $selected_row = choose_one_row_to_play(); 15656 } 15657 # $selected_row == -1 when there is none selected track to play 15658 if ( $selected_row == -1){ 15659 if ($loop_tracks eq $false){ 15660 $status_bar->push($context_id, $langs{msg022} ); 15661 $go_forward = $false; 15662 show_time(); 15663 } 15664 else { 15665 $force_unselect_all_tracks = $false; # to select all tracks 15666 unselect_cda(); # subroutine that select all tracks 15667 $selected_row = choose_one_row_to_play(); 15668 } 15669 @rows_already_played = (); 15670 $selected_row_last_value = -10; 15671 set_no_color_for_all(); 15672 } 15673 } 15674 if ( $selected_row == -1 ){ return $false; } # If there is no selected track 15675 15676 $total_time = $files_info[$selected_row]{length} if $selected_row != -1 ; # 2:56:34 02:32 15677 $total_time = time_to_sec($total_time); 15678 15679 # when cda is playing and the next selected_row is not cda 15680 if ( $extension_last_value eq 'cda' and $files_info[$selected_row]{extension_input} ne 'cda' ){ 15681 stop_cda(); # don't stop if the next track have cda extension_input 15682 } 15683 15684 # xine -A arts -V none -I -H "music.mp3" 15685 # mac "zzz.ape" - -d | play -t wav -d /dev/audio - 15686 15687 # see <man SDL> or <man SDL::Cdrom> 15688 #use SDL::Cdrom; 15689 #my $cdrom = SDL::Cdrom->new(0); 15690 #$cdrom->play(); 15691 15692 #my $music = $model->get_value($iter,COLUMN_FILEPATH); #print "music = $music\n"; 15693 my $music = $files_info[$selected_row]{filepath}; #print "music = $music\n"; 15694 my $buffer = 4 * 1024; # 4MB 15695 # $device_type = 'arts'; # oss, alsa, arts, esd, jack, nas 15696 # $device_path = '/dev/sound/adsp'; 15697 my @exec_argv; 15698 if ($Frequency == 0){ $Frequency = $files_info[$selected_row]{frequency}; } 15699 if ( not -e filename_from_unicode $music and $files_info[$selected_row]{extension_input} ne 'cda' ){ 15700 $files_info[$selected_row]{remove} = $true; 15701 go_forward(); 15702 return; 15703 } 15704 if ( defined $args{skip} ) { $count = $args{skip}; } # determine the start time to be played 15705 15706 if ($files_info[$selected_row]{extension_input} eq 'mp3' and ($mpg123_path or $mpg321_path or $madplay_path or $mplayer_path) ){ 15707 15708 # $totalSeconds = $Total_samples/$Frequency --> $Total_samples = $totalSeconds * $Frequency; 15709 # $Total_samples = $frame_count * 32*36 --> $frame_count = $Total_samples / 32*36 = ($totalSeconds * $Frequency) / 1152; 15710 my $frame = sprintf ('%.0f', ($count * $Frequency) / 1152 ); 15711 15712 if ($mpg321_path and $player_mp3 eq "mpg321" ){ @exec_argv = ($mpg321_path, '-o', $device_type, '-b', $buffer, '-q', '-k', $frame ); } 15713 elsif ($mpg123_path and $player_mp3 eq "mpg123" ){ @exec_argv = ($mpg123_path, '-q', '-k', $frame ); } 15714 elsif ($madplay_path and $player_mp3 eq "madplay"){ @exec_argv = ($madplay_path, '-Q', '-s', $count, '-o', $device_path ); } 15715 elsif ($mplayer_path and $player_mp3 eq "mplayer"){ @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', 15716 $buffer, '-vo', 'null', '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count ); } 15717 15718 push @exec_argv, filename_from_unicode $music; 15719 } 15720 elsif ( $files_info[$selected_row]{extension_input} eq 'mp4' and $mplayer_path ){ 15721 15722 @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 15723 '-really-quiet', '-slave', '-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music ); 15724 } 15725 elsif ($files_info[$selected_row]{extension_input} eq 'mpc' and ($mpcdec_path or $mplayer_path) ){ 15726 15727 if ($mplayer_path and $player_mpc eq "mplayer" ){ 15728 @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 15729 '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music ); 15730 } 15731 elsif ($mpcdec_path and $player_mpc eq "mpcdec" ){ 15732 @exec_argv = ($mpcdec_path, '--silent', '--start', $count, filename_from_unicode $music, $device_path ); 15733 } 15734 } 15735 elsif ($files_info[$selected_row]{extension_input} eq 'ogg' and ($ogg123_path or $mplayer_path) ){ 15736 15737 if ($mplayer_path and $player_ogg eq "mplayer" ){ 15738 @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 15739 '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music ); 15740 } 15741 elsif ($ogg123_path and $player_ogg eq "ogg123" ){ 15742 @exec_argv = ($ogg123_path, '-d', $device_type, '-b', $buffer, '-q', '-k', $count, filename_from_unicode $music ); 15743 } 15744 } 15745 elsif ($files_info[$selected_row]{extension_input} eq 'ape' and ( ($ape_path and ($play_path or $aplay_path)) or $mplayer_path ) ){ 15746 15747 if ($mplayer_path and $player_ape eq "mplayer" ){ 15748 @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 15749 '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music ); 15750 } 15751 elsif ( ($ape_path and $play_path) and $player_ape eq "mac" ){ 15752 # mac "zzz.ape" - -d | play -t wav -d /dev/audio - 15753 #@exec_argv = ($ape_path, filename_from_unicode $music, '-', '-d', '|', '/usr/bin/play', '-t', 'wav', '-'); 15754 #my $cmd = "$ape_path \"$music\" - -d | $play_path -t wav -d $device_path - "; 15755 my $cmd = "$ape_path \"$music\" - -d | $play_path -t wav - "; 15756 @exec_argv = ( filename_from_unicode "$cmd" ); 15757 } 15758 elsif ( ($ape_path and $aplay_path) and $player_ape eq "aplay" ){ 15759 # mac "zzz.ape" - -d | play -t wav -d /dev/audio - 15760 #@exec_argv = ($ape_path, filename_from_unicode $music, '-', '-d', '|', '/usr/bin/play', '-t', 'wav', '-'); 15761 #my $cmd = "$ape_path \"$music\" - -d | $play_path -t wav -d $device_path - "; 15762 my $cmd = "$ape_path \"$music\" - -d | $aplay_path -N -q - "; 15763 @exec_argv = ( filename_from_unicode "$cmd" ); 15764 } 15765 } 15766 elsif ($files_info[$selected_row]{extension_input} eq 'flac' and ($flac123_path or $mplayer_path) ){ 15767 15768 if ($mplayer_path and $player_flac eq "mplayer" ){ 15769 @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 15770 '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music ); 15771 } 15772 elsif ($flac123_path and $player_flac eq "flac123" ){ 15773 $count = 0; 15774 @exec_argv = ($flac123_path, '-d', $device_type, '-q', filename_from_unicode $music ); 15775 } 15776 } 15777 elsif ($files_info[$selected_row]{extension_input} eq 'wav' and ($aplay_path or $mplayer_path) ){ 15778 15779 if ($mplayer_path and $player_wav eq "mplayer" ){ 15780 @exec_argv = ($mplayer_path, '-ao', "$device_type,:mmap:noblock", '-cache', $buffer, '-vo', 'null', 15781 '-really-quiet', '-slave','-noconsolecontrols', '-nojoystick','-ss', $count, filename_from_unicode $music ); 15782 } 15783 elsif ($aplay_path and $player_wav eq "aplay" ){ 15784 $count = 0; 15785 @exec_argv = ($aplay_path, '-N', '-q', filename_from_unicode $music ); 15786 } 15787 elsif ($play_path and $player_wav eq "play" ){ 15788 $count = 0; 15789 @exec_argv = ($play_path, filename_from_unicode $music ); 15790 } 15791 } 15792 15793 if ($files_info[$selected_row]{extension_input} ne 'cda' and @exec_argv >=1){ 15794 $SIG{CHLD} = \&REAPER; # To reap/eliminate dead children ; see perlipc 15795 # see man perlfunc, perlfork, perlipc ; Learning Perl 14.6, 3a Ed. ; Perl Cookbook 16.10, 2a. Ed 15796 defined($pid_player = fork) or die "Can't fork: $!"; 15797 if( $pid_player == 0 ){ 15798 #Child process is here ; child process has a zero value 15799 open \*STDIN, '>/dev/null'; 15800 open \*STDOUT,'>/dev/null'; 15801 open \*STDERR,'>/dev/null'; 15802 exec @exec_argv; # see perlfunc 15803 die "cannot play audio: $!\n"; 15804 } 15805 #Parent process is here ; parent process has a nonzero value 15806 #waitpid($pid,0); 15807 } 15808 #print "count = $count ; pid_player = $pid_player; exec_argv = @exec_argv\n"; 15809 15810 if ($files_info[$selected_row]{extension_input} eq 'cda'){ 15811 # umount the audio cd drive if possible. This is need to play EXTRA CD. 15812 exec_cmd_system("umount $audiodevice_path" ); 15813 15814 if ($cdplayer eq "cdcd"){ 15815 my @cmd = ( $cdcd_path, '-d', $audiodevice_path, 'play', $selected_row + 1, $selected_row + 1 ); 15816 exec_cmd_system2(@cmd); 15817 } 15818 elsif ( $cdplayer eq "gnormalize::cdplay" ){ 15819 gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1); 15820 } 15821 elsif ( $cdplayer eq "Audio::CD" ){ # libcdaudio ;; Audio::CD ;; see <man Audio::CD> 15822 $audiocd = Audio::CD->init("$audiodevice_path"); 15823 $audiocd->play_track($selected_row + 1, $selected_row + 1); 15824 } 15825 #print "using command to play cdrom: cmd = $cmd\n"; 15826 } 15827 # draw scrolling text 15828 if ($selected_row != $selected_row_last_value){ show_scrolling_text(); } 15829 $selected_row_last_value = $selected_row; 15830 15831 $playing_music = $true; 15832 #while (Gtk2->events_pending()) {Gtk2->main_iteration()}; 15833 15834 # Now, scroll to the selected artist 15835 color_the_selected_tracks_and_scroll( select_color => 'playing' ); 15836 count_artists_and_album_already_played(update_model_artist => $true, update_model_album => $true); 15837 15838 # see <man Glib::MainLoop> 15839 # integer = Glib::Timeout->add ($interval, $callback, $data=undef, $priority=G_PRIORITY_DEFAULT) 15840 if ( defined($timer) ){ Glib::Source->remove($timer);} # to not duplicate the MainLoop 15841 $timer = Glib::Timeout->add (500, \&change_count, $total_time); # 250 milliseconds = 0.250 second 15842 # integer = Glib::IO->add_watch ($fd, $condition, $callback, $data=undef, $priority=G_PRIORITY_DEFAULT) 15843 15844} 15845# use constant INTERVAL => 1000; # for cd player; 250 milliseconds = 0.250 second 15846 15847sub choose_filter { # filter can be artist, album, genre, ... See 'sub change_filter' 15848 my $hash = shift; 15849 return unless $use_filter; # $use_filter == 0 15850 15851 my $play_tracks_from_different_albums = $true if $use_filter == 1; 15852 my $play_tracks_from_different_artists = $true if $use_filter == 2; 15853 my $play_tracks_from_different_genres = $true if $use_filter == 3; 15854 my $play_tracks_from_different_years = $true if $use_filter == 4; 15855 15856 return return_album_name ($hash) if $play_tracks_from_different_albums and defined $hash->{album}; 15857 return return_artist_name($hash) if $play_tracks_from_different_artists and defined $hash->{artist}; 15858 return $hash->{genre} if $play_tracks_from_different_genres and defined $hash->{genre}; 15859 return $hash->{year} if $play_tracks_from_different_years and defined $hash->{year}; 15860} 15861 15862 # Making Hashes of Arrays (Perl Cookbook, Chap. 11.2) 15863 # $hash{'a artist'} = [3,4,7, ..., n]; # anonymous array 15864 # To append a new value: push @{ $hash{'a artist'} }, $row; 15865 # To obtain an array without repeated values: my %unique = map {$_ => 1}, @numbers; 15866 15867# Make array with all selected rows that will be played. 'sub choose_one_row_to_play' returns the selected_row number. 15868sub choose_one_row_to_play { # 06Jun2008 15869 my $random_row = -1; # get by $selected_row 15870 my $debug = $false; # to print messages 15871 15872 my %treeview_play_info = get_treeview_play_informations(); 15873 my @rows_checked = @{$treeview_play_info{array_checked}}; # get array_with_files_checked 15874 #my $first_row_toggled = $rows_to_play[0]; 15875 #my $row_playing = $treeview_play_info{row_playing}; 15876 #my $first_row = $treeview_play_info{first_row}; 15877 15878 # The array '@rows_unchecked' will be used to get rows already played, but '@rows_already_played' would be used too. 15879 # '@rows_unchecked' have more informations, because '@rows_already_played' is always erased whenever quit from gnormalize. 15880 my @rows_unchecked = @{$treeview_play_info{array_unchecked}}; # To fill with the unchecked rows; 15881 print "\n\@rows_unchecked = @rows_unchecked\n" if $debug; 15882 15883 my @rows_to_play = @rows_checked; 15884 15885 if ( $use_filter and @rows_checked >= 1 and @rows_unchecked >= 1 ) { # Add loops with 2*O(N) efficiency order. 15886 15887 my %available_artists = (); # To find all available artists to play 15888 foreach my $row (@rows_checked){ # It has 1*O(N) efficiency order. 15889 my @artists = map { uc($_) } choose_filter($files_info[$row]); 15890 foreach my $art (@artists) { $available_artists{$art}++; } # Add +1 to the available_artists 15891 } 15892 my $num_dif_artists = keys %available_artists; # How can I know how many entries are in a hash? See 'man perlfaq4'. 15893 15894 my %artists_played = (); # Used to filter, such that 'filter' can be artist, album, genre, ... 15895 #foreach my $row_played (@rows_already_played) { 15896 foreach my $row_played (@rows_unchecked) { # Permutations like (A B C D)(C A D B)(D A B C)(D ... 15897 15898 my @art_played = map { uc($_) } choose_filter($files_info[$row_played]); 15899 foreach my $art (@art_played) { $artists_played{$art}++; } # Add +1 to the artist already played. 15900 if ($debug) { foreach my $art (@art_played) { print "\n\$row_played = $row_played ; played $artists_played{$art} time(s) --> {$art} \n"; } } 15901 } 15902 15903 my $minimum = $#rows_checked + 100; # Choose one great value 15904 foreach my $art ( keys %available_artists ) { # To find the minimum play times value 15905 if (not $artists_played{$art}) { $minimum = 0 ; last; } # played 0 times 15906 $minimum = $artists_played{$art} if $artists_played{$art} < $minimum; 15907 } 15908 print "\n\$minimum = $minimum ; " if $debug; 15909 15910 my @last_artists_played; # To avoid to play the same artist/album sequentially 15911 if (@rows_already_played >= 1){ 15912 my $last_row_played = $rows_already_played[$#rows_already_played]; 15913 @last_artists_played = map { uc($_) } choose_filter($files_info[$last_row_played]); 15914 foreach my $last_artist (@last_artists_played) { $artists_played{$last_artist}++ if ($num_dif_artists > @last_artists_played); } 15915 } 15916 15917 @rows_to_play = (); # Fill with rows to play 15918 while (@rows_checked >=1 and not @rows_to_play >= 1) { # if not select any rows_to_play, then $minimum += 1; 15919 foreach my $row (@rows_checked){ # It has 1*O(N) efficiency order. 15920 15921 my @artists = map { uc($_) } choose_filter($files_info[$row]); 15922 foreach my $art (@artists) { 15923 if (not $artists_played{$art} or $artists_played{$art} <= $minimum) { push @rows_to_play, $row; last; } # use 'last' to not duplicate rows. 15924 } 15925 } 15926 print "\@rows_to_play = @rows_to_play ; \@last_artists_played = @last_artists_played ; \$num_dif_artists = $num_dif_artists ; \$minimum_new = $minimum\n" if $debug; 15927 $minimum += 1; 15928 } 15929 } 15930 15931 # to remove one element from front of @array -- see perlfunc : splice 15932 if ( @rows_to_play >= 1 ){ # exist at least one element 15933 if ( $play_random eq $true ){ 15934 my $rand = int( rand(@rows_to_play) ); # pick one random element: 0<= rand < @rows_to_play number 15935 #print " rand[0 to $#rows_to_play] = $rand ;; all rows = @rows_to_play\n"; 15936 $random_row = splice(@rows_to_play, int( $rand ), 1); # pull one random element of @array 15937 } 15938 else { $random_row = splice(@rows_to_play, 0, 1);} # pull the first element of @array 15939 } 15940 15941 #print " random_row = $random_row ;; rows_to_play = @rows_to_play\n"; 15942 return $random_row ; # return $row that will be played 15943} 15944 15945 15946# This is a loop for "$timer = Glib::Timeout->add (250, \&change_count, $total_time);" 15947# at sub play_selection the show the time when button "play" is pressed. 15948my $count_blink = 0; # blink when paused. 15949sub change_count { # the main loop 15950 15951 # play all tracks - go to next track 15952 if ( ($count >= $total_time or $go_forward eq $true) and $playing_music and $files_info[$selected_row]{extension_input} eq 'cda') { 15953 go_forward(); 15954 } 15955 elsif ( defined $pid_player and $playing_music and $files_info[$selected_row]{extension_input} ne 'cda') { 15956 if ( waitpid($pid_player, WNOHANG) < 0 or $go_forward eq $true ){ go_forward(); } 15957 } 15958 if ( $go_back eq $true and @rows_already_played > 0 ) { 15959 go_back(); 15960 } 15961 $count = $count + 0.500 if ( not $pause ); # count is a number for seconds elapsed. 15962 15963 $count_blink += 0.500; 15964 get_current_track_and_time() if ( $files_info[$selected_row]{extension_input} eq 'cda' ); 15965 # need show time only if the count change its value. 15966 #if ( int($last_count) != int($count) or int($count) == 0 ){ show_time(); } 15967 show_time(); 15968 15969 return $true; # if return is $false; then stop Glib::Timeout 15970} 15971 15972sub go_forward { 15973 $go_forward = $true; 15974 my $row_played = $selected_row; 15975 15976 push @rows_already_played, $row_played; # if the row was played completely, then push it to @rows_already_played 15977 #print "--> rows_already_played = @rows_already_played \n"; 15978 15979 # To color the selected artist: 15980 color_the_selected_tracks_and_scroll( select_color => 'played', scroll => $false, row => $row_played ); 15981 15982 play_selection(go_forward => $true); # stop and play 15983 $go_forward = $false; 15984} 15985 15986sub go_back { 15987 $go_back = $true; 15988 my $row_playing = $selected_row; 15989 15990 #print "antes -- rows_already_played = @rows_already_played \n"; 15991 $selected_row = splice(@rows_already_played, -1); # remove the last element from @array 15992 #print "depois -- rows_already_played = @rows_already_played ;; selected_row = $selected_row\n"; 15993 15994 # To color the selected artist: 15995 color_the_selected_tracks_and_scroll( select_color => 'no_color', scroll => $false, row => $row_playing ); 15996 15997 play_selection(go_back => $true); # stop and play 15998 $go_back = $false; 15999} 16000 16001sub get_current_track_and_time { 16002 my $current_track; my $frame; my $status; my $current_position; 16003 my $abs_start_frame = $start_sector[$selected_row] + 150; # absolute start frame, 150 is the offset (gap) of first frame. 16004 my $abs_final_frame = $start_sector[$selected_row + 1] + 150; # absolute final frame for the selected track 16005 if ( $selected_row == -1 ){ return $true; } # If there is no selected row 16006 16007 if ( $cdplayer eq "Audio::CD" ){ 16008 if ( not $have_current_track ){ return $true; } 16009 my $info = $audiocd->stat; 16010 $status = $info->mode; 16011 if ( $status == 0 ){ $playing_music = $true; } 16012 if ( $status == 1 ){ $pause = $true; return $true; } else { $pause = $false; } 16013 if ( $status == 2 ){ $go_forward = $true; } # completed 16014 if ( $status == 3 ){ stop_playing_music(); } # stop 16015 if ( $status > 3 or $status < 0 ){ entry_cda_change(); } # Error 16016 16017 # status = 0 (playing) ;; status = 1 (paused) ;; status = 2 (completed) 16018 # status = 3 (NOSTATUS) ;; status = 4 (INVALID) ;; status = 5 (ERROR) ;; See /usr/include/cdaudio.h 16019 16020 my ($minutes, $seconds, $frames) = $info->time; # Returns the current disc play time 16021 $current_position = ($minutes * 60 + $seconds) * 75 + $frames; # absolute frame position 16022 } 16023 elsif ( $cdplayer eq "gnormalize::cdplay" ){ 16024 my $info = gnormalize::cdplay::Info(); 16025 if ( not $info ){ entry_cda_change(); return; } # Get Status Error 16026 $status = $info->{status}; 16027 16028 if ( $status eq 'play' ){ $playing_music = $true; } 16029 if ( $status eq 'paused' ){ $pause = $true; return $true; } else { $pause = $false; } 16030 if ( $status eq 'completed' ){ $go_forward = $true; } # completed 16031 if ( $status eq 'no_status' ){ stop_playing_music(); } # stop 16032 16033 #my($minutes, $seconds) = ( $info->{min}, $info->{sec} ); # don't use this because it shows regressive time! 16034 $current_position = $info->{frame_abs}; # absolute frame position 16035 } 16036 elsif ( $cdplayer eq "cdcd" ){ # not used, because cdcd consume so much process resource 16037 return $true; 16038 # status: Playing n�7 01:10.25/track 20:28.52/disc 16039 my $cmd = "cdcd -d $audiodevice_path status"; 16040 my $status = exec_cmd_system($cmd); 16041 if ( $status =~ /Playing n�(\d+)\s+(\d*:?\d+:\d+[\.,]\d+)\/track\s+(\d*:?\d+:\d+[\.,]\d+)\/disc/i ){ 16042 my $current_track = $1; 16043 $count = time_to_sec($2); 16044 #print " track = $1 ;; 2 = $2 ;; time_to_sec = ",time_to_sec($2)," ;; 3 = $3 \n"; 16045 } 16046 if ($status =~ /Stopped/i){ stop_playing_music(); } 16047 } 16048 16049 $frame = $current_position - $abs_start_frame; 16050 $frame = 0 if $frame < 0; 16051 #$count = number_value(sprintf("%02.2f", ($frame / 75 ))); 16052 $count = int($frame / 75) if not $pause; # get the new value, number of seconds = frame / 75 16053 16054 #$current_track = $info->{current_track}; # this is not correct on the boundary region between tracks. 16055 $current_track = get_current_track(); # Recompile and install Audio-CD-0.04-changed.tar.gz for "Audio::CD" 16056 16057 #print "count=$count;current_track=$current_track;selected_row=$selected_row;status=$status;". 16058 # "frame=$frame;current_position=$current_position\n"; 16059 16060 my $before_end = $abs_final_frame - 2 * 75; # remaining 2 sec. See sub play_cdrom_msf(). 16061 my $start_next_frame = $abs_final_frame + 40; 16062 16063 #if ( $current_position > $before_end and $current_track == $selected_row ) { $go_forward = $true; } 16064 # The boundary region where the regressive time and next track is showed. I want to avoid this. 16065 if ( $current_position > $before_end and $current_position <= $start_next_frame ){ $current_track = $selected_row + 1; } 16066 16067 if ( $current_track != $selected_row + 1 ){ # If another program changes the selected track. 16068 my ($iter, $path) = get_iter_path_given_track_art_alb ( value => $current_track, treeview => 'treeview_play', column => COLUMN_FILE ); 16069 16070 $treeview_play->scroll_to_cell($path, undef, $true ,0.50, 0.50) if $path; 16071 $count = 0; 16072 } 16073 $selected_row = $current_track - 1 if $current_track > 0; 16074 return $true; # if return is $false; then stop the Glib::Timeout loop 16075} 16076 16077sub get_current_track{ 16078 my $total_track = $#start_sector + 1; 16079 #my $total_track = $toc_audiocd->[0]->{total_track}; 16080 my $current_track = $total_track; # start value is the total audio track number 16081 my $current_position; 16082 my $offset_frame = 150; 16083 16084 if ( $cdplayer eq "gnormalize::cdplay" ){ 16085 $current_position = gnormalize::cdplay::Info()->{frame_abs}; # absolute frame position 16086 } 16087 elsif ( $cdplayer eq "Audio::CD" ){ 16088 my $info = $audiocd->stat; 16089 my ($minutes, $seconds, $frames) = $info->time; # Returns the current disc play time 16090 $current_position = ($minutes * 60 + $seconds) * 75 + $frames; 16091 } 16092 16093 for(my $track=1; $track < $total_track; $track++){ 16094 #if ($current_position < $toc_audiocd->[$track]->{frames_abs}){ $current_track = $track; last; } 16095 # 150 is the offset (gap) of first frame. So (absolute frames) = ($start_sector[$track] + 150) . 16096 if ( $current_position < $start_sector[$track] + $offset_frame ){ $current_track = $track; last; } 16097 } 16098 return $current_track; 16099} 16100 16101 16102my $pct_last_value = 0; 16103 16104sub show_time{ # show time on display 16105 if ( $playing_music eq $false ){ return; } 16106 16107 $total_time = $files_info[$selected_row]{length} if $selected_row != -1 ; 16108 $total_time = time_to_sec($total_time); 16109 16110 my $show_time = $total_time; # one track total time 16111 my $show_count = $count; # relative position 16112 16113 if ($show_time > 0){ 16114 # draw lapsed time ; show only not repeated value 16115 my $pct = number_value( sprintf("%.2f", $show_count/$show_time) ); 16116 if ($pct != $pct_last_value and $pct <= 1){ draw_lapsed_time($da, undef, "$pct"); } 16117 $pct_last_value = $pct; 16118 } 16119 16120 if ($selected_row != $selected_row_last_value){ show_scrolling_text(); } 16121 $selected_row_last_value = $selected_row; 16122 16123 stop_playing_music() if (not defined $pid_player and $files_info[$selected_row]{extension_input} ne 'cda'); 16124 16125 if ( $show_time_abs and $cdplayer eq "gnormalize::cdplay" and $files_info[$selected_row]{extension_input} eq 'cda' ){ 16126 #my $current_position = gnormalize::cdplay::Info()->{frame_abs}; # absolute frame position 16127 $show_count = int ( ( gnormalize::cdplay::Info()->{frame_abs} - $toc_audiocd->[0]->{frames_abs} ) / 75 ); 16128 $show_time = int (($toc_audiocd->[0]->{total_frames} / 75 )); # absolute time 16129 } 16130 elsif ( $show_time_abs and $cdplayer eq "Audio::CD" and $files_info[$selected_row]{extension_input} eq 'cda' ){ 16131 my $info = $audiocd->stat; 16132 my ($minutes, $seconds) = $info->time; # Returns the current disc play time 16133 $show_count = time_to_sec("$minutes:$seconds"); 16134 ($minutes, $seconds) = $info->length; # Returns the disc length time 16135 $show_time = time_to_sec("$minutes:$seconds"); 16136 } 16137 16138 my ($hour,$min,$sec) = sec_to_time($show_count); # current time 16139 my ($hour_r,$min_r,$sec_r) = $show_time >= $show_count ? sec_to_time($show_time - $show_count) : sec_to_time( 0 ); # time remaining 16140 my ($hour_t,$min_t,$sec_t) = sec_to_time($show_time); # total time 16141 16142 if ( $pause eq $true and $count_blink % 2 == 0 ){ # blink - piscar 16143 $min = -2; $min_r = -2; 16144 $count_blink = 0 if $count_blink > 1000; 16145 } 16146 16147 # print "--> hour = $hour ;; min = $min ;; sec = $sec ;; total = $show_time ;; count = $show_count\n"; 16148 if ( $show_time_remaining eq $false ){ draw_play_time($da, undef, ($min,$sec,$hour) ); } 16149 else{ draw_play_time($da, undef, ($min_r,$sec_r,$hour_r) ); } 16150 16151 return $true; 16152} 16153 16154sub stop_cda { # don't stop if the next track have cda extension_input 16155 16156 if ($cdplayer eq "cdcd") { 16157 my $cmd = "$cdcd_path -d $audiodevice_path stop "; 16158 exec_cmd_system($cmd); 16159 } 16160 elsif ( $cdplayer eq "gnormalize::cdplay" ){ 16161 gnormalize::cdplay::stop_cdrom(); 16162 } 16163 elsif ( $cdplayer eq "Audio::CD" ){ # libcdaudio ;; Audio::CD ;; see <man Audio::CD> 16164 $audiocd = Audio::CD->init("$audiodevice_path"); 16165 $audiocd->stop; 16166 } 16167 $playing_music = $false; 16168 16169 if (@rows_already_played > 0 and 1==2){ #debug 16170 print "extension_last_value = $extension_last_value ; extension_input = $files_info[$selected_row]{extension_input}\n"; 16171 } 16172} 16173 16174sub stop_playing_music{ 16175 16176 my %args = ( select_color => 'no_color', # ('no_color','playing','played') 16177 scroll => $false, 16178 set_rip => $false, 16179 change_color => $true, 16180 @_, # argument pair list goes here 16181 ); 16182 my $cmd; 16183 if ( not $playing_music ){ # update the 'cdrom:' entry only if audio cd is not playing 16184 $audiodevice_path = $entry_cda->get_text(); # /dev/hdc or /dev/cdrom or ... 16185 } 16186 if ( defined($timer) ){ Glib::Source->remove($timer);} # quit loop, see <man Glib::MainLoop> 16187 16188 return unless defined $files_info[$selected_row]{extension_input}; 16189 16190 if ( $playing_music and not ($go_back or $go_forward) and $files_info[$selected_row]{extension_input} eq 'cda' ){ 16191 stop_cda(); # don't stop if the next track have cda extension_input 16192 } 16193 16194 if ($files_info[$selected_row]{extension_input} ne 'cda' and defined $pid_player){ 16195 #print "pid_player = $pid_player\n"; 16196 kill 9, $pid_player; 16197 my $pid_mplayer = $pid_player + 1; 16198 kill 9, $pid_mplayer; 16199 $pid_player = undef; 16200 $playing_music = $false; 16201 } 16202 16203 draw_buttons(Draw_Play => $true); # play button -> 16204 $count = 0; 16205 $count_blink = 0; 16206 16207 if ( not $go_forward and not $go_back ){ # erase the color 16208 # To uncolor the selected artist, stopped artist line 16209 # color_the_selected_tracks_and_scroll( select_color => 'no_color', scroll => $false, set_rip => $false ); # default values 16210 color_the_selected_tracks_and_scroll( %args ) if $args{change_color}; 16211 } 16212} 16213 16214# convert x seconds to hour:min:sec format 16215sub sec_to_time{ 16216 my $i = number_value(shift); 16217 my ($hour,$min,$sec) = (0,0,0); 16218 16219 $min = sprintf("%02d", int($i/60) ); # 02d : leading zero 16220 my $remainder = $i - $min * 60; # $remainder = $i % 60 ;; see <man perlop> 16221 $sec = sprintf("%02d", $remainder ); 16222 #print "total_sec = $i --> hour = $hour ;; min = $min ;; sec = $sec\n"; 16223 return ($hour,$min,$sec); 16224} 16225#sec_to_time('44500,893'); 16226 16227# convert hour:min:sec format to x seconds. 16228sub time_to_sec{ # $time = 2:34:01 or 01:06.39 16229 my $time = shift; 16230 my $sec = 0; 16231 my $min = 0; 16232 my $hour = 0; 16233 16234 if ($time =~ /(\d+):(\d+):(\d+[\.,]?\d*)/){ 16235 $hour = $1; 16236 $min = $2; 16237 $sec = $3; 16238 } 16239 elsif ($time =~ /(\d+):(\d+[\.,]?\d*)/){ 16240 $min = $1; 16241 $sec = $2; 16242 } 16243 elsif ($time =~ /(\d+[\.,]?\d*)/){ 16244 $sec = $1; 16245 } 16246 $sec = sprintf("%02d", number_value($sec) ); # 02.0f : leading zero 16247 #print "hour = $hour ;; min = $min ;; sec = $sec ;; time = $time"; 16248 $time = int( $hour * 3600 + $min * 60 + $sec ); 16249 #print " --> time = $time\n"; 16250 return $time; 16251} 16252#time_to_sec ( "0:2,7456"); 16253 16254sub rip_audio_cdparanoia { # MAX LENGTH = 230 for filename 16255 my $track = shift; 16256 my $file_wav = shift; 16257 my $row = $track -1; 16258 #Ripping from sector 0 (track 1 [0:00.00]) 16259 # to sector 18511 (track 1 [4:06.61]) 16260 16261 my $opt = ""; 16262 if ($button_noia1->get_active){ $opt .= "-Z ";} 16263 if ($button_noia2->get_active){ $opt .= "-z ";} 16264 if ($button_noia3->get_active){ $opt .= "-Y ";} 16265 if ($button_noia4->get_active){ $opt .= "-X ";} 16266 16267 my $cmd = "$nice_path -n $priority $cdparanoia_path -d $audiodevice_path -e -w $opt $track "; 16268 16269 my $file_in = $directory_output . '/' . $file_wav; 16270 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 16271 16272 insert_msg("." , "small-ini"); 16273 insert_msg("$cmd \"$file_in2\" " , "small"); #print on debug textview 16274 insert_msg("\n" , "small"); 16275 16276 # Use 'filename_from_unicode' to convert from unicode to local encoding. 16277 $file_in2 = filename_from_unicode $file_in2; 16278 _utf8_on($file_in2); # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'. 16279 $cmd .= " \"$file_in2\" "; 16280 16281 my $pid = open( NOIA, "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 16282 $pid_rip_cda = $pid; 16283 16284 draw_input_output($da_arrow_dec,undef,("cda","wav")); 16285 16286 my $div = 0; # initial value 16287 my $saved_value = 0; 16288 while( <NOIA> ){ 16289 #print " fora $_\n"; 16290 # simple output: 16291 #outputting to track02.cdda.wav 16292 ##: -2 [wrote] @ 682079 16293 ##: -2 [wrote] @ 683255 16294 ##: -2 [wrote] @ 684431 16295 #Ripping from sector 0 (track 1 [0:00.00]) 16296 # to sector 18511 (track 1 [4:06.61]) 16297 # (== PROGRESS == [ > .| 019261 00 ] == :^D . ==) 16298 16299 if( $_ =~ /\[wrote\]\s+@\s+(\d+)/ ) 16300 { 16301 $saved_value = $div; 16302 # progress = (sector-start)/(end-start); 16303 # CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */: 1176 = (2352/2) 16304 my $sector = $1/1176; # sector divide by 1176 16305 $div = sprintf("%0.2f", ( $sector - $start_sector[$row] )/$music_sector[$row] ); 16306 $div = number_value($div); 16307 # show only not repeated value 16308 if ( $pbar->get_fraction() <=1 and $div > $saved_value ){ 16309 $pbar->set_fraction( $div ) ; 16310 my $pct = sprintf("%2d", 100*$div ); 16311 $status_bar->push($context_id, $langs{msg054}." - $pct%"); 16312 #print ( " div = $div ;; $1 / 1176 ;; start = $start_sector[$row] ;; music_sector[$row] = $music_sector[$row]\n"); 16313 } 16314 } 16315 while ( Gtk2->events_pending() ) { Gtk2->main_iteration() } 16316 if ( not $normalize_button->get_active and $pid_rip_cda >= 0 ) { 16317 $pid_rip_cda = StopProcessing($pid_rip_cda, $langs{msg055}, $file_wav ); 16318 exec_cmd_system2( 'rm', '-f', $file_in ); # remove wav file 16319 close( NOIA ); 16320 return $false; 16321 } 16322 } 16323 close( NOIA ); 16324 if ($normalize_button->get_active) { # if normalize button is active 16325 $pbar->set_fraction( 1 ) ; 16326 $pid_rip_cda = -1; # reset rip pid on the final of process 16327 return $true; 16328 } 16329} 16330 16331 16332sub rip_audio_cdda2wav { 16333 my $track = shift; 16334 my $file_wav = shift; 16335 my $row = $track-1; 16336 16337 my $opt = ""; 16338 if ($button_cdda1->get_active){ $opt .= "-paranoia ";} 16339 if ($button_cdda2->get_active){ $opt .= "-paraopts=disable ";} 16340 if ($button_cdda3->get_active){ $opt .= "-paraopts=no-verify ";} 16341 16342 # cdda2wav -g -no-infofile dev=/dev/hdc -t 2 track - see cdda2wav -help or man cdda2wav 16343 my $cmd = "$nice_path -n $priority $cdda2wav_path dev=$audiodevice_path -x -g -no-infofile $opt -t $track "; 16344 16345 my $file_in = $directory_output . '/' . $file_wav; 16346 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 16347 16348 insert_msg("." , "small-ini"); 16349 insert_msg("$cmd \"$file_in2\" " , "small"); #print on debug textview 16350 insert_msg("\n" , "small"); 16351 16352 # Use 'filename_from_unicode' to convert from unicode to local encoding. 16353 $file_in2 = filename_from_unicode $file_in2; 16354 _utf8_on($file_in2); # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'. 16355 $cmd .= " \"$file_in2\" "; 16356 16357 my $pid = open( CDRIP, "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 16358 $pid_rip_cda = $pid; ## set rip pid, pid > 0 16359 16360 my $div = 0; # initial value 16361 my $saved_value = 0; 16362 16363 ## loop for output - initial 16364 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 16365 while( <CDRIP> ){ 16366 # simple output: 16367 # 3% 16368 16369 if( $_ =~ /\s+(\d+)%/g ) 16370 { 16371 $saved_value = $div; 16372 $div = sprintf("%0.2f", $1/100 ); 16373 $div = number_value($div); 16374 # show only not repeated value 16375 if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 16376 $pbar->set_fraction( $div ) ; 16377 $status_bar->push($context_id, " ripping audio to wav - $1%"); 16378 #print ( " div = $div \n"); 16379 } 16380 } 16381 if( $_ =~ /100%.*successfully/i ){$pbar->set_fraction(1);} 16382 16383 while ( Gtk2->events_pending() ) { Gtk2->main_iteration() } 16384 if ( not $normalize_button->get_active and $pid_rip_cda >= 0 ) { 16385 $pid_rip_cda = StopProcessing($pid_rip_cda, " Stop ripping!", $file_wav); 16386 exec_cmd_system2( 'rm', '-f', $file_in ); # remove wav file 16387 $/="\n"; # abandon loop 16388 close( CDRIP ); 16389 return $false; 16390 } 16391 } 16392 $/="\n"; ## final of loop 16393 close( CDRIP ); 16394 16395 if ($normalize_button->get_active) { # if normalize button is active 16396 $pbar->set_fraction(1) ; 16397 $pid_rip_cda = -1; # reset rip pid on the final of process 16398 return $true; 16399 } 16400} 16401 16402##-----------------------------------------------------## 16403##-----------------------------------------------------## 16404 16405# flac --> wav 16406sub decode_flac_to_wav { 16407 my %args = ( @_ ); 16408 my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 16409 16410 my $file_in = $filepath; 16411 my $file_out = $directory_output . '/' . $file_wav; 16412 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 16413 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 16414 print "decode_flac_to_wav --> Could not find flac file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 16415 16416 my $cmd = "$nice_path -n $priority $flac_path -d \"$file_in2\" -f -o \"$file_out2\" "; 16417 16418 #print "\n$cmd\n"; 16419 insert_msg("." , "small-ini"); 16420 insert_msg("$cmd" , "small"); #print on debug textview 16421 insert_msg("\n" , "small"); 16422 16423 my $pid = open( FLACDEC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 16424 $pid_flac_decode = $pid; ## set flac pid, pid > 0 16425 16426 my $div = 0; # initial value 16427 my $saved_value = 0; 16428 16429 ## loop for output - initial 16430 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 16431 while( <FLACDEC> ) 16432 { 16433 #output: 16434 # 10-Que � feito de voc�.flac: 75% complete 16435 16436 if( $_ =~ /.*:\s+(\d+)%\scomplete/ ) 16437 { 16438 #print "\n<<>> $_ --->1=$1 \n"; 16439 $saved_value = $div; 16440 $div = sprintf("%0.2f", $1/100 ); 16441 $div = number_value($div); 16442 if ( $div > 1){ $div = 1;} # to avoid possible errors 16443 16444 # show only not repeated value 16445 if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 16446 $pbar->set_fraction( $div ) ; 16447 $status_bar->push($context_id, " flac decoding $1%"); 16448 #print ( " div = $div \n"); 16449 } 16450 } 16451 while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() } 16452 if ( not $normalize_button->get_active and $pid_flac_decode >= 0 ) { 16453 $pid_flac_decode = StopProcessing($pid_flac_decode, " Stop flac decoding!", $file_wav); 16454 exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file 16455 $/="\n"; # abandon loop 16456 close( FLACDEC ); 16457 return $false; 16458 } 16459 } 16460 $/="\n"; ## final of loop 16461 close( FLACDEC ); 16462 16463 if ($normalize_button->get_active ) { # if normalize button is active 16464 $pbar->set_fraction( 1 ) ; 16465 $pid_flac_decode = -1; # reset ape deocde pid on the final of process 16466 return $true; 16467 } 16468} 16469 16470 16471# mp4 --> wav 16472sub decode_mp4_to_wav { 16473 my %args = ( @_ ); 16474 my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 16475 16476 my $file_in = $filepath; 16477 my $file_out = $directory_output . '/' . $file_wav; 16478 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 16479 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 16480 print "decode_mp4_to_wav --> Could not find mp4 file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 16481 16482 my $cmd = "$nice_path -n $priority $faad_path \"$file_in2\" -f 1 -o \"$file_out2\" "; 16483 16484 insert_msg("." , "small-ini"); 16485 insert_msg("$cmd" , "small"); #print on debug textview 16486 insert_msg("\n" , "small"); 16487 16488 my $pid = open( FAADDEC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 16489 my $pid_faad_decode = $pid; ## set flac pid, pid > 0 16490 16491 my $div = 0; # initial value 16492 my $saved_value = 0; 16493 16494 $/="\r"; 16495 while( <FAADDEC> ) 16496 { 16497 #output: 16498 # 45% decoding music.mp4. 16499 16500 if( $_ =~ /^(\d+)%\s+decoding/ ) 16501 { 16502 $saved_value = $div; 16503 $div = sprintf("%0.2f", $1/100 ); 16504 $div = number_value($div); 16505 if ( $div > 1){ $div = 1;} # to avoid possible errors 16506 16507 # show only not repeated value 16508 if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 16509 $pbar->set_fraction( $div ) ; 16510 $status_bar->push($context_id, " faad decoding $1%"); 16511 } 16512 } 16513 while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() } 16514 if ( not $normalize_button->get_active and $pid_faad_decode >= 0 ) { 16515 $pid_faad_decode = StopProcessing($pid_faad_decode," Stop faad decoding!", $file_wav); 16516 exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file 16517 $/="\n"; # abandon loop 16518 close( FAADDEC ); 16519 return $false; 16520 } 16521 } 16522 $/="\n"; ## final of loop 16523 close( FAADDEC ); 16524 16525 if ($normalize_button->get_active ) { # if normalize button is active 16526 $pbar->set_fraction( 1 ) ; 16527 $pid_faad_decode = -1; # reset ape deocde pid on the final of process 16528 return $true; 16529 } 16530} 16531 16532 16533# ape --> wav # dependence: mac from APE-3.96b8-3plf-MonkeyAudio.i586.rpm 16534sub decode_ape_to_wav { 16535 my %args = ( @_ ); 16536 my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 16537 16538 my $file_in = $filepath; 16539 my $file_out = $directory_output . '/' . $file_wav; 16540 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 16541 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 16542 print "decode_ape_to_wav --> Could not find ape file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 16543 16544 my $cmd = "$nice_path -n $priority $ape_path \"$file_in2\" \"$file_out2\" -d "; 16545 16546 #print "\n$cmd\n"; 16547 insert_msg("." , "small-ini"); 16548 insert_msg("$cmd" , "small"); #print on debug textview 16549 insert_msg("\n" , "small"); 16550 16551 # STDIN is file descriptor number 0; STDOUT number 1; and STDERR number 2. 16552 # To exchange a command's STDOUT and STDERR, i.e., capture the STDERR 16553 # but have its STDOUT come out on our old STDERR: 3>&1 1>&2 2>&3 3>&- 16554 # 3>&1 : Make a new file descriptor, number 3, be a copy of number 1. 16555 # d3=d1 16556 # d1=d2 16557 # d2=d3 16558 my $pid = open( APEDEC, filename_from_unicode "$cmd 3>&1 1>&2 2>&3 3>&- |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 16559 $pid_ape = $pid; ## set ape pid, pid > 0 16560 16561 my $div = 0; # initial value 16562 my $saved_value = 0; 16563 16564 ## loop for output - initial 16565 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 16566 while( <APEDEC> ) 16567 { 16568 #output: 16569 #--- Monkey's Audio Console Front End (v3.96b8) (c) Matthew T. Ashland --- 16570 #Decompressing ... 16571 #Progress: 3.0% (357.7 sec remaining, 368.8 sec total) 16572 16573 if( $_ =~ /^Progress:\s+(\d+[\.,]\d)%\s\((.*remaining).*/i ) 16574 { 16575 #print "\n<<>> $_ --->1=$1 --->2=$2\n"; 16576 $saved_value = $div; 16577 $div = sprintf("%0.2f", $1/100 ); 16578 $div = number_value($div); 16579 if ( $div > 1){ $div = 1;} # to avoid possible errors 16580 16581 # show only not repeated value 16582 if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 16583 $pbar->set_fraction( $div ) ; 16584 $status_bar->push($context_id, " ape decoding $1% | $2"); 16585 #print ( " div = $div \n"); 16586 } 16587 } 16588 while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() } 16589 if ( not $normalize_button->get_active and $pid_ape >= 0 ) { 16590 $pid_ape = StopProcessing($pid_ape," Stop ape decoding!", $file_wav); 16591 exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file 16592 $/="\n"; # abandon loop 16593 close( APEDEC ); 16594 return $false; 16595 } 16596 } 16597 $/="\n"; ## final of loop 16598 close( APEDEC ); 16599 16600 if ($normalize_button->get_active ) { # if normalize button is active 16601 $pbar->set_fraction( 1 ) ; 16602 $pid_ape = -1; # reset ape deocde pid on the final of process 16603 return $true; 16604 } 16605} 16606 16607# mpc --> wav 16608sub decode_mpc_to_wav { 16609 my %args = ( @_ ); 16610 my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 16611 16612 my $file_in = $filepath; 16613 my $file_out = $directory_output . '/' . $file_wav; 16614 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 16615 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 16616 print "decode_mpc_to_wav --> Could not find mpc file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 16617 16618 my $cmd = "$nice_path -n $priority $mpcdec_path \"$file_in2\" --wav \"$file_out2\" "; 16619 16620 #print "\n$cmd\n"; 16621 insert_msg("." , "small-ini"); 16622 insert_msg("$cmd" , "small"); #print on debug textview 16623 insert_msg("\n" , "small"); 16624 16625 ## $res = pid of ogg 16626 my $res = open( MPCDEC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 16627 $pid_mpc_decode = $res; ## set ogg pid, pid > 0 16628 16629 my $div = 0; # initial value 16630 my $saved_value = 0; 16631 16632 ## loop for output - initial 16633 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 16634 while( <MPCDEC> ) 16635 { 16636 #output: 16637 # 203.6 kbps, 4:52.68, SV 7.0, Profile 'BrainDead' (Beta 1.14) 16638 # 1:20.58/ 4:52.68 decoded (27.5%) 16639 16640 if( $_ =~ /\sdecoded\s\((\s*\d*[\.,]\d)%\)/ ) 16641 { 16642 $saved_value = $div; 16643 $div = sprintf("%0.2f", $1/100 ); 16644 $div = number_value($div); 16645 if ( $div > 1){ $div = 1;} # to avoid possible errors 16646 16647 # show only not repeated value 16648 if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 16649 $pbar->set_fraction( $div ) ; 16650 $status_bar->push($context_id, " mpc decode $1%"); 16651 #print ( " div = $div \n"); 16652 } 16653 } 16654 while ( Gtk2->events_pending() ) { Gtk2->main_iteration() } 16655 16656 if ( not $normalize_button->get_active and $pid_mpc_decode >= 0 ) { 16657 $pid_mpc_decode = StopProcessing($pid_mpc_decode, " Stop mpc decoding!", $file_wav); 16658 if ( -e filename_from_unicode $file_out ){ 16659 exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file 16660 } 16661 close( MPCDEC ); 16662 return $false; 16663 } 16664 } 16665 $/="\n"; ## final of loop 16666 close( MPCDEC ); 16667 16668 if ($normalize_button->get_active ) { # if normalize button is active 16669 $pbar->set_fraction( 1 ) ; 16670 $status_bar->push($context_id, " mpc decode 100%"); 16671 $pid_mpc_decode = -1; # reset oggdec pid on the final of process 16672 return $true; 16673 } 16674} 16675 16676# ogg --> wav 16677 16678sub decode_ogg_to_wav { 16679 my %args = ( @_ ); 16680 my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 16681 16682 my $file_in = $filepath; 16683 my $file_out = $directory_output . '/' . $file_wav; 16684 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 16685 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 16686 print "decode_ogg_to_wav --> Could not find ogg file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 16687 16688 my $cmd = "$nice_path -n $priority $oggdec_path \"$file_in2\" -o \"$file_out2\" "; 16689 16690 #print "\n$cmd\n"; 16691 insert_msg("." , "small-ini"); 16692 insert_msg("$cmd" , "small"); #print on debug textview 16693 insert_msg("\n" , "small"); 16694 16695 my $res = open( OGGDEC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 16696 $pid_ogg_decode = $res; ## set ogg pid, pid > 0 16697 16698 my $div = 0; # initial value 16699 my $saved_value = 0; 16700 16701 ## loop for output - initial 16702 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 16703 while( <OGGDEC> ) 16704 { 16705 #output: 16706 # OggDec 1.0 16707 # Decoding "lix�o-��o ��t�es'a.ogg" to "lix�o-��o ��t�es'a.wav" 16708 # [ 5.5%] 16709 # [ 88.5%] 16710 # [100.0%] 16711 16712 if( $_ =~ /^\s*\[(\s*\d*)[\.,](\d)%\]/ ) 16713 { 16714 $saved_value = $div; 16715 $div = sprintf("%0.2f", $1/100 ); 16716 $div = number_value($div); 16717 if ( $div > 1){ $div = 1;} # to avoid possible errors 16718 16719 # show only not repeated value 16720 if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 16721 $pbar->set_fraction( $div ) ; 16722 $status_bar->push($context_id, " ogg decode $1%"); 16723 } 16724 } 16725 while ( Gtk2->events_pending() ) { Gtk2->main_iteration() } 16726 16727 if ( not $normalize_button->get_active and $pid_ogg_decode >= 0 ) { 16728 $pid_ogg_decode = StopProcessing($pid_ogg_decode, " Stop ogg decoding!", $file_wav); 16729 if ( -e filename_from_unicode $file_out ){ 16730 exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file 16731 } 16732 close( OGGDEC ); 16733 return $false; 16734 } 16735 } 16736 $/="\n"; ## final of loop 16737 close( OGGDEC ); 16738 16739 if ($normalize_button->get_active) { # if normalize button is active 16740 $pid_ogg_decode = -1; # reset oggdec pid on the final of process 16741 return $true; 16742 } 16743} 16744 16745 16746# mp3 --> wav 16747 16748sub decode_mp3_to_wav { 16749 my %args = ( @_ ); 16750 my $file_mp3 = $args{file_mp3}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 16751 16752 my $cmd = "$nice_path -n $priority $lame_path --verbose --decode "; 16753 16754 my $file_in = $filepath; 16755 my $file_out = $directory_output . '/' . $file_wav; 16756 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 16757 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 16758 print "decode_mp3_to_wav --> Could not find mp3 file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 16759 16760 $cmd .= "\"$file_in2\" \"$file_out2\""; 16761 16762 insert_msg("." , "small-ini"); 16763 insert_msg("$cmd" , "small"); #print on debug textview 16764 insert_msg("\n" , "small"); 16765 16766 my $pid = open( LAME, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 16767 $pid_lame_decode = $pid; ## set lame pid, pid > 0 see <man perlipc> 16768 16769 my $saved_value = 0; 16770 my $div = 0; 16771 16772 ## loop for output - initial 16773 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 16774 while( <LAME> ) 16775 { 16776 #output: 16777 #ID3v2 found. Be aware that the ID3 tag is currently lost when transcoding. 16778 #input: almir_sater-instrumental-01_corumb�.mp3 16779 # (44.1 kHz, 2 channels, MPEG-1 Layer III) 16780 #output: almir_sater-instrumental-01_corumb�.mp3.wav (16 bit, Microsoft WAVE) 16781 #skipping initial 1105 samples (encoder+decoder delay) 16782 #Frame# 2806/8937 160 kbps L R 16783 16784 #print (" $_ \n"); 16785 16786 if( $_ =~ /^\s*Frame\#\s+(\d+)\/(\d+)\s+.*/ ) 16787 { 16788 my $frames = $1; 16789 my $numframes = $2; 16790 if ( $2 == 0 ){return;} 16791 $saved_value = $div; 16792 $div = sprintf("%0.2f", $1/$2 ); 16793 $div = number_value($div); 16794 my $pct = sprintf("%2.0f", $div*100 ); 16795 if ( $div > 1){ $div = 1;} 16796 #next if ($div <= $saved_value); 16797 16798 if ( $pbar->get_fraction() <=1 and $div > $saved_value ) { 16799 $pbar->set_fraction( $div ) ; 16800 $status_bar->push($context_id, " lame decode $pct%"); 16801 } 16802 } 16803 while ( Gtk2->events_pending() ) { Gtk2->main_iteration() } 16804 16805 if ( not $normalize_button->get_active and $pid_lame_decode >= 0 ) { 16806 # set lamepid to -1 after stop the process 16807 $pid_lame_decode = StopProcessing($pid_lame_decode, $langs{msg057}, $file_wav ); 16808 # In the case of stop decode process, always remove file_wav if it exist 16809 # because the file_wav is not complete/entire 16810 if ( -e filename_from_unicode $file_out ){ 16811 exec_cmd_system2( 'rm', '-f', $file_out ); # remove wav file 16812 } 16813 close( LAME ); 16814 return $false; 16815 } 16816 } 16817 $/="\n"; ## final of loop 16818 close( LAME ); 16819 16820 if ($normalize_button->get_active) { # if normalize button is active 16821 $pid_lame_decode = -1; # reset lame pid on the final of process 16822 return $true; 16823 } 16824} 16825 16826sub normalize_wav { #29Abr2008 -- normalize_wav_with_wavegain 16827 my %args = ( @_ ); 16828 my $dir = $args{directory}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 16829 my $row = $args{row}; 16830 16831 $adjust = 0; 16832 $already_normalized = $false; 16833 16834 if ( not -e filename_from_unicode "$directory_output/$file_wav" ) { 16835 insert_msg("\n$directory_output/$file_wav : $! \n" , "small-red"); # print on debug textview 16836 $normalize_button->set_active($false); 16837 return $false; 16838 } 16839 16840 make_directory_final(%args); 16841 16842 # -12.0dB <= $gain <= +12.0dB ; $gain = 0.0dB correspond to 89dB standard value 16843 $gain = sprintf("%0.2f", $spinner->get_value ); 16844 $gain = number_value($gain); # For example, change '0,57' by '0.57'. 16845 16846 my $Coment = $entry_def_comment->get_text; 16847 $Coment = remove_change_10_chars($Coment); 16848 16849 if ( $Coment ne "" ) { 16850 16851 my $gain_com = $gain; 16852 $gain_com = 'Not Normalized' if $norm_type eq 'None'; 16853 $gain_com = '0.00' if $norm_type eq 'Album'; 16854 16855 $Coment =~ s/\%gain/$gain_com/ig; 16856 $files_info[$row]{comment} = $Coment; # change comment tag value 16857 } 16858 16859 # get the wave total miliseconds ;; 16860 # 2352 = bytes per frame, "raw" mode ;; 1 sec have 75 frames = 75 * 2352 bytes = 176400 bytes 16861 my $fileSize = -s filename_from_unicode "$directory_output/$file_wav"; # $fileSize = $FileLength + 8 = Wav DataLength + 44 16862 $metadata{'Length'} = int( ($fileSize - 44) / 176400 * 1000 ) ; # length of audio file in milliseconds 16863 #print " Length = $metadata{'Length'} ;; fileSize = $fileSize bytes\n"; 16864 16865 my @cmd_args = ( $nice_path, '-n', $priority, $wavegain_path, '-r', '-y' ); 16866 16867 if ( $norm_type eq "Track" ) { push @cmd_args, ( '-g', $gain ); } # add more args to command 16868 elsif ( $norm_type eq "Album" ) { push @cmd_args, ( '-g', '0.00' ); } # don't implemented yet! 16869 elsif ( $norm_type eq "None" ) { #----------------------------------# 16870 $pbar_n->set_text( $langs{msg045} ); # 16871 insert_msg( $langs{msg041} , "small-red"); # 16872 insert_msg("\n" , "small"); # 16873 $pid_normalize = -1; # 16874 return; # 16875 }#--------------------------------------------------------------------# 16876 16877 #my $cmd = "$wavegain_path -r -y -g $gain \"$directory_output/$file_wav\" "; 16878 my $cmd = "@cmd_args "; 16879 16880 my $file_in = $directory_output . '/' . $file_wav; 16881 (my $file_in2 = $file_in) =~ s/"/\\"/g; # change all " characters by \" 16882 print "normalize_wav --> Could not find wav file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 16883 16884 $cmd .= " \"$file_in2\""; 16885 16886 insert_msg("." , "small-ini"); 16887 insert_msg("$cmd" , "small"); #print on debug textview 16888 insert_msg("\n" , "small"); 16889 16890 my $div = 0; 16891 my $saved_value = 0; 16892 16893 $pbar_n->set_text( $langs{msg006} ); # "Analyzing with ReplayGain normalization algorithms ..." 16894 while (Gtk2->events_pending()) { Gtk2->main_iteration()}; 16895 16896 # see 'man perlfaq8', 'man IPC::Open3' or 'fttp://perldoc.perl.org'. 16897 # use open3 because it entries ('command', 'args') is Locale-independent (don't have conversion '0.30' to '0,30'). 16898 # use IPC::Open3; 16899 # use Symbol qw(gensym); 16900 16901 # Let STDOUT go to our own STDERR and capture a program's STDERR: 16902 # $pid = open3(\*CHLD_IN, \*CHLD_OUT, \*CHLD_ERR,'some cmd and args', 'optarg', ...); 16903 # my $pid = open3(gensym, ">&STDERR", \*NORMALIZE, @cmd_args) or die "Couldn't execute \"@cmd_args\": $!, stopped\n"; 16904 16905 my $pid = open( NORMALIZE, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 16906 $pid_normalize = $pid; # set normalize pid 16907 16908 $/="\r"; ## loop for output - initial 16909 while( <NORMALIZE> ) 16910 { 16911 # Analyzing... 16912 16913 # Gain | Peak | Scale | New Peak |Left DC|Right DC| Track 16914 # | | | |Offset | Offset | Track 16915 # -------------------------------------------------------------- 16916 # +6.91 dB | 14245 | 2.22 | 31561 | 0 | 0 | 05-Jo�o Bosco-Escadas da Penha.wav 16917 16918 # Applying Gain of +6.91 dB to file: 05-Jo�o Bosco-Escadas da Penha.wav 16919 #This file 100% done All files 99% done 16920 # WaveGain Processing completed normally 16921 16922 # No Title Gain adjustment or DC Offset correction required for file: 16923 16924 # Error renaming '/tmp/wavegain.tmp' to '04.wav' (uh-oh) 16925 # Error processing GAIN for file - 04.wav 16926 16927 #print "--> $_\n"; 16928 16929 if ( $_ =~ /^\s+Applying Gain of ([-+]\d+[.,]\d+) dB to file:/ ){ $adjust = $1; } 16930 16931 if ( $_ =~ /^This\sfile\s+(\d+)\%\s*done\s+All\sfiles/ ) 16932 { 16933 $saved_value = $div; 16934 $div = sprintf("%0.2f", $1/100 ); 16935 $div = number_value($div); 16936 if ( $div >= 1 ){ $div = 1;} # to avoid possible errors 16937 16938 # show only not repeated value 16939 if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 16940 $pbar_n->set_fraction( $div ) ; 16941 $pbar_n->set_text( $langs{msg050} . "${adjust}dB..."); 16942 $status_bar->push($context_id, $langs{msg051} . "${adjust}dB"); 16943 $pbar_n->set_orientation('left_to_right'); 16944 } 16945 } 16946 if ( $_ =~ /WaveGain Processing completed normally/ ) 16947 { 16948 $pbar_n->set_fraction( 1 ) ; 16949 $pbar_n->set_text( $langs{msg050} . "${adjust}dB..."); 16950 $status_bar->push($context_id, $langs{msg051} . "${adjust}dB"); 16951 } 16952 #if ( $_ =~ /Error renaming/){ insert_msg("$_" , "small-red"); insert_msg("\n" , "small"); } 16953 if ( $_ =~ /No Title Gain adjustment.*required/ ){ 16954 $already_normalized = $true; 16955 $pbar_n->set_fraction( 1 ) ; 16956 $pbar_n->set_text( $langs{msg047} ); 16957 insert_msg( $langs{msg048} . "\n", "small-red"); 16958 } 16959 while (Gtk2->events_pending()) { Gtk2->main_iteration()}; 16960 16961 if ( not $normalize_button->get_active and $pid_normalize >= 0 ) { 16962 $pid_normalize = StopProcessing($pid_normalize, $langs{msg049}, $file_wav ); 16963 $/="\n"; # abandon loop 16964 } 16965 } 16966 $/="\n"; ## final of loop 16967 close( NORMALIZE ); 16968 waitpid($pid, 0); 16969 16970 if ($normalize_button->get_active) { # if normalize button is active 16971 if ( not $already_normalized ){ 16972 insert_msg( $langs{msg053}."${adjust}dB." , "black"); 16973 insert_msg("\n" , "small"); 16974 } 16975 $pid_normalize = -1; # reset normalize pid on the final of process 16976 return $true; 16977 } 16978 else {return $false;} 16979} 16980 16981sub encode_wav_to_wav { # actualy, don't need to encode because the output is wav! 16982 my %args = ( @_ ); 16983 my $row = $args{row}; my $file_wav = $args{file_wav}; 16984 16985 my $file_in = $directory_output.'/'.$file_wav; 16986 my $file_out = $directory_final.'/'.$file_wav; 16987 16988 remove_apetag (%args, (filepath => $file_in) ); 16989 $metadata{'Encoded by'} = "WAVEGAIN with gnormalize (http://gnormalize.sourceforge.net)"; 16990 write_apetag (%args, (filepath => $file_in) ); 16991 16992 my @cmd = ( 'cp', '-f', $file_in, $file_out ); 16993 insert_msg("." , "small-ini"); 16994 insert_msg("@cmd" , "small"); # print on debug textview 16995 insert_msg("\n" , "small"); 16996 exec_cmd_system2(@cmd); 16997 16998 if ($normalize_button->get_active) { return $true; } 16999 else { return $false;} 17000} 17001 17002# wav --> ogg 17003sub encode_wav_to_ogg { 17004 my %args = ( @_ ); 17005 my $row = $args{row}; my $file_ogg = $args{file_ogg}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 17006 17007 my $Title = $files_info[$row]{title}; 17008 my $Artist = $files_info[$row]{artist}; 17009 my $Comment = $files_info[$row]{comment}; 17010 my $Album = $files_info[$row]{album}; 17011 my $Genre = $files_info[$row]{genre}; 17012 my $Year = $files_info[$row]{year}; 17013 my $Track_Number = $files_info[$row]{track}; 17014 my $Total_Track = $files_info[$row]{total_track}; 17015 17016 my $bitrate; 17017 my $mode; 17018 my $freq; 17019 17020 ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args); 17021 17022 # bug of oggenc: 17023 # The command, for example, "oggenc -q 5.5 -m 96 -M 320 music.wav" has a bug for options 17024 # -q, -m, and -M, such that -m is minimum allowed bitrate and -M is maximum allowed bitrate. 17025 # The solution is omit the options -m and -M, so the corrected command is 17026 # "oggenc -q 5.5 music.wav" used for variable bitrate. 17027 17028 my $cmd = "$nice_path -n $priority $oggenc_path "; 17029 17030 # oggenc commands 17031 if ( $encode eq "variable" ){ # VBR (variable bitrate) 17032 # m - minimum allowed bitrate - see <man oggenc> 17033 # M - maximum allowed bitrate 17034 # q - Variable BitRate - -1 <= quality <= 10 17035 # min and max: -m $vb_Min -M $vb_Max 17036 # $cmd = "$oggenc_path -q $Vogg -m $vb_Min -M $vb_Max "; # bug of oggenc. Don't use -m and -M options 17037 $cmd .= "-q $Vogg "; 17038 } 17039 else{ # for ABR (average bitrate) 17040 $cmd .= "-b $bitrate -m $vb_Min -M $vb_Max "; 17041 } 17042 $additional_command_ogg = $entry_command_ogg->get_text; 17043 $cmd .= " --resample \"$freq\" $additional_command_ogg "; 17044 17045 my $file_in = $directory_output . '/' . $file_wav; 17046 my $file_out = $directory_final . '/' . $file_ogg; 17047 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 17048 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 17049 print "encode_wav_to_ogg --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 17050 17051 $cmd .= " \"$file_in2\" -o \"$file_out2\" "; 17052 17053 insert_msg("." , "small-ini"); 17054 insert_msg("$cmd" , "small"); #print on debug textview 17055 insert_msg("\n" , "small"); 17056 17057 ## start encoding 17058 my $res = open( OGGENC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 17059 $pid_ogg_encode = $res; ## set ogg encode pid 17060 17061 my $saved_value = 0; 17062 my $div = 0; 17063 17064 ## loop for output - initial 17065 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 17066 while( <OGGENC> ) 17067 { 17068 ## this is output of oggenc: 17069 17070 # Opening with wav module: WAV file reader 17071 # Encoding "music.wav" to 17072 # "music.ogg" 17073 # at quality 3.00 17074 # [ 1.5%] [ 0m13s remaining] | 17075 # [ 21.6%] [ 0m08s remaining] / 17076 # [ 99.9%] [ 0m00s remaining] - 17077 # Done encoding file "music.ogg" 17078 # File length: 0m 56.0s 17079 # Elapsed time: 0m 10.7s 17080 # Rate: 5.3075 17081 # Average bitrate: 114.4 Kb/s 17082 17083 if( $_ =~ /^\s*\[(\s*\d*[\.,]\d)%\]\s+\[\s*(\d*)m(\d*)s\sremaining\]/ ) 17084 { 17085 $saved_value = $div; 17086 $div = sprintf("%0.2f", number_value($1)/100 ); 17087 $div = number_value($div); 17088 my $pct = sprintf("%02d", number_value($1) ); # 02d : leading zero 17089 if ( $div > 1){ $div = 1;} # to avoid possible errors 17090 17091 # show only not repeated value 17092 if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 17093 $pbar_encode->set_fraction( $div ) ; 17094 $status_bar->push($context_id, " ogg encode $pct% | time remaining = $2:$3"); 17095 } 17096 } 17097 while ( Gtk2->events_pending() ) { Gtk2->main_iteration() } 17098 17099 if ( not $normalize_button->get_active and $pid_ogg_encode >= 0 ) { 17100 $pid_ogg_encode = StopProcessing($pid_ogg_encode," Stop ogg encoding!", $file_wav); 17101 $/="\n"; # abandon loop 17102 } 17103 } 17104 $/="\n"; ## final of loop 17105 close(OGGENC); 17106 17107 my @cmd_tag = ( $vorbiscomment_path, '--raw', '-t', "title=$Title", '-t', "artist=$Artist" ); 17108 push @cmd_tag, ( '-t', "genre=$Genre", '-t', "date=$Year", '-t', "album=$Album" ); 17109 if ( $Total_Track ne "" and $Total_Track >= $Track_Number ) { 17110 push @cmd_tag, ( '-t', "tracknumber=$Track_Number/$Total_Track" ); } 17111 else { push @cmd_tag, ( '-t', "tracknumber=$Track_Number" ); } 17112 push @cmd_tag, ( '-t', "description=$Comment", '-t', "comment=$Comment", '-w' ); 17113 17114 if ( $vorbiscomment_path ne "" and $normalize_button->get_active ){ 17115 insert_msg("." , "small-ini"); 17116 insert_msg("@cmd_tag \"$file_out2\"" , "small"); #print on debug textview 17117 insert_msg("\n" , "small"); 17118 17119 push @cmd_tag, ( filename_from_unicode $file_out ); 17120 exec_cmd_system3(@cmd_tag); 17121 } 17122 17123 if ($normalize_button->get_active) { # if normalize button is active 17124 $pid_ogg_encode = -1; # reset pid on the final of process 17125 return $true; } 17126 else { return $false;} 17127} 17128 17129 17130# wav --> mpc 17131sub encode_wav_to_mpc { 17132 my %args = ( @_ ); 17133 my $row = $args{row}; my $file_mpc = $args{file_mpc}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 17134 17135 my $Title = $files_info[$row]{title}; 17136 my $Artist = $files_info[$row]{artist}; 17137 my $Comment = $files_info[$row]{comment}; 17138 my $Album = $files_info[$row]{album}; 17139 my $Genre = $files_info[$row]{genre}; 17140 my $Year = $files_info[$row]{year}; 17141 my $Track_Number = $files_info[$row]{track}; 17142 my $Total_Track = $files_info[$row]{total_track}; 17143 17144 my $bitrate; 17145 my $mode; 17146 my $freq; 17147 17148 ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args); 17149 17150 # --nmt x set NMT value to x dB (dflt: 6.5) 17151 # smr (signal to mask ratio) 17152 # --minSMR over 0 db will result in full bandwidth encoding. 17153 #$cmd = "$mpcenc_path --overwrite --quality $Vmpc --minSMR 0 --nmt 12 --tmn 32 "; 17154 my $profile = '--standard'; 17155 if ( $Vmpc < 2.5 ){ $profile = '--telephone'; } 17156 elsif ( $Vmpc < 3.5 ){ $profile = '--thumb'; } 17157 elsif ( $Vmpc < 4.5 ){ $profile = '--radio'; } 17158 elsif ( $Vmpc < 5.5 ){ $profile = '--standard'; } 17159 elsif ( $Vmpc < 6.5 ){ $profile = '--xtreme'; } 17160 elsif ( $Vmpc < 7.5 ){ $profile = '--insane'; } 17161 else { $profile = '--braindead'; } 17162 17163 $additional_command_mpc = $entry_command_mpc->get_text; 17164 17165 my $cmd = "$nice_path -n $priority $mpcenc_path --overwrite $profile $additional_command_mpc "; 17166 17167 my $file_in = $directory_output . '/' . $file_wav; 17168 my $file_out = $directory_final . '/' . $file_mpc; 17169 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 17170 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 17171 print "encode_wav_to_mpc --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 17172 17173 insert_msg("." , "small-ini"); 17174 insert_msg("$cmd \"$file_in2\" \"$file_out2\" " , "small"); #print on debug textview 17175 insert_msg("\n" , "small"); 17176 17177 # Use 'filename_from_unicode' to convert from unicode to local encoding. 17178 $file_in2 = filename_from_unicode $file_in2; 17179 $file_out2 = filename_from_unicode $file_out2; 17180 _utf8_on($file_in2); # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'. 17181 _utf8_on($file_out2); # Turns on the UTF8 flag in $file_out2 string. 17182 $cmd .= " \"$file_in2\" \"$file_out2\" "; 17183 17184 # start encoding 17185 my $res = open( MPCENC, "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 17186 $pid_mpc_encode = $res; # set mpc encode pid 17187 17188 my $saved_value = 0; 17189 my $div = 0; 17190 17191 ## loop for output - initial 17192 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 17193 while( <MPCENC> ) 17194 { 17195 ## this is output of mppenc: 17196 # %|avg.bitrate| speed|play time (proc/tot)| CPU time (proc/tot)| ETA 17197 # 5.9 119.8 kbps 7.67x 0:17.1 4:52.6 0:02.2 0:38.1 0:35.9 17198 # 24.4 126.3 kbps 7.49x 1:11.5 4:52.6 0:09.5 0:39.0 0:29.5 17199 # 24,4 17200 17201 # print "aquiiii: $_\n"; 17202 17203 if( $_ =~ /^\s+(\d+[\.,]\d+)\s+.*kbps\s+(\d+[\.,]\d+)x.*(\d+:\d+)/ ) 17204 { 17205 #print "\n<<>> $_ --->1=$1 --->2=$2 --->3=$3\n"; 17206 $saved_value = $div; 17207 $div = sprintf("%0.2f", $1/100 ); 17208 $div = number_value($div); 17209 my $speed = sprintf("%0.1f", $2 ); 17210 my $pct = sprintf("%02d", $1 ); # 02d : leading zero 17211 if ( $div > 1){ $div = 1;} # to avoid possible errors 17212 17213 # show only not repeated value 17214 if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 17215 $pbar_encode->set_fraction( $div ) ; 17216 # print ( " div = $div ; time remain = $3 \n"); 17217 $status_bar->push($context_id, " mpc encode $pct% | time remaining = $3 | encode speed = $speed"); 17218 } 17219 } 17220 while (Gtk2->events_pending()) { Gtk2->main_iteration()}; 17221 17222 if ( not $normalize_button->get_active and $pid_mpc_encode >= 0 ) { 17223 $pid_mpc_encode = StopProcessing($pid_mpc_encode," Stop mpc encoding!", $file_wav); 17224 $/="\n"; # abandon loop 17225 } 17226 } 17227 $/="\n"; ## final of loop 17228 close(MPCENC); 17229 17230 if( -e filename_from_unicode $file_out ) { 17231 17232 remove_apetag (%args, (filepath => $file_out) ); 17233 $metadata{'Encoded by'} = "MPCENC with gnormalize (http://gnormalize.sourceforge.net)"; 17234 write_apetag (%args, (filepath => $file_out) ); 17235 } 17236 else { print "encode_wav_to_mpc --> Could not find mpc file: $file_out\n"; } 17237 17238 if ($normalize_button->get_active) { # if normalize button is active 17239 $pid_mpc_encode = -1; # reset pid on the final of process 17240 return $true; } 17241 else { return $false;} 17242} 17243 17244 17245# wav --> ape 17246sub encode_wav_to_ape { 17247 my %args = ( @_ ); 17248 my $row = $args{row}; my $file_ape = $args{file_ape}; my $file_wav = $args{file_wav}; 17249 17250 my $Title = $files_info[$row]{title}; 17251 my $Artist = $files_info[$row]{artist}; 17252 my $Comment = $files_info[$row]{comment}; 17253 my $Album = $files_info[$row]{album}; 17254 my $Genre = $files_info[$row]{genre}; 17255 my $Year = $files_info[$row]{year}; 17256 my $Track_Number = $files_info[$row]{track}; 17257 my $Total_Track = $files_info[$row]{total_track}; 17258 17259 my $compress = $spinner_compress->get_value_as_int(); 17260 $additional_command_ape = $entry_command_ape->get_text; 17261 my $cmd = "$nice_path -n $priority $ape_path $additional_command_ape "; 17262 17263 my $file_in = $directory_output . '/' . $file_wav; 17264 my $file_out = $directory_final . '/' . $file_ape; 17265 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 17266 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 17267 print "encode_wav_to_ape --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 17268 17269 17270 insert_msg("." , "small-ini"); 17271 insert_msg("$cmd \"$file_in2\" \"$file_out2\" -c$compress " , "small"); #print on debug textview 17272 insert_msg("\n" , "small"); 17273 17274 # Use 'filename_from_unicode' to convert from unicode to local encoding. 17275 $file_in2 = filename_from_unicode $file_in2; 17276 $file_out2 = filename_from_unicode $file_out2; 17277 _utf8_on($file_in2); # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'. 17278 _utf8_on($file_out2); # Turns on the UTF8 flag in $file_out2 string. 17279 $cmd .= " \"$file_in2\" \"$file_out2\" -c$compress "; 17280 17281 # To exchange a command's STDOUT and STDERR in order to capture the STDERR 17282 my $pid = open( APEENC, "$cmd 3>&1 1>&2 2>&3 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 17283 $pid_ape = $pid; ## set ape pid, pid > 0 17284 17285 my $div = 0; # initial value 17286 my $saved_value = 0; 17287 17288 $/="\r"; ## loop for output - initial 17289 while( <APEENC> ) 17290 { 17291 #output: 17292 #--- Monkey's Audio Console Front End (v3.96b8) (c) Matthew T. Ashland --- 17293 #Decompressing ... 17294 #Progress: 3.0% (357.7 sec remaining, 368.8 sec total) 17295 17296 if( $_ =~ /^Progress:\s+(\d+[\.,]\d)%\s\((.*)\)/ ) 17297 { 17298 #print "\n<<>> $_ --->1=$1 --->2=$2\n"; 17299 $saved_value = $div; 17300 $div = sprintf("%0.2f", $1/100 ); 17301 $div = number_value($div); 17302 if ( $div > 1){ $div = 1;} # to avoid possible errors 17303 17304 # show only not repeated value 17305 if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 17306 $pbar_encode->set_fraction( $div ) ; 17307 $status_bar->push($context_id, " ape encoding $1% | $2"); 17308 #print ( " div = $div \n"); 17309 } 17310 } 17311 while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() } 17312 if ( not $normalize_button->get_active and $pid_ape >= 0 ) { 17313 $pid_ape = StopProcessing($pid_ape," Stop ape encoding!", $file_wav); 17314 $/="\n"; # abandon loop 17315 } 17316 } 17317 $/="\n"; ## final of loop 17318 close( APEENC ); 17319 17320 if( -e filename_from_unicode $file_out ) { 17321 17322 remove_apetag (%args, (filepath => $file_out) ); 17323 $metadata{'Encoded by'} = "MAC with gnormalize (http://gnormalize.sourceforge.net)"; 17324 write_apetag (%args, (filepath => $file_out) ); 17325 } 17326 else { print "encode_wav_to_ape --> Could not find ape file: $file_out\n"; } 17327 17328 if ($normalize_button->get_active) { # if normalize button is active 17329 $pid_ape = -1; # reset pid on the final of process 17330 return $true; } 17331 else { return $false;} 17332} 17333 17334# wav --> flac 17335sub encode_wav_to_flac { 17336 my %args = ( @_ ); 17337 my $row = $args{row}; my $file_flac = $args{file_flac}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 17338 17339 my $Title = $files_info[$row]{title}; 17340 my $Artist = $files_info[$row]{artist}; 17341 my $Comment = $files_info[$row]{comment}; 17342 my $Album = $files_info[$row]{album}; 17343 my $Genre = $files_info[$row]{genre}; 17344 my $Year = $files_info[$row]{year}; 17345 my $Track_Number = $files_info[$row]{track}; 17346 my $Total_Track = $files_info[$row]{total_track}; 17347 17348 my $cmd; # command 17349 my $bitrate; 17350 my $mode; 17351 my $freq; 17352 my $compress = $spinner_compress_flac->get_value(); 17353 17354 ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args); 17355 17356 $additional_command_flac = $entry_command_flac->get_text; 17357 $cmd = "$nice_path -n $priority $flac_path -$compress -f $additional_command_flac "; 17358 17359 my $file_in = $directory_output . '/' . $file_wav; 17360 my $file_out = $directory_final . '/' . $file_flac; 17361 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 17362 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 17363 print "encode_wav_to_flac --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 17364 17365 insert_msg("." , "small-ini"); 17366 insert_msg("$cmd \"$file_in2\" -o \"$file_out2\"" , "small"); #print on debug textview 17367 insert_msg("\n" , "small"); 17368 17369 # Use 'filename_from_unicode' to convert from unicode to local encoding. 17370 $file_in2 = filename_from_unicode $file_in2; 17371 $file_out2 = filename_from_unicode $file_out2; 17372 _utf8_on($file_in2); # Don't let Perl to convert $file_in2 to unicode. See 'man Encode'. 17373 _utf8_on($file_out2); # Turns on the UTF8 flag in $file_out2 string. 17374 $cmd .= " \"$file_in2\" -o \"$file_out2\" "; 17375 17376 my $pid = open( FLAC, "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 17377 $pid_flac_decode = $pid; ## set flac pid, pid > 0 17378 17379 my $div = 0; # initial value 17380 my $saved_value = 0; 17381 17382 ## loop for output - initial 17383 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 17384 while( <FLAC> ) 17385 { 17386 #output:options: -P 4096 -b 4608 -m -l 8 -q 0 -r 3,3 17387 #audio.wav: 51% complete, ratio=0.717 17388 17389 if( $_ =~ /.*:\s+(\d+)%\scomplete/ ) 17390 { 17391 #print "\n<<>> $_ --->1=$1 \n"; 17392 $saved_value = $div; 17393 $div = sprintf("%0.2f", $1/100 ); 17394 $div = number_value($div); 17395 if ( $div > 1){ $div = 1;} # to avoid possible errors 17396 17397 # show only not repeated value 17398 if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 17399 $pbar_encode->set_fraction( $div ) ; 17400 $status_bar->push($context_id, " flac encoding $1%"); 17401 } 17402 } 17403 while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() } 17404 if ( not $normalize_button->get_active and $pid_flac_decode >= 0 ) { 17405 $pid_flac_decode = StopProcessing($pid_flac_decode," Stop flac encoding!", $file_wav); 17406 $/="\n"; # abandon loop 17407 } 17408 } 17409 $/="\n"; ## final of loop 17410 close(FLAC); 17411 17412 # tag commands -- to see the entries: metaflac --list music.flac 17413 # --no-utf8-convert 17414 #$Album= encode("utf8",$Album); 17415 17416 my @cmd_tag = ( $metaflac_path, '--no-utf8-convert', "--set-tag=Title=$Title", "--set-tag=Artist=$Artist" ); 17417 push @cmd_tag, ( "--set-tag=Album=$Album", "--set-tag=Date=$Year", "--set-tag=Description=$Comment", "--set-tag=Comment=$Comment" ); 17418 if ($Total_Track ne "" and $Total_Track >= $Track_Number){ 17419 push @cmd_tag, ( "--set-tag=Tracknumber=$Track_Number/$Total_Track" ); } 17420 else { push @cmd_tag, ( "--set-tag=Tracknumber=$Track_Number" ); } 17421 push @cmd_tag, ( "--set-tag=Genre=$Genre" ); 17422 17423 17424 if ( $metaflac_path ne "" and $normalize_button->get_active ){ 17425 insert_msg("." , "small-ini"); 17426 insert_msg("@cmd_tag \"$file_out\"" , "small"); #print on debug textview 17427 insert_msg("\n" , "small"); 17428 17429 push @cmd_tag, ( filename_from_unicode $file_out ); 17430 exec_cmd_system3(@cmd_tag); 17431 } 17432 17433 if ($normalize_button->get_active) { # if normalize button is active 17434 $pid_flac_decode = -1; # reset pid on the final of process 17435 return $true; } 17436 else { return $false;} 17437} 17438 17439# wav --> mp4 17440sub encode_wav_to_mp4 { 17441 my %args = ( @_ ); 17442 my $row = $args{row}; my $file_mp4 = $args{file_mp4}; my $file_wav = $args{file_wav}; my $filepath = $args{filepath}; 17443 17444 my $Title = $files_info[$row]{title}; 17445 my $Artist = $files_info[$row]{artist}; 17446 my $Comment = $files_info[$row]{comment}; 17447 my $Album = $files_info[$row]{album}; 17448 my $Genre = $files_info[$row]{genre}; 17449 my $Year = $files_info[$row]{year}; 17450 my $Track_Number = $files_info[$row]{track}; 17451 my $Total_Track = $files_info[$row]{total_track}; 17452 17453 my $cmd; # command 17454 my $bitrate; 17455 my $mode; 17456 my $freq; 17457 my $compress = $spinner_compress_flac->get_value(); 17458 17459 $Track_Number =~ s/^0*//; #remove the leading zero 17460 $Total_Track =~ s/^0*//; 17461 17462 # tag commands for mp4 file 17463 my $cmd_tag = " -w"; 17464 if ( $Artist ne "" ){ $cmd_tag .= " --artist \"$Artist\""; } 17465 if ( $Title ne "" ){ $cmd_tag .= " --title \"$Title\""; } 17466 if ( $Album ne "" ){ $cmd_tag .= " --album \"$Album\""; } 17467 if ( $Year ne "" ){ $cmd_tag .= " --year \"$Year\""; } 17468 if ( $Genre ne "" ){ $cmd_tag .= " --genre \"$Genre\""; } 17469 if ( $Comment ne "" ){ $cmd_tag .= " --comment \"$Comment\""; } 17470 17471 if ( $Total_Track ne "" and $Total_Track >= $Track_Number ){ $cmd_tag .= " --track \"$Track_Number/$Total_Track\" "; } 17472 else { $cmd_tag .= " --track \"$Track_Number\" "; } 17473 17474 ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args); 17475 17476 $cmd = "$nice_path -n $priority $faac_path -c $freq "; 17477 # use --no-tns and --no-midslide to play correctly in the Quicktime player 17478 if ( $encode eq "variable" and $check_change_properties->get_active ){ 17479 $cmd .= " -q $Vmp4 "; } # VBR (variable bitrate) 17480 else{ $cmd .= " -b $bitrate "; } # ABR (average bitrate) 17481 17482 if ( $file_mp4 !~ /\.aac$/i ) { $cmd .= " $cmd_tag"; } #tag only for mp4|m4a 17483 17484 $additional_command_mp4 = $entry_command_mp4->get_text; 17485 $cmd .= " $additional_command_mp4 "; 17486 17487 my $file_in = $directory_output . '/' . $file_wav; 17488 my $file_out = $directory_final . '/' . $file_mp4; 17489 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 17490 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 17491 print "encode_wav_to_mp4 --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 17492 17493 $cmd .= " \"$file_in2\" -o \"$file_out2\" "; 17494 17495 insert_msg("." , "small-ini"); 17496 insert_msg("$cmd" , "small"); #print on debug textview 17497 insert_msg("\n" , "small"); 17498 17499 my $pid = open( AAC, filename_from_unicode "$cmd 2>&1 |" ) or die "Couldn't execute \"$cmd\": $!, stopped\n"; 17500 my $pid_faac_encode = $pid; ## set flac pid, pid > 0 17501 17502 my $div = 0; # initial value 17503 my $saved_value = 0; 17504 17505 ## loop for output - initial 17506 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 17507 while( <AAC> ) 17508 { 17509 # output: frame | bitrate | elapsed/estim | play/CPU | ETA 17510 # 300/4944 ( 6%)| 240.2 | 1.2/19.4 | 5.90x | 18.3 17511 # 4944/4944 (100%)| 217.8 | 18.9/18.9 | 6.08x | 0.0 17512 17513 if( $_ =~ /.*\(\s*(\d+)%\)\|\s+(\d+).*\s+(\d+[\.,]\d+)x\s+\|\s+(\d+[\.,]\d+).*/ ) 17514 { 17515 $saved_value = $div; 17516 $div = sprintf("%0.2f", $1/100 ); # eg (65%)/100 17517 $div = number_value($div); 17518 if ( $div > 1){ $div = 1;} # to avoid possible errors 17519 my $bitr = $2; 17520 my $speed = sprintf("%.1f", $3 ); 17521 my $time = sprintf("%02d", $4 ); 17522 my $pct = sprintf("%02d", $1 ); # 02d : leading zero 17523 17524 # show only not repeated value 17525 if ( $pbar_encode->get_fraction() <=1 and $div > $saved_value ) { 17526 $pbar_encode->set_fraction( $div ) ; 17527 $status_bar->push($context_id, " encoding $pct% | bitrate = $bitr | time = $time sec | speed = $speed "); 17528 } 17529 } 17530 while ( Gtk2->events_pending() and $normalize_button->get_active ) { Gtk2->main_iteration() } 17531 if ( not $normalize_button->get_active and $pid_faac_encode >= 0 ) { 17532 $pid_faac_encode = StopProcessing($pid_faac_encode," Stop faac encoding!", $file_wav); 17533 $/="\n"; # abandon loop 17534 } 17535 } 17536 $/="\n"; ## final of loop 17537 close(AAC); 17538 17539 if ($normalize_button->get_active) { # if normalize button is active 17540 $pid_faac_encode = -1; # reset pid on the final of process 17541 return $true; } 17542 else { return $false;} 17543} 17544 17545# wav --> wma : encode with ffmpeg 17546 17547 # see 'ffmpeg -h'; usage: ffmpeg [[infile options] -i infile]... {[outfile options] outfile} 17548 # -i filename input file name 17549 # -y overwrite output files 17550 # -aq quality set audio quality (codec-specific) 17551 # -ar rate set audio sampling rate (in Hz) 17552 # -ac channels set number of audio channels 17553 # -ab <int> E..A. set bitrate (in bits/s) 17554 17555 # -title string set the title 17556 # -author string set the author 17557 # -album string set the album 17558 # -comment string set the comment 17559 # -track <int> E.... set the track number 17560 # -year <int> E.... set the year 17561 17562 # encode: ffmpeg -y -i input.wav -ab 200k -ar 44100 -ac 2 -title "tito��" -author "aut��" -album "alb��" -comment "com��" -track "3" -year "2008" output.wma 17563 # decode: ffmpeg -y -i input.wma output.wav 17564 17565sub encode_wav_to_wma { # Not used yet 17566 my %args = ( @_ ); 17567 my $row = $args{row}; my $file_mp3 = $args{file_mp3}; my $file_wav = $args{file_wav}; 17568 17569 $file_mp3 = 'output.wma'; 17570 17571 my $filepath = $args{filepath}; 17572 17573 # get all the 8 tags 17574 my $Title = $files_info[$row]{title}; 17575 my $Artist = $files_info[$row]{artist}; 17576 my $Album = $files_info[$row]{album}; 17577 my $Comment = $files_info[$row]{comment}; 17578 my $Year = $files_info[$row]{year}; 17579 my $Genre = $files_info[$row]{genre}; 17580 my $Track_Number = $files_info[$row]{track}; 17581 my $Total_Track = $files_info[$row]{total_track}; 17582 17583 my $bitrate; 17584 my $mode; 17585 my $freq; 17586 17587 my $file_in = $directory_output . '/' . $file_wav; 17588 my $file_out = $directory_final . '/' . $file_mp3; 17589 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 17590 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 17591 print "encode_wav_to_wma --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 17592 17593 # tag commands for wma file 17594 my $cmd_tag = " "; 17595 if ( $Artist ne "" ){ $cmd_tag .= " -author \"$Artist\""; } 17596 if ( $Title ne "" ){ $cmd_tag .= " -title \"$Title\""; } 17597 if ( $Album ne "" ){ $cmd_tag .= " -album \"$Album\""; } 17598 if ( $Year ne "" ){ $cmd_tag .= " -year \"$Year\""; } 17599 #if ( $Genre ne "" ){ $cmd_tag .= " -genre \"$Genre\""; } 17600 if ( $Comment ne "" ){ $cmd_tag .= " -comment \"$Comment\""; } 17601 17602 #if ( $Total_Track ne "" and $Total_Track >= $Track_Number ){ $cmd_tag .= " -track \"$Track_Number/$Total_Track\" "; } 17603 #else { $cmd_tag .= " -track \"$Track_Number\" "; } 17604 17605 ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args); 17606 $additional_command_mp3 = $entry_command_mp3->get_text; 17607 17608 #my $cmd = "$nice_path -n $priority /usr/bin/ffmpeg -y -i \"$file_in2\" -ab ${bitrate}k -ar $freq -ac 2 $cmd_tag $additional_command_mp3 \"$file_out2\" "; 17609 my $cmd = " /usr/bin/ffmpeg -y -i \"$file_in2\" -ab ${bitrate}k -ar $freq -ac 2 \"$file_out2\""; 17610 17611 insert_msg("." , "small-ini"); 17612 insert_msg("$cmd" , "small"); #print on debug textview 17613 insert_msg("\n" , "small"); 17614 17615 ## start encoding process 17616 my $pid = open( FFMPEG, filename_from_unicode "$cmd 2>&1 |" ) or die "couldn't execute \"$cmd\": $!\n"; 17617 $pid_lame_encode = $pid; # set lame encode pid 17618 17619 my $div = 0; 17620 17621 $/="\r"; ## loop for output - initial 17622 while( <FFMPEG> ) 17623 { 17624 # size= 754kB time=25.1 bitrate= 245.7kbits/s 17625 # size= 1207kB time=40.3 bitrate= 245.3kbits/s 17626 print "aquiiii: $_\n"; 17627 17628 } 17629 $/="\n"; ## final of loop 17630 close( FFMPEG ); 17631 17632 if ($normalize_button->get_active) { # if normalize button is active 17633 $pid_lame_encode = -1; # reset pid on the final of process 17634 return $true; } 17635 else { return $false;} 17636} 17637 17638 17639# wav --> mp3 : encode with lame 17640sub encode_wav_to_mp3 { 17641 my %args = ( @_ ); 17642 my $row = $args{row}; my $file_mp3 = $args{file_mp3}; my $file_wav = $args{file_wav}; 17643 17644 my $filepath = $args{filepath}; 17645 #$filepath = filename_from_unicode $filepath if( ! -e $filepath ); 17646 17647 # get all the 8 tags 17648 my $Title = $files_info[$row]{title}; 17649 my $Artist = $files_info[$row]{artist}; 17650 my $Album = $files_info[$row]{album}; 17651 my $Comment = $files_info[$row]{comment}; 17652 my $Year = $files_info[$row]{year}; 17653 my $Genre = $files_info[$row]{genre}; 17654 my $Track_Number = $files_info[$row]{track}; 17655 my $Total_Track = $files_info[$row]{total_track}; 17656 17657 my $bitrate; 17658 my $mode; 17659 my $freq; 17660 17661 ($encode,$mode,$bitrate,$freq,$vb_Min,$vb_Max) = encode_settings(%args); 17662 17663 my $cmd = "$nice_path -n $priority $lame_path -q $quality -c "; 17664 17665 if ( $encode eq "constant" ){ $cmd .= "--cbr -b $bitrate "; } # CBR (constant bitrate) 17666 elsif ( $encode eq "average" ){ $cmd .= "--abr $bitrate -b $vb_Min -B $vb_Max --nohist "; } # ABR (average bitrate) 17667 elsif ( $encode eq "variable" and $check_change_properties->get_active ){ $cmd .= "--vbr-new -V $V -b $vb_Min -B $vb_Max --nohist "; } # VBR (variable bitrate) 17668 17669 # common commands of lame for all options of encode 17670 $cmd .= "-m \"$mode\" --resample $freq --replaygain-fast "; 17671 17672 $additional_command_mp3 = $entry_command_mp3->get_text; 17673 $cmd .= " --add-id3v2 --pad-id3v2 $additional_command_mp3 "; 17674 17675 my $file_in = $directory_output . '/' . $file_wav; 17676 my $file_out = $directory_final . '/' . $file_mp3; 17677 (my $file_in2 = $file_in ) =~ s/"/\\"/g; # change all " characters by \" 17678 (my $file_out2 = $file_out) =~ s/"/\\"/g; # change all " characters by \" 17679 print "encode_wav_to_mp3 --> Could not find wave file: $file_in\n" if( ! -e filename_from_unicode $file_in ); 17680 17681 $cmd .= " \"$file_in2\" \"$file_out2\" "; 17682 17683 insert_msg("." , "small-ini"); 17684 insert_msg("$cmd" , "small"); #print on debug textview 17685 insert_msg("\n" , "small"); 17686 17687 ## start encoding process 17688 my $pid = open( LAME, filename_from_unicode "$cmd 2>&1 |" ) or die "couldn't execute \"$cmd\": $!\n"; 17689 $pid_lame_encode = $pid; # set lame encode pid 17690 17691 my $div = 0; 17692 17693 ## loop for output - initial 17694 $/="\r"; ## from http://acidrip.thirtythreeandathird.net/ 17695 while( <LAME> ) 17696 { 17697 ## this is output of lame. 17698 #LAME version 3.96.1 (http://lame.sourceforge.net/) 17699 #CPU features: MMX (ASM used), 3DNow! (ASM used), SSE 17700 #Using polyphase lowpass filter, transition band: 17249 Hz - 17782 Hz 17701 #Encoding almir_sater-instrumental-03_vinheta_do_capeta.wav to lixo.mp3 17702 #Encoding as 44.1 kHz 128 kbps j-stereo MPEG-1 Layer III (11x) qval=3 17703 # Frame | CPU time/estim | REAL time/estim | play/CPU | ETA 17704 # 320/2171 ( 7%)| 0:05/ 0:09| 0:05/ 0:10| 5.8102x| 0:04 17705 # 1250/2171 (58%)| 0:05/ 0:09| 0:05/ 0:10| 5.8102x| 0:04 17706 17707 # print "aquiiii: $_\n"; 17708 17709 if( $_ =~ /^\s.*\s*\(\s*(\d+)%\)\|\s*.*\s+(\d+[\.,]\d+)x\|\s+(\d+\:\d+).*/ ) 17710 { 17711 $div = sprintf("%0.2f", $1/100 ); # eg (65%)/100 17712 $div = number_value($div); 17713 #print ( "div = $1 ; speed = $2 \n"); 17714 my $speed = sprintf("%.1f", $2 ); 17715 my $time = $3; 17716 my $pct = sprintf("%02d", $1 ); # 02d : leading zero 17717 17718 if ( $pbar_encode->get_fraction() <=1 and $pid_lame_encode>=0 ) { 17719 $pbar_encode->set_fraction( $div ) ; 17720 $status_bar->push($context_id, " lame encode $pct% | time remaining = $time | encode speed = $speed"); 17721 } 17722 } 17723 while ( Gtk2->events_pending() ) { Gtk2->main_iteration() } 17724 17725 if ( not $normalize_button->get_active and $pid_lame_encode >= 0 ) { 17726 $pid_lame_encode = StopProcessing($pid_lame_encode, $langs{msg058}, $file_wav ); 17727 $/="\n"; # abandon loop 17728 } 17729 } 17730 $/="\n"; ## final of loop 17731 close( LAME ); 17732 17733 if ($normalize_button->get_active) { 17734 print "encode_wav_to_mp3 --> Could not find mp3 file: $file_out\n" if( ! -e filename_from_unicode $file_out ); 17735 17736 # save the Total_Track in file_mp3 --- lame can not save the tag: 'track/Total_Track' 17737 $metadata{'Encoded by'} = "LAME with gnormalize (http://gnormalize.sourceforge.net)"; 17738 # to save ID3v2 tag 17739 save_ID3v2_mp3_tag($file_out, $Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Total_Track, $Genre); 17740 17741 save_ID3v1_mp3_tag($file_out, $Title, $Artist, $Album, $Year, $Comment, $Track_Number, $Genre ); 17742 } 17743 17744 if ($normalize_button->get_active) { # if normalize button is active 17745 $pid_lame_encode = -1; # reset pid on the final of process 17746 return $true; } 17747 else { return $false;} 17748} 17749 17750####----------------------Config----------------------#### 17751change_font_for_all_child($window_font_name); 17752#encode_choice_sensitive(); 17753$notebook->set_current_page ($notebook_page_num); 17754$notebook2->set_current_page ($notebook_page_num2); 17755 17756####-----------------------ARGV-----------------------#### 17757 17758sub arguments { 17759 17760 # Get the parameters from the command line. 17761 if (@ARGV == 1){ #number of arguments 17762 my $file = filename_to_unicode $ARGV[0]; 17763 17764 if ( ! -e filename_from_unicode $file ){ # if the file not exist 17765 print "This file not exist: $file\n"; 17766 return; 17767 } 17768 $file =~ s/(.*\/)//g; #copy and remove (path)/ 17769 insert_msg( $langs{msg078}.": $file\n\n" , "small"); 17770 ($directory = $ARGV[0]) =~ s/(.*)\/.*/$1\//g; 17771 17772 if ( $directory !~ /\// ){ # for the case of none directory: 'gnormalize music.mp3' 17773 $directory = filename_to_unicode "$ENV{'PWD'}"; # $directory = `pwd` 17774 } 17775 elsif ( $directory !~ /^\// ){ # for the case of directory like that: 'gnormalize some/place/music.mp3' 17776 $directory = filename_to_unicode "$ENV{'PWD'}/".$directory; 17777 } 17778 #print "file = $file ;; directory = $directory \n"; 17779 fill_with_all_informations($directory . '/' . $file); 17780 } 17781} 17782 17783arguments(); 17784 17785####---------------------- Quit ----------------------#### 17786 17787# Quit of gnormalize 17788sub Quit { 17789 stop_playing_music(); 17790 save_config(); 17791 Gtk2->main_quit; 17792 return $true; 17793} 17794 17795#print Claudio1::teste(); # only test 17796#gnormalize::cdplay::read_toc(); 17797#gnormalize::cdplay::play_cdrom_track(); 17798#gnormalize::cdplay::play_cdrom_msf2(); 17799#gnormalize::cdplay::play_cdrom_msf(8); 17800#gnormalize::cdplay::pause_cdrom(); 17801#gnormalize::cdplay::resume_cdrom(); 17802#gnormalize::cdplay::eject_cdrom(); 17803#gnormalize::cdplay::multi(); 17804#gnormalize::cdplay::get_vol(); 17805#gnormalize::cdplay::set_vol(11,11,11,11); 17806#gnormalize::cdplay::cdrom_read_audio(); 17807#print gnormalize::cdplay::msf_to_lba(0,0,0); 17808 17809#my $info = gnormalize::cdplay::Info(); 17810#print "current track = $info->{current_track}"; 17811 17812#gnormalize::factorial::print2(5); 17813 17814# Gtk event loop 17815Gtk2->main; # necess�rio para executar o programa 17816exit(0); 17817 17818####--------------------- The End ---------------------#### 17819 17820#-------------------------------------------------# 17821#------------------ New-Package ------------------# 17822# See perlmod, perlmodlib, perltoot 17823# See Learning Perl Objects, References and Modules, Chapter 2, 1o. Edition, 2003. 17824 17825#{ # start scope block 17826# package Claudio1; # now in package Claudio1. Only one test 17827# use strict; 17828 # See <man Exporter> 17829 17830# sub teste { # Claudio1::teste 17831# print "Claudio1::teste\n"; 17832# } 17833# 1; # don't forget to return a true value from the file 17834#} # end scope block 17835 17836#-------------------------------------------------# 17837#------------------ New-Package ------------------# 17838 17839######################-----gnormalize::cdplay-----###################### 17840 17841{ # start scope block 17842package gnormalize::cdplay; # New package to play Audio CD. 17843use strict; 17844use Fcntl; 17845 17846# require Exporter; 17847 17848# See <man Exporter> 17849our $VERSION = '0.01'; 17850 17851# See <man perlopentut> and stat() on perlfunc. 17852# See "Linux::CDROM::Cookbook" (Linux-CDROM-0.01.tar.gz), 17853# DOING EVEN MORE section by Tassilo von Parseval 17854 17855# see /usr/include/linux/cdrom.h 17856use constant CDROMPAUSE => 0x5301; # /* Pause Audio Operation */ 17857use constant CDROMRESUME => 0x5302; # /* Resume paused Audio Operation */ 17858use constant CDROMPLAYMSF => 0x5303; # /* Play Audio MSF (struct cdrom_msf) */ 17859use constant CDROMPLAYTRKIND => 0x5304; # /* Play Audio Track/index (struct cdrom_ti) */ 17860use constant CDROMREADTOCHDR => 0x5305; # /* Read TOC header (struct cdrom_tochdr) */ 17861use constant CDROMREADTOCENTRY => 0x5306; # /* Read TOC entry (struct cdrom_tocentry) */ 17862use constant CDROMSTOP => 0x5307; # /* Stop the cdrom drive */ 17863use constant CDROMSTART => 0x5308; # /* Start the cdrom drive */ 17864use constant CDROMEJECT => 0x5309; # /* Ejects the cdrom media */ 17865use constant CDROM_LEADOUT => 0xAA; # /* The leadout track is always 0xAA, regardless of # of tracks on disc */ 17866use constant CDROM_AUDIO_COMPLETED => 0x13; # /* audio play successfully completed */ 17867use constant CDROMVOLREAD => 0x5313; # /* Get the drive's volume setting (struct cdrom_volctrl) */ 17868use constant CDROMVOLCTRL => 0x530a; # /* Control output volume (struct cdrom_volctrl) */ 17869use constant CDROM_DRIVE_STATUS => 0x5326; # /* Get tray position, etc. */ 17870use constant CDROM_DISC_STATUS => 0x5327; # /* Get disc type, etc. */ 17871use constant CDROMSUBCHNL => 0x530b; # /* Read subchannel data (struct cdrom_subchnl) */ 17872use constant CDROMREADAUDIO => 0x530e; # /* (struct cdrom_read_audio) */ 17873use constant CDROMREADRAW => 0x5314; # /* read data in raw mode (2352 Bytes) 17874use constant CDROMMULTISESSION => 0x5310; # /* Obtain the start-of-last-session address of multi session disks 17875 # (struct cdrom_multisession) */ 17876use constant CD_MSF_OFFSET => 150; # /* MSF numbering offset of first frame */ 17877#/* CD-ROM address types (cdrom_tocentry.cdte_format) */ 17878use constant CDROM_LBA => 0x01; # /* "logical block": first frame is #0 */ 17879use constant CDROM_MSF => 0x02; # /* "minute-second-frame": binary, not bcd here! */ 17880 17881 # /* This struct is used by the CDROMPLAYMSF ioctl */ 17882 # struct cdrom_msf 17883 # { 17884 # __u8 cdmsf_min0; /* start minute */ 17885 # __u8 cdmsf_sec0; /* start second */ 17886 # __u8 cdmsf_frame0; /* start frame */ 17887 # __u8 cdmsf_min1; /* end minute */ 17888 # __u8 cdmsf_sec1; /* end second */ 17889 # __u8 cdmsf_frame1; /* end frame */ 17890 # }; 17891 17892 # /* Address in either MSF or logical format */ 17893 # union cdrom_addr 17894 # { 17895 # struct cdrom_msf0 msf; # 'CCCx' pack whith 32 bits = 4 bytes 17896 # int lba; # 'i' pack 17897 # }; 17898 17899 # /* Address in MSF format */ 17900 # struct cdrom_msf0 17901 # { 17902 # __u8 minute; 17903 # __u8 second; 17904 # __u8 frame; 17905 # }; 17906 17907 # /* This struct is used by the CDROMVOLCTRL and CDROMVOLREAD ioctls */ 17908 # struct cdrom_volctrl 17909 # { 17910 # __u8 channel0; 17911 # __u8 channel1; 17912 # __u8 channel2; 17913 # __u8 channel3; 17914 # }; 17915 17916sub msf_to_lba { 17917 my ($min, $sec, $frame) = @_; 17918 my $lba = ($min * 60 + $sec) * 75 + $frame - CD_MSF_OFFSET; 17919 return $lba; # Is equal to $ref_array->[$i]{begin_frames} 17920} 17921 17922sub play_cdrom_msf { # Play Audio cdrom on linux ;; Need read_toc() first. 17923 my $track = 1; # track to play 17924 my $delta = 0; # to advance or go back $delta seconds 17925 my $position = 0.00; # 0.00 to 1.00 ; play at relative position into the track 17926 my $cd_toc = $toc_audiocd; # $toc_audiocd ; to find the frames of the tracks 17927 17928 # See Perl Cookbook, 2nd Edition, Ch. 10.7 17929 my %args = ( 17930 Track => 1, # default value 17931 Advance => 0, 17932 Position => 0.00, 17933 @_, # argument pair list goes here 17934 ); 17935 if ( defined($args{Track}) ){ if ( $args{Track} =~ /^\d+$/ ){ $track = $args{Track}; } } 17936 else { return; } 17937 if ( $args{Advance} =~ /^[+-]?\d+$/ ){ $delta = $args{Advance}; } 17938 #gnormalize::cdplay::play_cdrom_msf(Track => $selected_row + 1, Position => 0.43); 17939 if ( $args{Position} =~ /^[\.\d]*$/ ){ $position = $args{Position}; } 17940 17941 my $info = Info(); # Get Status 17942 if ( not $info ){ return; } 17943 my $status = $info->{status}; 17944 if ( $status eq 'invalid' or $status eq 'error' ){ return $false; } 17945 17946 my $startframe = $cd_toc->[$track-1]->{frames_abs}; 17947 17948 if ( $delta != 0 ){ # advance $delta seconds 17949 my $new_frame = $info->{frame_abs} + $delta * 75; # current absolute frame + delta (seconds) 17950 if ( $new_frame > $startframe ) { $startframe = $new_frame; } 17951 } 17952 # 150 = 2*75, the gap before a audio track 17953 my $endframe = $cd_toc->[$track]->{frames_abs} - 1; 17954 17955 if ( $startframe < 0 or $endframe < 0 or $startframe >= $endframe ){ return $false; } 17956 if ( $position > 0 and $position <= 1 ){ $startframe = int($startframe + ($endframe - $startframe)*$position);} 17957 17958 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 17959 17960 my $min0 = int( $startframe / (60 * 75) ); 17961 my $sec0 = int( ($startframe % (60 * 75)) / 75 ); 17962 my $frame0 = int( $startframe % 75 ); 17963 my $min1 = int( $endframe / (60 * 75) ); 17964 my $sec1 = int( ($endframe / 75) % 60 ); 17965 my $frame1 = int( $endframe % 75 ); 17966 #print "startframe = $startframe ; endframe = $endframe ;; status = $status ; frames = ",$endframe - $startframe,"\n"; 17967 17968 my $cdrom_msf = pack "C6", $min0, $sec0, $frame0, $min1, $sec1, $frame1; 17969 17970 # See what operations can be performed on your machine at /usr/include/sys/ioctl.h 17971 # Play Audio CD in MSF struct 17972 ioctl(CD, CDROMPLAYMSF, $cdrom_msf ) or die "can not play cdrom [$!] [$audiodevice_path]"; 17973 17974 close(CD); 17975} 17976 17977sub play_cdrom_msf2 { # only for test 17978 if ( not Info() ){ return; } # Get Status 17979 17980 my $startframe = 202250; # 150: first pre gap 17981 my $endframe = 207630; 17982 17983 if ( $startframe < 0 or $endframe < 0 or $startframe >= $endframe ){ return $false; } 17984 17985 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 17986 17987 my $min0 = int( $startframe / (60 * 75) ); 17988 my $sec0 = int( ($startframe % (60 * 75)) / 75 ); 17989 my $frame0 = int( $startframe % 75 ); 17990 my $min1 = int( $endframe / (60 * 75) ); 17991 my $sec1 = int( ($endframe / 75) % 60 ); 17992 my $frame1 = int( $endframe % 75 ); 17993 #print "startframe = $startframe ; endframe = $endframe ;; status = $status ; frames = $frames \n"; 17994 17995 my $cdrom_msf = pack "C6", $min0, $sec0, $frame0, $min1, $sec1, $frame1; 17996 17997 # See what operations can be performed on your machine at /usr/include/sys/ioctl.h 17998 # Play Audio CD in MSF struct 17999 ioctl(CD, CDROMPLAYMSF, $cdrom_msf ) or die "can not play cdrom [$!] [$audiodevice_path]"; 18000 18001 close(CD); 18002} 18003 18004 18005sub pause_cdrom { # Pause Audio cdrom on linux 18006 if ( not Info() ){ return; } # Get Status 18007 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 18008 ioctl(CD, CDROMPAUSE, 1 ) or die "can not pause cdrom [$!] [$audiodevice_path]"; 18009 close(CD); 18010} 18011 18012sub resume_cdrom { # Resume Audio cdrom on linux 18013 if ( not Info() ){ return; } # Get Status 18014 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 18015 ioctl(CD, CDROMRESUME, 1 ) or die "can not resume cdrom [$!] [$audiodevice_path]"; 18016 close(CD); 18017} 18018 18019sub stop_cdrom { # Stop Audio cdrom on linux 18020 if ( not Info() ){ return; } # Get Status 18021 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 18022 ioctl(CD, CDROMSTOP, 1 ) or die "can not stop cdrom [$!] [$audiodevice_path]"; 18023 close(CD); 18024} 18025 18026sub eject_cdrom { # Eject Audio cdrom on linux 18027 if ( not Info() ){ return; } # Get Status 18028 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 18029 ioctl(CD, CDROMEJECT, 1 ) or die "can not stop cdrom [$!] [$audiodevice_path]"; 18030 close(CD); 18031} 18032 18033sub set_vol { # Set Volume 18034 if ( not Info() ){ return; } # Get Status 18035 # Set Volume 18036 my $channel0=shift || 0; #front_left ; 0 - 255 18037 my $channel1=shift || $channel0; #front_right 18038 my $channel2=shift || $channel0; #back_left 18039 my $channel3=shift || $channel0; #back_right 18040 18041 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 18042 18043 my $volctrl = pack "CCCC", $channel0, $channel1, $channel2, $channel3; 18044 ioctl(CD, CDROMVOLCTRL, $volctrl) or die "can not set volume [$!] [$audiodevice_path]"; 18045 18046 close(CD); 18047} 18048 18049sub get_vol { # Get Volume 18050 if ( not Info() ){ return; } # Get Status 18051 18052 my ($channel0, $channel1, $channel2, $channel3) = ( 0, 0, 0, 0); 18053 18054 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 18055 18056 # Get Volume 18057 my $volctrl = pack "CCCC", $channel0, $channel1, $channel2, $channel3; 18058 ioctl(CD, CDROMVOLREAD, $volctrl) or die "can not read volume [$!] [$audiodevice_path]"; 18059 ($channel0, $channel1, $channel2, $channel3) = unpack "CCCC", $volctrl; 18060 print "channel0 = $channel0 ; channel1 = $channel1 ; channel2 = $channel2 ; channel3 = $channel3\n"; 18061 18062 close(CD); 18063} 18064 18065sub multi { # Show if the cdrom have multisession 18066 #/* This struct is used with the CDROMMULTISESSION ioctl */ 18067 #struct cdrom_multisession 18068 #{ 18069 # union cdrom_addr addr; /* frame address: start-of-last-session 18070 # (not the new "frame 16"!). Only valid 18071 # if the "xa_flag" is true. */ 18072 # __u8 xa_flag; /* 1: "is XA disk" */ 18073 # __u8 addr_format; /* CDROM_LBA or CDROM_MSF */ 18074 #}; 18075 my ($min, $sec, $frame) = (0, 0, 0); 18076 my $flag = 0; 18077 my $cdrom_multi = pack "CCCxCC", $min, $sec, $frame, $flag, CDROM_MSF; # Set the format 18078 18079 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or die "can not open cdrom [$!] [$audiodevice_path]"; 18080 ioctl(CD, CDROMMULTISESSION, $cdrom_multi ) or die "multisession cdrom [$!] [$audiodevice_path]"; 18081 close(CD); 18082 ( $min, $sec, $frame, $flag ) = unpack "CCCxC", $cdrom_multi; 18083 # print "min = $min; sec = $sec ; frame = $frame ; flag = $flag \n"; 18084 # $flag = 1 if multisession 18085 return $flag; 18086} 18087 18088sub Info { # Inform the absolute and relative time and current track of Audio CD 18089 # Need read_toc() first 18090 18091 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) or return $false; 18092 18093 #/* This struct is used by the CDROMSUBCHNL ioctl */ 18094 # struct cdrom_subchnl 18095 # { 18096 # __u8 cdsc_format; /* Set CDROM_LBA or CDROM_MSF format */ 18097 # __u8 cdsc_audiostatus; 18098 # __u8 cdsc_adr: 4; /* (4 + 4) bits = 1 byte */ 18099 # __u8 cdsc_ctrl: 4; 18100 # __u8 cdsc_trk; # track 18101 # __u8 cdsc_ind; # index 18102 # 3x # <padding byte> 18103 # union cdrom_addr cdsc_absaddr; #absolute address 18104 # union cdrom_addr cdsc_reladdr; #relative address 18105 # }; 18106 18107 my $cdrom_subchnl = pack "C", CDROM_MSF; # Set the format 18108 ioctl(CD, CDROMSUBCHNL, $cdrom_subchnl) or return $false; 18109 my ( $cdsc_format, $status, $cdsc_adr_ctrl, $cdsc_trk, $cdsc_ind, 18110 $min_abs, $sec_abs, $frame_abs, $min, $sec, $frame ) = unpack "C5x3CCCxCCCx", $cdrom_subchnl; 18111 18112 # status, see /usr/include/linux/cdrom.h: 18113 # 21 (decimal) = 0x15 (hexagonal) /* no current audio status to return */ 18114 if ( $status == 0x00 ) { $status = 'invalid'; } 18115 elsif ( $status == 0x11 ) { $status = 'play'; } 18116 elsif ( $status == 0x12 ) { $status = 'paused'; } 18117 elsif ( $status == 0x13 ) { $status = 'completed'; } 18118 elsif ( $status == 0x14 ) { $status = 'error'; } 18119 elsif ( $status == 0x15 ) { $status = 'no_status'; } 18120 else { $status = 'no_disc'; } 18121 18122 my %info=(); 18123 18124 # $cdsc_trk shows next track at boundary region! 18125 # See 'sub get_current_track' how to get the correct current track. 18126 $info{current_track}=$cdsc_trk; #this is not always correct! (when not exist pre gap = 150) 18127 $info{status}=$status; 18128 18129 $info{min_abs}=$min_abs; 18130 $info{sec_abs}=$sec_abs; 18131 $frame_abs = int($frame_abs + $sec_abs*75 + $min_abs*60*75); # current absolute frame 18132 $info{frame_abs}=$frame_abs; 18133 #$info{time}=[ $min_abs , $sec_abs , $frame_abs ]; 18134 18135 $info{min}=$min; # It shows regressive time to next track 18136 $info{sec}=$sec; 18137 $frame = int($frame + $sec*75 + $min*60*75); # current relative frame 18138 $info{frame}=$frame; 18139 18140 #print "track = $cdsc_trk ; index = $cdsc_ind ; status = $status ; format = $cdsc_format \n"; 18141 #print "(min_abs = $min_abs ; sec_abs = $sec_abs ; frame_abs = $frame_abs) ;; (min = $min ; sec = $sec ; frame = $frame)\n"; 18142 18143 close(CD); 18144 18145 return \%info; 18146} 18147 18148# See CDDB_get and Linux::CDROM::Cookbook for some sugestions 18149# See /usr/include/linux/cdrom.h 18150sub read_toc { 18151 my $cdplayer = shift; # only show special track for $cdplayer = "gnormalize::cdplay" 18152 my $device = shift || $audiodevice_path; 18153 18154 my $tochdr=""; 18155 my $debug = 0; # values:0,1,2 ;; if value==1, show output like 'cdparanoia -Q' 18156 18157 my $open = sysopen (CD, $device, O_RDONLY | O_NONBLOCK); 18158 if ( not defined($open) ){ return $false; } 18159 18160 my $result = ioctl(CD, CDROMREADTOCHDR, $tochdr) ; # or die "can not read toc [$!] [$audiodevice_path]"; 18161 if ( not defined($result) ){ return $false; } # result = 0 but true 18162 18163 my ($start,$end) = unpack "CC",$tochdr; 18164 18165 # /* The leadout track is always 0xAA, regardless of # of tracks on disc */ 18166 # The index "CDROM_LEADOUT" 0xAA = 170 (decimal) is the final address of last track. 18167 my @tracks=(); 18168 for (my $i=$start; $i<=$end;$i++) { push @tracks,$i; } 18169 push @tracks,0xAA; 18170 18171 # /* Note that only "cdte_track" and "cdte_format" need to be set. All other slots 18172 # /* are only used for the return values. 18173 # /* This struct is used by the CDROMREADTOCENTRY ioctl */ 18174 # struct cdrom_tocentry 18175 # { 18176 # __u8 cdte_track; 18177 # __u8 cdte_adr :4; /* two 4-bit wide fields require 1 byte 18178 # __u8 cdte_ctrl :4; 18179 # __u8 cdte_format; /* Set CDROM_LBA or CDROM_MSF format 18180 # union cdrom_addr cdte_addr; /* It's either a "struct cdrom_msf0" or an integer. 18181 # __u8 cdte_datamode; 18182 # }; 18183 18184 # /* Address in either MSF or logical format */ 18185 # union cdrom_addr 18186 # { 18187 # struct cdrom_msf0 msf; 18188 # int lba; 18189 # }; 18190 18191 # /* Address in MSF format */ 18192 # struct cdrom_msf0 18193 # { 18194 # __u8 minute; 18195 # __u8 second; 18196 # __u8 frame; 18197 # }; 18198 18199 print "\n Tracks and absolutes frames:\n\n" if $debug==2; 18200 18201 my @array_toc=(); 18202 18203 foreach my $i (@tracks) { # track 0xAA = 170 get the total frames 18204 18205 # pack "C # cdte_track Byte 0 18206 # C # cdte_adr + cdte_ctrl Byte 1 18207 # C # cdte_format Byte 2 18208 # x # <padding byte> 18209 # i # cdte_addr 18210 # C # cdte_datamode Byte 8 18211 # ", track, 0, CDROM_LBA; 18212 18213 # if format = CDROM_MSF, then substitute "i" by "CCCx", both with 32 bits. 18214 18215 18216 my $tocentry=pack "CCCxCCCxC", $i,0,CDROM_MSF; # Set "cdte_track" and "cdte_format". 18217 ioctl(CD, CDROMREADTOCENTRY, $tocentry) or die "can not read track $i info [$!] [$audiodevice_path]"; 18218 my ($track, $adr_ctrl, $format, $min, $sec, $frame, $mode) = unpack "CCCxCCCxC", $tocentry; 18219 18220 my %cdtoc=(); 18221 18222 $cdtoc{track}=$track; 18223 $cdtoc{min_abs}=$min; 18224 $cdtoc{sec_abs}=$sec; 18225 $cdtoc{frame_abs}=$frame; 18226 my $frames_abs = int($frame+$sec*75+$min*60*75); 18227 $cdtoc{frames_abs}=$frames_abs; # Absolute position or StartSector 18228 18229 $cdtoc{data} = $false; 18230 18231 # /* bit to tell whether track is data or audio (cdrom_tocentry.cdte_ctrl) */ 18232 # 0x04 (hex) = 4 (dec) = 100 (bin) is equivalent to 0100 0000 = 0x40 (using 8 bits: 4-bits + 4-bits) 18233 if($adr_ctrl & 0x40) { $cdtoc{data} = $true; } 18234 printf "track=%02d ; min=%02d ; sec=%02d ; frame=%02d ; frames_abs=$frames_abs", $track, $min, $sec, $frame if $debug==2; 18235 if($cdtoc{data} and $debug==2) { print "track $track is data\n"; } 18236 elsif($debug==2){ print "\n"; } 18237 18238 push @array_toc, \%cdtoc; 18239 } 18240 close(CD); 18241 18242 # Taking a reference to an array (See 'Learning Perl Objects, References and Modules') 18243 my $ref_array = \@array_toc; 18244 18245 my $no_cdaudio = $true; # search for at least one audio track 18246 for (my $i = 0; $i <= $end; $i++) { 18247 if ( not $ref_array->[$i]->{data}){ 18248 $no_cdaudio = $false; 18249 $start = $i+1; 18250 last; 18251 } 18252 } 18253 if ($no_cdaudio){ return $false; } 18254 18255 # Very Special Case: When CD_MSF_OFFSET ( = $ref_array->[0]->{frames_abs} ) is not equal to 150 frames 18256 # define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ 18257 # For the case when the audio cd don't have the pre gap (with 150 frame) as first track. 18258 # k3b have this bad option for make audio cds. 18259 if ( $ref_array->[$start-1]->{frames_abs} > 75*20 and not $ref_array->[$start-1]->{data} and $cdplayer eq "gnormalize::cdplay" ){ 18260 # put one element (one hash) to the front of the array. see perlfunc 18261 unshift (@array_toc, {frames_abs => 150, data => 0, track => 1, min_abs => 0, sec_abs => 2} ); 18262 $end ++; 18263 } 18264 print "\nTable of contents (audio tracks only):\n". #Like 'cdparanoia -Q' 18265 "track length begin\n". 18266 "============================================\n" if $debug==1; 18267 18268 for (my $i = $start; $i <= $end; $i++) { # find relative frames 18269 18270 # 11400 frames, for CDROMMULTISESSION 18271 # 11400: multisession offset , adjust the end of last audio track to be in the first session 18272 if ( $ref_array->[$i]->{data} and not $ref_array->[$i-1]->{data} and multi() ){ 18273 if ( $ref_array->[$i-1]->{frames_abs} < $ref_array->[$i]->{frames_abs} - 11400 ){ 18274 $ref_array->[$i]->{frames_abs} -= 11400; 18275 $end = $i; # abandon the loop 18276 } 18277 } 18278 my $frames = $ref_array->[$i]->{frames_abs} - $ref_array->[$i-1]->{frames_abs}; # relative frames inter tracks 18279 my $begin_frames = $ref_array->[$i-1]->{frames_abs} - 150; # 150 is the offset (gap) of first frame. 18280 18281 my $min = $frames / (60 * 75); 18282 my $sec = ($frames / 75) % 60; 18283 $ref_array->[$i]{frames} = $frames; 18284 $ref_array->[$i]{min} = sprintf ( "%02d", $min); 18285 $ref_array->[$i]{sec} = sprintf ( "%02d", $sec); 18286 $ref_array->[$i]{begin_frames} = $begin_frames; # frames_abs - (150 frames = 2 sec of offset) 18287 18288 # like 'cdparanoia -Q' 18289 printf "%3d. %7ld [%02d:%02d.%02d] %7ld [%02d:%02d.%02d]\n", $i, 18290 $frames, ($frames / (60 * 75)), (($frames/75)%60), ($frames % 75), 18291 $begin_frames, ($begin_frames/(60*75)), (($begin_frames/75)%60), ($begin_frames % 75) 18292 if $debug==1; 18293 } 18294 $ref_array->[0]{total_track} = $end - $start + 1; #set total audio track number, not always equal to $#array_toc 18295 my $total_frames = $ref_array->[$end]->{frames_abs} - $ref_array->[$start-1]->{frames_abs}; 18296 $ref_array->[0]{total_frames} = $total_frames; 18297 printf "TOTAL %7ld [%02d:%02d.%02d] (audio only)\n", $total_frames, ($total_frames/(60*75)), 18298 (($total_frames/75)%60), ($total_frames % 75) if $debug==1; 18299 print "total audio tracks = $end ; total audio frames = $total_frames \n" if $debug==2; 18300 print "frame0 end at = $ref_array->[0]->{frames_abs} ; frame1 end at = $ref_array->[1]->{frames_abs}\n" if $debug==2; 18301 18302 return \@array_toc; 18303} 18304 18305# Read Audio cdrom on linux and rip 18306sub cdrom_read_audio { # Don't work yet! 18307 18308 my $track = shift || 8; # track to rip 18309 my $nframes = shift || 1; # 2646 /* The maximum possible returned bytes */ 18310 #my $cd_toc = $toc_audiocd; # $toc_audiocd ; to find the frames of the tracks 18311 my $cd_toc = read_toc(); 18312 18313 my $startframe = $cd_toc->[$track-1]->{frames_abs} - 150; #LBA 18314 18315 #/* This struct is used by the CDROMREADAUDIO ioctl */ 18316 #struct cdrom_read_audio 18317 #{ 18318 # union cdrom_addr addr; /* frame address */ 18319 # __u8 addr_format; /* CDROM_LBA or CDROM_MSF */ 18320 # int nframes; /* number of frames to read at once */ ; 1 <= nframes <= 75 18321 # __u8 __user *buf; /* frame buffer (size: nframes*2352 bytes) */ 18322 #}; # unary * Dereference-address operator. See perlop and perlref 18323 # Dereferencing means getting at the value that a reference points to. 18324 # int *ptr; ptr = &count ; "&" stores the address of count in ptr 18325 # total = *ptr; The value in the address stored in ptr is assigned to total 18326 # See 'Advanced Perl Programming', Chap. 1. ;; Programming Perl, 3a. Ed, Chap. 8.3 18327 # CD_FRAMESIZE_RAW = 2352 18328 # char * s : While Perl passes arguments to functions by reference, C passes arguments by value; see perlxstut. 18329 # default Perl doesn't currently support the const char * type. 18330 18331 # "The stack is a special type of array that is used to pass information to functions and pass return 18332 # values from functions back to the calling statement." The Complete Reference 2nd Ed, pag 694. 18333 18334 # __u8 buff[CD_FRAMESIZE_RAW]; 18335 #cda.buf = (__u8 *)&buff[0]; 18336 #for(i = start_lba; i < end_lba; i++) 18337 #{ 18338 # memset(buff, 0, sizeof(buff)); # see <man memset> 18339 # cda.addr.lba = i; 18340 # printf("lba: %u\n", i); 18341 # ioctl(fd, CDROMREADAUDIO, &cda); 18342 # for(n = 0; n < CD_FRAMESIZE_RAW/2; n++){ buff[n] = __swab16(buff[n]);} 18343 # 18344 # write(out, (__u8 *)buff, CD_FRAMESIZE_RAW); 18345 #} 18346 #close(fd); close(out); 18347 18348 #use Devel::Pointer; 18349 #$a = address_of($b); # a = &b; 18350 #$b = deref($a); # b = *a; 18351 18352 my $format; 18353 my $buffer_size = $nframes * 2352; 18354 18355 my @buf = ( ); for (my $i=0;$i<2352;$i++){$buf[$i]=1 } 18356 my $addr = \@buf; # reference like '&' unary operator 18357 printf "startframe = $startframe; track = $track ; value = $$addr[0] ; buf = $addr, men = %p\n", $addr; 18358 18359 my $cdrom_rip = pack "iCiC", $startframe, CDROM_LBA, 1 , $$addr[0]; # SCALAR reference 18360 18361 sysopen (CD,$audiodevice_path, O_RDONLY | O_NONBLOCK) 18362 or die "can not open cdrom [$!] [$audiodevice_path]"; 18363 18364 ioctl(CD, CDROMREADAUDIO, $cdrom_rip ) 18365 or die "can not rip the audio data from cdrom [$!] [$audiodevice_path]"; 18366 18367 ($startframe, $format, $nframes, $addr) = unpack "iCiC", $cdrom_rip; 18368 18369 # leave room for WAV header (44 bytes) 18370 #seek WAV, 44, 0; 18371 #print "cdrom_rip = $cdrom_rip; value = $$addr[0]; addr = $addr; startframe = $startframe\n"; 18372 18373 open WAV, ">/tmp/track${track}.wav" or die $!; 18374 binmode WAV; 18375 18376 #print WAV $cdrom_rip; 18377 for (my $i=0;$i<2352;$i++){ print WAV $buf[$i]; } 18378 #syswrite(WAV, $buffer, 2352 ); 18379 close(WAV); 18380 18381 close(CD); 18382} 18383 183841; 18385} # end scope block 18386 18387 18388#-------------------------------------------------# 18389#------------------ New-Package ------------------# 18390# See perlmod, perlmodlib, perltoot 18391# See Learning Perl Objects, References and Modules, Chapter 2, 1o. Edition, 2003. 18392#{ 18393# package gnormalize::factorial; # use C functions 18394# use strict; 18395 # See man Inline and Inline::C-Cookbook 18396 #use Inline C => Config => LIBS => '-lmac'; # libmac 18397 # Perl CODE goes here 18398 18399# sub print2 { 18400# printf "%3d! = %10d\n", $_, factorial($_) for 1..10; 18401# } 18402# 1; 18403 18404 # C CODE goes here 18405# use Inline C => Config => LIBS => '-lmac'; 18406# use Inline C => 18407# " 18408# double factorial(double x) { 18409# if (x < 2) return 1; 18410# return x * factorial(x - 1); 18411# } 18412# " 18413#} 18414 18415 18416########################-----MP3::Info-----######################## 18417 18418 18419{ # start scope block 18420 18421package MP3::Info::Internal; 18422 18423require 5.006; 18424 18425use overload; 18426use strict; 18427use Carp; 18428 18429use vars qw( 18430 @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION $REVISION 18431 @mp3_genres %mp3_genres @winamp_genres %winamp_genres $try_harder 18432 @t_bitrate @t_sampling_freq @frequency_tbl %v1_tag_fields 18433 @v1_tag_names %v2_tag_names %v2_to_v1_names $AUTOLOAD 18434 @mp3_info_fields %rva2_channel_types 18435); 18436 18437@ISA = 'Exporter'; 18438@EXPORT = qw( 18439 set_mp3tag get_mp3tag get_mp3info remove_mp3tag 18440 use_winamp_genres 18441); 18442@EXPORT_OK = qw(@mp3_genres %mp3_genres use_mp3_utf8); 18443%EXPORT_TAGS = ( 18444 genres => [qw(@mp3_genres %mp3_genres)], 18445 utf8 => [qw(use_mp3_utf8)], 18446 all => [@EXPORT, @EXPORT_OK] 18447); 18448 18449# $Id$ 18450($REVISION) = ' $Revision: 1.19 $ ' =~ /\$Revision:\s+([^\s]+)/; 18451$VERSION = '1.20'; 18452 18453=pod 18454 18455=head1 NAME 18456 18457MP3::Info - Manipulate / fetch info from MP3 audio files 18458 18459=head1 SYNOPSIS 18460 18461 #!perl -w 18462 use MP3::Info; 18463 my $file = 'Pearls_Before_Swine.mp3'; 18464 set_mp3tag($file, 'Pearls Before Swine', q"77's", 18465 'Sticks and Stones', '1990', 18466 q"(c) 1990 77's LTD.", 'rock & roll'); 18467 18468 my $tag = get_mp3tag($file) or die "No TAG info"; 18469 $tag->{GENRE} = 'rock'; 18470 set_mp3tag($file, $tag); 18471 18472 my $info = get_mp3info($file); 18473 printf "$file length is %d:%d\n", $info->{MM}, $info->{SS}; 18474 18475=cut 18476 18477{ 18478 my $c = -1; 18479 # set all lower-case and regular-cased versions of genres as keys 18480 # with index as value of each key 18481 %mp3_genres = map {($_, ++$c, lc, $c)} @mp3_genres; 18482 18483 # do it again for winamp genres 18484 $c = -1; 18485 %winamp_genres = map {($_, ++$c, lc, $c)} @winamp_genres; 18486} 18487 18488=pod 18489 18490 my $mp3 = new MP3::Info $file; 18491 $mp3->title('Perls Before Swine'); 18492 printf "$file length is %s, title is %s\n", 18493 $mp3->time, $mp3->title; 18494 18495 18496=head1 DESCRIPTION 18497 18498=over 4 18499 18500=item $mp3 = MP3::Info-E<gt>new(FILE) 18501 18502OOP interface to the rest of the module. The same keys 18503available via get_mp3info and get_mp3tag are available 18504via the returned object (using upper case or lower case; 18505but note that all-caps "VERSION" will return the module 18506version, not the MP3 version). 18507 18508Passing a value to one of the methods will set the value 18509for that tag in the MP3 file, if applicable. 18510 18511=cut 18512 18513sub new { 18514 my($pack, $file) = @_; 18515 18516 my $info = get_mp3info($file) or return undef; 18517 my $tags = get_mp3tag($file) || { map { ($_ => undef) } @v1_tag_names }; 18518 my %self = ( 18519 FILE => $file, 18520 TRY_HARDER => 0 18521 ); 18522 18523 @self{@mp3_info_fields, @v1_tag_names, 'file'} = ( 18524 @{$info}{@mp3_info_fields}, 18525 @{$tags}{@v1_tag_names}, 18526 $file 18527 ); 18528 18529 return bless \%self, $pack; 18530} 18531 18532sub can { 18533 my $self = shift; 18534 return $self->SUPER::can(@_) unless ref $self; 18535 my $name = uc shift; 18536 return sub { $self->$name(@_) } if exists $self->{$name}; 18537 return undef; 18538} 18539 18540sub AUTOLOAD { 18541 my($self) = @_; 18542 (my $name = uc $AUTOLOAD) =~ s/^.*://; 18543 18544 if (exists $self->{$name}) { 18545 my $sub = exists $v1_tag_fields{$name} 18546 ? sub { 18547 if (defined $_[1]) { 18548 $_[0]->{$name} = $_[1]; 18549 set_mp3tag($_[0]->{FILE}, $_[0]); 18550 } 18551 return $_[0]->{$name}; 18552 } 18553 : sub { 18554 return $_[0]->{$name} 18555 }; 18556 18557 no strict 'refs'; 18558 *{$AUTOLOAD} = $sub; 18559 goto &$AUTOLOAD; 18560 18561 } else { 18562 carp(sprintf "No method '$name' available in package %s.", 18563 __PACKAGE__); 18564 } 18565} 18566 18567sub DESTROY { 18568 18569} 18570 18571 18572=item use_mp3_utf8([STATUS]) 18573 18574Tells MP3::Info to (or not) return TAG info in UTF-8. 18575TRUE is 1, FALSE is 0. Default is TRUE, if available. 18576 18577Will only be able to turn it on if Encode is available. ID3v2 18578tags will be converted to UTF-8 according to the encoding specified 18579in each tag; ID3v1 tags will be assumed Latin-1 and converted 18580to UTF-8. 18581 18582Function returns status (TRUE/FALSE). If no argument is supplied, 18583or an unaccepted argument is supplied, function merely returns status. 18584 18585This function is not exported by default, but may be exported 18586with the C<:utf8> or C<:all> export tag. 18587 18588=cut 18589 18590my $unicode_module = eval { require Encode; require Encode::Guess }; 18591my $UNICODE = use_mp3_utf8($unicode_module ? 1 : 0); 18592 18593sub use_mp3_utf8 { 18594 my $val = shift; 18595 no warnings; 18596 18597 $UNICODE = 0; 18598 18599 if ($val == 1) { 18600 18601 if ($unicode_module) { 18602 $Encode::Guess::NoUTFAutoGuess = 1; 18603 $UNICODE = 1; 18604 } 18605 } 18606 18607 return $UNICODE; 18608} 18609 18610=pod 18611 18612=item use_winamp_genres() 18613 18614Puts WinAmp genres into C<@mp3_genres> and C<%mp3_genres> 18615(adds 68 additional genres to the default list of 80). 18616This is a separate function because these are non-standard 18617genres, but they are included because they are widely used. 18618 18619You can import the data structures with one of: 18620 18621 use MP3::Info qw(:genres); 18622 use MP3::Info qw(:DEFAULT :genres); 18623 use MP3::Info qw(:all); 18624 18625=cut 18626 18627sub use_winamp_genres { 18628 %mp3_genres = %winamp_genres; 18629 @mp3_genres = @winamp_genres; 18630 return 1; 18631} 18632 18633=pod 18634 18635=item remove_mp3tag (FILE [, VERSION, BUFFER]) 18636 18637Can remove ID3v1 or ID3v2 tags. VERSION should be C<1> for ID3v1 18638(the default), C<2> for ID3v2, and C<ALL> for both. 18639 18640For ID3v1, removes last 128 bytes from file if those last 128 bytes begin 18641with the text 'TAG'. File will be 128 bytes shorter. 18642 18643For ID3v2, removes ID3v2 tag. Because an ID3v2 tag is at the 18644beginning of the file, we rewrite the file after removing the tag data. 18645The buffer for rewriting the file is 4MB. BUFFER (in bytes) ca 18646change the buffer size. 18647 18648Returns the number of bytes removed, or -1 if no tag removed, 18649or undef if there is an error. 18650 18651=cut 18652 18653sub remove_mp3tag { 18654 my($file, $version, $buf) = @_; 18655 my($fh, $return); 18656 18657 $buf ||= 4096*1024; # the bigger the faster 18658 $version ||= 1; 18659 18660 if (not (defined $file && $file ne '')) { 18661 $@ = "No file specified"; 18662 return undef; 18663 } 18664 18665 if (not -s $file) { 18666 $@ = "File is empty"; 18667 return undef; 18668 } 18669 18670 if (ref $file) { # filehandle passed 18671 $fh = $file; 18672 } else { 18673 if (not open $fh, '+<', $file) { 18674 $@ = "Can't open $file: $!"; 18675 return undef; 18676 } 18677 } 18678 18679 binmode $fh; 18680 18681 if ($version eq 1 || $version eq 'ALL') { 18682 seek $fh, -128, 2; 18683 my $tell = tell $fh; 18684 if (<$fh> =~ /^TAG/) { 18685 truncate $fh, $tell or carp "Can't truncate '$file': $!"; 18686 $return += 128; 18687 } 18688 } 18689 18690 if ($version eq 2 || $version eq 'ALL') { 18691 my $v2h = _get_v2head($fh); 18692 if ($v2h) { 18693 local $\; 18694 seek $fh, 0, 2; 18695 my $eof = tell $fh; 18696 my $off = $v2h->{tag_size}; 18697 18698 while ($off < $eof) { 18699 seek $fh, $off, 0; 18700 read $fh, my($bytes), $buf; 18701 seek $fh, $off - $v2h->{tag_size}, 0; 18702 print $fh $bytes; 18703 $off += $buf; 18704 } 18705 18706 truncate $fh, $eof - $v2h->{tag_size} 18707 or carp "Can't truncate '$file': $!"; 18708 $return += $v2h->{tag_size}; 18709 } 18710 } 18711 18712 _close($file, $fh); 18713 18714 return $return || -1; 18715} 18716 18717 18718=pod 18719 18720=item set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM]) 18721 18722=item set_mp3tag (FILE, $HASHREF) 18723 18724Adds/changes tag information in an MP3 audio file. Will clobber 18725any existing information in file. 18726 18727Fields are TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE. All fields have 18728a 30-byte limit, except for YEAR, which has a four-byte limit, and GENRE, 18729which is one byte in the file. The GENRE passed in the function is a 18730case-insensitive text string representing a genre found in C<@mp3_genres>. 18731 18732Will accept either a list of values, or a hashref of the type 18733returned by C<get_mp3tag>. 18734 18735If TRACKNUM is present (for ID3v1.1), then the COMMENT field can only be 1873628 bytes. 18737 18738ID3v2 support may come eventually. Note that if you set a tag on a file 18739with ID3v2, the set tag will be for ID3v1[.1] only, and if you call 18740C<get_mp3tag> on the file, it will show you the (unchanged) ID3v2 tags, 18741unless you specify ID3v1. 18742 18743=cut 18744 18745sub set_mp3tag { 18746 my($file, $title, $artist, $album, $year, $comment, $genre, $tracknum) = @_; 18747 my(%info, $oldfh, $ref, $fh); 18748 local %v1_tag_fields = %v1_tag_fields; 18749 18750 # set each to '' if undef 18751 for ($title, $artist, $album, $year, $comment, $tracknum, $genre, 18752 (@info{@v1_tag_names})) 18753 {$_ = defined() ? $_ : ''} 18754 18755 ($ref) = (overload::StrVal($title) =~ /^(?:.*\=)?([^=]*)\((?:[^\(]*)\)$/) 18756 if ref $title; 18757 # populate data to hashref if hashref is not passed 18758 if (!$ref) { 18759 (@info{@v1_tag_names}) = 18760 ($title, $artist, $album, $year, $comment, $tracknum, $genre); 18761 18762 # put data from hashref into hashref if hashref is passed 18763 } elsif ($ref eq 'HASH') { 18764 %info = %$title; 18765 18766 # return otherwise 18767 } else { 18768 carp(<<'EOT'); 18769Usage: set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM]) 18770 set_mp3tag (FILE, $HASHREF) 18771EOT 18772 return undef; 18773 } 18774 18775 if (not (defined $file && $file ne '')) { 18776 $@ = "No file specified"; 18777 return undef; 18778 } 18779 18780 if (not -s $file) { 18781 $@ = "File is empty"; 18782 return undef; 18783 } 18784 18785 # comment field length 28 if ID3v1.1 18786 $v1_tag_fields{COMMENT} = 28 if $info{TRACKNUM}; 18787 18788 18789 # only if -w is on 18790 if ($^W) { 18791 # warn if fields too long 18792 foreach my $field (keys %v1_tag_fields) { 18793 $info{$field} = '' unless defined $info{$field}; 18794 if (length($info{$field}) > $v1_tag_fields{$field}) { 18795 carp "Data too long for field $field: truncated to " . 18796 "$v1_tag_fields{$field}"; 18797 } 18798 } 18799 18800 if ($info{GENRE}) { 18801 carp "Genre `$info{GENRE}' does not exist\n" 18802 unless exists $mp3_genres{$info{GENRE}}; 18803 } 18804 } 18805 18806 if ($info{TRACKNUM}) { 18807 $info{TRACKNUM} =~ s/^(\d+)\/(\d+)$/$1/; 18808 unless ($info{TRACKNUM} =~ /^\d+$/ && 18809 $info{TRACKNUM} > 0 && $info{TRACKNUM} < 256) { 18810 carp "Tracknum `$info{TRACKNUM}' must be an integer " . 18811 "from 1 and 255\n" if $^W; 18812 $info{TRACKNUM} = ''; 18813 } 18814 } 18815 18816 if (ref $file) { # filehandle passed 18817 $fh = $file; 18818 } else { 18819 if (not open $fh, '+<', $file) { 18820 $@ = "Can't open $file: $!"; 18821 return undef; 18822 } 18823 } 18824 18825 binmode $fh; 18826 $oldfh = select $fh; 18827 seek $fh, -128, 2; 18828 # go to end of file if no tag, beginning of file if tag 18829 seek $fh, (<$fh> =~ /^TAG/ ? -128 : 0), 2; 18830 18831 # get genre value 18832 $info{GENRE} = $info{GENRE} && exists $mp3_genres{$info{GENRE}} ? 18833 $mp3_genres{$info{GENRE}} : 255; # some default genre 18834 18835 local $\; 18836 # print TAG to file 18837 if ($info{TRACKNUM}) { 18838 print pack 'a3a30a30a30a4a28xCC', 'TAG', @info{@v1_tag_names}; 18839 } else { 18840 print pack 'a3a30a30a30a4a30C', 'TAG', @info{@v1_tag_names[0..4, 6]}; 18841 } 18842 18843 select $oldfh; 18844 18845 _close($file, $fh); 18846 18847 return 1; 18848} 18849 18850=pod 18851 18852=item get_mp3tag (FILE [, VERSION, RAW_V2]) 18853 18854Returns hash reference containing tag information in MP3 file. The keys 18855returned are the same as those supplied for C<set_mp3tag>, except in the 18856case of RAW_V2 being set. 18857 18858If VERSION is C<1>, the information is taken from the ID3v1 tag (if present). 18859If VERSION is C<2>, the information is taken from the ID3v2 tag (if present). 18860If VERSION is not supplied, or is false, the ID3v1 tag is read if present, and 18861then, if present, the ID3v2 tag information will override any existing ID3v1 18862tag info. 18863 18864If RAW_V2 is C<1>, the raw ID3v2 tag data is returned, without any manipulation 18865of text encoding. The key name is the same as the frame ID (ID to name mappings 18866are in the global %v2_tag_names). 18867 18868If RAW_V2 is C<2>, the ID3v2 tag data is returned, manipulating for Unicode if 18869necessary, etc. It also takes multiple values for a given key (such as comments) 18870and puts them in an arrayref. 18871 18872If the ID3v2 version is older than ID3v2.2.0 or newer than ID3v2.4.0, it will 18873not be read. 18874 18875Strings returned will be in Latin-1, unless UTF-8 is specified (L<use_mp3_utf8>), 18876(unless RAW_V2 is C<1>). 18877 18878Also returns a TAGVERSION key, containing the ID3 version used for the returned 18879data (if TAGVERSION argument is C<0>, may contain two versions). 18880 18881=cut 18882 18883sub get_mp3tag { 18884 my ($file, $ver, $raw_v2, $find_ape) = @_; 18885 my ($tag, $v2h, $fh); 18886 18887 my $v1 = {}; 18888 my $v2 = {}; 18889 my $ape = {}; 18890 my %info = (); 18891 my @array = (); 18892 18893 $raw_v2 ||= 0; 18894 $ver = !$ver ? 0 : ($ver == 2 || $ver == 1) ? $ver : 0; 18895 18896 if (not (defined $file && $file ne '')) { 18897 $@ = "No file specified"; 18898 return undef; 18899 } 18900 18901 my $filesize = -s $file; 18902 18903 if (!$filesize) { 18904 $@ = "File is empty"; 18905 return undef; 18906 } 18907 18908 if (ref $file) { # filehandle passed 18909 $fh = $file; 18910 } else { 18911 if (not open $fh, '<', $file) { 18912 $@ = "Can't open $file: $!"; 18913 return undef; 18914 } 18915 } 18916 18917 binmode $fh; 18918 18919 # Try and find an APE Tag - this is where FooBar2k & others 18920 # store ReplayGain information 18921 if ($find_ape) { 18922 18923 $ape = _parse_ape_tag($fh, $filesize, \%info); 18924 } 18925 18926 if ($ver < 2) { 18927 18928 $v1 = _get_v1tag($fh, \%info); 18929 18930 if ($ver == 1 && !$v1) { 18931 _close($file, $fh); 18932 $@ = "No ID3v1 tag found"; 18933 return undef; 18934 } 18935 } 18936 18937 if ($ver == 2 || $ver == 0) { 18938 ($v2, $v2h) = _get_v2tag($fh); 18939 } 18940 18941 if (!$v1 && !$v2 && !$ape) { 18942 _close($file, $fh); 18943 $@ = "No ID3 tag found"; 18944 return undef; 18945 } 18946 18947 if (($ver == 0 || $ver == 2) && $v2) { 18948 18949 if ($raw_v2 == 1 && $ver == 2) { 18950 18951 %info = %$v2; 18952 18953 $info{'TAGVERSION'} = $v2h->{'version'}; 18954 18955 } else { 18956 18957 _parse_v2tag($raw_v2, $v2, \%info); 18958 18959 if ($ver == 0 && $info{'TAGVERSION'}) { 18960 $info{'TAGVERSION'} .= ' / ' . $v2h->{'version'}; 18961 } else { 18962 $info{'TAGVERSION'} = $v2h->{'version'}; 18963 } 18964 } 18965 } 18966 18967 unless ($raw_v2 && $ver == 2) { 18968 foreach my $key (keys %info) { 18969 if (defined $info{$key}) { 18970 $info{$key} =~ s/\000+.*//g; 18971 $info{$key} =~ s/\s+$//; 18972 } 18973 } 18974 18975 for (@v1_tag_names) { 18976 $info{$_} = '' unless defined $info{$_}; 18977 } 18978 } 18979 18980 if (keys %info && exists $info{'GENRE'} && ! defined $info{'GENRE'}) { 18981 $info{'GENRE'} = ''; 18982 } 18983 18984 _close($file, $fh); 18985 18986 return keys %info ? {%info} : undef; 18987} 18988 18989sub _get_v1tag { 18990 my ($fh, $info) = @_; 18991 18992 seek $fh, -128, 2; 18993 read($fh, my $tag, 128); 18994 18995 if (!defined($tag) || $tag !~ /^TAG/) { 18996 18997 return 0; 18998 } 18999 19000 if (substr($tag, -3, 2) =~ /\000[^\000]/) { 19001 19002 (undef, @{$info}{@v1_tag_names}) = 19003 (unpack('a3a30a30a30a4a28', $tag), 19004 ord(substr($tag, -2, 1)), 19005 $mp3_genres[ord(substr $tag, -1)]); 19006 19007 $info->{'TAGVERSION'} = 'ID3v1.1'; 19008 19009 } else { 19010 19011 (undef, @{$info}{@v1_tag_names[0..4, 6]}) = 19012 (unpack('a3a30a30a30a4a30', $tag), 19013 $mp3_genres[ord(substr $tag, -1)]); 19014 19015 $info->{'TAGVERSION'} = 'ID3v1'; 19016 } 19017 19018 if ($UNICODE) { 19019 19020 # Save off the old suspects list, since we add 19021 # iso-8859-1 below, but don't want that there 19022 # for possible ID3 v2.x parsing below. 19023 my $oldSuspects = $Encode::Encoding{'Guess'}->{'Suspects'}; 19024 19025 for my $key (keys %{$info}) { 19026 19027 next unless $info->{$key}; 19028 19029 # Try and guess the encoding. 19030 my $value = $info->{$key}; 19031 my $icode = Encode::Guess->guess($value); 19032 19033 unless (ref($icode)) { 19034 19035 # Often Latin1 bytes are 19036 # stuffed into a 1.1 tag. 19037 Encode::Guess->add_suspects('iso-8859-1'); 19038 19039 while (length($value)) { 19040 19041 $icode = Encode::Guess->guess($value); 19042 19043 last if ref($icode); 19044 19045 # Remove garbage and retry 19046 # (string is truncated in the 19047 # middle of a multibyte char?) 19048 $value =~ s/(.)$//; 19049 } 19050 } 19051 19052 $info->{$key} = Encode::decode(ref($icode) ? $icode->name : 'iso-8859-1', $info->{$key}); 19053 } 19054 19055 Encode::Guess->set_suspects(keys %{$oldSuspects}); 19056 } 19057 19058 return 1; 19059} 19060 19061sub _parse_v2tag { 19062 my ($raw_v2, $v2, $info) = @_; 19063 19064 # Make sure any existing TXXX flags are an array. 19065 # As we might need to append comments to it below. 19066 if ($v2->{'TXXX'} && ref($v2->{'TXXX'}) ne 'ARRAY') { 19067 19068 $v2->{'TXXX'} = [ $v2->{'TXXX'} ]; 19069 } 19070 19071 # J.River Media Center sticks RG tags in comments. 19072 # Ugh. Make them look like TXXX tags, which is really what they are. 19073 if (ref($v2->{'COMM'}) eq 'ARRAY' && grep { /Media Jukebox/ } @{$v2->{'COMM'}}) { 19074 19075 for my $comment (@{$v2->{'COMM'}}) { 19076 19077 if ($comment =~ /Media Jukebox/) { 19078 19079 # we only want one null to lead. 19080 $comment =~ s/^\000+//g; 19081 19082 push @{$v2->{'TXXX'}}, "\000$comment"; 19083 } 19084 } 19085 } 19086 19087 my $hash = $raw_v2 == 2 ? { map { ($_, $_) } keys %v2_tag_names } : \%v2_to_v1_names; 19088 19089 for my $id (keys %$hash) { 19090 19091 next if !exists $v2->{$id}; 19092 19093 if ($id =~ /^UFID?$/) { 19094 19095 my @ufid_list = split(/\0/, $v2->{$id}); 19096 19097 $info->{$hash->{$id}} = $ufid_list[1] if ($#ufid_list > 0); 19098 19099 } elsif ($id =~ /^RVA[D2]?$/) { 19100 19101 # Expand these binary fields. See the ID3 spec for Relative Volume Adjustment. 19102 if ($id eq 'RVA2') { 19103 19104 # ID is a text string 19105 ($info->{$hash->{$id}}->{'ID'}, my $rvad) = split /\0/, $v2->{$id}; 19106 19107 my $channel = $rva2_channel_types{ ord(substr($rvad, 0, 1, '')) }; 19108 19109 $info->{$hash->{$id}}->{$channel}->{'REPLAYGAIN_TRACK_GAIN'} = 19110 sprintf('%f', _grab_int_16(\$rvad) / 512); 19111 19112 my $peakBytes = ord(substr($rvad, 0, 1, '')); 19113 19114 if (int($peakBytes / 8)) { 19115 19116 $info->{$hash->{$id}}->{$channel}->{'REPLAYGAIN_TRACK_PEAK'} = 19117 sprintf('%f', _grab_int_16(\$rvad) / 512); 19118 } 19119 19120 } elsif ($id eq 'RVAD' || $id eq 'RVA') { 19121 19122 my $rvad = $v2->{$id}; 19123 my $flags = ord(substr($rvad, 0, 1, '')); 19124 my $desc = ord(substr($rvad, 0, 1, '')); 19125 19126 # iTunes appears to be the only program that actually writes 19127 # out a RVA/RVAD tag. Everyone else punts. 19128 for my $type (qw(REPLAYGAIN_TRACK_GAIN REPLAYGAIN_TRACK_PEAK)) { 19129 19130 for my $channel (qw(RIGHT LEFT)) { 19131 19132 my $val = _grab_uint_16(\$rvad) / 256; 19133 19134 # iTunes uses a range of -255 to 255 19135 # to be -100% (silent) to 100% (+6dB) 19136 if ($val == -255) { 19137 $val = -96.0; 19138 } else { 19139 $val = 20.0 * log(($val+255)/255)/log(10); 19140 } 19141 19142 $info->{$hash->{$id}}->{$channel}->{$type} = $flags & 0x01 ? $val : -$val; 19143 } 19144 } 19145 } 19146 19147 } elsif ($id =~ /^A?PIC$/) { 19148 19149 my $pic = $v2->{$id}; 19150 19151 # if there is more than one picture, just grab the first one. 19152 if (ref($pic) eq 'ARRAY') { 19153 $pic = (@$pic)[0]; 19154 } 19155 19156 use bytes; 19157 19158 my $valid_pic = 0; 19159 my $pic_len = 0; 19160 my $pic_format = ''; 19161 19162 # look for ID3 v2.2 picture 19163 if ($pic && $id eq 'PIC') { 19164 19165 # look for ID3 v2.2 picture 19166 my ($encoding, $format, $picture_type, $description) = unpack 'Ca3CZ*', $pic; 19167 $pic_len = length($description) + 1 + 5; 19168 19169 # skip extra terminating null if unicode 19170 if ($encoding) { $pic_len++; } 19171 19172 if ($pic_len < length($pic)) { 19173 $valid_pic = 1; 19174 $pic_format = $format; 19175 } 19176 19177 } elsif ($pic && $id eq 'APIC') { 19178 19179 # look for ID3 v2.3 picture 19180 my ($encoding, $format) = unpack 'C Z*', $pic; 19181 19182 $pic_len = length($format) + 2; 19183 19184 if ($pic_len < length($pic)) { 19185 19186 my ($picture_type, $description) = unpack "x$pic_len C Z*", $pic; 19187 19188 $pic_len += 1 + length($description) + 1; 19189 19190 # skip extra terminating null if unicode 19191 if ($encoding) { $pic_len++; } 19192 19193 $valid_pic = 1; 19194 $pic_format = $format; 19195 } 19196 } 19197 19198 # Proceed if we have a valid picture. 19199 if ($valid_pic && $pic_format) { 19200 19201 my ($data) = unpack("x$pic_len A*", $pic); 19202 19203 if (length($data) && $pic_format) { 19204 19205 $info->{$hash->{$id}} = { 19206 'DATA' => $data, 19207 'FORMAT' => $pic_format, 19208 } 19209 } 19210 } 19211 19212 } else { 19213 my $data1 = $v2->{$id}; 19214 19215 # this is tricky ... if this is an arrayref, 19216 # we want to only return one, so we pick the 19217 # first one. but if it is a comment, we pick 19218 # the first one where the first charcter after 19219 # the language is NULL and not an additional 19220 # sub-comment, because that is most likely to be 19221 # the user-supplied comment 19222 if (ref $data1 && !$raw_v2) { 19223 if ($id =~ /^COMM?$/) { 19224 my($newdata) = grep /^(....\000)/, @{$data1}; 19225 $data1 = $newdata || $data1->[0]; 19226 } elsif ($id !~ /^(?:TXXX?|PRIV)$/) { 19227 # We can get multiple User Defined Text frames in a mp3 file 19228 $data1 = $data1->[0]; 19229 } 19230 } 19231 19232 $data1 = [ $data1 ] if ! ref $data1; 19233 19234 for my $data (@$data1) { 19235 # TODO : this should only be done for certain frames; 19236 # using RAW still gives you access, but we should be smarter 19237 # about how individual frame types are handled. it's not 19238 # like the list is infinitely long. 19239 $data =~ s/^(.)//; # strip first char (text encoding) 19240 my $encoding = $1; 19241 my $desc; 19242 19243 # Comments & Unsyncronized Lyrics have the same format. 19244 if ($id =~ /^(COM[M ]?|USLT)$/) { # space for iTunes brokenness 19245 19246 $data =~ s/^(?:...)//; # strip language 19247 } 19248 19249 if ($UNICODE) { 19250 19251 if ($encoding eq "\001" || $encoding eq "\002") { # UTF-16, UTF-16BE 19252 # text fields can be null-separated lists; 19253 # UTF-16 therefore needs special care 19254 # 19255 # foobar2000 encodes tags in UTF-16LE 19256 # (which is apparently illegal) 19257 # Encode dies on a bad BOM, so it is 19258 # probably wise to wrap it in an eval 19259 # anyway 19260 $data = eval { Encode::decode('utf16', $data) } || Encode::decode('utf16le', $data); 19261 19262 } elsif ($encoding eq "\003") { # UTF-8 19263 19264 # make sure string is UTF8, and set flag appropriately 19265 $data = Encode::decode('utf8', $data); 19266 19267 } elsif ($encoding eq "\000") { 19268 19269 # Only guess if it's not ascii. 19270 if ($data && $data !~ /^[\x00-\x7F]+$/) { 19271 19272 # Try and guess the encoding, otherwise just use latin1 19273 my $dec = Encode::Guess->guess($data); 19274 19275 if (ref $dec) { 19276 $data = $dec->decode($data); 19277 } else { 19278 # Best try 19279 $data = Encode::decode('iso-8859-1', $data); 19280 } 19281 } 19282 } 19283 19284 } else { 19285 19286 # If the string starts with an 19287 # UTF-16 little endian BOM, use a hack to 19288 # convert to ASCII per best-effort 19289 my $pat; 19290 if ($data =~ s/^\xFF\xFE//) { 19291 $pat = 'v'; 19292 } elsif ($data =~ s/^\xFE\xFF//) { 19293 $pat = 'n'; 19294 } 19295 19296 if ($pat) { 19297 $data = pack 'C*', map { 19298 (chr =~ /[[:ascii:]]/ && chr =~ /[[:print:]]/) 19299 ? $_ 19300 : ord('?') 19301 } unpack "$pat*", $data; 19302 } 19303 } 19304 19305 # We do this after decoding so we could be certain we're dealing 19306 # with 8-bit text. 19307 if ($id =~ /^(COM[M ]?|USLT)$/) { # space for iTunes brokenness 19308 19309 $data =~ s/^(.*?)\000//; # strip up to first NULL(s), 19310 # for sub-comments (TODO: 19311 # handle all comment data) 19312 $desc = $1; 19313 19314 } elsif ($id =~ /^TCON?$/) { 19315 19316 my ($index, $name); 19317 19318 # Turn multiple nulls into a single. 19319 $data =~ s/\000+/\000/g; 19320 19321 # Handle the ID3v2.x spec - 19322 # 19323 # just an index number, possibly 19324 # paren enclosed - referer to the v1 genres. 19325 if ($data =~ /^ \(? (\d+) \)?\000?$/sx) { 19326 19327 $index = $1; 19328 19329 # Paren enclosed index with refinement. 19330 # (4)Eurodisco 19331 } elsif ($data =~ /^ \( (\d+) \)\000? ([^\(].+)$/x) { 19332 19333 ($index, $name) = ($1, $2); 19334 19335 # List of indexes: (37)(38) 19336 } elsif ($data =~ /^ \( (\d+) \)\000?/x) { 19337 19338 my @genres = (); 19339 19340 while ($data =~ s/^ \( (\d+) \)\000?//x) { 19341 19342 push @genres, $mp3_genres[$1]; 19343 } 19344 19345 $data = \@genres; 19346 } 19347 19348 # Text based genres will fall through. 19349 if ($name && $name ne "\000") { 19350 $data = $name; 19351 } elsif (defined $index) { 19352 $data = $mp3_genres[$index]; 19353 } 19354 } 19355 19356 if ($raw_v2 == 2 && $desc) { 19357 $data = { $desc => $data }; 19358 } 19359 19360 if ($raw_v2 == 2 && exists $info->{$hash->{$id}}) { 19361 19362 if (ref $info->{$hash->{$id}} eq 'ARRAY') { 19363 push @{$info->{$hash->{$id}}}, $data; 19364 } else { 19365 $info->{$hash->{$id}} = [ $info->{$hash->{$id}}, $data ]; 19366 } 19367 19368 } else { 19369 19370 # User defined frame 19371 if ($id eq 'TXXX') { 19372 19373 my ($key, $val) = split(/\0/, $data); 19374 $info->{uc($key)} = $val; 19375 19376 } elsif ($id eq 'PRIV') { 19377 19378 my ($key, $val) = split(/\0/, $data); 19379 $info->{uc($key)} = unpack('v', $val); 19380 19381 } else { 19382 19383 $info->{$hash->{$id}} = $data; 19384 } 19385 } 19386 } 19387 } 19388 } 19389} 19390 19391sub _get_v2tag { 19392 my($fh) = @_; 19393 my($off, $end, $myseek, $v2, $v2h, $hlen, $num, $wholetag); 19394 19395 $v2 = {}; 19396 $v2h = _get_v2head($fh) or return; 19397 19398 if ($v2h->{major_version} < 2) { 19399 carp "This is $v2h->{version}; " . 19400 "ID3v2 versions older than ID3v2.2.0 not supported\n" 19401 if $^W; 19402 return; 19403 } 19404 19405 # use syncsafe bytes if using version 2.4 19406 # my $bytesize = ($v2h->{major_version} > 3) ? 128 : 256; 19407 19408 # alas, that's what the spec says, but iTunes and others don't syncsafe 19409 # the length, which breaks MP3 files with v2.4 tags longer than 128 bytes, 19410 # like every image file. 19411 my $bytesize = 256; 19412 19413 if ($v2h->{major_version} == 2) { 19414 $hlen = 6; 19415 $num = 3; 19416 } else { 19417 $hlen = 10; 19418 $num = 4; 19419 } 19420 19421 $off = $v2h->{ext_header_size} + 10; 19422 $end = $v2h->{tag_size} + 10; # should we read in the footer too? 19423 19424 seek $fh, $v2h->{offset}, 0; 19425 read $fh, $wholetag, $end; 19426 19427 $wholetag =~ s/\xFF\x00/\xFF/gs if $v2h->{unsync}; 19428 19429 $myseek = sub { 19430 my $bytes = substr($wholetag, $off, $hlen); 19431 return unless $bytes =~ /^([A-Z0-9]{$num})/ 19432 || ($num == 4 && $bytes =~ /^(COM )/); # stupid iTunes 19433 my($id, $size) = ($1, $hlen); 19434 my @bytes = reverse unpack "C$num", substr($bytes, $num, $num); 19435 19436 for my $i (0 .. ($num - 1)) { 19437 $size += $bytes[$i] * $bytesize ** $i; 19438 } 19439 19440 my $flags = {}; 19441 if ($v2h->{major_version} > 3) { 19442 my @bits = split //, unpack 'B16', substr($bytes, 8, 2); 19443 $flags->{frame_unsync} = $bits[14]; 19444 $flags->{data_len_indicator} = $bits[15]; 19445 } 19446 19447 return($id, $size, $flags); 19448 }; 19449 19450 while ($off < $end) { 19451 my($id, $size, $flags) = &$myseek or last; 19452 19453 my $bytes = substr($wholetag, $off+$hlen, $size-$hlen); 19454 19455 my $data_len; 19456 if ($flags->{data_len_indicator}) { 19457 $data_len = 0; 19458 my @data_len_bytes = reverse unpack 'C4', substr($bytes, 0, 4); 19459 $bytes = substr($bytes, 4); 19460 for my $i (0..3) { 19461 $data_len += $data_len_bytes[$i] * 128 ** $i; 19462 } 19463 } 19464 19465 # perform frame-level unsync if needed (skip if already done for whole tag) 19466 $bytes =~ s/\xFF\x00/\xFF/gs if $flags->{frame_unsync} && !$v2h->{unsync}; 19467 19468 # if we know the data length, sanity check it now. 19469 if ($flags->{data_len_indicator} && defined $data_len) { 19470 carp "Size mismatch on $id\n" unless $data_len == length($bytes); 19471 } 19472 19473 if (exists $v2->{$id}) { 19474 if (ref $v2->{$id} eq 'ARRAY') { 19475 push @{$v2->{$id}}, $bytes; 19476 } else { 19477 $v2->{$id} = [$v2->{$id}, $bytes]; 19478 } 19479 } else { 19480 $v2->{$id} = $bytes; 19481 } 19482 $off += $size; 19483 } 19484 19485 return($v2, $v2h); 19486} 19487 19488 19489=pod 19490 19491=item get_mp3info (FILE) 19492 19493Returns hash reference containing file information for MP3 file. 19494This data cannot be changed. Returned data: 19495 19496 VERSION MPEG audio version (1, 2, 2.5) 19497 LAYER MPEG layer description (1, 2, 3) 19498 STEREO boolean for audio is in stereo 19499 19500 VBR boolean for variable bitrate 19501 BITRATE bitrate in kbps (average for VBR files) 19502 FREQUENCY frequency in kHz 19503 SIZE bytes in audio stream 19504 OFFSET bytes offset that stream begins 19505 19506 SECS total seconds 19507 MM minutes 19508 SS leftover seconds 19509 MS leftover milliseconds 19510 TIME time in MM:SS 19511 19512 COPYRIGHT boolean for audio is copyrighted 19513 PADDING boolean for MP3 frames are padded 19514 MODE channel mode (0 = stereo, 1 = joint stereo, 19515 2 = dual channel, 3 = single channel) 19516 FRAMES approximate number of frames 19517 FRAME_LENGTH approximate length of a frame 19518 VBR_SCALE VBR scale from VBR header 19519 19520On error, returns nothing and sets C<$@>. 19521 19522=cut 19523 19524sub get_mp3info { 19525 my($file) = @_; 19526 my($off, $byte, $eof, $h, $tot, $fh); 19527 19528 if (not (defined $file && $file ne '')) { 19529 $@ = "No file specified"; 19530 return undef; 19531 } 19532 19533 if (not -s $file) { 19534 $@ = "File is empty"; 19535 return undef; 19536 } 19537 19538 if (ref $file) { # filehandle passed 19539 $fh = $file; 19540 } else { 19541 if (not open $fh, '<', $file) { 19542 $@ = "Can't open $file: $!"; 19543 return undef; 19544 } 19545 } 19546 19547 $off = 0; 19548 $tot = 8192; 19549 19550 # Let the caller change how far we seek in looking for a header. 19551 if ($try_harder) { 19552 $tot *= $try_harder; 19553 } 19554 19555 binmode $fh; 19556 seek $fh, $off, 0; 19557 read $fh, $byte, 4; 19558 19559 if ($off == 0) { 19560 if (my $v2h = _get_v2head($fh)) { 19561 $tot += $off += $v2h->{tag_size}; 19562 seek $fh, $off, 0; 19563 read $fh, $byte, 4; 19564 } 19565 } 19566 19567 $h = _get_head($byte); 19568 my $is_mp3 = _is_mp3($h); 19569 19570 # the head wasn't where we were expecting it.. dig deeper. 19571 unless ($is_mp3) { 19572 19573 # do only one read - it's _much_ faster 19574 $off++; 19575 seek $fh, $off, 0; 19576 read $fh, $byte, $tot; 19577 19578 my $i; 19579 19580 # now walk the bytes looking for the head 19581 for ($i = 0; $i < $tot; $i++) { 19582 19583 last if ($tot - $i) < 4; 19584 19585 my $head = substr($byte, $i, 4) || last; 19586 19587 next if (ord($head) != 0xff); 19588 19589 $h = _get_head($head); 19590 $is_mp3 = _is_mp3($h); 19591 last if $is_mp3; 19592 } 19593 19594 # adjust where we are for _get_vbr() 19595 $off += $i; 19596 19597 if ($off > $tot && !$try_harder) { 19598 _close($file, $fh); 19599 $@ = "Couldn't find MP3 header (perhaps set " . 19600 '$MP3::Info::try_harder and retry)'; 19601 return undef; 19602 } 19603 } 19604 19605 my $vbr = _get_vbr($fh, $h, \$off); 19606 19607 seek $fh, 0, 2; 19608 $eof = tell $fh; 19609 seek $fh, -128, 2; 19610 $eof -= 128 if <$fh> =~ /^TAG/ ? 1 : 0; 19611 19612 _close($file, $fh); 19613 19614 $h->{size} = $eof - $off; 19615 $h->{offset} = $off; 19616 19617 return _get_info($h, $vbr); 19618} 19619 19620sub _get_info { 19621 my($h, $vbr) = @_; 19622 my $i; 19623 19624 # No bitrate or sample rate? Something's wrong. 19625 unless ($h->{bitrate} && $h->{fs}) { 19626 return {}; 19627 } 19628 19629 $i->{VERSION} = $h->{IDR} == 2 ? 2 : $h->{IDR} == 3 ? 1 : 19630 $h->{IDR} == 0 ? 2.5 : 0; 19631 $i->{LAYER} = 4 - $h->{layer}; 19632 $i->{VBR} = defined $vbr ? 1 : 0; 19633 19634 $i->{COPYRIGHT} = $h->{copyright} ? 1 : 0; 19635 $i->{PADDING} = $h->{padding_bit} ? 1 : 0; 19636 $i->{STEREO} = $h->{mode} == 3 ? 0 : 1; 19637 $i->{MODE} = $h->{mode}; 19638 19639 $i->{SIZE} = $vbr && $vbr->{bytes} ? $vbr->{bytes} : $h->{size}; 19640 $i->{OFFSET} = $h->{offset}; 19641 19642 my $mfs = $h->{fs} / ($h->{ID} ? 144000 : 72000); 19643 $i->{FRAMES} = int($vbr && $vbr->{frames} 19644 ? $vbr->{frames} 19645 : $i->{SIZE} / ($h->{bitrate} / $mfs) 19646 ); 19647 19648 if ($vbr) { 19649 $i->{VBR_SCALE} = $vbr->{scale} if $vbr->{scale}; 19650 $h->{bitrate} = $i->{SIZE} / $i->{FRAMES} * $mfs; 19651 if (not $h->{bitrate}) { 19652 $@ = "Couldn't determine VBR bitrate"; 19653 return undef; 19654 } 19655 } 19656 19657 $h->{'length'} = ($i->{SIZE} * 8) / $h->{bitrate} / 10; 19658 $i->{SECS} = $h->{'length'} / 100; 19659 $i->{MM} = int $i->{SECS} / 60; 19660 $i->{SS} = int $i->{SECS} % 60; 19661 $i->{MS} = (($i->{SECS} - ($i->{MM} * 60) - $i->{SS}) * 1000); 19662# $i->{LF} = ($i->{MS} / 1000) * ($i->{FRAMES} / $i->{SECS}); 19663# int($i->{MS} / 100 * 75); # is this right? 19664 $i->{TIME} = sprintf "%.2d:%.2d", @{$i}{'MM', 'SS'}; 19665 19666 $i->{BITRATE} = int $h->{bitrate}; 19667 # should we just return if ! FRAMES? 19668 $i->{FRAME_LENGTH} = int($h->{size} / $i->{FRAMES}) if $i->{FRAMES}; 19669 $i->{FREQUENCY} = $frequency_tbl[3 * $h->{IDR} + $h->{sampling_freq}]; 19670 19671 return $i; 19672} 19673 19674sub _get_head { 19675 my($byte) = @_; 19676 my($bytes, $h); 19677 19678 $bytes = _unpack_head($byte); 19679 @$h{qw(IDR ID layer protection_bit 19680 bitrate_index sampling_freq padding_bit private_bit 19681 mode mode_extension copyright original 19682 emphasis version_index bytes)} = ( 19683 ($bytes>>19)&3, ($bytes>>19)&1, ($bytes>>17)&3, ($bytes>>16)&1, 19684 ($bytes>>12)&15, ($bytes>>10)&3, ($bytes>>9)&1, ($bytes>>8)&1, 19685 ($bytes>>6)&3, ($bytes>>4)&3, ($bytes>>3)&1, ($bytes>>2)&1, 19686 $bytes&3, ($bytes>>19)&3, $bytes 19687 ); 19688 19689 $h->{bitrate} = $t_bitrate[$h->{ID}][3 - $h->{layer}][$h->{bitrate_index}]; 19690 $h->{fs} = $t_sampling_freq[$h->{IDR}][$h->{sampling_freq}]; 19691 19692 return $h; 19693} 19694 19695sub _is_mp3 { 19696 my $h = $_[0] or return undef; 19697 return ! ( # all below must be false 19698 $h->{bitrate_index} == 0 19699 || 19700 $h->{version_index} == 1 19701 || 19702 ($h->{bytes} & 0xFFE00000) != 0xFFE00000 19703 || 19704 !$h->{fs} 19705 || 19706 !$h->{bitrate} 19707 || 19708 $h->{bitrate_index} == 15 19709 || 19710 !$h->{layer} 19711 || 19712 $h->{sampling_freq} == 3 19713 || 19714 $h->{emphasis} == 2 19715 || 19716 !$h->{bitrate_index} 19717 || 19718 ($h->{bytes} & 0xFFFF0000) == 0xFFFE0000 19719 || 19720 ($h->{ID} == 1 && $h->{layer} == 3 && $h->{protection_bit} == 1) 19721 # mode extension should only be applicable when mode = 1 19722 # however, failing just becuase mode extension is used when unneeded is a bit strict 19723 # || 19724 #($h->{mode_extension} != 0 && $h->{mode} != 1) 19725 ); 19726} 19727 19728sub _vbr_seek { 19729 my $fh = shift; 19730 my $off = shift; 19731 my $bytes = shift; 19732 my $n = shift || 4; 19733 19734 seek $fh, $$off, 0; 19735 read $fh, $$bytes, $n; 19736 19737 $$off += $n; 19738} 19739 19740sub _get_vbr { 19741 my($fh, $h, $roff) = @_; 19742 my($off, $bytes, @bytes, %vbr); 19743 19744 $off = $$roff; 19745 19746 $off += 4; 19747 19748 if ($h->{ID}) { # MPEG1 19749 $off += $h->{mode} == 3 ? 17 : 32; 19750 } else { # MPEG2 19751 $off += $h->{mode} == 3 ? 9 : 17; 19752 } 19753 19754 _vbr_seek($fh, \$off, \$bytes); 19755 return unless $bytes eq 'Xing'; 19756 19757 _vbr_seek($fh, \$off, \$bytes); 19758 $vbr{flags} = _unpack_head($bytes); 19759 19760 if ($vbr{flags} & 1) { 19761 _vbr_seek($fh, \$off, \$bytes); 19762 $vbr{frames} = _unpack_head($bytes); 19763 } 19764 19765 if ($vbr{flags} & 2) { 19766 _vbr_seek($fh, \$off, \$bytes); 19767 $vbr{bytes} = _unpack_head($bytes); 19768 } 19769 19770 if ($vbr{flags} & 4) { 19771 _vbr_seek($fh, \$off, \$bytes, 100); 19772# Not used right now ... 19773# $vbr{toc} = _unpack_head($bytes); 19774 } 19775 19776 if ($vbr{flags} & 8) { # (quality ind., 0=best 100=worst) 19777 _vbr_seek($fh, \$off, \$bytes); 19778 $vbr{scale} = _unpack_head($bytes); 19779 } else { 19780 $vbr{scale} = -1; 19781 } 19782 19783 $$roff = $off; 19784 return \%vbr; 19785} 19786 19787sub _get_v2head { 19788 my $fh = $_[0] or return; 19789 my($v2h, $bytes, @bytes); 19790 $v2h->{offset} = 0; 19791 19792 # check first three bytes for 'ID3' 19793 seek $fh, 0, 0; 19794 read $fh, $bytes, 3; 19795 19796 # TODO: add support for tags at the end of the file 19797 if ($bytes eq 'RIF' || $bytes eq 'FOR') { 19798 _find_id3_chunk($fh, $bytes) or return; 19799 $v2h->{offset} = tell $fh; 19800 read $fh, $bytes, 3; 19801 } 19802 19803 return unless $bytes eq 'ID3'; 19804 19805 # get version 19806 read $fh, $bytes, 2; 19807 $v2h->{version} = sprintf "ID3v2.%d.%d", 19808 @$v2h{qw[major_version minor_version]} = 19809 unpack 'c2', $bytes; 19810 19811 # get flags 19812 read $fh, $bytes, 1; 19813 my @bits = split //, unpack 'b8', $bytes; 19814 if ($v2h->{major_version} == 2) { 19815 $v2h->{unsync} = $bits[7]; 19816 $v2h->{compression} = $bits[8]; 19817 $v2h->{ext_header} = 0; 19818 $v2h->{experimental} = 0; 19819 } else { 19820 $v2h->{unsync} = $bits[7]; 19821 $v2h->{ext_header} = $bits[6]; 19822 $v2h->{experimental} = $bits[5]; 19823 $v2h->{footer} = $bits[4] if $v2h->{major_version} == 4; 19824 } 19825 19826 # get ID3v2 tag length from bytes 7-10 19827 $v2h->{tag_size} = 10; # include ID3v2 header size 19828 $v2h->{tag_size} += 10 if $v2h->{footer}; 19829 read $fh, $bytes, 4; 19830 @bytes = reverse unpack 'C4', $bytes; 19831 foreach my $i (0 .. 3) { 19832 # whoaaaaaa nellllllyyyyyy! 19833 $v2h->{tag_size} += $bytes[$i] * 128 ** $i; 19834 } 19835 19836 # get extended header size 19837 $v2h->{ext_header_size} = 0; 19838 if ($v2h->{ext_header}) { 19839 read $fh, $bytes, 4; 19840 @bytes = reverse unpack 'C4', $bytes; 19841 19842 # use syncsafe bytes if using version 2.4 19843 my $bytesize = ($v2h->{major_version} > 3) ? 128 : 256; 19844 for my $i (0..3) { 19845 $v2h->{ext_header_size} += $bytes[$i] * $bytesize ** $i; 19846 } 19847 } 19848 19849 return $v2h; 19850} 19851 19852sub _find_id3_chunk { 19853 my($fh, $filetype) = @_; 19854 my($bytes, $size, $tag, $pat, $mat); 19855 19856 read $fh, $bytes, 1; 19857 if ($filetype eq 'RIF') { # WAV 19858 return 0 if $bytes ne 'F'; 19859 $pat = 'a4V'; 19860 $mat = 'id3 '; 19861 } elsif ($filetype eq 'FOR') { # AIFF 19862 return 0 if $bytes ne 'M'; 19863 $pat = 'a4N'; 19864 $mat = 'ID3 '; 19865 } 19866 seek $fh, 12, 0; # skip to the first chunk 19867 19868 while ((read $fh, $bytes, 8) == 8) { 19869 ($tag, $size) = unpack $pat, $bytes; 19870 return 1 if $tag eq $mat; 19871 seek $fh, $size, 1; 19872 } 19873 19874 return 0; 19875} 19876 19877sub _unpack_head { 19878 unpack('l', pack('L', unpack('N', $_[0]))); 19879} 19880 19881sub _grab_int_16 { 19882 my $data = shift; 19883 my $value = unpack('s',substr($$data,0,2)); 19884 $$data = substr($$data,2); 19885 return $value; 19886} 19887 19888sub _grab_uint_16 { 19889 my $data = shift; 19890 my $value = unpack('S',substr($$data,0,2)); 19891 $$data = substr($$data,2); 19892 return $value; 19893} 19894 19895sub _grab_int_32 { 19896 my $data = shift; 19897 my $value = unpack('V',substr($$data,0,4)); 19898 $$data = substr($$data,4); 19899 return $value; 19900} 19901 19902sub _parse_ape_tag { 19903 my ($fh, $filesize, $info) = @_; 19904 19905 my $ape_tag_id = 'APETAGEX'; 19906 19907 seek $fh, -256, 2; 19908 read($fh, my $tag, 256); 19909 my $pre_tag = substr($tag, 0, 128, ''); 19910 19911 # Try and bail early if there's no ape tag. 19912 if (substr($pre_tag, 96, 8) ne $ape_tag_id && substr($tag, 96, 8) ne $ape_tag_id) { 19913 19914 seek($fh, 0, 0); 19915 return 0; 19916 } 19917 19918 my $id3v1_tag_size = 128; 19919 my $ape_tag_header_size = 32; 19920 my $lyrics3_tag_size = 10; 19921 my $tag_offset_start = 0; 19922 my $tag_offset_end = 0; 19923 19924 seek($fh, (0 - $id3v1_tag_size - $ape_tag_header_size - $lyrics3_tag_size), 2); 19925 19926 read($fh, my $ape_footer_id3v1, $id3v1_tag_size + $ape_tag_header_size + $lyrics3_tag_size); 19927 19928 if (substr($ape_footer_id3v1, (length($ape_footer_id3v1) - $id3v1_tag_size - $ape_tag_header_size), 8) eq $ape_tag_id) { 19929 19930 $tag_offset_end = $filesize - $id3v1_tag_size; 19931 19932 } elsif (substr($ape_footer_id3v1, (length($ape_footer_id3v1) - $ape_tag_header_size), 8) eq $ape_tag_id) { 19933 19934 $tag_offset_end = $filesize; 19935 } 19936 19937 seek($fh, $tag_offset_end - $ape_tag_header_size, 0); 19938 19939 read($fh, my $ape_footer_data, 32); 19940 19941 my $ape_footer = _parse_ape_header_or_footer($ape_footer_data); 19942 19943 if (keys %{$ape_footer}) { 19944 19945 my $ape_tag_data = ''; 19946 19947 if ($ape_footer->{'flags'}->{'header'}) { 19948 19949 seek($fh, ($tag_offset_end - $ape_footer->{'tag_size'} - $ape_tag_header_size), 0); 19950 19951 $tag_offset_start = tell($fh); 19952 19953 read($fh, $ape_tag_data, $ape_footer->{'tag_size'} + $ape_tag_header_size); 19954 19955 } else { 19956 19957 $tag_offset_start = $tag_offset_end - $ape_footer->{'tag_size'}; 19958 19959 seek($fh, $tag_offset_start, 0); 19960 19961 read($fh, $ape_tag_data, $ape_footer->{'tag_size'}); 19962 } 19963 19964 my $ape_header_data = substr($ape_tag_data, 0, $ape_tag_header_size, ''); 19965 my $ape_header = _parse_ape_header_or_footer($ape_header_data); 19966 19967 for (my $c = 0; $c < $ape_header->{'tag_items'}; $c++) { 19968 19969 # Loop through the tag items 19970 my $tag_len = _grab_int_32(\$ape_tag_data); 19971 my $tag_flags = _grab_int_32(\$ape_tag_data); 19972 19973 $ape_tag_data =~ s/^(.*?)\0//; 19974 19975 my $tag_item_key = uc($1 || 'UNKNOWN'); 19976 19977 $info->{$tag_item_key} = substr($ape_tag_data, 0, $tag_len, ''); 19978 } 19979 } 19980 19981 seek($fh, 0, 0); 19982 19983 return 1; 19984} 19985 19986sub _parse_ape_header_or_footer { 19987 my $bytes = shift; 19988 my %data = (); 19989 19990 if (substr($bytes, 0, 8, '') eq 'APETAGEX') { 19991 19992 $data{'version'} = _grab_int_32(\$bytes); 19993 $data{'tag_size'} = _grab_int_32(\$bytes); 19994 $data{'tag_items'} = _grab_int_32(\$bytes); 19995 $data{'global_flags'} = _grab_int_32(\$bytes); 19996 19997 # trim the reseved bytes 19998 _grab_int_32(\$bytes); 19999 _grab_int_32(\$bytes); 20000 20001 $data{'flags'}->{'header'} = ($data{'global_flags'} & 0x80000000) ? 1 : 0; 20002 $data{'flags'}->{'footer'} = ($data{'global_flags'} & 0x40000000) ? 1 : 0; 20003 $data{'flags'}->{'is_header'} = ($data{'global_flags'} & 0x20000000) ? 1 : 0; 20004 } 20005 20006 return \%data; 20007} 20008 20009sub _close { 20010 my($file, $fh) = @_; 20011 unless (ref $file) { # filehandle not passed 20012 close $fh or carp "Problem closing '$file': $!"; 20013 } 20014} 20015 20016BEGIN { 20017 @mp3_genres = ( 20018 'Blues', 20019 'Classic Rock', 20020 'Country', 20021 'Dance', 20022 'Disco', 20023 'Funk', 20024 'Grunge', 20025 'Hip-Hop', 20026 'Jazz', 20027 'Metal', 20028 'New Age', 20029 'Oldies', 20030 'Other', 20031 'Pop', 20032 'R&B', 20033 'Rap', 20034 'Reggae', 20035 'Rock', 20036 'Techno', 20037 'Industrial', 20038 'Alternative', 20039 'Ska', 20040 'Death Metal', 20041 'Pranks', 20042 'Soundtrack', 20043 'Euro-Techno', 20044 'Ambient', 20045 'Trip-Hop', 20046 'Vocal', 20047 'Jazz+Funk', 20048 'Fusion', 20049 'Trance', 20050 'Classical', 20051 'Instrumental', 20052 'Acid', 20053 'House', 20054 'Game', 20055 'Sound Clip', 20056 'Gospel', 20057 'Noise', 20058 'AlternRock', 20059 'Bass', 20060 'Soul', 20061 'Punk', 20062 'Space', 20063 'Meditative', 20064 'Instrumental Pop', 20065 'Instrumental Rock', 20066 'Ethnic', 20067 'Gothic', 20068 'Darkwave', 20069 'Techno-Industrial', 20070 'Electronic', 20071 'Pop-Folk', 20072 'Eurodance', 20073 'Dream', 20074 'Southern Rock', 20075 'Comedy', 20076 'Cult', 20077 'Gangsta', 20078 'Top 40', 20079 'Christian Rap', 20080 'Pop/Funk', 20081 'Jungle', 20082 'Native American', 20083 'Cabaret', 20084 'New Wave', 20085 'Psychadelic', 20086 'Rave', 20087 'Showtunes', 20088 'Trailer', 20089 'Lo-Fi', 20090 'Tribal', 20091 'Acid Punk', 20092 'Acid Jazz', 20093 'Polka', 20094 'Retro', 20095 'Musical', 20096 'Rock & Roll', 20097 'Hard Rock', 20098 ); 20099 20100 @winamp_genres = ( 20101 @mp3_genres, 20102 'Folk', 20103 'Folk-Rock', 20104 'National Folk', 20105 'Swing', 20106 'Fast Fusion', 20107 'Bebop', 20108 'Latin', 20109 'Revival', 20110 'Celtic', 20111 'Bluegrass', 20112 'Avantgarde', 20113 'Gothic Rock', 20114 'Progressive Rock', 20115 'Psychedelic Rock', 20116 'Symphonic Rock', 20117 'Slow Rock', 20118 'Big Band', 20119 'Chorus', 20120 'Easy Listening', 20121 'Acoustic', 20122 'Humour', 20123 'Speech', 20124 'Chanson', 20125 'Opera', 20126 'Chamber Music', 20127 'Sonata', 20128 'Symphony', 20129 'Booty Bass', 20130 'Primus', 20131 'Porn Groove', 20132 'Satire', 20133 'Slow Jam', 20134 'Club', 20135 'Tango', 20136 'Samba', 20137 'Folklore', 20138 'Ballad', 20139 'Power Ballad', 20140 'Rhythmic Soul', 20141 'Freestyle', 20142 'Duet', 20143 'Punk Rock', 20144 'Drum Solo', 20145 'Acapella', 20146 'Euro-House', 20147 'Dance Hall', 20148 'Goa', 20149 'Drum & Bass', 20150 'Club-House', 20151 'Hardcore', 20152 'Terror', 20153 'Indie', 20154 'BritPop', 20155 'Negerpunk', 20156 'Polsk Punk', 20157 'Beat', 20158 'Christian Gangsta Rap', 20159 'Heavy Metal', 20160 'Black Metal', 20161 'Crossover', 20162 'Contemporary Christian', 20163 'Christian Rock', 20164 'Merengue', 20165 'Salsa', 20166 'Thrash Metal', 20167 'Anime', 20168 'JPop', 20169 'Synthpop', 20170 ); 20171 20172 @t_bitrate = ([ 20173 [0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256], 20174 [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160], 20175 [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160] 20176 ],[ 20177 [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448], 20178 [0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384], 20179 [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320] 20180 ]); 20181 20182 @t_sampling_freq = ( 20183 [11025, 12000, 8000], 20184 [undef, undef, undef], # reserved 20185 [22050, 24000, 16000], 20186 [44100, 48000, 32000] 20187 ); 20188 20189 @frequency_tbl = map { $_ ? eval "${_}e-3" : 0 } 20190 map { @$_ } @t_sampling_freq; 20191 20192 @mp3_info_fields = qw( 20193 VERSION 20194 LAYER 20195 STEREO 20196 VBR 20197 BITRATE 20198 FREQUENCY 20199 SIZE 20200 OFFSET 20201 SECS 20202 MM 20203 SS 20204 MS 20205 TIME 20206 COPYRIGHT 20207 PADDING 20208 MODE 20209 FRAMES 20210 FRAME_LENGTH 20211 VBR_SCALE 20212 ); 20213 20214 %rva2_channel_types = ( 20215 0x00 => 'OTHER', 20216 0x01 => 'MASTER', 20217 0x02 => 'FRONT_RIGHT', 20218 0x03 => 'FRONT_LEFT', 20219 0x04 => 'BACK_RIGHT', 20220 0x05 => 'BACK_LEFT', 20221 0x06 => 'FRONT_CENTER', 20222 0x07 => 'BACK_CENTER', 20223 0x08 => 'SUBWOOFER', 20224 ); 20225 20226 %v1_tag_fields = 20227 (TITLE => 30, ARTIST => 30, ALBUM => 30, COMMENT => 30, YEAR => 4); 20228 20229 @v1_tag_names = qw(TITLE ARTIST ALBUM YEAR COMMENT TRACKNUM GENRE); 20230 20231 %v2_to_v1_names = ( 20232 # v2.2 tags 20233 'TT2' => 'TITLE', 20234 'TP1' => 'ARTIST', 20235 'TAL' => 'ALBUM', 20236 'TYE' => 'YEAR', 20237 'COM' => 'COMMENT', 20238 'TRK' => 'TRACKNUM', 20239 'TCO' => 'GENRE', # not clean mapping, but ... 20240 # v2.3 tags 20241 'TIT2' => 'TITLE', 20242 'TPE1' => 'ARTIST', 20243 'TALB' => 'ALBUM', 20244 'TYER' => 'YEAR', 20245 'COMM' => 'COMMENT', 20246 'TRCK' => 'TRACKNUM', 20247 'TCON' => 'GENRE', 20248 # v2.3 tags - needed for MusicBrainz 20249 'UFID' => 'Unique file identifier', 20250 'TXXX' => 'User defined text information frame', 20251 ); 20252 20253 %v2_tag_names = ( 20254 # v2.2 tags 20255 'BUF' => 'Recommended buffer size', 20256 'CNT' => 'Play counter', 20257 'COM' => 'Comments', 20258 'CRA' => 'Audio encryption', 20259 'CRM' => 'Encrypted meta frame', 20260 'ETC' => 'Event timing codes', 20261 'EQU' => 'Equalization', 20262 'GEO' => 'General encapsulated object', 20263 'IPL' => 'Involved people list', 20264 'LNK' => 'Linked information', 20265 'MCI' => 'Music CD Identifier', 20266 'MLL' => 'MPEG location lookup table', 20267 'PIC' => 'Attached picture', 20268 'POP' => 'Popularimeter', 20269 'REV' => 'Reverb', 20270 'RVA' => 'Relative volume adjustment', 20271 'SLT' => 'Synchronized lyric/text', 20272 'STC' => 'Synced tempo codes', 20273 'TAL' => 'Album/Movie/Show title', 20274 'TBP' => 'BPM (Beats Per Minute)', 20275 'TCM' => 'Composer', 20276 'TCO' => 'Content type', 20277 'TCR' => 'Copyright message', 20278 'TDA' => 'Date', 20279 'TDY' => 'Playlist delay', 20280 'TEN' => 'Encoded by', 20281 'TFT' => 'File type', 20282 'TIM' => 'Time', 20283 'TKE' => 'Initial key', 20284 'TLA' => 'Language(s)', 20285 'TLE' => 'Length', 20286 'TMT' => 'Media type', 20287 'TOA' => 'Original artist(s)/performer(s)', 20288 'TOF' => 'Original filename', 20289 'TOL' => 'Original Lyricist(s)/text writer(s)', 20290 'TOR' => 'Original release year', 20291 'TOT' => 'Original album/Movie/Show title', 20292 'TP1' => 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group', 20293 'TP2' => 'Band/Orchestra/Accompaniment', 20294 'TP3' => 'Conductor/Performer refinement', 20295 'TP4' => 'Interpreted, remixed, or otherwise modified by', 20296 'TPA' => 'Part of a set', 20297 'TPB' => 'Publisher', 20298 'TRC' => 'ISRC (International Standard Recording Code)', 20299 'TRD' => 'Recording dates', 20300 'TRK' => 'Track number/Position in set', 20301 'TSI' => 'Size', 20302 'TSS' => 'Software/hardware and settings used for encoding', 20303 'TT1' => 'Content group description', 20304 'TT2' => 'Title/Songname/Content description', 20305 'TT3' => 'Subtitle/Description refinement', 20306 'TXT' => 'Lyricist/text writer', 20307 'TXX' => 'User defined text information frame', 20308 'TYE' => 'Year', 20309 'UFI' => 'Unique file identifier', 20310 'ULT' => 'Unsychronized lyric/text transcription', 20311 'WAF' => 'Official audio file webpage', 20312 'WAR' => 'Official artist/performer webpage', 20313 'WAS' => 'Official audio source webpage', 20314 'WCM' => 'Commercial information', 20315 'WCP' => 'Copyright/Legal information', 20316 'WPB' => 'Publishers official webpage', 20317 'WXX' => 'User defined URL link frame', 20318 20319 # v2.3 tags 20320 'AENC' => 'Audio encryption', 20321 'APIC' => 'Attached picture', 20322 'COMM' => 'Comments', 20323 'COMR' => 'Commercial frame', 20324 'ENCR' => 'Encryption method registration', 20325 'EQUA' => 'Equalization', 20326 'ETCO' => 'Event timing codes', 20327 'GEOB' => 'General encapsulated object', 20328 'GRID' => 'Group identification registration', 20329 'IPLS' => 'Involved people list', 20330 'LINK' => 'Linked information', 20331 'MCDI' => 'Music CD identifier', 20332 'MLLT' => 'MPEG location lookup table', 20333 'OWNE' => 'Ownership frame', 20334 'PCNT' => 'Play counter', 20335 'POPM' => 'Popularimeter', 20336 'POSS' => 'Position synchronisation frame', 20337 'PRIV' => 'Private frame', 20338 'RBUF' => 'Recommended buffer size', 20339 'RVAD' => 'Relative volume adjustment', 20340 'RVRB' => 'Reverb', 20341 'SYLT' => 'Synchronized lyric/text', 20342 'SYTC' => 'Synchronized tempo codes', 20343 'TALB' => 'Album/Movie/Show title', 20344 'TBPM' => 'BPM (beats per minute)', 20345 'TCOM' => 'Composer', 20346 'TCON' => 'Content type', 20347 'TCOP' => 'Copyright message', 20348 'TDAT' => 'Date', 20349 'TDLY' => 'Playlist delay', 20350 'TENC' => 'Encoded by', 20351 'TEXT' => 'Lyricist/Text writer', 20352 'TFLT' => 'File type', 20353 'TIME' => 'Time', 20354 'TIT1' => 'Content group description', 20355 'TIT2' => 'Title/songname/content description', 20356 'TIT3' => 'Subtitle/Description refinement', 20357 'TKEY' => 'Initial key', 20358 'TLAN' => 'Language(s)', 20359 'TLEN' => 'Length', 20360 'TMED' => 'Media type', 20361 'TOAL' => 'Original album/movie/show title', 20362 'TOFN' => 'Original filename', 20363 'TOLY' => 'Original lyricist(s)/text writer(s)', 20364 'TOPE' => 'Original artist(s)/performer(s)', 20365 'TORY' => 'Original release year', 20366 'TOWN' => 'File owner/licensee', 20367 'TPE1' => 'Lead performer(s)/Soloist(s)', 20368 'TPE2' => 'Band/orchestra/accompaniment', 20369 'TPE3' => 'Conductor/performer refinement', 20370 'TPE4' => 'Interpreted, remixed, or otherwise modified by', 20371 'TPOS' => 'Part of a set', 20372 'TPUB' => 'Publisher', 20373 'TRCK' => 'Track number/Position in set', 20374 'TRDA' => 'Recording dates', 20375 'TRSN' => 'Internet radio station name', 20376 'TRSO' => 'Internet radio station owner', 20377 'TSIZ' => 'Size', 20378 'TSRC' => 'ISRC (international standard recording code)', 20379 'TSSE' => 'Software/Hardware and settings used for encoding', 20380 'TXXX' => 'User defined text information frame', 20381 'TYER' => 'Year', 20382 'UFID' => 'Unique file identifier', 20383 'USER' => 'Terms of use', 20384 'USLT' => 'Unsychronized lyric/text transcription', 20385 'WCOM' => 'Commercial information', 20386 'WCOP' => 'Copyright/Legal information', 20387 'WOAF' => 'Official audio file webpage', 20388 'WOAR' => 'Official artist/performer webpage', 20389 'WOAS' => 'Official audio source webpage', 20390 'WORS' => 'Official internet radio station homepage', 20391 'WPAY' => 'Payment', 20392 'WPUB' => 'Publishers official webpage', 20393 'WXXX' => 'User defined URL link frame', 20394 20395 # v2.4 additional tags 20396 # note that we don't restrict tags from 2.3 or 2.4, 20397 'ASPI' => 'Audio seek point index', 20398 'EQU2' => 'Equalisation (2)', 20399 'RVA2' => 'Relative volume adjustment (2)', 20400 'SEEK' => 'Seek frame', 20401 'SIGN' => 'Signature frame', 20402 'TDEN' => 'Encoding time', 20403 'TDOR' => 'Original release time', 20404 'TDRC' => 'Recording time', 20405 'TDRL' => 'Release time', 20406 'TDTG' => 'Tagging time', 20407 'TIPL' => 'Involved people list', 20408 'TMCL' => 'Musician credits list', 20409 'TMOO' => 'Mood', 20410 'TPRO' => 'Produced notice', 20411 'TSOA' => 'Album sort order', 20412 'TSOP' => 'Performer sort order', 20413 'TSOT' => 'Title sort order', 20414 'TSST' => 'Set subtitle', 20415 20416 # grrrrrrr 20417 'COM ' => 'Broken iTunes comments', 20418 ); 20419} 20420 20421=pod 20422 20423=back 20424 20425=head1 TROUBLESHOOTING 20426 20427If you find a bug, please send me a patch (see the project page in L<"SEE ALSO">). 20428If you cannot figure out why it does not work for you, please put the MP3 file in 20429a place where I can get it (preferably via FTP, or HTTP, or .Mac iDisk) and send me 20430mail regarding where I can get the file, with a detailed description of the problem. 20431 20432If I download the file, after debugging the problem I will not keep the MP3 file 20433if it is not legal for me to have it. Just let me know if it is legal for me to 20434keep it or not. 20435 20436 20437=head1 TODO 20438 20439=over 4 20440 20441=item ID3v2 Support 20442 20443Still need to do more for reading tags, such as using Compress::Zlib to decompress 20444compressed tags. But until I see this in use more, I won't bother. If something 20445does not work properly with reading, follow the instructions above for 20446troubleshooting. 20447 20448ID3v2 I<writing> is coming soon. 20449 20450=item Get data from scalar 20451 20452Instead of passing a file spec or filehandle, pass the 20453data itself. Would take some work, converting the seeks, etc. 20454 20455=item Padding bit ? 20456 20457Do something with padding bit. 20458 20459=item Test suite 20460 20461Test suite could use a bit of an overhaul and update. Patches very welcome. 20462 20463=over 4 20464 20465=item * 20466 20467Revamp getset.t. Test all the various get_mp3tag args. 20468 20469=item * 20470 20471Test Unicode. 20472 20473=item * 20474 20475Test OOP API. 20476 20477=item * 20478 20479Test error handling, check more for missing files, bad MP3s, etc. 20480 20481=back 20482 20483=item Other VBR 20484 20485Right now, only Xing VBR is supported. 20486 20487=back 20488 20489 20490=head1 THANKS 20491 20492Edward Allen, 20493Vittorio Bertola, 20494Michael Blakeley, 20495Per Bolmstedt, 20496Tony Bowden, 20497Tom Brown, 20498Sergio Camarena, 20499Chris Dawson, 20500Anthony DiSante, 20501Luke Drumm, 20502Kyle Farrell, 20503Jeffrey Friedl, 20504brian d foy, 20505Ben Gertzfield, 20506Brian Goodwin, 20507Todd Hanneken, 20508Todd Harris, 20509Woodrow Hill, 20510Kee Hinckley, 20511Roman Hodek, 20512Ilya Konstantinov, 20513Peter Kovacs, 20514Johann Lindvall, 20515Alex Marandon, 20516Peter Marschall, 20517michael, 20518Trond Michelsen, 20519Dave O'Neill, 20520Christoph Oberauer, 20521Jake Palmer, 20522Andrew Phillips, 20523David Reuteler, 20524John Ruttenberg, 20525Matthew Sachs, 20526scfc_de, 20527Hermann Schwaerzler, 20528Chris Sidi, 20529Roland Steinbach, 20530Brian S. Stephan, 20531Stuart, 20532Dan Sully, 20533Jeffery Sumler, 20534Predrag Supurovic, 20535Bogdan Surdu, 20536Pierre-Yves Thoulon, 20537tim, 20538Pass F. B. Travis, 20539Tobias Wagener, 20540Ronan Waide, 20541Andy Waite, 20542Ken Williams, 20543Ben Winslow, 20544Meng Weng Wong. 20545 20546 20547=head1 CURRENT AUTHOR 20548 20549Dan Sully E<lt>dan | at | slimdevices.comE<gt> & Slim Devices, Inc. 20550 20551=head1 AUTHOR EMERITUS 20552 20553Chris Nandor E<lt>pudge@pobox.comE<gt>, http://pudge.net/ 20554 20555=head1 COPYRIGHT AND LICENSE 20556 20557Copyright (c) 2006 Dan Sully & Slim Devices, Inc. All rights reserved. 20558 20559Copyright (c) 1998-2005 Chris Nandor. All rights reserved. 20560 20561This program is free software; you can redistribute it and/or modify it under 20562the same terms as Perl itself. 20563 20564=head1 SEE ALSO 20565 20566=over 4 20567 20568=item Slim Devices 20569 20570 http://www.slimdevices.com/ 20571 20572=item mp3tools 20573 20574 http://www.zevils.com/linux/mp3tools/ 20575 20576=item mpgtools 20577 20578 http://www.dv.co.yu/mpgscript/mpgtools.htm 20579 http://www.dv.co.yu/mpgscript/mpeghdr.htm 20580 20581=item mp3tool 20582 20583 http://www.dtek.chalmers.se/~d2linjo/mp3/mp3tool.html 20584 20585=item ID3v2 20586 20587 http://www.id3.org/ 20588 20589=item Xing Variable Bitrate 20590 20591 http://www.xingtech.com/support/partner_developer/mp3/vbr_sdk/ 20592 20593=item MP3Ext 20594 20595 http://rupert.informatik.uni-stuttgart.de/~mutschml/MP3ext/ 20596 20597=item Xmms 20598 20599 http://www.xmms.org/ 20600 20601 20602=back 20603 20604=cut 20605 20606 20607 20608 206091; 20610} # end scope block 20611 20612########################-----CDDB_get-----######################## 20613 20614{ # start scope block 20615# (c) 2004 Armin Obersteiner <armin@xos.net> 20616package CDDB_get::Internal; 20617 20618use Config; 20619 20620use strict; 20621use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $debug); 20622 20623require Exporter; 20624 20625@ISA = qw(Exporter AutoLoader); 20626# Items to export into callers namespace by default. Note: do not export 20627# names by default without a very good reason. Use EXPORT_OK instead. 20628# Do not simply export all your public functions/methods/constants. 20629@EXPORT_OK = qw( 20630 get_cddb 20631 get_discids 20632); 20633$VERSION = '2.27'; 20634 20635use Fcntl; 20636use IO::Socket; 20637use Data::Dumper qw(Dumper); 20638 20639#$debug=1; 20640 20641# setup for linux, solaris x86, solaris spark 20642# you freebsd guys give me input 20643 20644# listed variables to be "local" to the enclosing block. See 'man perlsub'. 20645my ( $os, $machine, $CDROMREADTOCHDR, $CDROMREADTOCENTRY, $CDROM_MSF ); 20646my ( $CDDB_HOST, $CDDB_PORT, $CDDB_MODE, $CD_DEVICE ); 20647my ( $HELLO_ID, $PROTO_VERSION, $BIG_ENDIAN, $BITS_64 ); 20648 20649sub set_standard_values { 20650 20651 print STDERR "cddb: checking for os ... " if $debug; 20652 20653 $os=`uname -s`; 20654 $machine=`uname -m`; 20655 chomp $os; 20656 chomp $machine; 20657 20658 print STDERR "$os ($machine) " if $debug; 20659 20660 # cdrom IOCTL magic (from c headers) 20661 # linux x86 is default 20662 20663 # /usr/include/linux/cdrom.h 20664 $CDROMREADTOCHDR=0x5305; 20665 $CDROMREADTOCENTRY=0x5306; 20666 $CDROM_MSF=0x02; 20667 20668 # default config 20669 20670 $CDDB_HOST = "freedb.freedb.org"; 20671 $CDDB_PORT = 8880; 20672 $CDDB_MODE = "cddb"; 20673 $CD_DEVICE = "/dev/cdrom"; 20674 20675 $HELLO_ID = "root nowhere.com fastrip 0.77"; 20676 $PROTO_VERSION = 5; 20677 20678 # endian check 20679 20680 $BIG_ENDIAN = unpack("h*", pack("s", 1)) =~ /01/; 20681 20682 if($BIG_ENDIAN) { 20683 print STDERR "[big endian] " if $debug; 20684 } else { 20685 print STDERR "[little endian] " if $debug; 20686 } 20687 20688 # 64bit pointer check 20689 20690 $BITS_64 = $Config{ptrsize} == 8 ? 1 : 0; 20691 20692 if($BITS_64) { 20693 print STDERR "[64 bit]\n" if $debug; 20694 } else { 20695 print STDERR "[32 bit]\n" if $debug; 20696 } 20697 20698 if($os eq "SunOS") { 20699 # /usr/include/sys/cdio.h 20700 $CDROMREADTOCHDR=0x49b; # 1179 20701 $CDROMREADTOCENTRY=0x49c; # 1180 20702 20703 if(-e "/vol/dev/aliases/cdrom0") { 20704 $CD_DEVICE="/vol/dev/aliases/cdrom0"; 20705 } else { 20706 if($machine =~ /^sun/) { 20707 # on sparc and old suns 20708 $CD_DEVICE="/dev/rdsk/c0t6d0s0"; 20709 } else { 20710 # on intel 20711 $CD_DEVICE="/dev/rdsk/c1t0d0p0"; 20712 } 20713 } 20714 } elsif($os =~ /BSD/i) { # works for netbsd, infos for other bsds welcome 20715 # /usr/include/sys/cdio.h 20716 20717 $CDROMREADTOCHDR=0x40046304; 20718 $CDROMREADTOCENTRY=0xc0086305; 20719 20720 if($BITS_64) { 20721 $CDROMREADTOCENTRY=0xc0106305; 20722 } 20723 20724 $CD_DEVICE="/dev/cd0a"; 20725 20726 if($os eq "OpenBSD") { 20727 $CD_DEVICE="/dev/cd0c"; 20728 } 20729 } 20730} 20731 20732sub read_toc { 20733 my $device=shift; 20734 my $tochdr=chr(0) x 16; 20735 20736 set_standard_values(); 20737 20738 sysopen (CD,$device, O_RDONLY | O_NONBLOCK) or die "cannot open cdrom [$!] [$device]"; 20739 #print "\n read_toc --> \$tochdr = $tochdr\n"; 20740 #print "\n read_toc --> \$device = $device\n"; 20741 #print "\n read_toc --> \$CDROMREADTOCHDR = $CDROMREADTOCHDR\n"; 20742 ioctl(CD, $CDROMREADTOCHDR, $tochdr) or die "cannot read toc [$!] [$device]"; 20743 20744 my ($start,$end); 20745 if($os =~ /BSD/) { 20746 ($start,$end)=unpack "CC",(substr $tochdr,2,2); 20747 } else { 20748 ($start,$end)=unpack "CC",$tochdr; 20749 } 20750 print STDERR "start track: $start, end track: $end\n" if $debug; 20751 20752 my @tracks=(); 20753 20754 for (my $i=$start; $i<=$end;$i++) { 20755 push @tracks,$i; 20756 } 20757 push @tracks,0xAA; 20758 20759 my @r=(); 20760 my $tocentry; 20761 my $toc=""; 20762 my $size=0; 20763 for(@tracks) { 20764 $toc.=" "; 20765 $size+=8; 20766 } 20767 20768 if($os =~ /BSD/) { 20769 my $size_hi=int($size / 256); 20770 my $size_lo=$size & 255; 20771 20772 if($BIG_ENDIAN) { 20773 if($BITS_64) { 20774 # better but just perl >= 5.8.0 20775 # $tocentry=pack "CCCCx![P]P", $CDROM_MSF,0,$size_hi,$size_lo,$toc; 20776 $tocentry=pack "CCCCxxxxP", $CDROM_MSF,0,$size_hi,$size_lo,$toc; 20777 } else { 20778 $tocentry=pack "CCCCP8l", $CDROM_MSF,0,$size_hi,$size_lo,$toc; 20779 } 20780 } else { 20781 if($BITS_64) { 20782 $tocentry=pack "CCCCxxxxP", $CDROM_MSF,0,$size_lo,$size_hi,$toc; 20783 } else { 20784 $tocentry=pack "CCCCP8l", $CDROM_MSF,0,$size_lo,$size_hi,$toc; 20785 } 20786 } 20787 ioctl(CD, $CDROMREADTOCENTRY, $tocentry) or die "cannot read track info [$!] [$device]"; 20788 } 20789 20790 my $count=0; 20791 foreach my $i (@tracks) { 20792 my ($min,$sec,$frame); 20793 unless($os =~ /BSD/) { 20794 $tocentry=pack "CCC", $i,0,$CDROM_MSF; 20795 $tocentry.=chr(0) x 16; 20796 ioctl(CD, $CDROMREADTOCENTRY, $tocentry) or die "cannot read track $i info [$!] [$device]"; 20797 ($min,$sec,$frame)=unpack "CCCC", substr($tocentry,4,4); 20798 } else { 20799 ($min,$sec,$frame)=unpack "CCC", substr($toc,$count+5,3); 20800 } 20801 $count+=8; 20802 20803 my %cdtoc=(); 20804 20805 $cdtoc{min}=$min; 20806 $cdtoc{sec}=$sec; 20807 $cdtoc{frame}=$frame; 20808 $cdtoc{frames}=int($frame+$sec*75+$min*60*75); 20809 20810 my $data = unpack("C",substr($tocentry,1,1)); 20811 $cdtoc{data} = 0; 20812 if($data & 0x40) { 20813 $cdtoc{data} = 1; 20814 } 20815 20816 push @r,\%cdtoc; 20817 } 20818 close(CD); 20819 20820 return @r; 20821} 20822 20823sub cddb_sum { 20824 my $n=shift; 20825 my $ret=0; 20826 20827 while ($n > 0) { 20828 $ret += ($n % 10); 20829 $n = int $n / 10; 20830 } 20831 return $ret; 20832} 20833 20834sub cddb_discid { 20835 my $total=shift; 20836 my $toc=shift; 20837 20838 my $i=0; 20839 my $t=0; 20840 my $n=0; 20841 20842 while ($i < $total) { 20843 $n = $n + cddb_sum(($toc->[$i]->{min} * 60) + $toc->[$i]->{sec}); 20844 $i++; 20845 } 20846 $t = (($toc->[$total]->{min} * 60) + $toc->[$total]->{sec}) - 20847 (($toc->[0]->{min} * 60) + $toc->[0]->{sec}); 20848 return (($n % 0xff) << 24 | $t << 8 | $total); 20849} 20850 20851sub get_discids { 20852 my $cd=shift; 20853 $CD_DEVICE = $cd if (defined($cd)); 20854 20855 my @toc=read_toc($CD_DEVICE); 20856 my $total=$#toc; 20857 20858 my $id=cddb_discid($total,\@toc); 20859 20860 return [$id,$total,\@toc]; 20861} 20862 20863sub get_cddb { 20864 my $config=shift; 20865 my $diskid=shift; 20866 my $id; 20867 my $toc; 20868 my $total; 20869 my @r; 20870 20871 set_standard_values(); 20872 20873 my $input = $config->{input}; 20874 my $multi = $config->{multi}; 20875 $input = 0 if $multi; 20876 20877 print STDERR Dumper($config) if $debug; 20878 20879 $CDDB_HOST = $config->{CDDB_HOST} if (defined($config->{CDDB_HOST})); 20880 $CDDB_PORT = $config->{CDDB_PORT} if (defined($config->{CDDB_PORT})); 20881 $CDDB_MODE = $config->{CDDB_MODE} if (defined($config->{CDDB_MODE})); 20882 $CD_DEVICE = $config->{CD_DEVICE} if (defined($config->{CD_DEVICE})); 20883 $HELLO_ID = $config->{HELLO_ID} if (defined($config->{HELLO_ID})); 20884 $PROTO_VERSION = $config->{PROTO_VERSION} if (defined($config->{PROTO_VERSION})); 20885 my $HTTP_PROXY = $config->{HTTP_PROXY} if (defined($config->{HTTP_PROXY})); 20886 my $FW=1 if (defined($config->{FW})); 20887 20888 if(defined($diskid)) { 20889 $id=$diskid->[0]; 20890 $total=$diskid->[1]; 20891 $toc=$diskid->[2]; 20892 } else { 20893 my $diskid=get_discids($CD_DEVICE); 20894 $id=$diskid->[0]; 20895 $total=$diskid->[1]; 20896 $toc=$diskid->[2]; 20897 } 20898 20899 my @list=(); 20900 my $return; 20901 my $socket; 20902 20903 my $id2 = sprintf "%08x", $id; 20904 my $query = "cddb query $id2 $total"; 20905 for (my $i=0; $i<$total ;$i++) { 20906 $query.=" $toc->[$i]->{frames}"; 20907 } 20908 20909 # this was to old total calculation, does not work too well, its included if new version makes problems 20910 # $query.=" ". int(($toc->[$total]->{frames}-$toc->[0]->{frames})/75); 20911 20912 $query.=" ". int(($toc->[$total]->{frames})/75); 20913 20914 print Dumper($toc) if $debug; 20915 20916 if ($CDDB_MODE eq "cddb") { 20917 print STDERR "cddb: connecting to $CDDB_HOST:$CDDB_PORT\n" if $debug; 20918 20919 $socket=IO::Socket::INET->new(PeerAddr=>$CDDB_HOST, PeerPort=>$CDDB_PORT, 20920 Proto=>"tcp",Type=>SOCK_STREAM) or die "cannot connect to cddb db: $CDDB_HOST:$CDDB_PORT [$!]"; 20921 20922 $return=<$socket>; 20923 unless ($return =~ /^2\d\d\s+/) { 20924 die "not welcome at cddb db"; 20925 } 20926 20927 print $socket "cddb hello $HELLO_ID\n"; 20928 20929 $return=<$socket>; 20930 print STDERR "hello return: $return" if $debug; 20931 unless ($return =~ /^2\d\d\s+/) { 20932 die "handshake error at cddb db: $CDDB_HOST:$CDDB_PORT"; 20933 } 20934 20935 print $socket "proto $PROTO_VERSION\n"; 20936 20937 $return=<$socket>; 20938 print STDERR "proto return: $return" if $debug; 20939 unless ($return =~ /^2\d\d\s+/) { 20940 die "protokoll mismatch error at cddb db: $CDDB_HOST:$CDDB_PORT"; 20941 } 20942 20943 print STDERR "cddb: sending: $query\n" if $debug; 20944 print $socket "$query\n"; 20945 20946 $return=<$socket>; 20947 chomp $return; 20948 20949 print STDERR "cddb: result: $return\n" if $debug; 20950 } elsif ($CDDB_MODE eq "http") { 20951 my $query2=$query; 20952 $query2 =~ s/ /+/g; 20953 my $id=$HELLO_ID; 20954 $id =~ s/ /+/g; 20955 20956 my $url = "/~cddb/cddb.cgi?cmd=$query2&hello=$id&proto=$PROTO_VERSION"; 20957 20958 my $host=$CDDB_HOST; 20959 my $port=80; 20960 20961 my ($user,$pass); 20962 20963 if($HTTP_PROXY) { 20964 if($HTTP_PROXY =~ /^(http:\/\/|)(.+?):(.+)\@(.+?):(.+)/) { 20965 $user=$2; 20966 $pass=$3; 20967 $host=$4; 20968 $port=$5; 20969 } elsif($HTTP_PROXY =~ /^(http:\/\/|)(.+?):(\d+)/) { 20970 $host=$2; 20971 $port=$3; 20972 } 20973 $url="http://$CDDB_HOST".$url." HTTP/1.0"; 20974 } 20975 20976 print STDERR "cddb: connecting to $host:$port\n" if $debug; 20977 20978 $socket=IO::Socket::INET->new(PeerAddr=>$host, PeerPort=>$port, 20979 Proto=>"tcp",Type=>SOCK_STREAM) or die "cannot connect to cddb db: $host:$port [$!]"; 20980 20981 print STDERR "cddb: http send: GET $url\n" if $debug; 20982 print $socket "GET $url\n"; 20983 20984 if($user) { 20985 my $cred = encode_base64("$user:$pass"); 20986 print $socket "Proxy-Authorization: Basic $cred\n"; 20987 } 20988 20989 print $socket "\n"; 20990 print $socket "\n" if $FW; 20991 20992 if($HTTP_PROXY) { 20993 while(<$socket> =~ /^\S+/){}; 20994 } 20995 20996 $return=<$socket>; 20997 chomp $return; 20998 20999 print STDERR "cddb: http result: $return\n" if $debug; 21000 } else { 21001 die "unkown mode: $CDDB_MODE for querying cddb"; 21002 } 21003 21004 $return =~ s/\r//g; 21005 21006 my ($err) = $return =~ /^(\d\d\d)\s+/; 21007 unless ($err =~ /^2/) { 21008 die "query error at cddb db: $CDDB_HOST:$CDDB_PORT"; 21009 } 21010 21011 if($err==202) { 21012 return undef; 21013 } elsif(($err==211) || ($err==210)) { 21014 while(<$socket>) { 21015 last if(/^\./); 21016 push @list,$_; 21017 s/\r//g; 21018 print STDERR "unexact: $_" if $debug; 21019 } 21020 } elsif($err==200) { 21021 $return =~ s/^200 //; 21022 push @list,$return; 21023 } else { 21024 die "cddb: unknown: $return"; 21025 } 21026 21027 my @to_get; 21028 21029 unless($multi) { 21030 if (@list) { 21031 my $index; 21032 if($input==1) { 21033 print "This CD could be:\n\n"; 21034 my $i=1; 21035 for(@list) { 21036 my ($tit) = $_ =~ /^\S+\s+\S+\s+(.*)/; 21037 print "$i: $tit\n"; 21038 $i++ 21039 } 21040 print "\n0: none of the above\n\nChoose: "; 21041 my $n=<STDIN>; 21042 $index=int($n); 21043 } else { 21044 $index=1; 21045 } 21046 21047 if ($index == 0) { 21048 return undef; 21049 } else { 21050 push @to_get,$list[$index-1]; 21051 } 21052 } 21053 } else { 21054 push @to_get,@list; 21055 } 21056 21057 my $i=0; 21058 for my $get (@to_get) { 21059 #200 misc 0a01e802 Meredith Brooks / Bitch Single 21060 my ($cat,$id,$at) = $get =~ /^(\S+?)\s+(\S+?)\s+(.*)/; 21061 21062 my $artist; 21063 my $title; 21064 21065 if($at =~ /\//) { 21066 ($artist,$title)= $at =~ /^(.*?)\s\/\s(.*)/; 21067 } else { 21068 $artist=$at; 21069 $title=$at; 21070 } 21071 21072 my %cd=(); 21073 $cd{artist}=$artist; 21074 chomp $title; 21075 $title =~ s/\r//g; 21076 $cd{title}=$title; 21077 $cd{cat}=$cat; 21078 $cd{id}=$id; 21079 21080 my @lines; 21081 21082 $query="cddb read $cat $id"; 21083 21084 if ($CDDB_MODE eq "cddb") { 21085 print STDERR "cddb: getting: $query\n" if $debug; 21086 print $socket "$query\n"; 21087 21088 while(<$socket>) { 21089 last if(/^\./); 21090 push @lines,$_; 21091 } 21092 if(@to_get-1 == $i) { 21093 print $socket "quit\n"; 21094 close $socket; 21095 } 21096 21097 } elsif ($CDDB_MODE eq "http") { 21098 close $socket; 21099 21100 my $query2=$query; 21101 $query2 =~ s/ /+/g; 21102 my $id=$HELLO_ID; 21103 $id =~ s/ /+/g; 21104 21105 my $url = "/~cddb/cddb.cgi?cmd=$query2&hello=$id&proto=$PROTO_VERSION"; 21106 21107 my $host=$CDDB_HOST; 21108 my $port=80; 21109 21110 my ($user,$pass); 21111 21112 if($HTTP_PROXY) { 21113 if($HTTP_PROXY =~ /^(http:\/\/|)(.+?):(.+)\@(.+?):(.+)/) { 21114 $user=$2; 21115 $pass=$3; 21116 $host=$4; 21117 $port=$5; 21118 } elsif($HTTP_PROXY =~ /^(http:\/\/|)(.+?):(\d+)/) { 21119 $host=$2; 21120 $port=$3; 21121 } 21122 $url="http://$CDDB_HOST".$url." HTTP/1.0"; 21123 } 21124 21125 print STDERR "cddb: connecting to $host:$port\n" if $debug; 21126 21127 $socket=IO::Socket::INET->new(PeerAddr=>$host, PeerPort=>$port, 21128 Proto=>"tcp",Type=>SOCK_STREAM) or die "cannot connect to cddb db: $host:$port [$!]"; 21129 21130 print STDERR "cddb: http send: GET $url\n" if $debug; 21131 print $socket "GET $url\n"; 21132 21133 if($user) { 21134 my $cred = encode_base64("$user:$pass"); 21135 print $socket "Proxy-Authorization: Basic $cred\n"; 21136 } 21137 21138 print $socket "\n"; 21139 print $socket "\n" if $FW; 21140 21141 if($HTTP_PROXY) { 21142 while(<$socket> =~ /^\S+/){}; 21143 } 21144 21145 while(<$socket>) { 21146 last if(/^\./); 21147 push @lines,$_; 21148 } 21149 close $socket; 21150 } else { 21151 die "unkown mode: $CDDB_MODE for querying cddb"; 21152 } 21153 21154 # xmcd 21155 # 21156 # Track frame offsets: 21157 # 150 21158 # ... 21159 # 210627 21160 # 21161 # Disc length: 2952 seconds 21162 # 21163 # Revision: 1 21164 # Submitted via: xmcd 2.0 21165 # 21166 21167 for(@lines) { 21168 last if(/^\./); 21169 next if(/^\d\d\d/); 21170 push @{$cd{raw}},$_; 21171 #TTITLE0=Bitch (Edit) 21172 if(/^TTITLE(\d+)\=\s*(.*)/) { 21173 my $t= $2; 21174 chop $t; 21175 $cd{frames}[$1]=$toc->[$1]->{frames}; 21176 $cd{data}[$1]=$toc->[$1]->{data}; 21177 unless (defined $cd{track}[$1]) { 21178 $cd{track}[$1]=$t; 21179 } else { 21180 $cd{track}[$1]=$cd{track}[$1].$t; 21181 } 21182 } elsif(/^DYEAR=\s*(\d+)/) { 21183 $cd{'year'} = $1; 21184 } elsif(/^DGENRE=\s*(\S+.*)/) { 21185 my $t = $1; 21186 chop $t; 21187 $cd{'genre'} = $t; 21188 } elsif(/^\#\s+Revision:\s+(\d+)/) { 21189 $cd{'revision'} = $1; 21190 } 21191 } 21192 21193 $cd{tno}=$#{$cd{track}}+1; 21194 $cd{frames}[$cd{tno}]=$toc->[$cd{tno}]->{frames}; 21195 21196 return %cd unless($multi); 21197 push @r,\%cd; 21198 $i++; 21199 } 21200 21201 return @r; 21202} 21203 21204 21205 1; # don't forget to return a true value from the file 21206} # end scope block 21207 21208