前回は input_metadata() を通して、アルバム全体に共通する情報を集める仕組みを確認しました。
今回はその続きとして、各トラックごとの情報を集める input_tracks() を見ていくことにします。
1. はじめに
CUE シートは「アルバム情報 → トラック情報 → テキスト生成」という三段構造になっている。
その中で input_tracks() は、まさに “曲ごとの情報を順番に集める” 役割を担っている。
2. input_tracks() の目的は「曲ごとの情報を集める」だけ
input_metadata() がアルバム全体の情報をまとめたのに対し、input_tracks() は、1 曲目から最終曲まで、必要な情報を一つずつ入力してもらい、それらをリストとしてまとめて返す関数である。
ここで扱う情報は主に次の二つ。
・曲名(TITLE)
・曲の長さ(MM:SS → フレーム数)
CUE シートでは TRACK 行が曲数ぶん必要になるが、この段階では「INDEX(曲の開始位置)」はまだ決めない。
INDEX は「オフセット+それまでの曲の長さの合計」から自動計算できるため、input_tracks() では「曲名」と「曲の長さ」だけを集めることに専念している。
input_tracks() は metadata["total_tracks"] を参照しながら、「何曲ぶん入力するか」を決めてループを回す。
3. metadata を渡す理由
関数の呼び出しは次のようになっている。
tracks = input_tracks(metadata)
metadata を渡している理由は、トラック入力や一覧表示に必要な情報が
metadata に含まれているためである。
・アルバムの総トラック数(total_tracks)
・オフセット(offset_frames:開始位置の補正)
・アルバムアーティスト名(必要に応じて参照)
input_tracks() の中では、まず total_tracks を使って
「何曲ぶん入力するか」を決める。
さらに、入力後の確認フェーズでは offset_frames を起点として、
各トラックの長さを足し上げながら INDEX を計算し、
「TRACK xx: 曲名 / MM:SS → INDEX 01 mm:ss:ff」
という形で一覧表示している。
4. input_tracks() の全体像(◆A〜◆H 対応)
前回の input_metadata() と同じように、
今回もコードの各処理に ◆A〜◆H の記号を付けて、
フローチャートと 1 対 1 で対応するようにしている。
これにより、読者は「どの処理がどの図に対応しているか」を迷わず追えるようになる。
以下が、コメント付きの input_tracks() の全体像である。
# === トラック情報入力(曲名と時間) ===
def input_tracks(metadata: Metadata) -> list[dict]:
tracks = []
print("\n🎼 トラック情報の入力:")
# ◆A: 1曲目から順に、曲名と時間を入力
for i in range(1, metadata["total_tracks"] + 1):
# ◆B: 曲名を入力
title = input(f"TRACK {i:02} の曲名: ")
# ◆C: 時間(MM:SS)を入力し、形式チェック
while True:
new_length = input(f"TRACK {i:02} の曲時間(MM:SS): ").strip()
try:
duration = mmss_to_frames(new_length)
break
except ValueError:
print("⚠️ MM:SS 形式で入力してください(例: 3:35)")
# ◆D: 入力された1曲分を tracks に追加
tracks.append({"title": title, "duration": duration})
# ◆E: 入力後の一覧確認ループ
while True:
print("\n📜 トラック一覧:")
current_index = metadata["offset_frames"]
# ◆F: INDEX を計算しながら一覧表示
for i, track in enumerate(tracks, start=1):
index_time = frames_to_cuetime(current_index)
mmss = frames_to_mmss(track["duration"])
print(f" TRACK {i:02}: {track['title']} / {mmss} → INDEX 01 {index_time}")
current_index += track["duration"]
# ◆G: この内容でよいか確認
if confirm("このトラック情報でよろしいですか"):
return tracks
# ◆H: 修正処理(0 = metadata に戻る)
print("修正したいトラック番号を入力してください(0 = メタ情報に戻る)")
try:
choice = int(input("修正対象番号: "))
if choice == 0:
metadata = input_metadata(existing=metadata)
elif 1 <= choice <= metadata["total_tracks"]:
track = tracks[choice - 1]
# 曲名修正
new_title = input(
f"TRACK {choice:02} の曲名(現在: {track['title']}): "
).strip()
if new_title:
track["title"] = new_title
# 時間修正
new_mmss = input(
f"TRACK {choice:02} の曲時間(MM:SS、現在: {frames_to_mmss(track['duration'])}): "
).strip()
if new_mmss:
try:
track["duration"] = mmss_to_frames(new_mmss)
except ValueError:
print("⚠️ MM:SS 形式で入力してください(例: 3:35)")
else:
print("⚠️ 無効な番号です")
except ValueError:
print("⚠️ 数値で入力してください")

5. input_tracks() が返すもの
最終的に input_tracks() は、各曲の情報を辞書としてまとめたリストを返す。
例:
[
{"title": "曲名1", "duration": 12345},
{"title": "曲名2", "duration": 17890},
...
]
ここでの duration はフレーム数であり、
実際の CUE シートに書き出すときには、
・オフセット(offset_frames)
・各トラックの duration の累積
を使って INDEX 01 mm:ss:ff を計算する。
この tracks リストが、次の generate_cue_text() に渡され、TRACK 行の生成に使われる。
6. 次回予告
次回は generate_cue_text() の実際のコードを引用しながら、
・metadata と tracks をどのように受け取り
・どのように INDEX を計算し
・どのように CUE シートのテキストへ落とし込んでいくのか
を順番に見ていく予定だ。
いかがだろうか?ここまで来ると、CUE シート生成の全体像が「入力 → 確認 → テキスト生成」という一本の線としてはっきり見えてくると思います。