Любое программное обеспечение для обнаружения ударов для Linux?

15585
kolypto

Amarok 2 может искать в музыкальной коллекции, используя поле 'bpm' тега ID3v2. Было бы очень хорошо пометить всю музыкальную коллекцию так, чтобы я мог найти «настроение» трека, который мне нравится.

Однако я не нашел никакого программного обеспечения для обнаружения ударов, которое могло бы мне помочь. Вы когда-нибудь использовали один? CLI, предпочтительно. Также мне интересно, есть ли что-нибудь похожее для пометки FLAC одинаковым полем 'bpm'.

Спасибо! :)

PS Я знаю, что есть хорошая функция панели настроений, но она бесполезна для поиска.

28
ты видел эту страницу? http://www.mmartins.com/mmartins/bpmdetection/bpmdetection.asp Похоже, именно то, что вы ищете. DaveParillo 14 лет назад 3
@DaveParillo, что ссылка «настроение трека» - это ссылка на ваш жесткий диск, и поэтому она бесполезна для всех, кроме вас Justin Smith 14 лет назад 0
@ Джастин Смит, он имел в виду файл в документах BpmDj :) Вот онлайн-версия: http://bpmdj.yellowcouch.org/clustering.html kolypto 14 лет назад 0
@ Джастин - извините - я думаю, дергается спусковой крючок. DaveParillo 14 лет назад 0

9 ответов на вопрос

15
kolypto

На сайте DaveParillo предположил, что я нашел проект BpmDj . У него есть bpmcountисполняемый файл, который очень хорошо вычисляет bpm: он обрабатывает mp3 и flac:

161.135 Metallica/2008 - Death Magnetic/01-That Was Just Your Life.flac 63.5645 Doom3.mp3 

Осталось только пометить коллекцию. Я буду обновлять этот ответ всякий раз, когда мне удастся. Спасибо! :)


Шаг 1

Запустите bpmcountвсю коллекцию и сохраните результаты в текстовый файл. Проблема заключается в том, что bpmcountвремя от времени происходит сбой, и он пытается использовать до 2 ГБ памяти, когда обрабатывает несколько файлов, поэтому мы должны передавать его с именами файлов по одному. Как это:

musicdir='/home/ootync/music' find "$musicdir" -iregex ".*\.\(mp3\|ogg\|flac\|ape\)" -exec bpmcount {} \; \ | fgrep "$musicdir" > "$musicdir/BPMs.txt" 

Шаг 2

Нам понадобятся некоторые дополнительные пакеты: apt-get install vorbis-tools flac python-mutagen. Теперь посмотрим, как можно добавить тег 'bpm':

mid3v2 --TBPM 100 doom3.mp3 vorbiscomment -a -t "BPM=100" mother.ogg metaflac --set-tag="BPM=100" metallica.flac 

Увы, у меня нет * .ape треков

Теперь у нас есть BPM, и вся коллекция должна быть переназначена. Вот сценарий:

cat "$musicdir/BPMs.txt" | while read bpm file ; do bpm=`printf "%.0f" "$bpm"` ; case "$file" in  *.mp3) mid3v2 --TBPM "$bpm" "$file" > /dev/null ;;  *.ogg) vorbiscomment -a -t "BPM=$bpm" "$file" ;;  *.flac) metaflac --set-tag="BPM=$bpm" "$file" ;;  esac done 

Шаг 2.1. Пересмотр. Вот скрипт, который добавит BPM-теги в вашу коллекцию.

Он запускает один процесс на ядро ​​процессора, чтобы ускорить процесс. Кроме того, он не использует временные файлы и способен определять, был ли файл уже помечен.

Кроме того, я обнаружил, что FLAC иногда имеет внутри ID3 и VorbisComment. Этот скрипт обновляет оба.

