2008年4月7日月曜日

GNU Toolchain for ARM

androidはじめました」ということで,まずはARMのクロスコンパイラをOS X上に準備。CodeSourceryから提供されるGNU Toolchainをベースに環境を構築することにして
  • Target: ARM GNU/Linux,Host: IA32 GNU/Linuxのバイナリ
  • Target: ARM GNU/Linuxのソース
をダウンロード。

2008年4月4日金曜日

iTunesのプレイリストをSO905iへ

m4aファイルに3gpメタデータを埋め込むことができたので,iTunesのプレイリストからmicroSDカードへのAACファイルの書き込み,メタデータ埋め込みを自動化してみる。iTunesのプレイリストに登録された曲の取得にはScriptingBridgeを使う。
(1) iTunesのプレイリスト"SO905i"からScriptingBridgeを通してtrack一覧を取得,(2) 各ファイルの拡張子を.m4aから.3gpに変えながらmicroSDにコピー,(3)3gpメタデータを埋め込む,という手順でrubyスクリプトを作ってみた。

#!/usr/bin/env ruby

# configuration
LIB_NAME = 'ライブラリ'
PLAYLIST_NAME = 'SO905i'
DEST_DIR = '/Volume/Untitled/MUSIC'
ITUNES_BASE = '/Users/nishio/Music/iTunes/iTunes Music/'
CMD_M4A = '/Users/nishio/bin/AtomicParsley'
CMD_3GP = '/Users/nishio/bin/AtomicParsley_3gp'

# load libraries
require 'fileutils'
require 'pathname'
require 'osx/cocoa' # load cocoa library.
include OSX # setup for scripting bridge.
OSX.require_framework 'ScriptingBridge'

