1月 02 2008

WavPack 形式で CD をリッピング

Published by HoLY at 0:03:28 under tech

WavPack形式でCDを(トラックごとに分けずに)ファイル一つにまとめてリッピングする方法についてメモ。

はじめてWavPack形式で年末くらいに買ってきたCDをデータ化したりしてる。

これまでは惰性で可逆圧縮で某変換機を使って (tta+cue).mka 作ってたけど、 某変換機のあまりの××さに嫌気が差したのと、mka はステたかった というのもあり情報収集しなおした。

条件は

  • ファイルひとつでアルバムを収録できる(画像は今回は不問、最悪 mka でできればよし)
  • wav を抽出できる
  • cue を抽出できる
  • デコード速度がなるべく速い(エンコードは気にしない)
  • foobar2k でトラックごとに聞ければOK

んで FLAC か WavPack か TAK で Internal CueSheet にすればよさそう。

FLAC よりは全体的に WavPack だよなー(あまりまじめに比較してないけど)。 んで TAK はヨサゲっぽいけど、バイナリでしか配布されてないんだよなってことでパス(ちなみにWavPackはBSDライセンス)。

ということで wv にしてみましたとさ。と、ここまでが前置き。

  • 既存の wav+cue をさくさく wv に変換したいなあ。(今回は tta+cue とかは考えずに)
  • EAC を使ってるので、EAC から一気に wv までいけると便利だ。

ってなことで、Ruby でスクリプト書いて exerb で実行ファイルにして使ってみたり(encwv.exe)。 スクリプト(encwv.rb)はこんな感じ。wavpack.exe をダウンロードして同じフォルダに置いて使う。

ドラッグアンドドロップで encwv.exe に wav ファイルまたは cue ファイルを与えると変換してくれる。 複数指定もOK。

#!/usr/local/bin/ruby
require 'optparse'

options = {}
opt = OptionParser.new
opt.banner = "Usage: #{opt.program_name} source.wav [options]"
opt.on('-w VAL', '--wavpack VAL', 'full path of wavpack path (default: wavpack.exe)') {|v| options[:wavpack] = v }
opt.on('-o VAL', '--option VAL', 'wavpack option (default: "-m -t")') {|v| options[:option] = v }
opt.on('-e VAL', '--eac VAL', 'original filename(%o) in EAC (used in EAC only!)') {|v| options[:eac] = v }
opt.permute!(ARGV) 

unless ARGV[0]
  $stderr.puts opt.help
  exit 1
end

def search_file(filename, suffix = '.cue')
  if File.exist? filename + suffix
    return filename + suffix
  end
  while /\./ =~ filename 
    filename.sub!(/\.[^\.]+$/, '')
    if File.exist? filename + suffix
      return filename + suffix
    end
  end
  nil
end

ARGV.each do |filename|
  wavpack = options[:wavpack] || %|"wavpack.exe"|
  option  = options[:option]  || '-m -t'
  srcfile = filename.sub(/\.[^\.]+$/, '.wav')
  if options[:eac]
    dirname  = File.dirname(srcfile)
    basefile = [dirname,options[:eac]].join(File::ALT_SEPARATOR||File::SEPARATOR)
    cuefile  = search_file(basefile) or raise "cue file not found"
  else
    cuefile = search_file(srcfile) or raise "cuefile not found."
  end
  outfile = cuefile.sub(/\.[^\.]+$/, '.wv')

  option << %| -w "CUESHEET=@#{cuefile}"|

  cmd = %|#{wavpack} #{option} "#{srcfile}" "#{outfile}"|
  puts cmd
  puts "--"
  exit -1 if !system(cmd) 
end

EAC の設定

んで EAC からこいつを使う場合はこうする。

実行ファイル化しない場合

  • エンコードに使用するプログラムのパスを指定 [ruby.exe へのフルパス (C:\Program Files\ruby-1.8\bin\ruby.exe)]
  • コマンドラインオプション追加 [encwv.rbへのフルパス] -w [wavpack.exeへのフルパス] -e %o %s

実行ファイル化した encwv.exe を使う場合

  • エンコードに使用するプログラムのパスを指定 [encwv.exe へのフルパス]
  • コマンドラインオプション追加 → 「-w [wavpack.exeへのフルパス] -e %o %s」

wavpack.exe の位置にパスが通っている場合には -w オプションは不要。

なんか EAC の挙動に依存して余計なコードが増えてたりして微妙だけど、とりあえず上手く動いた(バージョンは 0.95b4)。

まあそんな感じで快適なリッピング生活ができるようになったとさ。めでたし。既存の (tta+cue).mka とかにも対応できるといいけどなあ。

蛇足

FLAC とか TAK な人はこちらのサイト「”flacencode” - FLAC/TAK + Internal cuesheet 活用支援」 を参考にするといいかも。こちらは (tta+cue).mka → FLAC なんかを一発で行うツールを公開してる。ソースがあったらさくっとwv対応のを作れるのになあ。w

追記

D&D でやる方式では、 「&()[]{}^=;!’+,`~」の入ったパスはうまく引数として渡らない可能性がある(シェルの引数として引用符付きで展開されないから)。 スペースを含むパスだと引用符付きで渡されるので問題なくパスが渡る。

さすがにexerbでやる限界のような気はする。解決する場合は別の言語で書き換えた方がいいね。w

追記2

ちなみに wv を wav+cue に戻すには、wav を作るには wavunpack.exe に食わせればよく、 cue に関しては CUESHEET タグの内容を取得すればよい。いろいろなやり方があると思うけれど、例えばこんな感じでもできる(適当すぎるけど)。文字コードがUTF-8に変換されているので、完全に同じものを復元できるかは分からない。だがおそらく mka から元の cue を復元するよりはまとも。

filename = ARGV[0]
unless File.exists? filename: raise "File not found"; end
orig = open(filename, 'rb')
cue  = open(filename.sub(/\.[^\.]+$/,'.cue'), 'wb')
bufsize = 1024*1024
prevpos = 0 # XXX
while buf = orig.read(bufsize)
  $stderr.puts orig.pos
  if pos = buf.index("CUESHEET")
  $stderr.puts "find!"
  $stderr.puts "pos = #{f.pos+pos} byte"
    orig.pos = prevpos + pos + 9
    buf = orig.read(100*1024)
    $stderr.puts buf
    endpos = buf.index("APETAGEX")
    $stderr.puts endpos
    cue.puts buf[0, endpos]
    break
  end
  prevpos = orig.pos
end

Trackback URI | Comments RSS

Leave a Reply