#!/bin/bash  function display_help() { cat <<-HELP Recursive BPM-writer for multicore CPUs. It analyzes BPMs of every media file and writes a correct tag there. Usage: $(basename "$0") path [...] HELP exit 0 }  [ $# -lt 1 ] && display_help  #=== Requirements requires="bpmcount mid3v2 vorbiscomment metaflac" which $requires > /dev/null || { echo "E: These binaries are required: $requires" >&2 ; exit 1; }  #=== Functions  function bpm_read(){ local file="$1" local ext="$" declare -l ext # Detect { case "$ext" in 'mp3') mid3v2 -l "$file" ;; 'ogg') vorbiscomment -l "$file" ;; 'flac') metaflac --export-tags-to=- "$file" ;; esac ; } | fgrep 'BPM=' | cut -d'=' -f2 } function bpm_write(){ local file="$1" local bpm="$" local ext="$" declare -l ext echo "BPM=$bpm @$file" # Write case "$ext" in 'mp3') mid3v2 --TBPM "$bpm" "$file" ;; 'ogg') vorbiscomment -a -t "BPM=$bpm" "$file" ;; 'flac') metaflac --set-tag="BPM=$bpm" "$file" mid3v2 --TBPM "$bpm" "$file" # Need to store to ID3 as well :( ;; esac }  #=== Process function oneThread(){ local file="$1" #=== Check whether there's an existing BPM local bpm=$(bpm_read "$file") [ "$bpm" != '' ] && return 0 # there's a nonempty BPM tag #=== Detect a new BPM # Detect a new bpm local bpm=$(bpmcount "$file" | grep '^[0-9]' | cut -f1) [ "$bpm" == '' ] && { echo "W: Invalid BPM '$bpm' detected @ $file" >&2 ; return 0 ; } # problems # Write it bpm_write "$file" "$" >/dev/null }  NUMCPU="$(grep ^processor /proc/cpuinfo | wc -l)" find $@ -type f -regextype posix-awk -iregex '.*\.(mp3|ogg|flac)' \ | while read file ; do [ `jobs -p | wc -l` -ge $NUMCPU ] && wait echo "$file" oneThread "$file" & done 

Наслаждайтесь! :)