###
### convert m4a metadata to 3gp metadata
###
def m4a_to_3gp(file)
file = file.gsub(/"/) {|s| '\\' + s} # escape double quote
# parse .m4a atom
h = Hash.new
open("| #{CMD_M4A} \"#{file}\" -t") { |f|
while line = f.gets
line =~ /Atom "(.*)".* contains: (.*)/
h[$1] = $2.gsub(/"/) {|s| '\\' + s} # escape double quote
end
}

# put .3gp atom
h["trkn"] =~ /([0-9]*) of [0-9]*/
num = $1
args = "--3gp-title \"#{h["\302\251nam"]}\" lang=jpn --3gp-performer \"#{h["\302\251ART"]}\" lang=jpn --3gp-album \"#{h["\302\251alb"]}\" track=#{num} lang=jpn --3gp-genre \"#{h["\302\251gen"]}\" lang=jpn --3gp-year '#{h["\302\251day"]}' --overWrite"
system("#{CMD_3GP} \"#{file}\" #{args}")
end

######################################################################
# main routine begins here.

iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
iTunes.sources.each do |source|
next unless source.name == LIB_NAME
source.userPlaylists.each do |playlist|
next unless playlist.name == PLAYLIST_NAME
base = Pathname.new(ITUNES_BASE)
playlist.fileTracks.each do |track|
next unless track.enabled?

path = track.location.path
path_name = Pathname.new(path)
ext_name = File.extname(path)
dst_name = DEST_DIR + path_name.relative_path_from(base)
dst_dir = File.dirname(dst_name)

# create destination directories if not exists.
if !FileTest.exist?(dst_dir) then
puts "make directory: #{dst_dir}"
FileUtils.mkdir_p(dst_dir)
end

# copy a file
puts "copy file: #{dst_name}"
case ext_name
when '.m4a' then
dst_name = File.join(dst_dir, File.basename(dst_name, ext_name) + '.3gp')
FileUtils.cp(path, dst_name)
m4a_to_3gp(dst_name)
else
FileUtils.cp(path, dst_name)
end
end
end
end

2008年3月28日金曜日

m4aから3gpへのメタデータ変換

iTunesで作成したAACファイル(.m4a)のメタデータをAtomicParsleyで表示してみる。
$ ~/bin/AtomicParsley 16\ 後出し.m4a -t
Atom "©nam" contains: 後出し
Atom "©ART" contains: ケツメイシ
Atom "©wrt" contains: ケツメイシ
Atom "©alb" contains: ケツノポリス2
Atom "©gen" contains: Hip Hop/Rap
Atom "trkn" contains: 16 of 16
Atom "disk" contains: 1 of 1
Atom "©day" contains: 2002
Atom "cpil" contains: false
Atom "tmpo" contains: 0


PS3で作成した AAC ファイル(.3gp)のメタデータをAtomicParsleyで表示してみると
$ ~/bin/AtomicParsley_3gp スタート.3gp -t
User data "titl" [lang=jpn (utf16)] : スタート
User data "perf" [lang=jpn (utf16)] : ケツメイシ
User data "gnre" [lang=jpn (utf16)] : Rock
User data "albm" [lang=jpn (utf16)] : ケツノポリス5 | Track: 1
User data "yrrc" : 2007

なので'©nam'を'titl','©ART'を'perf',’©alb'を'albm','©gen'を'gnre'に書き込めばよい。

AtomicParsleyとrubyで変換スクリプトをquick hack。

#!/usr/bin/env ruby

# config
CMD_M4A = '/Users/nishio/bin/AtomicParsley'
CMD_3GP = '/Users/nishio/bin/AtomicParsley_3gp'

# convert m4a metadata to 3gp metadata
def m4a_to_3gp(file)
file = file.gsub(/"/) {|s| '\\' + s} # escape double quote
# parse .m4a atom
h = Hash.new
open("| #{CMD_M4A} \"#{file}\" -t") { |f|
while line = f.gets
line =~ /Atom "(.*)".* contains: (.*)/
h[$1] = $2.gsub(/"/) {|s| '\\' + s} # escape double quote
end
}

# put .3gp atom
h["trkn"] =~ /([0-9]*) of [0-9]*/
num = $1
args = "--3gp-title \"#{h["\302\251nam"]}\" lang=jpn --3gp-performer \"#{h["\302\251ART"]}\" lang=jpn --3gp-album \"#{h["\302\251alb"]}\" track=#{num} lang=jpn --3gp-genre \"#{h["\302\251gen"]}\" lang=jpn --3gp-year '#{h["\302\251day"]}' --overWrite"
system("#{CMD_3GP} \"#{file}\" #{args}")
end

# main begins.
file = ARGV[0]
m4a_to_3gp(file)

3gpメタデータの書き込み

SO905iでも正しく表示が行われるPS3で作成した AAC ファイル(.3gp)のメタデータをAtomicParsleyで表示してみると
$ ~/bin/AtomicParsley スタート.3gp -t
User data "titl" [lang=jpn (utf16)] : スタート
User data "perf" [lang=jpn (utf16)] : ケツメイシ
User data "gnre" [lang=jpn (utf16)] : Rock
User data "albm" [lang=jpn (utf16)] : ケツノポリス5 | Track: 1
User data "yrrc" : 2007


なので,iTunesで作られたAACファイルにAtomicParsleyを使って'titl', 'perf', 'albm', 'gnre'を書き込んでやればSO905i上でも曲データが表示されるようになると思われる。試しにalbmを書き込んでみると……
$ ~/bin/AtomicParsley 16\ 後出し.m4a --3gp-album "Test Album" lang=jpn
AtomicParsley warning:
the 'albm' tag is only allowed on files of '3gp6' brand & later.
Skipping.
No changes.


どうやらAtomicParsleyは 'ftyp' atom の majorBrand の値を見てメタデータ形式を決定しているようなので,iTunes で作成した AAC ファイルに 3gp6 のtag を(無理やり)書き込めるよう AtomicParsleyを修正してみた。iTunes で作成したAACファイルのmajorBrandは'M4A ',PS3で作成したAACのmajorBrandは'3gp6'なので,AtomicParsley.cpp内部で'M4A 'を'3gp6'と同様に扱うよう修正。
*** AtomicParsley.cpp.orig 2008-03-28 01:42:33.000000000 +0900
--- AtomicParsley.cpp 2008-03-28 01:43:56.000000000 +0900
***************
*** 2114,2119 ****
--- 2114,2120 ----
metadata_style = THIRD_GEN_PARTNER;
break;

+ case 0x4D344120 : //'M4A ' -- these are all listed at http://www.mp4ra.org/filetype.html as registered brands
case 0x33677036 : //'3gp6'

case 0x33677236 : //'3gr6' progressive
***************
*** 2129,2135 ****
metadata_style = ITUNES_STYLE;
psp_brand = true;
break;
! case 0x4D344120 : //'M4A ' -- these are all listed at http://www.mp4ra.org/filetype.html as registered brands
case 0x4D344220 : //'M4B '
case 0x4D345020 : //'M4P '
case 0x4D345620 : //'M4V '
--- 2130,2136 ----
metadata_style = ITUNES_STYLE;
psp_brand = true;
break;
! //case 0x4D344120 : //'M4A ' -- these are all listed at http://www.mp4ra.org/filetype.html as registered brands
case 0x4D344220 : //'M4B '
case 0x4D345020 : //'M4P '
case 0x4D345620 : //'M4V '


修正した実行ファイル(AtomicParsley_3gp)でもう一度 albm を書き込んでみると
$ ~/bin/AtomicParsley_3gp 16\ 後出し.m4a --3gp-album "Test Album" lang=jpn --overWrite
......
Finished writing to temp file.
$ ~/bin/AtomicParsley_3gp 16\ 後出し.m4a -t
User data "albm" [lang=jpn (utf8)] : Test Album


m4aファイルに3gpのメタデータを追記できた。

2008年3月27日木曜日

m4a と 3gp のメタデータ

iTunesで作成した AAC ファイルを SO905i に持っていくと曲メタデータが「不明」となってしまう。これではあまりに不便なので変換する方法を調べてみる。

MP3 であれば id3 でメタデータが格納されているが,iTunes の AAC ファイルのメタデータは独自のatomに格納しているようだ。
AtomicParsleyを使えば iTunes 形式と 3GPP 形式のメタデータの編集ができそう。
AtomicParsley is a lightweight command line program for reading, parsing and setting metadata into MPEG-4 files supporting these styles of metadata:

iTunes-style metadata into .mp4, .m4a, .m4p, .m4v, .m4b files
3gp-style assets (3GPP TS 26.444 version 6.4.0 Release 6 specification conforming) in 3GPP, 3GPP2, MobileMP4 & derivatives
ISO copyright notices at movie & track level for MPEG-4 & derivative files
uuid private user extension text & file embedding for MPEG-4 & derivative files