Linux Audioスクリプト再生(4)
以上、Linux Audioの「ALSA」基本オーディオシステムに備わっている
aplayというアプリを用いた再生法でしたが、次は音源処理アプリである「sox」に備わっている
sox-play ( play )を使った再生法です。
aplayの時に準じて、音源フォルダー内の音源を頭から数字、アルファベット順に再生するスクリプトです。
まず念のためまずsoxがインストールされていることをご確認ください。
sox --versionこれでバージョンを確認してちゃんと出てくれば問題ありませんし、
あるいは最初から
sudo apt install soxとインストールを行うのもいいかもしれません。もしすでにsoxがインストールされていればその旨表示されます。もしインストールされていなければこれでインストールが実行されます。
次に再生のための「スクリプトファイル」を準備します。
ターミナルを開いて
sudo gedit sp.shと入力してファイルを作成します。その中に下記をコピペしてください。geditがインストールされていなければ
sudo apt install geditでインストールしてください。geditはとても使いやすいアプリです。これまでは「nano」を使っていましたが、コピペなどの使い勝手が全く違って便利で使いやすいです。
次にgeditで開いたファイルに
####################################################################
#!/bin/bash
# USBオーディオ検出の強化版
# USB-DAC/DDCを検出して設定する
usb_card_info=$(aplay -l | grep -E '^card [0-9]+: .*USB Audio|USB-Audio' | head -n 1)
if [ -n "$usb_card_info" ]; then
# card X: のXを取得
usb_card_num=$(echo "$usb_card_info" | awk '{print $2}' | sed 's/://')
# device Y: のYを取得 (USBオーディオは通常device 0が多い)
# ただし、device 情報がない行もあるため、安全のため0を使用
# より厳密にするなら、grep -A1 で次の行も見て device 番号を特定する
usb_device_num=0 # ほとんどのUSB DACはdevice 0
SOUND_DEVICE="hw:${usb_card_num},${usb_device_num}"
echo "USB オーディオデバイスを検出しました: $SOUND_DEVICE"
else
echo "USB オーディオデバイスが見つかりません。デフォルトのデバイスを使用します。"
SOUND_DEVICE="default"
fi
# 設定
VOLUME_STEP=2 # 音量調整のステップ(dB)
current_volume=-8 # 初期音量(dB)
current_index=0
playing=true
# 画像表示用のプロセスID
image_pid=""
# WAVとFLACファイルのリストを取得して配列に保存
echo "音楽ファイルを検索中..."
mapfile -d $'\0' files < <(find . \( -name "*.wav" -o -name "*.flac" \) -print0 | sort -z -V)
total_files=${#files[@]}
if [ $total_files -eq 0 ]; then
echo "WAVまたはFLACファイルが見つかりません"
exit 1
fi
echo "$total_files 個の音楽ファイルを見つけました"
# 再生中のプロセスIDを保存する変数
player_pid=""
# プロセスをクリーンアップする関数
cleanup_processes() {
if [ ! -z "$player_pid" ]; then
kill $player_pid 2>/dev/null || true
fi
if [ ! -z "$image_pid" ]; then
kill $image_pid 2>/dev/null || true
fi
# すべてのplayとSoxプロセスを確実に終了
pkill -f "play.*${files[$current_index]}" 2>/dev/null || true
pkill -f "sox.*${files[$current_index]}" 2>/dev/null || true
pkill -f "feh --fullscreen" 2>/dev/null || true
# プロセスが完全に終了するのを少し待つ
sleep 0.2
}
# フォルダ内の最大サイズの画像を探して表示する関数
show_largest_image() {
# 現在のファイルが存在しない場合は処理をスキップ
if [ ! -f "${files[$current_index]}" ]; then
echo "警告: ファイルが見つかりません: ${files[$current_index]}"
return
fi
local dir=$(dirname "${files[$current_index]}")
# 既存の画像表示プロセスを終了
if [ ! -z "$image_pid" ]; then
kill $image_pid 2>/dev/null || true
fi
# フォルダ内の画像ファイルを検索
local largest_image=$(find "$dir" -type f \( -name "*.jpg" -o -name "*.jpeg" -o -name "*.png" -o -name "*.gif" \) -exec du -k {} \; | sort -nr | head -n1 | cut -f2)
# 画像が見つかった場合は表示
if [ ! -z "$largest_image" ] && [ -f "$largest_image" ]; then
echo "画像を表示: $largest_image"
# fehコマンドが存在するかチェック
if command -v feh &> /dev/null; then
# 画像を最大化して表示 (--scale-down: 画像が画面より大きい場合のみ縮小、--zoom max: 可能な限り拡大)
feh --fullscreen --borderless --zoom max --scale-down "$largest_image" &
image_pid=$!
else
echo "警告: feh がインストールされていないため、画像を表示できません"
fi
else
echo "表示できる画像が見つかりません"
fi
}
# ファイルの拡張子を取得する関数
get_file_extension() {
local filename="$1"
echo "${filename##*.}" | tr '[:upper:]' '[:lower:]'
}
# 曲情報を表示する関数(メタデータ取得をバックグラウンドプロセスに変更)
show_now_playing() {
local file="${files[$current_index]}"
# ファイルが存在するか確認
if [ ! -f "$file" ]; then
echo "警告: ファイルが見つかりません: $file"
return
fi
local ext=$(get_file_extension "$file")
echo "再生中 ($((current_index+1))/$total_files): $file (${ext^^}形式) (音量: ${current_volume}dB)"
# SoXコマンドが存在するかチェック
if command -v sox &> /dev/null; then
# メタデータ表示をバックグラウンドで実行し、出力をファイルに保存
tmp_metadata=$(mktemp)
(sox --i "$file" > "$tmp_metadata" 2>/dev/null || true) &
# 少し待ってからメタデータを表示し、一時ファイルを削除
(sleep 0.5 && cat "$tmp_metadata" && rm "$tmp_metadata") &
else
echo "警告: sox がインストールされていないため、メタデータを表示できません"
fi
}
# 曲を再生する関数
play_file() {
local file="${files[$current_index]}"
# ファイルの存在チェック
if [ ! -f "$file" ]; then
echo "エラー: ファイルが見つかりません: $file"
# 次の曲に進む
current_index=$(( (current_index + 1) % total_files ))
if [ $current_index -eq 0 ]; then
echo "利用可能なファイルがありません。終了します。"
cleanup_processes
exit 1
fi
play_file
return
fi
# 既存のプロセスをクリーンアップ
cleanup_processes
# コマンドの存在チェック
if ! command -v play &> /dev/null || ! command -v sox &> /dev/null; then
echo "エラー: SoX (play/sox) がインストールされていません"
exit 1
fi
echo "再生を開始: $file"
# 音量調整を計算(SoXのgainに適用)
local gain_value=$current_volume
# 新しい再生プロセスを開始(エラー処理を追加)
# SoXのplay コマンドを使用
(play --buffer 500000 "|sox -n -p trim 0.0 0.7" "$file" \
norm -4 \
compand 0.3,0.8 6:-70,-60,-20 -6 -90 0.2 \
gain -8 \
equalizer 40 1.0q +2 \
equalizer 60 1.2q +3 \
equalizer 80 1.5q +2 \
equalizer 120 1.8q +2 \
equalizer 180 2.0q -1 \
equalizer 250 2.0q -2 \
equalizer 1k 0.7q -3 \
equalizer 3k 0.7q +2 \
contrast 15 \
gain $gain_value 2>/dev/null) &
player_pid=$!
# プロセスが正常に開始されたか確認
sleep 0.5
if ! ps -p $player_pid > /dev/null; then
echo "警告: 再生プロセスの開始に失敗しました。シンプルな再生方法を試します。"
# 代替再生方法を試す
(play "$file" gain $gain_value 2>/dev/null) &
player_pid=$!
fi
show_now_playing
# 関連画像を表示
show_largest_image
}
# キーボード入力を処理する関数
handle_input() {
read -rsn1 -t 0.1 key
if [ -z "$key" ]; then
return
fi
case "$key" in
q) # 終了
echo "プレーヤーを終了します"
cleanup_processes
exit 0
;;
n) # 次の曲
echo "次の曲へ"
current_index=$(( (current_index + 1) % total_files ))
play_file
;;
p) # 前の曲
echo "前の曲へ"
current_index=$(( (current_index - 1 + total_files) % total_files ))
play_file
;;
+) # 音量を上げる
if command -v bc &> /dev/null; then
current_volume=$(echo "$current_volume + $VOLUME_STEP" | bc)
else
current_volume=$((current_volume + VOLUME_STEP))
fi
echo "音量: ${current_volume}dB"
play_file
;;
-) # 音量を下げる
if command -v bc &> /dev/null; then
current_volume=$(echo "$current_volume - $VOLUME_STEP" | bc)
else
current_volume=$((current_volume - VOLUME_STEP))
fi
echo "音量: ${current_volume}dB"
play_file
;;
i) # 現在の曲情報を表示(メインプロセスをブロックしないバージョン)
# すでに表示されている基本情報に加えて詳細情報を表示
echo "タグ情報を取得中..."
if command -v sox &> /dev/null; then
(sox --i "${files[$current_index]}" 2>/dev/null || echo "タグ情報がありません") &
else
echo "sox がインストールされていないため、タグ情報を取得できません"
fi
;;
l) # 曲リストを表示
echo "曲リスト:"
for i in "${!files[@]}"; do
local ext=$(get_file_extension "${files[$i]}")
if [ $i -eq $current_index ]; then
echo "→ $((i+1))/${#files[@]}: ${files[$i]} (${ext^^})"
else
echo " $((i+1))/${#files[@]}: ${files[$i]} (${ext^^})"
fi
done
;;
r) # 画像表示を更新
echo "画像を再読み込み..."
show_largest_image
;;
d) # サウンドデバイス情報を表示
echo "現在のサウンドデバイス: $SOUND_DEVICE"
echo "利用可能なサウンドデバイス:"
# SOXのサウンドデバイス情報表示
if command -v sox &> /dev/null; then
sox -h | grep "AUDIO DEVICE" -A 20
else
echo "sox がインストールされていないため、デバイス情報を取得できません"
fi
;;
h) # ヘルプを表示
echo "ショートカットキー:"
echo " n: 次の曲"
echo " p: 前の曲"
echo " +: 音量を上げる"
echo " -: 音量を下げる"
echo " i: 現在の曲情報"
echo " l: 曲リスト表示"
echo " r: 画像を再表示"
echo " d: サウンドデバイス情報"
echo " h: このヘルプを表示"
echo " q: 終了"
;;
esac
}
# 終了時にプロセスをクリーンアップ
trap cleanup_processes EXIT
# メインループ
echo "WAV/FLACプレーヤーを起動しました(h でヘルプ表示)"
play_file
# 非ブロッキングモードでキー入力を処理
stty -echo
while true; do
handle_input
# プロセスが終了していたら次の曲へ(エラーチェック付き)
if [ ! -z "$player_pid" ]; then
if ! ps -p $player_pid > /dev/null 2>&1; then
echo "プレーヤープロセスが終了しました。次の曲へ自動進行します。"
current_index=$(( (current_index + 1) % total_files ))
play_file
fi
else
# プロセスIDが空の場合(再生に失敗した場合など)
echo "再生プロセスが見つかりません。再起動します。"
play_file
fi
sleep 0.1
done
stty echo
#########################################################################
これをコピペして保存してください。そののちスクリプト稼働権限を与えるため
sudo chmod +x sp.shと入力します。
再生法
再生法は以下の通りです。
最初に音源の入ったフォルダーを出しておきます。内部にはたくさんのフォルダーや音源ファイルが入っていても問題ありません。フォルダーの階層も何層でも問題ありません。自分がこれを上から順に再生したいと思うフォルダーを見つけ出しておきます。そしてフォルダー上で右クリックしてターミナルを開き、
~/sp.shと入力すれば自動的にUSB-DAC/DDCカードを探し出してくれ、やがてDAC/DDCに出力が始まります。もちろん、DAC/DDC以下の再生装置はすべてちゃんと準備しておきます。
再生が開始されますと、PC前面にフォルダー内にあるジャケット画像を表示しつつすべてフォルダー内の曲が再生されます。
キーボードショートカット操作法がわからなくなったら再生の途中で
Escボタンを押さえてまず表示画像を閉じてのち、
hキーを押さえますとヘルプが表示されますので、それに従って操作してください。ヘルプ内容は
echo "ショートカットキー:"
echo " n: 次の曲"
echo " p: 前の曲"
echo " +: 音量を上げる"
echo " -: 音量を下げる"
echo " i: 現在の曲情報"
echo " l: 曲リスト表示"
echo " r: 画像を再表示"
echo " d: サウンドデバイス情報"
echo " h: このヘルプを表示"
echo " q: 終了"となっています。そこにあるように例えばジャケット画像をもう一度表示させるには
rキーを押さえます。
再生の途中で終了するには
qキーを押さえてください。
これで"sox-play"を使った半自動再生が可能となります。これはあくまでも曲をフォルダー毎に上から順に再生するスクリプトです。
いかがですか。先の"aplay"を使ったスクリプト再生と聴き比べてみてください。それぞれ特徴のある面白い音がするでしょう。