Отлично! Я не удосужился попробовать это прошлой ночью. Что касается тегов командной строки, попробуйте mid3v2: http://linux.die.net/man/1/mid3v2, работоспособный по крайней мере до тех пор, пока Ex Falso не поддержит редактирование командной строки. Последний идентификатор id3v2 - «TBPM» DaveParillo 14 лет назад 0
Спасибо, попробую через пару дней и опубликую результаты :) Интересно, поддерживает ли FLAC такую ​​вещь: мне придется это проверить. kolypto 14 лет назад 1
Хорошая работа на шаге № 2. Хотелось бы, чтобы я проголосовал дважды! DaveParillo 14 лет назад 1
Спасибо :) Увы, мой Amarok не заметил новый тег во FLAC, который мне больше всего понравился :). kolypto 14 лет назад 1
Как вы это установили? Представленные ими обороты не работают на моем компьютере, и я борюсь с компиляцией. pedrosaurio 12 лет назад 0
@pedrosaurio, я скомпилировал его :) Просто внимательно посмотрите на ошибки, которые вы получаете во время `make`, и установите упомянутые пакеты kolypto 12 лет назад 0
По-видимому, bpmdj - это приложение для Android; как вы извлекли из него функцию bpmcount? Это доступно отдельно отдельно или нам нужно купить приложение? Benubird 9 лет назад 0
@ kolypto ссылка больше не работает на исходный код. Это то же самое, что и [это] (http://bpmdj.yellowcouch.org/try-desktop.html)? max pleaner 8 лет назад 0
8
mmx

Это инструмент командной строки, чтобы обнаружить BPM и поместить его в теги файла FLAC:

http://www.pogo.org.uk/~mark/bpm-tools/

Последняя версия также обрабатывает mp3 и ogg vorbis. encoded 11 лет назад 0
В Ubuntu есть [пакеты bpm-tools] (http://packages.ubuntu.com/saucy/bpm-tools), доступные в saucy. naught101 10 лет назад 0
5
meridius

I used kolypto's original script using bpmcount and rewrote it for bpm-tag (utility of bpm-tools) which I had better luck with installing. I also made some improvements of my own.

You can find it on GitHub https://github.com/meridius/bpmwrap

Для работы на Mac потребовалось несколько модификаций, которые я включил в свой ответ ниже (потому что это слишком долго для комментария) Adrian 8 лет назад 0
2
DaveParillo

Я не знаю инструмента, который делает именно то, что вы ищете, но я играл с MusicIP .

Использовал версию linux / java - для полного анализа музыкальной библиотеки требуется много времени, но это действительно работает. Вы можете найти песни, которые похожи на другие песни. Вы можете щелкнуть правой кнопкой мыши по сгенерированному плейлисту и выбрать опцию, чтобы выбрать больше или меньше песен, подобных выбранной. Вы также можете выбрать для устранения определенных жанров. Это круто, но после того, как фактор вау исчез, я перестал им пользоваться.

Бесплатная версия экспортирует плейлисты до 75 песен в (как минимум) формате m3u.

В настоящее время он не поддерживается, но я думаю, что они пытались сделать его коммерческим, как Predexis .

1
Dom

Хотя это не просто инструмент, который, как вы говорите, вы ищете, медиаплеер Banshee может определять удары в минуту.

Я использую Banshee для воспроизведения, организации и синхронизации музыки с портативными плеерами. Я не аффилирован, но мне больше всего нравится программа, которую я пробовал. Он также может генерировать «умные плейлисты» на основе всевозможных свойств треков, включая bpm.

Существует расширение, которое анализирует всевозможные вещи о песне и найдет песни, похожие на ту, которую вы играете. Он называется Mirage, и я использовал его некоторое время, но больше не пользуюсь, поскольку создал несколько плейлистов, которые соответствуют разным настроениям (не обязательно похожи по словам Mirage).

Я не знаю, сохранит ли Banshee bpm, который он обнаружил, обратно в тег ID3v2 "bpm" файла. Если кто-нибудь знает, как легко проверить тег bpm из-за пределов программы, я проверю.

1
Shevek

Это не Linux, но может хорошо работать в Wine - я использую MixMeister BPM Analyzer

0
Sergio

Я нашел другой инструмент для пометки файлов MP3 с правильным значением BPM.

Это называется BPMDetect . Открытый исходный код. QT libs отлично работает под Gnome. Поставляется с графическим интерфейсом, но может быть скомпилирован как версия только для консоли (запустите "scons console = 1", как указано в readme.txt).

Иначе, в конце концов, я тоже использовал «bpmcount» из BpmDJ, так как у меня были трудности с компиляцией BPMDetect на 64-битном хосте Ubuntu (из-за зависимости fmodex). Поэтому я взял (очень крутой и хорошо написанный) сценарий оболочки выше (см. Ниже), двоичный файл "bpmcount", извлеченный из [x64 .rpm] [3], доступного на веб-сайте BpmDJ (я только что извлек .rpm с

pm2cpio bpmdj-4.2.pl2-0.x86_64.rpm|cpio -idv 

и это сработало как шарм. Мне просто нужно было изменить вышеописанный скрипт, так как он не работал на моей стороне (проблема с stdout / stderr двоичного файла bpmcount). Моя модификация о перенаправлении файла:

local bpm=$(bpmcount "$file" 3>&1 1>/dev/null 2>&3 | grep '^[0-9]' | cut -f1) 
0
J. Katzwinkel

В этом вопросе по стеку рекомендуется другой инструмент : aubio, который поставляется вместе с модулями python.

Я не пробовал, потому что был немного занят, заботясь о компиляции BpmDj . На случай, если кто-то еще столкнется с подобными проблемами во время попытки, я настоятельно рекомендую убедиться:

  1. скачав последнюю версию исходников BpmDj
  2. имея соответствующие библиотеки повышения

С последними обновлениями компилятора g ++, похоже, возникли некоторые проблемы, особенно касающиеся последних выпусков Debian и Ubuntu. Как только он узнал об этих проблемах, автор проявил любезность, чтобы исправить возникшие несовместимости и собрать новый выпуск, который теперь компилируется как шарм. Так что любой, кто был близок к тому, чтобы впадать в отчаяние из-за неумолимых ошибок компиляции в последнее время: вы спасены сейчас.

@ mmx, ваши инструменты тоже хорошо выглядят, но они полагаются SoX, что по умолчанию не имеет функций mp3. Поэтому им нужно сначала скомпилировать SoX с поддержкой Lame / MAD, что, к сожалению, слишком много усилий для таких же ленивых людей, как я.

0
Adrian

Чтобы заставить решение @meridius работать на моем Mac, мне пришлось немного поработать и немного изменить скрипт:

# Let's install bpm-tools git clone http://www.pogo.org.uk/~mark/bpm-tools.git cd bpm-tools make && make install # There will be errors, but they did not affect the result  # The following three lines could be replaced by including this directory in your $PATH ln -s <absolute path to bpm-tools>/bpm /usr/local/bin/bpm ln -s <absolute path to bpm-tools>/bpm-tag /usr/local/bin/bpm-tag ln -s <absolute path to bpm-tools>/bpm-graph /usr/local/bin/bpm-graph cd ..  # Time to install a bunch of GNU tools # Not all of these packages are strictly necessary for this script, but I decided I wanted the whole GNU toolchain in order to avoid this song-and-dance in the future brew install coreutils findutils gnu-tar gnu-sed gawk gnutls gnu-indent gnu-getopt bash flac vorbis-tools brew tap homebrew/dupes; brew install grep  # Now for Mutagen (contains mid3v2) git clone https://github.com/nex3/mutagen.git cd mutagen ./setup.py build sudo ./setup.py install # There will be errors, but they did not affect the result cd .. 

Затем мне пришлось изменить скрипт, чтобы он указывал на GNU-версии всего и несколько других настроек:

#!/usr/local/bin/bash  # ================================= FUNCTIONS =================================  function help() { less <<< 'BPMWRAP  Description: This BASH script is a wrapper for bpm-tag utility of bpm-tools and several audio tagging utilities. The purpose is to make BPM (beats per minute) tagging as easy as possible. Default behaviour is to look through working directory for *.mp3 files and compute and print their BPM in the following manner: [current (if any)] [computed] [filename]  Usage: bpmwrap [options] [directory or filenames]  Options: You can specify files to process by one of these ways: 1) state files and/or directories containing them after options 2) specify --import file 3) specify --input file With either way you still can filter the resulting list using --type option(s). Remember that the script will process only mp3 files by default, unless specified otherwise!  -i, --import file Use this option to set BPM tag for all files in given file instead of computing it. Expected format of every row is BPM number and absolute path to filename separated by semicolon like so: 145;/home/trinity/music/Apocalyptica/07 beyond time.mp3 Remember to use --write option too. -n, --input file Use this option to give the script list of FILES to process INSTEAD of paths where to look for them. Each row whould have one absolute path. This will bypass the searching part and is that way useful when you want to process large number of files several times. Like when you are not yet sure what BPM limits to set. Extension filtering will still work. -o, --output file Save output also to a file. -l, --list-save file Save list of files about to get processed. You can use this list later as a file for --input option. -t, --type filetype Extension of file type to work with. Defaults to mp3. Can be specified multiple times for more filetypes. Currently supported are mp3 ogg flac. -e, --existing-only Only show BPM for files that have it. Do NOT compute new one. -w, --write Write computed BPM to audio file but do NOT overwrite existing value. -f, --force Write computed BPM to audio file even if it already has one. Aplicable only with --write option. -m, --min minbpm Set minimal BPM to look for when computing. Defaults to bpm-tag minimum 84. -x, --max maxbpm Set maximal BPM to look for when computing. Defaults to bpm-tag maximum 146. -v, --verbose Show "progress" messages. -c, --csv-friendly Use semicolon (;) instead of space to separate output columns. -h, --help Show this help.  Note: Program bpm-tag (on whis is this script based) is looking only for lowercase file extensions. If you get 0 (zero) BPM, this should be the case. So just rename the file.  License: GPL V2  Links: bpm-tools (http://www.pogo.org.uk/~mark/bpm-tools/)  Dependencies: bpm-tag mid3v2 vorbiscomment metaflac  Author: Martin Lukeš (martin.meridius@gmail.com) Based on work of kolypto (http://superuser.com/a/129157/137326) ' }  # Usage: result=$(inArray $needle haystack[@]) # @param string needle # @param array haystack # @returns int (1 = NOT / 0 = IS) in array function inArray() { needle="$1" haystack=("${!2}") out=1 for e in "$" ; do if [[ "$e" = "$needle" ]] ; then out=0 break fi done echo $out }  # Usage: result=$(implode $separator array[@]) # @param char separator # @param array array to implode # @returns string separated array elements function implode() { separator="$1" array=("${!2}") IFSORIG=$IFS IFS="$separator" echo "$" IFS=$IFSORIG }  # @param string file # @returns int BPM value function getBpm() { local file="$1" local ext="$" declare -l ext # convert to lowercase { case "$ext" in 'mp3') mid3v2 -l "$file" ;; 'ogg') vorbiscomment -l "$file" ;; 'flac') metaflac --export-tags-to=- "$file" ;; esac ; } | fgrep 'BPM=' -a | cut -d'=' -f2 }  # @param string file # @param int BPM value function setBpm() { local file="$1" local bpm="$" local ext="$" declare -l ext # convert to lowercase case "$ext" in 'mp3') mid3v2 --TBPM "$bpm" "$file" ;; 'ogg') vorbiscomment -a -t "BPM=$bpm" "$file" ;; 'flac') metaflac --set-tag="BPM=$bpm" "$file" mid3v2 --TBPM "$bpm" "$file" # Need to store to ID3 as well :( ;; esac }  # # @param string file # # @returns int BPM value function computeBpm() { local file="$1" local m_opt="" [ ! -z "$m" ] && m_opt="-m $m" local x_opt="" [ ! -z "$x" ] && x_opt="-x $x" local row=$(bpm-tag -fn $m_opt $x_opt "$file" 2>&1 | fgrep "$file") echo $(echo "$row" \ | gsed -r 's/.+ ([0-9]+\.[0-9]) BPM/\1/' \ | gawk '') }  # @param string file # @param int file number # @param int BPM from file list given by --import option function oneThread() { local file="$1" local filenumber="$2" local bpm_hard="$3" local bpm_old=$(getBpm "$file") [ -z "$bpm_old" ] && bpm_old="NONE" if [ "$e" ] ; then # only show existing myEcho "$filenumber/$NUMFILES$$bpm_old$$file" else # compute new one if [ "$bpm_hard" ] ; then local bpm_new="$bpm_hard" else local bpm_new=$(computeBpm "$file") fi [ "$w" ] && { # write new one if [[ ! ( ("$bpm_old" != "NONE") && ( -z "$f" ) ) ]] ; then setBpm "$file" "$bpm_new" else [ "$v" ] && myEcho "Non-empty old BPM value, skipping ..." fi } myEcho "$filenumber/$NUMFILES$$bpm_old$$bpm_new$$file" fi }  function myEcho() { [ "$o" ] && echo -e "$1" >> "$o" echo -e "$1" }   # ================================== OPTIONS ==================================  eval set -- $(/usr/local/Cellar/gnu-getopt/1.1.6/bin/getopt -n $0 -o "-i:n:o:l:t:ewfm:x:vch" \ -l "import:,input:,output:,list-save:,type:,existing-only,write,force,min:,max:,verbose,csv-friendly,help" -- "$@")  declare i n o l t e w f m x v c h declare -a INPUTFILES declare -a INPUTTYPES while [ $# -gt 0 ] ; do case "$1" in -i|--import) shift ; i="$1" ; shift ;; -n|--input) shift ; n="$1" ; shift ;; -o|--output) shift ; o="$1" ; shift ;; -l|--list-save) shift ; l="$1" ; shift ;; -t|--type) shift ; INPUTTYPES=("$" "$1") ; shift ;; -e|--existing-only) e=1 ; shift ;; -w|--write) w=1 ; shift ;; -f|--force) f=1 ; shift ;; -m|--min) shift ; m="$1" ; shift ;; -x|--max) shift ; x="$1" ; shift ;; -v|--verbose) v=1 ; shift ;; -c|--csv-friendly) c=1 ; shift ;; -h|--help) h=1 ; shift ;; --) shift ;; -*) echo "bad option '$1'" ; exit 1 ;; #FIXME why this exit isn't fired? *) INPUTFILES=("$" "$1") ; shift ;; esac done   # ================================= DEFAULTS ==================================  #NOTE Remove what requisities you don't need but don't try to use them after! # always mp3/flac ogg flac REQUIRES="bpm-tag mid3v2 vorbiscomment metaflac" which $REQUIRES > /dev/null || { myEcho "These binaries are required: $REQUIRES" >&2 ; exit 1; }  [ "$h" ] && { help exit 0 }  [[ $m && $x && ( $m -ge $x ) ]] && { myEcho "Minimal BPM can't be bigger than NOR same as maximal BPM!" exit 1 } [[ "$i" && "$n" ]] && { echo "You cannot specify both -i and -n options!" exit 1 } [[ "$i" && ( "$m" || "$x" ) ]] && { echo "You cannot use -m nor -x option with -i option!" exit 1 } [ "$e" ] && { [[ "$w" || "$f" ]] && { echo "With -e option you don't have any value to write!" exit 1 } [[ "$m" || "$x" ]] && { echo "With -e option you don't have any value to count!" exit 1 } }  for file in "$o" "$l" ; do if [ -f "$file" ] ; then while true ; do read -n1 -p "Do you want to overwrite existing file $? (Y/n): " key case "$key" in y|Y|"") echo "" > "$file" ; break ;; n|N) exit 0 ;; esac echo "" done echo "" fi done  [ ${#INPUTTYPES} -eq 0 ] && INPUTTYPES=("mp3")  # NUMCPU="$(ggrep ^processor /proc/cpuinfo | wc -l)" NUMCPU="$(sysctl -a | ggrep machdep.cpu.core_count | gsed -r 's/(.*)([0-9]+)(.*)/\2/')" LASTPID=0 TYPESALLOWED=("mp3" "ogg" "flac") # declare -A BPMIMPORT # array of BPMs from --import file, keys are file names declare -A BPMIMPORT # array of BPMs from --import file, keys are file names  for type in "$" ; do [[ $(inArray $type TYPESALLOWED[@]) -eq 1 ]] && { myEcho "Filetype $type is not one of allowed types ($)!" exit 1 } done  ### here are three ways how to pass files to the script... if [ "$i" ] ; then # just parse given file list and set BPM to listed files if [ -f "$i" ] ; then # myEcho "Setting BPM tags from given file ..." while read row ; do bpm="$" file="$" ext="$" ext="$" # convert to lowercase if [ -f "$file" ] ; then if [ $(inArray $ext INPUTTYPES[@]) -eq 0 ] ; then FILES=("$" "$file") BPMIMPORT["$file"]="$bpm" else myEcho "Skipping file on row $rownumber (unwanted filetype $ext) ... $file" fi else myEcho "Skipping non-existing file $file" fi done < "$i" else myEcho "Given import file does not exists!" exit 1 fi elif [ "$n" ] ; then # get files from file list if [ -f "$n" ] ; then rownumber=1 while read file ; do if [ -f "$file" ] ; then ext="$" ext="$" # convert to lowercase if [ $(inArray $ext INPUTTYPES[@]) -eq 0 ] ; then FILES=("$" "$file") else myEcho "Skipping file on row $rownumber (unwanted filetype $ext) ... $file" fi else myEcho "Skipping file on row $rownumber (non-existing) ... $file" fi let rownumber++ done < "$n" unset rownumber else myEcho "Given input file $n does not exists!" exit 1 fi else # get files from given parameters [ ${#INPUTFILES[@]} -eq 0 ] && INPUTFILES=`pwd` for file in "$" ; do [ ! -e "$file" ] && { myEcho "File or directory $file does not exist!" exit 1 } done impl_types=`implode "|" INPUTTYPES[@]` while read file ; do echo -ne "Creating list of files ... (${#FILES[@]}) $\033[0K"\\r FILES=("$" "$file") done < <(gfind "$" -type f -regextype posix-awk -iregex ".*\.($impl_types)") echo -e "Counted ${#FILES[@]} files\033[0K"\\r fi  [ "$l" ] && printf '%s\n' "$" > "$l"  NUMFILES=${#FILES[@]} FILENUMBER=1  [ $NUMFILES -eq 0 ] && { myEcho "There are no $ files in given files/paths." exit 1 }  declare SEP=" " [ "$c" ] && SEP=";"   # =============================== MAIN SECTION ================================  if [ "$e" ] ; then # what heading to show myEcho "num$old$filename" else myEcho "num$old$new$filename" fi  for file in "$" ; do [ `jobs -p | wc -l` -ge $NUMCPU ] && wait [ "$v" ] && myEcho "Parsing ($/$)\t$file ..." oneThread "$file" "$FILENUMBER" "$" & LASTPID="$!" let FILENUMBER++ done  [ "$v" ] && myEcho "Waiting for last process ..." wait $LASTPID [ "$v" ] && myEcho \\n"DONE" 

Спасибо за ваш тяжелый труд @kolypto и @meridius.

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

Похожие вопросы