От одного аудиофрагмента к пакетной обработке

ShellBeginner
Практиковаться сейчас

Введение

Fieldnote Audio Studio нужны короткие фрагменты для прослушивания записей. Вы создадите WAV длительностью три секунды, воспроизведёте его и превратите одну команду в повторно используемый скрипт Bash. Подготовленные записи — оригинальные синтетические звуки, а не запись с микрофона.

Предполагается, что вы знаете основные аргументы, условия, циклы, массивы и функции Bash из Shell for Beginners. Здесь объясняются необходимые параметры обработки звука и кавычки. FFmpeg уже готов к работе. Терминал Workspace и страница Listening Room используют один контейнер; каждая лабораторная работа настраивается независимо.

Создайте и воспроизведите аудиофрагмент

На этом шаге вы сначала услышите, что содержит правильно созданный фрагмент, а затем приступите к скрипту пакетной обработки.

Начните в Workspace, подготовленном для имён файлов UTF-8. Рабочий каталог — подготовленная студия. Если команда сообщает об отсутствующем относительном пути, узнайте текущий каталог через pwd и вернитесь этой полной командой cd. Выполняйте всю работу курса здесь.

cd /home/labex/project/audio-studio
ls input

Вы должны увидеть Morning bells.wav, 海辺.wav и -closing.wav. Каждая запись — восьмисекундный монофонический WAV с 16-битными отсчётами PCM и частотой 22050 отсчётов в секунду. PCM хранит отсчёты непосредственно. Мы сохраним формат и оставим только начало. Поддерживаются обычные нескрытые файлы непосредственно во входном каталоге с расширением .wav в нижнем регистре; проект не обходит подкаталоги рекурсивно и не обрабатывает произвольные кодеки.

Сначала создайте single — каталог для отдельных экспериментов. mkdir -p создаёт его при необходимости и допускает уже существующий каталог.

mkdir -p single

В следующей команде -i задаёт вход, -t 3 ограничивает выход тремя секундами, а -c:a pcm_s16le выбирает знаковый 16-битный PCM. Параметры описывают последующий вход или выход, поэтому их положение важно. -v error скрывает обычные сообщения о ходе работы, сохраняя ошибки. -nostdin запрещает FFmpeg читать интерактивные команды из ввода терминала и делает его удобнее для безопасного использования в циклах. Последний путь задаёт выходной файл.

Двойные кавычки сохраняют путь с пробелами как один аргумент. Начальный ./ или абсолютный префикс каталога также не даёт принять имя, начинающееся с -, за параметр. Используйте новый выходной файл: при отключённом взаимодействии через стандартный ввод FFmpeg обычно отказывается перезаписывать существующий файл.

ffmpeg -nostdin -v error -i "input/Morning bells.wav" -t 3 -c:a pcm_s16le "single/Morning bells.wav"

При таком уровне журналирования успешное преобразование ничего не печатает. $? — собственный код завершения предыдущей команды: ноль означает успех, ненулевое значение — ошибку. Считайте его сразу: любая следующая команда заменяет это значение.

printf 'Conversion exit: %s\n' "$?"

Ожидается Conversion exit: 0. Этот код говорит об успешном выполнении преобразования; воспроизведение проверит пригодность самого файла.

Переключитесь на вкладку Listening Room и обновите страницу. В разделе First preview запустите Morning bells кнопкой воспроизведения. Послушайте меняющиеся тоны, переместите ползунок внутрь фрагмента и убедитесь, что он заканчивается на трёх секундах. Выберите Download WAV, чтобы сохранить тот же файл. Страница читает только ваши реальные выходные файлы и не восполняет отсутствующий звук из библиотеки. Вернитесь в Workspace.

Первый трёхсекундный фрагмент в Listening Room

Найдите элементы воспроизведения и перемещения по записи, а также ссылку Download WAV под First preview.

Если входной путь набран неверно, посмотрите ls input, исправьте имя в кавычках и повторите команду. Если ненужный эксперимент уже занял выходное имя, перед повтором удалите только этот файл командой rm -- "single/Morning bells.wav". -- завершает параметры и не означает «удалить всё». На протяжении работы не меняйте library, archive, notes.txt и scratch-other.

Оформите преобразование как повторно используемую функцию

На этом шаге вы передадите вход, выход и длительность одному преобразованию, вместо того чтобы менять команду для каждой записи.

Начните в Workspace, в /home/labex/project/audio-studio. Функция даёт имя группе команд. Внутри make_preview значения $1, $2 и $3 являются аргументами функции. Скрипт получает собственные аргументы и передаёт их дальше по порядку. Кавычки в "$1" сохраняют каждый путь целиком, включая пробелы и Unicode.

Следующий here-document записывает небольшой скрипт. cat > preview-one.sh заменяет этот файл скрипта. <<'BASH' воспринимает следующие строки буквально до строки, содержащей только BASH; кавычки вокруг разделителя не дают текущей оболочке раскрыть $1 при сохранении. Первая строка выбирает Bash при запуске скрипта как программы. Здесь мы явно выполним его через bash.

cat > preview-one.sh <<'BASH'
#!/usr/bin/env bash
make_preview() {
  ffmpeg -nostdin -v error -i "$1" -t "$3" -c:a pcm_s16le "$2"
}
make_preview "$1" "$2" "$3"
BASH

