Путь Unix:
способ проигрывания списка MP3-файлов
Автор: (C) Жаовай [Zhaoway]
Перевод: (C) С.
Скороходов
Уже существует немало навороченных, с кричащим интерфейсом, MP3-проигрывателей для Linux, но ни один из них даже отдаленно не приближается к Истинно Юниксоидному Образу [True Unix Touch-n-Feel]. Все они попались на удочку убогой идеи Гуевого Пользовательского Интерфейса [Gooey User Interface -- игра слов, gooey означает липкий (в контексте завалявшейся в кармане старой конфеты), слащавый, сентиментальный. прим. перев.] и я отказываюсь даже перечислять в этой статье их имена. Ведь статья посвящена Единственно Правлиьному в Unix Способу [The One True Unix Way of doing things]. В конце концов, удовольствие, получаемое от прослушивания, обычно НЕ ПОДРАЗУМЕВАЕТ участие зрения, так почему же не дать глазам роздых, выкинув эти графические примочки и полностью сконцентрировавшись на прекрасной музыке?
Все мы, естественно, убежденные сторонники Linux. (О, я слышу, как вы спрашиваете, почему я говорю Linux, а не Unix? М-м, приятно иметь дело с внимательными читателями -- гы-гы). Но это не означает, что мы менее дружелюбны к новичкам, чем члены любого другого около-компьютерного сообщества. Ни в коем разе! Поэтому я начну с того, что объясню тем из вас, кто еще не прошел Посвящения, в чем, собственно, состоит Единственно Верный UNIX-Способ Сделать Что-либо. Стоп, стоп, стоп! Я услышал, как некоторые из вас пытаются промямлить гадкий, самоуверенный, отравленный философией бред душевнобольного:). О-кей, дадим этим новичкам пинка, а я уж дам вам вкусить от истины из этой статьи. Совет новичкам: просто притовритесь, что вы уже не новичок.
Первым делом бросим взгляд на консольные MP3-проигрыватели. Затем я расскажу
про некоторые гибкие способы управления списками проигрываемых MP3-файлов и
продемонстрирую "нарезку" из коротких шелл-скриптов и маленькую программку на C,
которые помогут нам добиться желаемого. Очень полезная утилита
rename
, входящая в стандартную поставку Perl, она тоже будет кратко представлена.
Рынок предлагает много консольных MP3-проигрывателей. Блин, я хотел сказать
-- Интернет. Но я хочу представить лишь своего любимца:
alsaplayer-text
, уже включенного в поставку Debian GNU/Linux. (Пакет Debian называется
просто alsaplayer-text
). Он используется, а это и интересует нас в
первую очередь, например, так:
% alsaplayer-text -l 85 -n some.mp3 >/dev/null
2>&1;
Ключ -l
управляет громкостью и может принимать значения из
диапазона 0-100. Ключ -n
требует запуска в командном режиме, а
"охвостье" >/dev/null 2>&1
-- обычный способ избавиться
от вывода ненужных сообщений. И помните -- нашего лучшего друга зовут
man
. Изложенного выше вполне достаточно для проигрывания музыки
из скриптов. А с помощью скриптов мы получим максимальную гибкость, причем не
сходя с Единственно Верного "Юниксвея".
Далее, нам понадобится консольный же редактор тэгов ID3. Тэг ID3 -- это
запихнутая в MP3-файл информация, что-либо сообщающая о содержащейся в нем
музыке: название, имя испольнителя и т.д. Редактор тэгов, на который мы положим
свой взгляд назвается mp3info
, он тоже упакован для Debian. Пакет
называетя mp3info
, так что просто сделайте apt-get install
mp3info
, все очень просто (если вам повезло и у вас Debian GNU/Linux).
Теперь рассмотрим сценарий использования, чем и завершим наш брифинг по
управлению MP3-файлами из командной строки:
zw@q ~/mp3/chopin % mp3info chopin:revolutionary_etude:robin_alciatore.mp3 File: chopin:revolutionary_etude:robin_alciatore.mp3 Title: CHOPIN: "REVOLUTIONARY" ETUDE Track: Artist: CHOPIN PIANO FAVORITES Album: Year: Comment: http://www.mp3.com/chopinpiano Genre: Blues [0] zw@q ~/mp3/chopin %
Признаю, что дисплей выглядит неброско, а представленная информация неудовлетворительна. Например, о классическом фортепианном произведении хотелось бы узнать поболее того, что втистнуто в бедный ID3 тэг. Читетели приглашаются вносить собственные улучшения.
Часто хочется проигрывать песни в случайном порядке. Для этого нам нужна
утилита, выбирающая строки в случайном порядке, которая находится здесь: rand.c. Она читает строки (имена файлов) из
stdin
, "перетасовывает" их в случайном порядке, а затем печатает
одну строку за другой в stdout
, вот так:
zw@q ~/mp3/chopin % ls chopin:nocturne_in_c_minor:robin_alciatore.mp3 chopin:nocturne_in_db_major:elena_kuschnerova.mp3 chopin:nocturne_in_e_major:joerg_demus.mp3 chopin:nocturne_in_f#_major:john_bell_young.mp3 chopin:nocturne_in_g_minor:robin_alciatore.mp3 zw@q ~/mp3/chopin % ls|rand chopin:nocturne_in_g_minor:robin_alciatore.mp3 chopin:nocturne_in_e_major:joerg_demus.mp3 chopin:nocturne_in_db_major:elena_kuschnerova.mp3 chopin:nocturne_in_f#_major:john_bell_young.mp3 chopin:nocturne_in_c_minor:robin_alciatore.mp3 zw@q ~/mp3/chopin %
После скачивания MP3-файлов из Интернета, многие файлы содержат в именах
пробелы, а в скриптах имена файлов с пробелами -- это просто вилы. Мы, конечно,
можем смошенничать при помощи "волшебной" переменной окружения
$IFS
, но я предлагаю удобную утилиту, которая поставляется вместе
со стандартным дистрибутивом Perl и позволяет переименовать "пучок" файлов в
соответсвии с регулярным выражением. Леди и джентлмены, поприветствуем
очаровательную /usr/bin/rename
.
zw@q ~/mp3/u2 % ls u2 all that you can't leave behind new york.mp3 u2 all that you can't leave behind peace on earth.mp3 u2 all that you can't leave behind stuck in a moment you can't get over.mp3 zw@q ~/mp3/u2 % rename 's/^(u2) /$1:/; s/(behind) /$1:/; s/ /_/g' *.mp3 zw@q ~/mp3/u2 % ls u2:all_that_you_can't_leave_behind:new_york.mp3 u2:all_that_you_can't_leave_behind:peace_on_earth.mp3 u2:all_that_you_can't_leave_behind:stuck_in_a_moment_you_can't_get_over.mp3 zw@q ~/mp3/u2 %
Ну что, теперь захотелось выучить Perl?
Если вам случалось открывать playlist MP3 (файл с расширением
*.m3u
) в текстовом редакторе, вы видели, что файл содержит не более
чем список полных (с путем) имен музыкальных файлов MP3. Ну и почему бы нам не
пойти дальше и не воспользоваться директориями с жесткими и/или символическими
ссылками для достижения того же эффекта? Ведь скрипты смогут обрабатывать такой
список гораздо легче (например, просто командой ls
), вместо того,
чтобы "парсить" текстовой файл?
В ходе нашей подготовки, мы просто создадим новую директорию-playlist
командой mkdir
, а затем "подошьем" нужные MP3-файлы к этому списку
командой ln
. Если MP3-файл находится в другой файловой системе,
тогда нам придется прибегнуть к символическим ссылкам ln -s
, но
"жесткие" ссылки имеют то преимущество, что, в то время, как перемещение
куда-либо исходных MP3-файлов "бьет" символические ссылки (и, кстати,
традиционные "плейлисты", т.е. файлы *.m3u
, тоже), "жесткие" ссылки
продолжают работать. Поверьте моему опыту, эта "фича" очень важна. Вы просто не
можете себе представить, сколько раз вам захочется переместить MP3-файлы
туда-сюда после того, как они скачаны из И-нета или "содраны" с аудио-CD!
zw@q ~/mp3 % ls chopin classical-all debussy fav nightly u2 zw@q ~/mp3 % find chopin chopin chopin/chopin:nocturne_in_db_major:robin_alciatore.mp3 chopin/chopin:berceuse:robin_alciatore.mp3 chopin/chopin:nocturne_in_db_major:elena_kuschnerova.mp3 chopin/chopin:nocturne_in_c_minor:robin_alciatore.mp3 zw@q ~/mp3 % find nightly nightly nightly/chopin:nocturne_in_db_major:robin_alciatore.mp3 nightly/chopin:berceuse:robin_alciatore.mp3 nightly/ravel:gaspard_de_la_nuit:elena_kuschnerova.mp3 nightly/chopin:nocturne_in_db_major:elena_kuschnerova.mp3 nightly/chopin:nocturne_in_c_minor:robin_alciatore.mp3
Теперь, когда подготовка закончена, привожу фрагмент моего
~/.zshrc
. Приспособить его к вашему любимому шеллу будет несложно.
Немало и возможностей для внесения улучшений. Самым очевидным является
использование для получения информации о произведении mp3info
(как
описывалось выше), вместо того, чтобы полагаться на имя файла.
PLAYLISTS=$HOME/mp3 # Первый аргумент - список для проигрывания # Второй аргумент - громкость воспроизведения play() { # Установка ALSA-драйвера звуковой карты. if [[ -z lsmod | grep snd-card-cmipci ]]; then sudo modprobe snd-card-cmipci; fi # Проигрываем список. while true; do for i in find $PLAYLISTS/$1 -name '*.mp3' | rand ; do j= basename $i | sed -e 's/:/: /g; s/_/ /g; s/,/, /g; s/.mp3$//;' ; echo -n "Проигрываем $j "; alsaplayer-text -l $2 -q -n "$i" >/dev/null 2>&1; echo "ГОТОВО."; done done }
В приведенном фрагменте, мы сначала проверяем, что ALSA-драйвер звуковой
карты уже установлен. Если нет, то устанавливаем его вызовом
modprobe
. Моя "звуковуха" C-Media 8738
требует
ALSA-драйвера smd-card-cmipci
. У вас все, вероятно, будет иначе.
Вы, возможно, вообще не пользуетесь ALSA (Advanced Linux Sound Architecture). В
этой статье я не могу углубляться в то, как наладить звук в Linux. Если у вас
проблемы, или если вам интересна ALSA, загляните на Linux Documentation Project или домашнюю
страницу ALSA. Ну, или обратитесь к
своему местному гуру:).
Этот скрипт проигрывает в случайном порядке все внесенные в список песни, в
чем можно убедиться из приведенного ниже вывода. Пока играется песня можно даже
"перескочить" к следующей песне нажав Ctrl-C
. Нажав
Ctrl-Z
или "kill'нув" процесс, можно остановить проигрывание (что,
конечно, не есть очень элегантный способ).
zw@q ~ % play chopin 75 Playing chopin: nocturne in e major: joerg demus DONE. Playing chopin: nocturne in db major: robin alciatore DONE. Playing chopin: nocturne for violin and piano: alexander skwortsow, violin DONE.
Для достижения удовлетворения результатом, вы можете легко написать собственные скрипты, если, конечно, подключите воображение. Открывайте этот Сезам! Теперь ваша очередь, дорогой читатель! Спасибо, что проследовали со мной по Одному Из Путей Unix! Пока!
Удачи и не вешайте носа!
Код C программы "Строкотасователя"
/* This is m3u rand version 0.1 GNU GPL protected. See COPYRIGHT file * for details. Send bug reports and suggestions to the author: * * (C) Copyright 2001 zhaoway <[email protected]> * * This program randomizes lines read from stdin then writes resulted * lines to stdout. * #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h>
#include <time.h> struct item { char *str; struct item *next; struct item *prev; } *first; /* count the lines */ int lines; void die(char *str) { fprintf(stderr, "m3u-rand: die! %s\n", str); exit(1); } void read_items(void) { struct item *last, *this; size_t zero = 0; lines = 0; first = (struct item *) malloc(sizeof(struct item)); if (first == NULL) die("not enough memory!"); first->str = NULL; first->next = first; first->prev = first; this = first; last = NULL; /* getline() is _GNU_SOURCE */ while (getline(&(this->str), &zero, stdin) != -1) { if (last != NULL) last->next = this; last = this; this = (struct item *) malloc(sizeof(struct item)); if (this == NULL) die("not enough memory!"); this->str = NULL; this->next = first; this->prev = last; lines++; } first->prev = last; free(this); } void disp_items(void) { struct item *this; int count = lines; if (first == NULL) return; else this = first; while (count-- > 0) { printf("%s", this->str); this = this->next; } } void rand_items(void) { int num, count = lines; struct item *this, *last = NULL; if (first == NULL) return; else this = first; srand(time(0)); while (count > 0) { num = rand() % count--; while (num-- > 0) this = this->next; this->prev->next = this->next; this->next->prev = this->prev; if (last != NULL) { last->next = this; this->prev = last; } else first = this; last = this; this = this->next; } first->prev = last; if (last != NULL) last->next = first; } int main(int argc, char *argv[]) { read_items(); rand_items(); disp_items(); return(0); }
Жаовай живет в Наньдзине, в Китае. Свое время он делит между прелестной подружкой, стареьнким "пнем" и чистой математикой. (Он занимается "высшематематическим самообразованием", так что если у вас завалялось несколько лишних, но драгоценных марок и/или книг по высшей математике, то не стесняйтесь послать ему копию). Еще он на добровольной основе участвует в проекте Debian GNU/Linux.
Команда переводчиков: Владимир Меренков, Александр Михайлов, Иван Песин, Сергей Скороходов, Александр Саввин, Роман Шумихин.
Со всеми предложениями, идеями и комментариями обращайтесь к Сергею Скороходову ([email protected])
Сайт рассылки: http://gazette.linux.ru.net