我有一堆音频文件,我想使用 Sox 为每个单独的文件创建频谱图。通常,对于单个文件,我这样做:
sox audiofile.flac -n spectrogram
但是我不知道如何将此方法扩展到多个文件。理想情况下,我希望我的输出.png
文件具有与其各自的音频文件关联的文件名;例如,audiofile1.png
对于audiofile1.flac
,audiofile2.png
对于audiofile2.flac
等等。
有人知道怎么做这个吗?
答案1
感谢约瑟夫的回答。也许它在他发帖时有效,但我必须在红袜接受命令-o
后立即添加。spectrogram
for file in *.flac;do
outfile="${file%.*}.png"
sox "$file" -n spectrogram -o "$outfile"
done
您甚至可以更进一步,将文件的标题添加到图像中的频谱图上方,并使其更宽以查看更多细节。默认图像对我来说有点小。
for file in *.flac;do
outfile="${file%.*}.png"
title_in_pic="${file%.*}"
sox "$file" -n spectrogram -t "$title_in_pic" -o "$outfile" -x 2000
done
答案2
您可以将命令包含在循环中:
for file in *.flac
do
outfile="${file%.*}.png"
sox "$file" -n spectrogram "$outfile"
done
至于文件命名,sox(1) 手册页似乎建议您可以在命令行上显式命名输出文件,以便可以在循环中使用它。
循环中的第一行使用了 Bash参数替换.flac
从文件名中删除扩展名并添加.png
扩展名。
答案3
这是我的“获取频谱图”解决方案......
- 处理更多编解码器,如 aac、opus
- 处理更多容器,如 mp4、mkv、avi、m4a
- 将频谱图高度标准化为 24kHz
- 仅绘制一个通道 = 单声道
- 标准化音量
- 保留输出文件的输入文件扩展名
#!/bin/bash
# aspec.sh
# get spectrograms of audio streams
#
# usage: aspec.sh a.mp3 b.m4a c.mp4 d.mkv ....
#
# dependencies: sox, ffmpeg
# license: public domain, warranty: none
# version: 2019-05-17 by milahu
ff_args="" # ffmpeg arguments
sx_args="" # sox arguments
ff_args+=" -loglevel error"
ff_astream=0 # only use first audio stream
ff_args+=" -map 0:a:${ff_astream}?"
ff_args+=" -ac 1" # use only one audio channel
sx_args+=" channels 1"
sx_args+=" gain -n -3" # normalize volume to -3dB
# set sampling rate
# only analyze frequencies below f_max = rate / 2
# also normalize spectrogram height to f_max
#sx_args+=" rate 6k" # only show f < 3kHz "where the human auditory system is most sensitive"
sx_args+=" rate 48k" # only show f < 24kHz
# use wav as temporary format, if sox cant read file
ff_args+=" -c:a pcm_s16le -f wav"
sx_type="wav"
# process files from "argv"
for i in "$@"
do
echo "$i"
o="$i.sg.png" # output file
t=$(basename "$i") # title above spectrogram
c="spectrogram by SoX, the Sound eXchange tool" # comment below spectrogram
# try to read original format
echo analyze
sox "$i" -n \
$sx_args \
spectrogram -o "$o" -c "$c" -t "$t" \
2>&1 | grep -v "no handler for detected file type"
if (( ${PIPESTATUS[0]} != 0 ))
then
# sox failed. convert audio and retry
echo convert
# get duration of stream or container
# spectrogram filter has no "ignore length" option
# and without a "duration prediction" will only read 8 seconds
d=$(ffprobe "$i" -v error -of compact=s=_ \
-select_streams "0:a:${ff_astream}?" \
-show_entries stream=duration:format=duration \
| sort | grep -v =N/A \
| tail -n 1 | cut -d= -f2)
# 'tail -n 1' --> prefer stream duration
# 'head -n 1' --> prefer container duration
if [[ -z "$d" ]]
then
echo -e "skip. duration not found FIXME\n"
continue
fi
# bash "process substitution" magic
sox \
--type "$sx_type" \
--ignore-length \
<( ffmpeg -i "$i" $ff_args - ) \
--null \
$sx_args \
spectrogram -d "$d" -o "$o" -c "$c" -t "$t"
fi
echo -e "done\n$o\n"
done