用.cue文件切割.wav文件
skrypto
|
1#
skrypto 发表于 2007-02-11 10:37
用.cue文件切割.wav文件
先发布源代码,再说明干什么用,免得烂在我的硬盘里。
[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/env perl
# This program splits a wav file that contains multiple tracks into multiple wav # files, each of which contains one track based on indices provided by a cue file. # Written by Shufeng Tan <shufengtan@gmail.com> January, 2007 # It is assumed that the cue file is in the same directory with the wav file. # The cue file with the same basename with the wav file will be picked. # Failing that, the program will pick the first cue file listed by DirHandle. use strict; use Audio::Wav; use Data::Dumper; use DirHandle; use FileHandle; use File::Basename; my $wavfile = shift; die "Usage: $0 file.wav\n" unless $wavfile; die "File $wavfile not found.\n" unless -f $wavfile; my $cuefile = find_cue_file($wavfile); warn "CUE file not found for $wavfile\n" unless $cuefile; my $WAV = new Audio::Wav; my $read = $WAV->read($wavfile); my $details = $read->details; my $Track_Details = { bits_sample => $details->{bits_sample}, sample_rate => $details->{sample_rate}, channels => $details->{channels}, }; exit unless $cuefile; my @tracks = parse_cue_file($cuefile, $read); print "$#tracks tracks from $cuefile\n"; my $Max_Buf_Len = 1048576; foreach my $i (0 .. ($#tracks-1)) { my $track_info = $tracks[$i]; my $track = $track_info->{TRACK}; my $name = $track_info->{TITLE}; my $artist = $track_info->{PERFORMER}; my $track_file = "${track}_$name.wav"; $track_file =~ tr|/:| |; my @pos = @{$track_info->{POS}}; my $track_len = $tracks[$i+1]->{POS}->[0] - $pos[0]; print "TRACK $track '$name' by '$artist' $track_len bytes POS=[@pos]\n"; my $write = $WAV->write($track_file, $Track_Details); $write->set_info('software' => 'Audio::Wav', 'artist' => $artist, 'name' => $name); $read->move_to($pos[0]); my $read_len = 0; while($read_len < $track_len) { my $remain = $track_len - $read_len; my $buf_len = $remain >= $Max_Buf_Len ? $Max_Buf_Len : $remain; my $buf = $read->read_raw($buf_len); my $buf_len2 = length($buf); $read_len += $buf_len2; $write->write_raw($buf, $buf_len2); if ($buf_len != $buf_len2) { print "Last track: $read_len out of $track_len bytes\n"; last; } } $write->finish(); } exit; sub find_cue_file { my ($file) = @_; if ($file =~ s/\.\w+$/.cue/) { return $file if -f $file; $file =~ s/\.cue$/.CUE/; return $file if -f $file; } my $dir = dirname($file); my $dh = new DirHandle $dir; if (defined $dh) { while(my $f = $dh->read) { return "$dir/$f" if $f =~ /\.cue$/i; } } } sub parse_cue_file { my ($cuefile, $wav_in) = @_; my $cueh = new FileHandle $cuefile; return unless defined $cueh; my $wav_data = $wav_in->{data}; print Data::Dumper->Dump([$wav_data]); return unless defined $wav_data; my $wav_sec = $wav_data->{length}; my $wav_offset = $wav_data->{data_start}; my $wav_bps = $wav_data->{bytes_sec}; my (@tracks, $href); while(<$cueh>) { chomp; s/\r$//; if (/^\s*TRACK\s+(\d+)/i) { push(@tracks, $href) if defined $href; $href = { TRACK => $1 }; } elsif (/^\s*INDEX\s+\d+\s+0?(\d+):0?(\d+):0?(\d+)/i) { my $pos = $wav_offset + ($1*60 + $2) * $wav_bps + $3*$wav_bps/75; $href->{POS} = exists($href->{POS}) ? [@{$href->{POS}}, $pos] : [$pos]; } elsif (/^\s*(\w+)\s*(\S.*)/) { my ($key, $val) = ($1, $2); $val =~ s/^"//; $val =~ s/"$//; $href->{$key} = $val if defined $href; } } if (defined $href) { push @tracks, $href; push @tracks, { POS => [$wav_data->{total_length}] }; } return @tracks; } |