Создайте с помощью функции другой, двухсекундный фрагмент. 2 — аргумент длительности, а не часть какого-либо имени файла.

bash preview-one.sh "input/海辺.wav" "single/海辺.wav" 2
printf 'Conversion exit: %s\n' "$?"

Снова ожидается ноль. Обновите Listening Room, воспроизведите 海辺 под First preview и заметьте, что теперь фрагмент заканчивается на двух секундах. Вернитесь в Workspace. Одна функция уже работает с разными путями и длительностями; далее добавим набор входов.

Обработайте все записи

На этом шаге вы опубликуете новый каталог с фрагментом для каждого входа.

Начните в Workspace. Скрипт принимает ровно три аргумента: входной каталог, новый выходной каталог и целую длительность от одной до пяти секунд. Для первого запуска входной каталог и родительский каталог выхода должны существовать и быть раздельными; сам выход должен находиться вне входа. Существующий выход нужно отклонять, чтобы новый запуск не перезаписал хороший результат. Не запускайте два процесса записи для одного выходного пути одновременно. Это обычная обработка ошибок, а не гарантия безопасности параллельной записи.

Перед записью разберитесь с новыми частями. realpath преобразует существующий входной каталог в абсолютный путь и даёт каждому входу безопасный префикс каталога. shopt -s nullglob делает так, что *.wav без совпадений раскрывается в ноль элементов, а не в буквальный путь со звёздочкой. files=(...) сохраняет совпадения в массиве; кавычки вокруг каталога сохраняют пробелы, а незаключённый в кавычки *.wav продолжает сопоставлять имена. ${#files[@]} считает элементы, а "${files[@]}" передаёт каждый отдельно.

$(command) захватывает вывод команды. || exit 2 останавливает скрипт при её ошибке. Между проверками || означает ИЛИ: [ -e "$2" ] || [ -L "$2" ] считает любой из этих типов существующего объекта основанием для отказа.

case выбирает ветвь; 1|2|3|4|5 разрешает одно из этих значений. [ -e path ] проверяет существование объекта, а -L обнаруживает и символическую ссылку с отсутствующей целью. ${source##*/} удаляет самый длинный префикс, заканчивающийся на /, оставляя имя файла. if ! command выполняет ветвь ошибки, если команда вернула ненулевой код. >&2 отправляет объяснение в поток ошибок, а exit 1 завершает работу с ошибкой.

Замените подготовленный неполный batch.sh первой рабочей версией ниже. Она рассчитана на исправные входы этого занятия. Ошибка преобразования возвращает ненулевой код, но может оставить частично заполненный новый каталог; следующая пошаговая работа научит предотвращать такую публикацию.

cat > batch.sh <<'BASH'
#!/usr/bin/env bash
if [ "$#" -ne 3 ]; then
  printf 'Usage: batch.sh INPUT OUTPUT SECONDS\n' >&2
  exit 2
fi
case "$3" in 1|2|3|4|5) ;; *) exit 2 ;; esac
if [ -e "$2" ] || [ -L "$2" ]; then
  printf 'Output already exists\n' >&2
  exit 2
fi
input=$(realpath -- "$1") || exit 2
shopt -s nullglob
files=("$input"/*.wav)
if [ "${#files[@]}" -eq 0 ]; then
  printf 'No WAV inputs\n' >&2
  exit 1
fi
mkdir -- "$2" || exit 1
make_preview() {
  ffmpeg -nostdin -v error -i "$1" -t "$3" -c:a pcm_s16le "$2"
}
for source in "${files[@]}"; do
  name=${source##*/}
  if ! make_preview "$source" "$2/$name" "$3"; then
    printf 'Could not convert: %s\n' "$name" >&2
    exit 1
  fi
done
printf 'Published %s previews\n' "${#files[@]}"
BASH

Создайте трёхсекундный набор в новом каталоге previews. Опубликованная папка должна содержать ровно один соответствующий WAV на каждый вход, с исходными именами и без дополнительных файлов.

bash batch.sh input previews 3

Ожидается Published 3 previews. Обновите Listening Room. Под Your listening pack воспроизведите все три фрагмента, перемещайтесь внутри каждого и скачайте один. Все длятся три секунды и содержат начало собственной записи, включая -closing. Отдельные эксперименты сохраняются отдельно.

Вернувшись в Workspace, намеренно повторите команду. Это ожидаемый отказ, а не поломка среды.

bash batch.sh input previews 3
printf 'Repeat exit: %s\n' "$?"

Ожидаются Output already exists и Repeat exit: 2. Сохраните хороший набор; для последующих экспериментов выберите другое новое выходное имя. При пустом входе скрипт также может явно завершиться ошибкой, не притворяясь, что создал полезный набор. Теперь у вас есть повторно используемая пакетная обработка; дальше вы улучшите поведение при повреждении одной записи.

Резюме

Вы создали звук, который можно воспроизвести, сохранили полные имена файлов кавычками и объединили функцию с циклом по массиву в повторно используемую обработку Bash. Вы прочитали собственные коды завершения команд и отказались перезаписывать существующий набор. Следующая работа добавляет промежуточный каталог, чтобы не публиковать частичный новый набор после ошибки преобразования.