免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6120 | 回复: 6
打印 上一主题 下一主题

用.cue文件切割.wav文件 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-02-11 10:37 |只看该作者 |倒序浏览
先发布源代码,再说明干什么用,免得烂在我的硬盘里。

  1. #!/usr/bin/env perl
  2. # This program splits a wav file that contains multiple tracks into multiple wav
  3. # files, each of which contains one track based on indices provided by a cue file.
  4. # Written by Shufeng Tan <shufengtan@gmail.com> January, 2007
  5. # It is assumed that the cue file is in the same directory with the wav file.
  6. # The cue file with the same basename with the wav file will be picked.
  7. # Failing that, the program will pick the first cue file listed by DirHandle.

  8. use strict;
  9. use Audio::Wav;
  10. use Data::Dumper;
  11. use DirHandle;
  12. use FileHandle;
  13. use File::Basename;

  14. my $wavfile = shift;
  15. die "Usage: $0 file.wav\n" unless $wavfile;
  16. die "File $wavfile not found.\n" unless -f $wavfile;

  17. my $cuefile = find_cue_file($wavfile);
  18. warn "CUE file not found for $wavfile\n" unless $cuefile;

  19. my $WAV = new Audio::Wav;
  20. my $read = $WAV->read($wavfile);
  21. my $details = $read->details;
  22. my $Track_Details = {
  23.         bits_sample => $details->{bits_sample},
  24.         sample_rate => $details->{sample_rate},
  25.         channels => $details->{channels},
  26. };

  27. exit unless $cuefile;
  28. my @tracks = parse_cue_file($cuefile, $read);

  29. print "$#tracks tracks from $cuefile\n";

  30. my $Max_Buf_Len = 1048576;

  31. foreach my $i (0 .. ($#tracks-1)) {
  32.         my $track_info = $tracks[$i];
  33.         my $track = $track_info->{TRACK};
  34.         my $name = $track_info->{TITLE};
  35.         my $artist = $track_info->{PERFORMER};
  36.         my $track_file = "${track}_$name.wav";
  37.         $track_file =~ tr|/:|  |;
  38.         my @pos = @{$track_info->{POS}};
  39.         my $track_len = $tracks[$i+1]->{POS}->[0] - $pos[0];
  40.         print "TRACK $track '$name' by '$artist' $track_len bytes POS=[@pos]\n";

  41.         my $write = $WAV->write($track_file, $Track_Details);
  42.         $write->set_info('software' => 'Audio::Wav', 'artist' => $artist, 'name' => $name);

  43.         $read->move_to($pos[0]);
  44.         my $read_len = 0;
  45.         while($read_len < $track_len) {
  46.                 my $remain = $track_len - $read_len;
  47.                 my $buf_len = $remain >= $Max_Buf_Len ? $Max_Buf_Len : $remain;
  48.                 my $buf = $read->read_raw($buf_len);
  49.                 my $buf_len2 = length($buf);
  50.                 $read_len += $buf_len2;
  51.                 $write->write_raw($buf, $buf_len2);
  52.                 if ($buf_len != $buf_len2) {
  53.                         print "Last track: $read_len out of $track_len bytes\n";
  54.                         last;
  55.                 }
  56.         }
  57.         $write->finish();
  58. }

  59. exit;

  60. sub find_cue_file {
  61.         my ($file) = @_;
  62.         if ($file =~ s/\.\w+$/.cue/) {
  63.                 return $file if -f $file;
  64.                 $file =~ s/\.cue$/.CUE/;
  65.                 return $file if -f $file;
  66.         }
  67.         my $dir = dirname($file);
  68.         my $dh = new DirHandle $dir;
  69.         if (defined $dh) {
  70.                 while(my $f = $dh->read) {
  71.                         return "$dir/$f" if $f =~ /\.cue$/i;
  72.                 }
  73.         }
  74. }

  75. sub parse_cue_file {
  76.         my ($cuefile, $wav_in) = @_;
  77.         my $cueh = new FileHandle $cuefile;
  78.         return unless defined $cueh;
  79.         my $wav_data = $wav_in->{data};
  80.         print Data::Dumper->Dump([$wav_data]);
  81.         return unless defined $wav_data;
  82.         my $wav_sec = $wav_data->{length};
  83.         my $wav_offset = $wav_data->{data_start};
  84.         my $wav_bps = $wav_data->{bytes_sec};
  85.         my (@tracks, $href);
  86.         while(<$cueh>) {
  87.                 chomp;
  88.                 s/\r$//;
  89.                 if (/^\s*TRACK\s+(\d+)/i) {
  90.                         push(@tracks, $href) if defined $href;
  91.                         $href = { TRACK => $1 };
  92.                 } elsif (/^\s*INDEX\s+\d+\s+0?(\d+):0?(\d+):0?(\d+)/i) {
  93.                         my $pos = $wav_offset + ($1*60 + $2) * $wav_bps + $3*$wav_bps/75;
  94.                         $href->{POS} = exists($href->{POS}) ? [@{$href->{POS}}, $pos] : [$pos];
  95.                 } elsif (/^\s*(\w+)\s*(\S.*)/) {
  96.                         my ($key, $val) = ($1, $2);
  97.                         $val =~ s/^"//;
  98.                         $val =~ s/"$//;
  99.                         $href->{$key} = $val if defined $href;
  100.                 }
  101.         }
  102.         if (defined $href) {
  103.                 push @tracks, $href;
  104.                 push @tracks, { POS => [$wav_data->{total_length}] };
  105.         }
  106.         return @tracks;
  107. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2007-02-11 10:51 |只看该作者
Good Topic!再写个说明文档吧.

论坛徽章:
0
3 [报告]
发表于 2007-02-11 11:01 |只看该作者
话要从bittorrent说起,很多下载的文件都把整盘CD十几首歌放在一个APE文件里,另外配一个CUE文件说明每一首歌的开始和结束时间。
一般来说文件名都叫CDImage.ape和CDImage.cue。

论坛徽章:
0
4 [报告]
发表于 2007-02-11 11:06 |只看该作者
APE是一种无损压缩格式,我只知道一个叫Monkey's Audio的软件可以把APE格式解压成WAV格式。
CDImage.ape => CDImage.wav

论坛徽章:
0
5 [报告]
发表于 2007-02-11 11:13 |只看该作者
把CDImage.wav和CDImage.cue放在同一个目录里就可以用上面的程序把一个大WAV文件分成几个小文件。

$ ls
CDImage.ape    CDImage.cue    CDImage.wav
$ /usr/local/bin/wavcut.pl CDImage.wav

论坛徽章:
0
6 [报告]
发表于 2007-02-11 11:35 |只看该作者
最后别忘了存.wav文件的目录里最好只能有一个.cue文件,如果有好几个.cue文件的话,主文件名(除掉后坠.cue)必须和.wav的相同。要不然回乱套了。

论坛徽章:
0
7 [报告]
发表于 2008-06-13 23:28 |只看该作者
很不错啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP