Вы находитесь на странице: 1из 64

МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ

Федеральное государственное автономное образовательное учреждение


высшего образования
«Южно-Уральский государственный университет
(национальный исследовательский университет)»
Высшая школа электроники и компьютерных наук
Кафедра системного программирования

РАБОТА ПРОВЕРЕНА ДОПУСТИТЬ К ЗАЩИТЕ


Рецензент Заведующий кафедрой, д.ф.-м.н.,
Ст. преподаватель кафедры МиМОМ профессор
ФГБОУ ВО «ЮУрГГПУ», к.ф.-м.н. __________ Л.Б. Соколинский
__________ А.М. Шарафутдинова
«___»___________ 2021 г.
«___»_______________ 2021 г.

Разработка веб-приложения для определения степени


сходства музыкальных треков

ВЫПУСКНАЯ КВАЛИФИКАЦИОННАЯ РАБОТА


ЮУрГУ – 02.04.02.2021.308-453.ВКР

Научный руководитель,
доцент кафедры СП, к.ф.-м.н.
__________ С.А. Иванов

Автор работы,
студент группы КЭ-220
__________ Д.И. Ураканов

Ученый секретарь
(нормоконтролер)
_____________ И.Д. Володченко
«___»___________ 2021 г.

Челябинск, 2021 г.
МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ
Федеральное государственное автономное образовательное учреждение
высшего образования
«Южно-Уральский государственный университет
(национальный исследовательский университет)»
Высшая школа электроники и компьютерных наук
Кафедра системного программирования

УТВЕРЖДАЮ
Зав. кафедрой СП
__________ Л.Б. Соколинский
08.02.2021 г.

ЗАДАНИЕ
на выполнение выпускной квалификационной работы магистра
студенту группы КЭ-220
Ураканову Денису Ивановичу,
обучающемуся по направлению
02.04.02 «Фундаментальная информатика и информационные технологии»
(магистерская программа «Машинное обучение и анализ больших данных»)

1. Тема работы (утверждена приказом ректора от 26.04.2021 г. № 714-13/12)


Разработка веб-приложения для определения степени сходства музыкальных
треков.
2. Срок сдачи студентом законченной работы: 28.05.2021 г.
3. Исходные данные к работе
3.1. How does Shazam work [Электронный ресурс] URL: http://coding-
geek.com/how-shazam-works/ (дата обращения: 07.02.2021 г.).
3.2. An Industrial-Strength Audio Search Algorithm [Электронный ресурс]
URL: https://www.ee.columbia.edu/~dpwe/papers/Wang03-shazam.pdf (дата об-
ращения: 07.02.2021 г.).
3.3. Audio Fingerprinting Extraction Based on Locally Linear Embedding for Au-
dio Retrieval System [Электронный ресурс] URL: https://www.mdpi.com/2079-
9292/9/9/1483 (дата обращения: 07.02.2021 г.).
4. Перечень подлежащих разработке вопросов
4.1. Провести анализ существующих алгоритмов определения схожих треков
и выполнить обзор аналогов.
4.2. Выполнить проектирование архитектуры приложения.
4.3. Осуществить выбор средств реализации задачи.
4.4. Организовать структуру баз данных и очередей сообщений.
4.5. Реализовать модуль системы поиска схожих записей.
4.6. Реализовать серверную и клиентскую части веб-приложения.
4.7. Протестировать разработанное веб-приложение.
5. Дата выдачи задания: 08.02.2021 г.

Научный руководитель,
доцент кафедры СП, к.ф.-м.н. С.А. Иванов

Задание принял к исполнению Д.И. Ураканов


ОГЛАВЛЕНИЕ
ВВЕДЕНИЕ .......................................................................................................... 5
1. ТЕОРЕТИЧЕСКАЯ ЧАСТЬ ........................................................................... 7
1.1 Обзор литературы изучаемой темы .................................................. 7
1.2. Базовый принцип работы .................................................................. 9
1.2. Подход к созданию отпечатка .......................................................... 9
1.4. Согласованность по времени .......................................................... 11
1.5. Удаление выбросов в наборе дельт ................................................ 13
1.6. Ранжирование списка схожих аудиозаписей ................................ 14
1.7. Обзор аналогов ................................................................................. 14
2. ПРОЕКТИРОВАНИЕ ................................................................................... 17
2.1. Требования к системе ...................................................................... 17
2.2. Варианты использования ................................................................ 18
2.3. Общая архитектура системы........................................................... 19
2.4. Управление профилем и списком аудиозаписей .......................... 20
2.5. Состояние объекта класса аудиозаписи ........................................ 25
3. РЕАЛИЗАЦИЯ .............................................................................................. 27
3.1. Организация схемы реляционной базы данных ........................... 27
3.2. Организация очередей сообщений ................................................. 29
3.3. Реализация модуля создания отпечатка ........................................ 30
3.4. Реализация модуля выполнения анализа ....................................... 42
3.4. Реализация модуля Rest-сервер ...................................................... 48
3.5. Реализация модуля SPA .................................................................. 51
4. ТЕСТИРОВАНИЕ ......................................................................................... 56
4.1. Модульное тестирование ................................................................ 56
4.2. Функциональное тестирование ...................................................... 58
4.3. Проверка качества поиска схожих треков..................................... 59
ЗАКЛЮЧЕНИЕ ................................................................................................. 62
ЛИТЕРАТУРА ................................................................................................... 63
ВВЕДЕНИЕ
Актуальность
На сегодняшний день существуют множество способов передачи ме-
диа контента (видео, аудио). Известные музыкальные сервисы оснащены си-
стемой рекомендаций по существующей библиотеки. Но на данный момент
нет удобной возможности исполнителям искать схожие аудиозаписи по
определенному треку вне какого-либо известного сервиса с алгоритмами ре-
комендаций.
Актуальность темы, связанной с созданием сервиса по определению
степени сходства музыкальных треков, заключается в том, что множество
создателей аудиокомпозиций желают оценить свои произведения на сход-
ство с другими. Данная задача не заключается в нахождении определенного
единственного трека, что уже успешно и очень быстро выполняют суще-
ствующие на рынке приложения, а в составлении списка схожих треков на
данную аудиозапись. Обычным пользователям иногда нужна помощь в
нахождении похожего аудио-трека в личной библиотеки записей, а не в об-
лачном глобальном хранилище стримингового сервиса.
На основании вышеизложенного можно утверждать, что инструмент,
предоставляющий возможности нахождения схожих аудио треков, может
быть актуален.
Постановка задачи
Целью данной выпускной квалификационной работы является разра-
ботка веб-приложения для определения степени сходства музыкальных тре-
ков.
Для достижения поставленной цели, необходимо решить следующие
задачи:
1) провести анализ существующих алгоритмов определения схожих
треков и выполнить обзор аналогов;
2) выполнить проектирование архитектуры приложения;

5
3) осуществить выбор средств реализации задачи;
4) организовать структуру баз данных и очередей сообщений;
5) реализовать модуль системы поиска схожих записей;
6) реализовать серверную и клиентскую части веб-приложения;
7) протестировать разработанное веб-приложение.
Структура и содержание работы
Работа состоит из введения, четырех глав, заключения и списка лите-
ратуры. Объем работы составляет 64 страницы, объем списка литературы –
21 источник.
Первая глава «Теоретическая часть» содержит обзор и сравнительное
исследование существующих подходов для поиска схожих аудиозаписей. В
главе рассмотрены основные пункты одного из алгоритмов для дальнейшей
реализации. В данной части также приводится сравнительный обзор анало-
гов на рынке.
Вторая глава «Проектирование» посвящена проектированию архитек-
туры веб-приложения для определения степени сходства музыкальных тре-
ков. В главе описаны основные компоненты системы, которые необходимо
реализовать.
В третьей главе «Реализация» содержится описание основных шагов
для реализации каждого компонента и интеграции в единую систему. В
главе предлагаются также собственные решения поставленных задач и их
обоснования.
В четвертой главе «Тестирование» приведены результаты тестов и
экспериментов для демонстрации степени корректной работы веб-приложе-
ния.
В заключении перечислены достигнутые результаты в выполнении за-
дач и приведены направления дальнейших исследований.

6
1. ТЕОРЕТИЧЕСКАЯ ЧАСТЬ
1.1 Обзор литературы изучаемой темы
Литература, посвященная анализу звуковых сигналов и спектрограмм,
появилась задолго до создания систем анализа музыкальных записей. Од-
ним из первых приложений на массовом рынке стал Shazam. Со-основатель
компании-разработчика Ли-Чун Ванг написал статью [1] о глобальной кон-
цепции работы такого типа систем. В рамках данной статьи описываются
основные подходы к созданию алгоритма, устойчивого к шумам и искаже-
ниям, вычислительно эффективного и масштабируемого, способного
быстро идентифицировать короткий фрагмент музыки, записанной даже че-
рез микрофон телефона при наличии голосов на переднем плане, шумов, и
подвергающемуся сжатию кодека.
Основное понятие в данной статье и дальнейшей работе это отпечаток
аудиозаписи. «Отпечаток» аудиозаписи – это набор хеш-токенов, определя-
ющие идентификатор записи в ключе и некоторую адресацию частот в спек-
трограмме, хешированную, например, в формате md5, в значении ключа. Та-
кой «отпечаток» позволяет хранить основную информацию об аудиозаписи
в удобном формате в специальных хранилищах типа «hash-value» для быст-
рого доступа к ним.
Алгоритм, описанный в статье, определяет основные шаги для созда-
ния такой системы: оцифровка, дискретизация, перевод от стерео к моно,
даунсэмплинг (снижение частоты дискретизации), выполнение FFT (Быст-
рое преобразование Фурье), построение спектрограммы, выделение наибо-
лее сильных частот в единицу времени, сохранение в базу данных
хеш-токенов (отпечатков) и сравнение отпечатков записей между собой.
Более подробно с содержательным описанием оригинального доку-
мента процессы создания отпечатка описываются в статье в Интернете [5].
Здесь основные шаги, описанные в статье, вполне полно иллюстрируют про-
цесс, но детали, которые необходимы при разработке аналогичной системы,

7
опускаются или на них мало обращается внимание. Например, выполнение
даунсэмплинга должно зависеть от ряда параметров, но каких именно, в ста-
тье не указывается. Или, например, при создании хэш-токена, требуется вы-
числить определенную разницу во времени. В статьях не указаны приемы и
способы нахождения наиболее оптимальных значений для хэш-токена.
В статье [3] предпринята попытка создания алгоритма, основанной на
локально-линейном внедрении (Local Linear Embedding, LLE) с получением
отпечатка аудиозаписи, который потенциально занимает меньше места в
хранилище. Таким образом, анализатор меньше тратит времени на операции
чтение и записи с хранилищем. В данном алгоритме полосы делятся вокруг
каждого пика в частотной области на четыре группы подобластей, и вычис-
ляется энергия каждой подобласти. Затем выполняется алгоритм LLE для
каждой группы, а отпечаток аудиозаписи кодируется путем сравнения со-
седних энергий.
Общее между классическим подходом в Shazam и LLE в том, что со-
храняются не просто значения пиковых частот в аудиозаписи, а относитель-
ное положение определенной частоты среди ближайших к нему пиковых ча-
стот. Такой подход на порядок лучше «грубой силы» (brute force) тем, что
требуется меньше места в хранилище отпечатков. Разница в том, что LLE
оперирует понятиями «энергия области вокруг пиковой частоты», в то же
время, в классическом подходе выполняется получение относительного по-
ложения точки сигнала с помощью нахождения разницы во времени между
интересующей частотой и соседними.
В данной работе будет рассмотрен и реализован алгоритм на основа-
нии статьи [1] в рамках функционала необходимого для осуществления по-
ставленных требований.

8
1.2. Базовый принцип работы
В статье [1] предлагается, что каждый аудиофайл подвергается созда-
нию отпечатка – процессу извлечения воспроизводимых хеш-токенов. От-
печатки неизвестного образца сравниваются с большим набором отпечат-
ков, полученными из базы данных. И база данных, и исследуемый
аудиофайл подвергаются одинаковому процессу создания отпечатка.
Соответствующие кандидатуры впоследствии оцениваются на пред-
мет правильности совпадения. Один из критериев правильности совпадения
является синхронизация по времени. Группа хеш-токенов может быть ло-
кально равно удалена от той же идентичной группы хеш-токенов другой
аудиозаписи, что может означать, что исследуемая аудиозапись является ча-
стью из любого временного диапазона другой аудиозаписи.
Для решения проблемы надежной идентификации песен при наличии
шумов и искажений необходимо принимать в расчет только наиболее силь-
ные по амплитуде частоты в срезе временной области. Такие пики в каждой
временной области с наибольшей вероятностью выдержат искажения.
Наборы таких пиков на спектрограмме двух похожих аудиозаписей будет
достаточно или полностью схожими. Спектрограмма отображает мощность
сигнала с течением времени на различных частотах [11]. Спектрограммы
могут быть двухмерными графиками с третьей переменной, представленной
цветом, или трехмерными графиками с четвертой цветовой переменной.

1.2. Подход к созданию отпечатка


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

9
Вместо того, чтобы сравнивать каждую частотно-временную точку на
спектрограмме одну за другой, необходимо искать несколько точек одно-
временно – в Shazam эта группа точек называется целевой зоной [12].
Чтобы быть уверенным в том, что и отрывок, и полная песня, будут
генерировать одни и те же целевые зоны, понадобятся соотношения между
частотно-временными точками в фильтрованной спектрограмме.
1. Если две частотно-временные точки имеют одинаковое время, то
точка с самой низкой частотой идет первой.
2. Впереди идут точки с самым маленьким временем.
Далее необходимо создать относительные адреса сразу целевой зоны,
а не определенной одной точки. Необходимо выбрать опорную точку за пре-
делом самой целевой зоны.
Допустим, что для работы размер целевой зоны равен 5, а опорная
точка – это третья точка перед каждой зоной.

Рисунок 1 – Визуализация целевой зоны, целевой точки и опорной точки

10
На рисунке 1 продемонстрирован график, на котором ось абсцисс это
время, ось ординат – это частота. Точка номер «0» является опорной точкой,
а точка номер «3» является целевой точкой.
Далее необходимо сформировать адрес следующего плана:
[«Частота опорной точки», «Частота целевой точки», «Разница во вре-
мени между опорной точкой и целевой точкой»].
Например, адрес точки номер «4» в рамках зоны отмеченной на ри-
сунке 1 будет [10, 10, 2], а для точки номер «6» в той же зоне [10, 30, 2].
Для более оптимального хранения в виде ключа в «hash-value» храни-
лище адрес в виде массива можно захэшировать в md5.
Статья [5], описывающая основы работы системы Shazam, указывает,
что в рамках значения захэшированного ключа следует использовать кор-
теж из абсолютного времени опорной точки в песне и идентификатора
песни в реляционной базе. Абсолютное время опорной точки необходимо
для согласованности по времени.

1.4. Согласованность по времени


На рисунке 2 изображен возможный сымитированный случай, когда
существуют две целевые зоны, которые принадлежат двум различным пес-
ням (верхний график – к первой исследуемой песне, нижний – ко второй).
То есть целевые зоны просто поменяли местами в этих аудиозаписях. Если
не учитывать временную согласованность, эти целевые зоны увеличивали
бы процент совпадения между двумя песнями, в то время как они звучат по-
разному, поскольку ноты в этих целевых зонах не воспроизводятся в одина-
ковом порядке.
Таким образом, следует дать оценку на схожесть двух аудиозаписей
не только исходя из наличия одинаковых ключей в хранилище и их количе-
ства, но из согласованности во времени. Именно поэтому в хранилище в зна-
чении поля ключа сохраняется абсолютное время.

11
Рисунок 2 – Похожие целевые зоны в разных аудиозаписях

С помощью абсолютного времени возможно найти разницу (дельту)


между интересующей аудиозаписью и сравниваемой. Соответственно, если
множество дельт стремятся к похожему значению, можно делать вывод о
схожести данных записей.
Анализ согласованности по времени можно определить следующим
образом:
1) выполнение создание отпечатка интересующей аудиозаписи;
2) выполнение нахождения записи в хранилище по ключу с исполь-
зованием полученных ключей из отпечатка;

12
3) в значении ключа должно быть поле с идентификатором интересу-
ющей аудиозаписи и, возможно, поля с идентификаторами иных аудиозапи-
сей;
4) если существуют поля с идентификаторами других аудиозаписей,
то вычисляется дельта между абсолютным временем исследуемой записи и
интересующей.
Данные сохраняются в хэш-таблицу для последующей обработки.

1.5. Удаление выбросов в наборе дельт


Система должна определять схожие аудиозаписи, а не определенную
одну наиболее идентичную запись. Поэтому следует учитывать, что реми-
ксы интересующего трека или записи с частичными шумами должны опре-
деляться как похожие.
При этом существуют ремиксы, которые лишь отдаленно напоминают
оригинал двумя схожими секундами. Также следует учитывать, что в ауди-
озаписях (и в интересующей, и в сравниваемой) может быть тишина. Ти-
шина в песне может давать некорректную согласованность.
Поэтому следует до суммирования всех дельт выполнить удаление
выбросов и аномалий. Данный шаг не представлен в статьях и не указана на
это проблема, но она существует. Будет использован собственный подход.
Для данной работы выбран статистический метод нахождения выбро-
сов – правило трех сигм [18]. Если принять, что значения дельт подчиняются
нормальному распределению, тогда будет рассчитано среднее значение и
среднеквадратическое отклонение и отброшены значения за пределами
трех/двух/одной (в зависимости от результатов тестирования) сигмы.
Таким образом, набор дельт времени согласованности записей будет
очищен от значений относительно далеких от среднего на определенную
сигму. Данная операция не только уточняет список похожих аудиозаписей,
но и позволяет сократить вычисления на следующих шагах.

13
1.6. Ранжирование списка схожих аудиозаписей
Теперь нужно ранжировать список сравниваемых к интересующей
аудиозаписи между собой от наиболее схожих к наименее. В данной вы-
пускной работе предложены два подхода: использование среднеквадратиче-
ского отклонения или ранжирование по количеству дельт.
Так как наиболее схожие аудиозаписи имеют наименьшее различие в
значениях дельт времени, то можно утверждать, что значение дисперсии
набора дельт обратно пропорционально схожести аудиозаписей.
Второй предложенный подход заключается в подсчете количества
дельт времени, причем только тех, которые наиболее близки к определен-
ным N дельтам. Данные N дельт – это первые N дельт в списке дельт, отсор-
тированном в порядке уменьшения количества совпадений. Второй подход
хорошо подходит для случаев, когда исследуемый небольшой отрывок
имеет сравнительно маленькое значение дисперсии по сравнению с другими
аудиозаписями из-за небольшой энтропии дельт, связанной с короткой про-
должительностью записи.

1.7. Обзор аналогов


Алгоритмы по анализу звуковых сигналов присутствуют в том или
ином виде во многих софтверных приложениях разного масштаба. Суще-
ствуют системы нахождения похожих аудиозаписей как от IT-гигантов, ин-
тегрированные в собственные поисковики или в другие продукты компа-
нии, или обычные приложения, свободно скачиваемся с AppStore или
Google Play.
Глобально аналоги можно разделить на несколько групп.
1. Приложения для поиска определенной песни (таблица 1).
Пример: Shazam, SoundHound.

14
Таблица 1 – Преимущества и недостатки приложений для поиска
определенной песни
Преимущества Недостатки
Быстрое и качественное нахожде- Приложение отвечает, что найден один трек,
ние определенного музыкального либо дает сигнал, что в базе не найдено похо-
трека. жих треков, либо указывает на неверный трек.
Обычно огромная база индексируе-
мых музыкальных треков.
Внедренная в приложение система
профиля, истории и удобного UI.

Такой тип приложений удобен всем, если есть определенная цель –


найти именно этот музыкальный трек, предоставив системе лишь звуковой
сигнал. К сожалению, такой подход не дает понять, а какие есть похожие
треки на данный воспроизведенный – даже если его нет в базе приложения.
2. Системы рекомендаций, интегрированные в уже существующее
музыкальное приложение (таблица 2).
Пример: Spotify.
Таблица 2 – Преимущества и недостатки приложений для поиска
определенной песни
Преимущества Недостатки
Получение информации по рекоменда- Выдача рекомендаций в неявном для поль-
циям исходя из истории пользователь- зователя режиме и по неявным критериям
ских музыкальных треков отбора.
Обычно огромная база индексируемых Получение (хоть и нескольких) рекомендо-
музыкальных треков. ванных плейлистов необязательно подходя-
щих в данный момент времени.
Стриминг музыкальных треков.

Таким образом, данный тип приложений использует алгоритмы по по-


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

15
3. Системы нахождения аудиозаписей, интегрированные в поиско-
вые движки (таблица 3).
Пример: Google Assistant (Android).
Таблица 3 – Преимущества и недостатки систем, интегрированных
в поисковые движки
Преимущества Недостатки
Получение схожего трека по записи с Результат поиска – один определенный трек
микрофона или напева при полном соответствии
Выдача ресурсов от компании Google, Такие системы не могут проанализировать
где возможно прослушать полностью только личные пользовательские аудиоза-
писи
Получение нескольких схожих треков,
но только при частичном соответствии

Данная группа аналогов, в частности Google Assistant, выполняет


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

16
2. ПРОЕКТИРОВАНИЕ
2.1. Требования к системе
Функциональные требования
1. Система должна предоставлять интерфейс для загрузки аудиоза-
писей пользователей.
2. Система должна выполнять создание «отпечатка» аудиозаписи по
требованию пользователя. С ростом количества запросов на создание «от-
печатка» система не должна терять производительность в любом ином
функционале.
3. Система должна выполнять анализ по нахождению схожих аудио-
записей по требованию пользователя. С ростом количества запросов на по-
иск система не должна терять производительность в любом ином функцио-
нале.
4. Система должна выполнять обновление списка схожих аудиозапи-
сей по требованию пользователя.
5. Система должна предоставлять интерфейс для просмотра схожих
аудиозаписей в ранжированном списке от наиболее схожих к наименее.
6. Система должна предоставлять возможность прослушивания
аудиозаписей.
7. Система должна предоставлять форму регистрации и авторизации.
Нефункциональные требования
1. Приложение должно работать с форматами .mp3, .ogg, .wav.
2. Приложение должно быть спроектировано таким образом, чтобы
иметь возможность горизонтального и вертикального масштабирования.
3. Определенные части приложения должны иметь возможность за-
пускаться в Docker контейнерах для удобного процесса развертывания на
различном оборудовании, создав при этом изоляцию непосредственно мо-
дуля от железа, на котором работает программа.

17
4. Каждый пользователь, работающий в системе должен, зарегистри-
роваться в системе, указав: e-mail пользователя, пароль для входа в систему.
Каждый пользователь должен иметь доступ к тому материалу, к которому
он привязан с учетом прав доступа.
5. Авторизация производится с помощью JWT (JSON Web Tokens).
6. Пользователь при входе в систему обязан указывать логин и па-
роль.
7. Пользователь при регистрации в системе обязать указывать пароль
два раза (для подтверждения).
8. Пароль шифруется на стороне сервера-обработчика.
9. Важные конфиденциальные данные передаются на сервер POST
запросом.

2.2. Варианты использования


На рисунке 3 представлена диаграмма использования веб-приложения
по нахождению схожих аудиозаписей.

Рисунок 3 – Диаграмма вариантов использования

18
Пользователь системы имеет возможность прослушать открытые
аудиозаписи сообщества. Закрытые аудиозаписи видны только самому за-
грузившему в систему.
Авторизованный пользователь может управлять личным профилем,
например, изменять пароль или добавлять новую информацию о себе. К
тому же такой пользователь вправе управлять списком собственных аудио-
записей: добавлять новые, удалять или изменить название загруженного
трека. В дополнение к этому пользователь по требованию может создать от-
печаток аудиозаписи в хранилище. С имеющимся отпечатком система мо-
жет выполнить поиск схожих аудиозаписей в рамках личной библиотеки
пользователя или в рамках сообщества.

2.3. Общая архитектура системы


Общая архитектура системы представлена на рисунке 4 в виде диа-
граммы компонентов. Архитектура состоит из следующих компонентов:
клиент в виде Браузера, Rest-сервер, реляционная база данных, NoSQL
«ключ-значение» база данных, очередь сообщений, модуль создания отпе-
чатка аудиозаписи и модуль выполнения анализа.

Рисунок 4 – Диаграмма компонентов

Клиентское веб-приложение является точкой входа в систему. Дан-


ный компонент выполняет роль графического интерфейса пользователя в

19
системе. Создаваемые запросы передаются с помощью REST HTTP на Rest-
сервер.
Rest-сервер выполняет авторизацию пользователей, передает нужную
информацию по требованию из реляционной базы данных и для выполнения
трудоемких операций отправляет сообщения в одну из очередей.
Реляционная база данных хранит информацию о пользователях и
аудиозаписях. В базе содержится информация о текущем состоянии выпол-
нении операций над определенной аудиозаписью.
Очередь сообщений является удобным средством для реализации
асинхронного выполнения задач, когда существуют операции, которые тре-
буют большего времени выполнения.
Модуль создания отпечатка принимает от очереди сообщение, в кото-
ром содержится информация о типе операции и нужных идентификаторах,
по которым возможно получить информацию из реляционной базы данных.
NoSQL база данных «ключ-значение» необходима для хранения отпе-
чатков аудиозаписей.

2.4. Управление профилем и списком аудиозаписей


В данном проекте помимо основной задачи по нахождению схожих
аудиозаписей и удобной визуализации в браузере, необходимо определить
и реализовать базовые функции управления профилем и списком аудиоза-
писей.
На рисунке 5 представлена диаграмма взаимодействия по редактиро-
ванию профиля пользователя.
Данная диаграмма отображает, что клиентское веб-приложение пере-
дает токен авторизации Rest-серверу. Сервер, используя токен, определяет
пользователя и дает возможность обновлять свой профиль, то есть экзем-

20
пляры класса User. Обновленную информацию Rest-сервер отправляет об-
ратно клиенту. На клиентской стороне возможна реализация реактивного
обновления, например, с помощью веб-сокетов.

Рисунок 5 – Диаграмма взаимодействия управления профилем

На рисунке 6 представлена диаграмма взаимодействия по прослуши-


ванию открытых аудиозаписей.

Рисунок 6 – Диаграмма взаимодействия по прослушиванию аудиозаписей

21
При открытии страницы, отображающей список аудиозаписей, клиент
получает сначала список DTO (Data Transfer Object) данных записей. По тре-
бованию клиента запустить прослушивание аудиозаписи выполняется пере-
дача байтов информации записи. Передача возможна не только от бинар-
ного поля в базе данных, но и от файла в S3 (Simple Storage Service, Объект-
ное облачное хранилище).
На рисунке 7 представлена диаграмма по управлению списком аудио-
записей пользователя.

Рисунок 7 – Диаграмма взаимодействия по управлению списком


аудиозаписей

22
Данная диаграмма схожа по смыслу с диаграммой рисунка 6. Сначала
при запросе от пользователя Rest-сервер обрабатывает токен (resolve(token))
и по нему же определяет какой именно список аудиозаписей необходимо
отправить клиенту. В данном случае графический интерфейс пользователя
передает обновленную информацию объектам класса Track. К тому же поль-
зователь может как добавлять, так и удалять объекты класса Track.
Диаграмма вариантов использования уже демонстрировала, что поль-
зователь может сначала загрузить аудиозапись, только затем выполнить со-
здание отпечатка, а затем с уже существующим отпечатком в NoSQL «hash-
value» хранилище выполнить поиск схожих треков. На рисунке 8 представ-
лена диаграмма взаимодействия создания отпечатка аудиозаписи.

Рисунок 8 – Диаграмма взаимодействия создания отпечатка

23
Для выполнения создания отпечатка актор может загрузить новую
аудиозапись, что необязательно, или выполнить операцию над уже суще-
ствующей записью. Актор отправляет сообщение о создании отпечатка с ин-
формацией о самой записи и параметрами. Далее работу принимают сер-
висы и хранилища.
Сервис TrackService является бизнес сервисом в компоненте «Rest-
сервис», его задача – отправить в очередь по созданию отпечатка информа-
цию о выполнения данной операции. Параллельно выполнению ранее опи-
санного процесса FingerprintModule (модуль в компоненте «Модуль созда-
ния отпечатка») уже получает очередное сообщения из очереди по созданию
отпечатка. В данном сообщении содержится необходимая для данного мо-
дуля информация: идентификатор аудиозаписи, по которым можно взять
непосредственно саму бинарную запись из реляционной базы данных, и воз-
можные параметры для уточнения выполнения операции. В рамках созда-
ния отпечатка модуль постоянно обращается к хранилищу «hash-value»,
чтобы сохранить часть отпечатка исследуемой записи.
На рисунке 9 представлена диаграмма взаимодействия выполнения
анализа схожих треков. Актор отправляет сообщение с информацией о
треке, у которого необходимо найти схожие записи, и типе операции (искать
схожие в рамках личной библиотеки пользователя или среди открытых со-
общества). TrackService отправляет сообщение в очередь, предназначенную
для анализа аудиозаписей. AnalyzeModule (модуль в компоненте «Модуль
выполнения анализа») принимает сообщения от очереди. В сообщении со-
держится информация об идентификаторе аудиозаписи и типе операции.
В процессе выполнения логики по поиску похожих аудиозаписей мо-
дуль обращается к хранилищу типа «ключ-значение» для получения необ-
ходимых данных для анализа.
После выполнения процедуры результат сохраняется в определенное
поле записи трека в реляционной базе данных.

24
Рисунок 9 – Диаграмма взаимодействия анализа схожих треков

2.5. Состояние объекта класса аудиозаписи


На рисунке 10 изображена диаграмма состояний объекта класса Track
(класс, определяющий свойства и методы аудиозаписи).
Изначально файл аудиозаписи находится в состоянии «В процессе за-
грузки» во время загрузки файла на клиентскую часть пользователя (GUI,
браузер). После загрузки данный файл (состояние «Загружен») можно будет
удалить, если пользователю что-либо не понравится. Если пользователь ре-
шит окончательно сохранить данную запись, то объект переходит в компо-
зитный статус «Сохранен в БД». Статус объекта может быть параллельно в
двух ветках состояний – состояния приватности и состояния анализа. В пер-
вом случае объект может быть переведен в противоположный по значению
статус через метод класса setIsPrivate().

25
Рисунок 10 – Диаграмма состояний класса Track (класса аудиозаписи)

Состояние анализа оригинальности переходит из состояния «Готов к


созданию отпечатка» к «Создание отпечатка в процессе выполнения» после
начала выполнения создания отпечатка и сохранения статуса в базу данных
с помощью установки через метод setFingerprintStatus(status[0]). Объект пе-
реходит в состояние «Выполнено взятие отпечатка», что означает, что за-
пись готова быть проанализирована на схожесть с другими («Готов к ана-
лизу отпечатка»). После запуска метода анализа и смены статуса через ме-
тод setAnalyzeStatus(status[0]) объект класса переходит в состояние «Анализ
отпечатка в процессе выполнения». После завершения и установки статуса
через метод setAnalyzeStatus(status[1]) объект класса снова может быть го-
тов к анализу, то есть объект переходит в состояние «Готов к анализу отпе-
чатка».

26
3. РЕАЛИЗАЦИЯ
3.1. Организация схемы реляционной базы данных
Выбор СУБД
Для постоянного хранения данных о пользователях и аудиозаписях в
системе необходима база данных (БД). Так как доменная структура не явля-
ются специфичными, то следует выбрать классическую реляционную СУБД
(система управления базами данных). В качестве такой СУБД выбрана Post-
greSQL [8]. У данной СУБД есть ряд преимуществ: свободное распростра-
нение, высокопроизводительные механизмы транзакций и наличие большой
документации [21].
Схема базы данных
На рисунке 11 изображена схема базы данных для разрабатываемой
системы.

Рисунок 11 – Схема базы данных

Таблица Track содержит данные об аудиозаписях. В таблице 4 ука-


заны поля таблицы Track их описание.

27
Таблица 4 – Описание полей таблицы Track
Поле Описание
Id Идентификатор записи
Compare_list Список с ранжированными идентификаторами аудиозапи-
сей наиболее похожих на текущую. Поле заполняется по-
сле выполнения методов модуля анализа отпечатка.
Content Непосредственно содержимое аудиозаписи
Created_date Дата создания записи в БД
File_name Наименование файла аудиозаписи
Fingerprint_index_status Статус выполнения создания отпечатка
Global_index_status Статус выполнения поиска похожих аудиозаписей в рам-
ках всех открытых записей сообщества
Local_index_status Статус выполнения поиска похожих аудиозаписей в рам-
ках библиотеки пользователя
Modified_date Дата изменения записи в БД
Name Пользовательское наименование аудиозаписи
User_id Внешний ключ на идентификатор (id) таблицы users
Length Длина аудиозаписи
Visible_status Статус области видимости аудиозаписи

Таблица Users содержит данные о пользователях. В таблице 5 указаны


поля таблицы Users и их описание.
Таблица 5 – Описание полей таблицы Users
Поле Описание
Id Идентификатор записи
Created_date Дата создания записи в БД
Email Электронная почта пользователя при регистрации
Enabled Флаг блокировки/доступа пользователя в систему
Login Логин пользователя
Modified_date Дата изменения записи в БД
Password Пароль пользователя

Таблица Users_role перечисляет роли в системе. В таблице 6 указаны


поля таблицы Users_role и их описание.
Таблица 6 – Описание полей таблицы Users_role
Поле Описание
Id Идентификатор записи
Name Наименование роли

28
Таблица Users_role_rel служит для создания связи многие-ко-многим
между таблицами Users и Track. Таким образом привязывается определен-
ная роль к пользователю. В таблице 7 указаны поля таблицы Users_role_rel
и их описание.
Таблица 7 – Описание полей таблицы Users_role_rel
Поле Описание
User_id Внешний ключ на идентификатор записи таблицы Users
Track_id Внешний ключ на идентификатор записи таблицы Track

3.2. Организация очередей сообщений


В качестве брокера сообщений был выбран RabbitMQ [9]. Данный
брокер реализует стандарт AMQP. Существует множество библиотек для
разных языков программирования по взаимодействию с данным брокером.
К тому же более настраиваемые и сложные брокеры для асинхронного вза-
имодействия (например, Apache Kafka) являются излишними для текущих
поставленных задач.
Создание точек обмена и очередей
AMQP (Advanced Message Queuing Protocol) – открытый протокол для
передачи сообщений между компонентами системы [4].
Сообщение (message) – единица передаваемых данных.
Точка обмена распределяет сообщения в одну или несколько очере-
дей. При этом в точке обмена сообщения не хранятся. Точки обмена бывают
трех типов:
1) fanout – сообщение передается во все прицепленные к ней очереди;
2) direct – сообщение передается в очередь с именем, совпадающим с
ключом маршрутизации;
3) topic – сообщение передается в очереди, для которых совпадает
маска на ключ маршрутизации, например, app.notification.sms.# – в очередь
будут доставлены все сообщения, отправленные с ключами, начинающи-
мися с app.notification.sms.

29
В очереди (queue) сообщения хранятся сообщения до тех пор, пока не
будут забраны клиентом.
Для асинхронной работы Rest-сервера, модуля создания отпечатка и
модуля анализа отпечатка необходимы две очереди: в первой передается ин-
формация для выполнения создания отпечатка, во второй для выполнения
анализа.
В RabbitMQ для данных целей созданы две точки обмена: track-ana-
lyze-exchange и track-fingerpring-exchange с типом fanout (рисунок 12).

Рисунок 12 – Точки обмена

Для данных точек обмена необходимо определить две очереди: track-


analyze и track-fingerprint (рисунок 13).

Рисунок 13 – Очереди сообщений

3.3. Реализация модуля создания отпечатка


Модуль создания отпечатка и модуль выполнения анализа (по ри-
сунку 4) являются ключевыми в бизнес логике веб-приложения по опреде-
лению степени сходства музыкальных треков. Далее будут описаны шаги в
реализации данных компонент.
Основным средством для реализации данного модуля является Python
3.8 и библиотека на данном языке librosa. Данный выбор обусловлен тем,
что язык Python для реализации приложений профиля «proof of concept» яв-
ляется удобным, так как является языком высокого уровня и поддержива-
ется множество библиотек для обработки различных объектов. При выборе

30
иного языка потребовалось либо писать определенные операции абсолютно
с нуля, либо пытаться дополнять возможности библиотеки. Одной из клю-
чевых библиотек, использующихся в модуле, является librosa. С ее помо-
щью выполняется быстрое преобразование Фурье и визуализация спектро-
граммы – что экономит время на этапе разработки.
Аналогово-цифровое преобразование звука и быстрое преобразо-
вание Фурье
Звук – это упругие волны в среде, которые невидимы, но воспринима-
емые человеческим ухом (волна воздействует на барабанную перепонку
уха). Звуковая волна является продольной волной сжатия и разрежения [14].
Любая волна может быть с любой точностью аппроксимирована (прибли-
жена) совокупностью синусоидальных волн.
Сначала выполняется аналогово-цифровое преобразование звука.
Цифровой звук – это аналоговый звуковой сигнал, представленный посред-
ством дискретных численных значений его амплитуды [19].
Оцифровка звука включает в себя два процесса.
1. Процесс дискретизации (осуществление выборки) сигнала по вре-
мени.
2. Процесс квантования по амплитуде.
Процесс дискретизации по времени – процесс получения значений
сигнала, который преобразуется с определенным временным шагом – шагом
дискретизации. Количество замеров величины сигнала, осуществляемых в
единицу времени, называют частотой дискретизации или частотой выборки,
или частотой сэмплирования (от англ. «sampling» – «выборка») [13].
Чем меньше шаг дискретизации, тем выше частота дискретизации и
тем более точное представление о сигнале нами будет получено. Соответ-
ственно, есть и обратная сторона – увеличение частоты сэмплирования уве-

31
личивает выходной временной ряд, представляющий набор частот, ампли-
туд и времени. Слишком большую информацию о звуковом сигнале трудно
хранить в рамках миллиона записей и неэффективно обрабатывать.
В научном сообществе данная проблема выбора оптимальной частоты
дискретизации уже была давно решена. Люди могут слышать звуки от 20 Гц
до 20 кГц. Исходя из теоремы Котельникова [15], чтобы оцифрованный сиг-
нал содержал информацию о всем диапазоне слышимых частот исходного
аналогового сигнала (20 Гц – 20 кГц) необходимо, чтобы выбранное значе-
ние частоты дискретизации составляло не менее 40 кГц.
В рамках реализуемого приложения система уже будет принимать
оцифрованный звук, но необходим ресэмплинг (изменение частоты сэмпли-
рования на иную).
Для выполнения многих уже известных операций над звуковым сиг-
налом в работе используется библиотека на языке Python librosa. С помощью
данной библиотеки получим временной ряд, репрезентирующий синусои-
дальную кривую по времени (рисунок 14).
x, sr = librosa.load("dst.wav", sr=SR)

Рисунок 14 – Получение временного ряда аудиозаписи

Метод не только возвращает временной ряд, но и выполняет ресэм-


плинг по той частоте, которая указана в параметре sr (sampling rate, частота
сэмплирования).
Далее выполняется преобразование Фурье для получения информа-
ции по частотам, амплитудам для каждой частоты в определенный момент
времени [2]. Существует ряд алгоритмов данного преобразования, но наибо-
лее известно быстрое преобразование Фурье (FFT). Быстрое преобразование
Фурье (БПФ, FFT) – алгоритм ускоренного вычисления дискретного преоб-
разования Фурье, позволяющий получить результат за время, меньшее чем
O(N2) [17].

32
Кратковременное быстрое преобразование Фурье (Short-time Fourier
Transform) выполняет быстрое преобразование Фурье не над всем массивом
данных, а только над ее частью, называемой «окном» (window) (рисунок 15).

Рисунок 15 – Окно кратковременного быстрого преобразования Фурье

Также существует параметр значения сдвига (hop size), который опре-


деляет степень наложения окон между собой. Существование данного пара-
метра обусловлено спецификой самого преобразования Фурье для звуковых
сигналов и позволяет получить более корректный результат для частот
ближних к границам окна (рисунок 16).
После выполнения быстрого преобразования Фурье будет получена
двумерная матрица, строки которой это так называемые частотные бины
(frequency bins), а столбцы это временные бины (time frame или frame bins).
Значения матрицы – это амплитуды частоты.

33
Рисунок 16 – Размер сдвига кратковременного БПФ

Переводы значений из размера окна (framesize), частоты дискретиза-


ции (samples) и значения сдвига (hop-size) в количество таких частотных би-
нов (frequency bins) и в количество временных бинов (time frames) выполня-
ются согласно формулам (1) и (2) [6]:
𝑓𝑟𝑎𝑚𝑒𝑠𝑖𝑧𝑒 (1)
𝑓𝑟𝑒𝑞𝑢𝑒𝑛𝑐𝑦 𝑏𝑖𝑛𝑠 = + 1,
2

𝑠𝑎𝑚𝑝𝑙𝑒𝑠 − 𝑓𝑟𝑎𝑚𝑒𝑠𝑖𝑧𝑒 (2)


𝑡𝑖𝑚𝑒 𝑓𝑟𝑎𝑚𝑒𝑠 = + 1,
ℎ𝑜𝑝𝑠𝑖𝑧𝑒
где frequency bins – количество частотных бинов БПФ;
time frames – количество временных фреймов (или бинов) БПФ;
framesize – размер окна БПФ;
samples – частота дискретизации;
hopsize – значения сдвига окна БПФ.

34
Используя библиотеку librosa, выполним быстрое преобразование
Фурье.
В листинге 1 указан ряд констант:
1) FRAME_SIZE – размер окна;
2) HOP_SIZE – размер hop size;
3) SR – значение частоты дискретизации;
4) CHUNKS – массив для распределения строк frequency bins для со-
здания отпечатка.
Листинг 1 – Быстрое преобразование Фурье
FRAME_SIZE = 2048
HOP_SIZE = 512
SR = 22100
CHUNKS = [0, 10, 30, 60, 100, 200, 1024]
X = librosa.stft(x, n_fft=FRAME_SIZE, hop_length=HOP_SIZE)

Данный метод возвращает матрицу, которая содержит переменные


комплексных чисел для выражения амплитуды частоты определенного бина
частоты в определенном бине времени.
Для корректной дальнейшей работы необходимо перейти к логариф-
мической шкале. В библиотеке librosa также существует метод для этой
цели – amplitude_to_db() (рисунок 17).
Xdb = librosa.amplitude_to_db(abs(X))

Рисунок 17 – Переход к логарифмической шкале

Данное преобразование позволяет использовать спектрограмму для


анализа аудиозаписи и визуально заметить более слабые по амплитуде ча-
стоты (рисунок 18).

35
Рисунок 18 – Спектрограмма с логарифмической шкалой

Определение сильных частотных бинов в логарифмическом


диапазоне
В определенных жанрах музыки преобладают те или иные диапазоны
частот. Например, в капелла поют сопрано со средними или средневысо-
кими частотами, а в джазе и рэпе преобладают часто низкие частоты. Выяв-
ление наиболее сильных по амплитуде частот поможет анализировать спек-
трограмму без учета шумов и прочих выбросов. Но необходимо принимать
во внимание каждый из диапазонов частот.
Метод на рисунке 17 возвращает двумерный массив, где строки это
бины частот, а столбцы это бины времени. Необходимо выделить наиболее
сильные частоты в каждом из диапазонов и сохранить в выходную матрицу
(листинг 2).
В листинге 2 метод getMaxList(Xdb) принимает двумерную матрицу
из метода, указанного на рисунке 17, и возвращает двумерный массив.
Листинг 2 – Получение максимальной частоты в диапазоне бинов
def getMaxList(Xdb):
max_list = []
for iter, chunk_val in enumerate(CHUNKS):
max_chunk_list = []
if iter + 1 < len(CHUNKS):
Xbd_chunk = Xdb[chunk_val:(CHUNKS[iter+1])]
Xbd_chunk = np.array(Xbd_chunk).T.tolist()
for max_candidates in Xbd_chunk:

36
max_val = max(max_candidates)
max_chunk_list.append((max_val, chunk_val + max_candi-
dates.index(max_val)))
max_list.append(max_chunk_list)
return max_list

Возвращаемая матрица хранит максимумы значений амплитуд опре-


деленного диапазона указанных с помощью массива CHUNKS. Также в кор-
теже с данной амплитудой хранится номер частотного бина, чтобы в буду-
щем алгоритм смог понять, к какой частоте принадлежит данная амплитуда.
Перевод номера частотного бина в значение частоты Hz будет выполнена с
помощью библиотеки librosa.
Пример:
Вход (листинг 3):
Листинг 3 – Входная матрица метода getMaxList()
[[0 3 1 4 0 2]
[2 1 3 0 4 1]
[2 2 1 2 1 3]
[0 4 3 4 2 0]]

Выход (листинг 4):


Листинг 4 – Выходная матрица метода getMaxList()
[[(2, 1), (3, 0), (3, 1), (4, 0), (4, 1), (2, 0)],
[(2, 2), (2, 2), (1, 2), (2, 2), (1, 2), (3, 2)],
[(0, 3), (4, 3), (3, 3), (4, 3), (2, 3), (0, 3)]]

Определение частотных бинов выше среднего значения


Последний выполненный шаг имеет ограничение: в большинстве пе-
сен некоторые части очень тихие (например, начало и конец песни). Выпол-
нив предыдущий шаг, будет получены ложные сильные по амплитуде ча-
стоты. Необходимо избежать этого, вычислив среднее значение среди пико-
вых частот из каждого диапазона текущего быстрого преобразования Фурье
(листинг 5).
Но данный подход не сможет помочь с абсолютной тишиной в треках,
так как среднее значение по всем диапазонам будет равна нулю. Решение

37
данного аспекта будет реализовано при поиске схожих, используя статисти-
ческие методы нахождения выбросов и аномалий.
Листинг 5 – Получение пиковых частот выше среднего значения
def getMaxOverAverage(max_list):
means = []
for index in range(0, len(max_list[0])):
column = list(map(lambda x: x[index], max_list))
means.append(np.mean(list(map(lambda x: x[0], column))))

trans_max_list = np.array(max_list).transpose(1, 0, 2).tolist()

max_over_average = []
for iter, max_list_column in enumerate(trans_max_list):
new_max_list_col = []
for max_list_value_tuple in max_list_column:
if max_list_value_tuple[0] < means[iter]:
new_max_list_col.append((max_list_value_tuple[0], -1000))
else:
new_max_list_col.append((max_list_value_tuple[0],
max_list_value_tuple[1]))
max_over_average.append(new_max_list_col)

max_over_average = np.array(max_over_average).transpose(1, 0,
2).tolist()
return max_over_average

На выходе будет получена матрица аналогичная выходной матрице


прошлого шага, но в кортеже с амплитудой меньше среднего в срезе вре-
менного бина (т.е. столбца двумерной матрицы) вторым элементом является
значение -1000, как метка того, что данная амплитуда не принимает значе-
ние в дальнейшем анализе.
Трансформирование матрицы
Далее необходимо выполнить трансформацию матрицы на более
удобную форму и избавиться от информации об амплитуде, так как данный
параметр уже сыграл свою роль в алгоритме – уже произведена выборка ча-
стот по амплитуде. К тому же, элемент в матрице является не примитивом,
а кортежем, что при дальнейших операциях является неудобной формой, так
как вложенность такого массива трехмерная.
Необходимо выполнить транспонирование матрицы, удалить частоты
с меткой, определяющей амплитуду ниже среднего, и привести к массиву с

38
элементами типа массив целочисленных значений, где первый элемент это
временной бин, а второй бин – это бин частоты (листинг 6).
Листинг 6 – Выполнение трансформации матрицы
def getMaxCoordArray(max_over_average):
max_over_average = np.array(max_over_average).transpose(1, 0,
2).tolist()

new_current_column_max_y = []
new_current_column_max_x = []

for iter, column_max in enumerate(max_over_average):


for max_iter, max_tuple in enumerate(column_max):
if max_tuple[1] != -1000:
new_current_column_max_y.append(max_tuple[1])
new_current_column_max_x.append(iter + 1)

maxima_array = [new_current_column_max_x, new_current_column_max_y]


maxima_array = np.array(maxima_array).T.tolist()
return maxima_array

Пример:
Вход (листинг 7):
Листинг 7 – Входная матрица метода getMaxCoordArray()
[[[2, 1], [3, 0], [3, 1], [4, 0], [4, 1], [2, 0]],
[[2, 2], [2, -1000], [1, -1000], [2, -1000], [1, -1000], [3, 2]],
[[0, -1000], [4, 3], [3, 3], [4, 3], [2, -1000], [0, -1000]]]

Выход (листинг 8):


Листинг 8 – Выходная матрица метода getMaxCoordArray()
[[1, 1],[1, 2],[2, 0],[2, 3],[3, 1],[3, 3],
[4, 0],[4, 3],[5, 1],[6, 0],[6, 2]]

Создание и сохранение отпечатка в хранилище


Как было отмечено в пункте 1.2 необходимо образовать целевые зоны.
После создания целевых зон будет сформирован ключ следующего фор-
мата: [«Частота опорной точки», «Частота целевой точки», «Разница во вре-
мени между опорной точкой и целевой точкой»]. Данный ключ будет захэ-
широван в md5. Значение по ключу должен быть кортеж, состоящий абсо-
лютное время опорной точки в треке и идентификатор в базе данных.

39
Redis позволяет хранить информацию в формате HASH-VALUE. Дан-
ный формат наиболее подходит для текущей задачи. Так как в роли ключа
будет захэшированное значение адреса целевой точки (ключ уникален в
рамках базы), поле в рамках ключа – это идентификатор аудиозаписи в ре-
ляционной базе данных PostgreSQL (поле уникально в рамках ключа), а зна-
чение поля – это абсолютное время опорной точки в аудиозаписи.
В работе используется целевая зона из 25 точек, а опорная точка – это
третья точка до целевой зоны. Данные параметры выбраны эмпирическим
путем исходя из тестирования алгоритма (листинг 9).
Листинг 9 – Создание и сохранение отпечатка в хранилище
def getFingerPrint(max_coord, track_id):
max_coord = np.array(max_coord).T.tolist()

# Перевод из фреймов в секунды


transformed_columns = []
for column in max_coord[0]:
transformed_columns.append(frameIndexToTime(column, SR, HOP_SIZE,
FRAME_SIZE))

# Перевод из freq frame в непосредственно частоту (Hz)


transformed_rows = []
for row in max_coord[1]:
transformed_rows.append(freqBinToFreqVal(int(row), SR, FRAME_SIZE))

maxima_array = [transformed_columns, transformed_rows]


maxima_array = np.array(maxima_array).T.tolist()

iter_proc = 0
for iter, maxima in enumerate(maxima_array):
if iter > 2:
anchor_point = maxima_array[iter - 3]
for target_point in maxima_array[iter:(iter + 25)]:
delta_time = target_point[0] - anchor_point[0]
address = [anchor_point[1], target_point[1], delta_time]
key = hashlib.md5(str(address).encode()).hexdigest()
iter_proc = iter_proc + 1
if redis_instance.hexists(key, track_id) == 1:
if redis_instance.hexists(key, track_id) != 1:
redis_instance.hset(key, track_id, anchor_point[0])
else:
redis_instance.hset(key, track_id, anchor_point[0])

Метод frameIndexToTime() необходим для перевода временного бина


от быстрого преобразования Фурье к обычным секундам. Метод
freqBinToFreqVal() служит для перевода частотного бина к частоте (Hz).
Данные методы вспомогательные, и обеспечивают работу основного метода

40
построения отпечатка. В методе создания отпечатка getFingerPrint() исполь-
зуется библиотека redis для взаимодействия с хранилищем Redis. Метод
HSET() позволяет сохранить HASH-VALUE значение. Метод HEXISTS()
служит для определения – есть ли в базе определенный ключ с определен-
ным полем.
Интегрирование всех методов для создания отпечатка
Каждый из прошедших шагов выполняет определенную задачу в бо-
лее глобальной – создание и сохранение отпечатка аудиозаписи, информа-
ция о которой хранится в реляционной базе.
Определим далее порядок их следования, интегрировав в одном ме-
тоде process(), который запускается при получении очередного сообщения в
модуль создания отпечатка (листинг 10).
Листинг 10 – Интегрирование методов создания отпечатка
def process(track_id: int):
content = get_track_content_by_id(session, track_id)

Xdb, length = getXdb(content)


max_list = getMaxList(Xdb)
max_over_average = getMaxOverAverage(max_list)
maxima_array = getMaxCoordArray(max_over_average)
getFingerPrint(maxima_array, int(track_id))

update_track_index_status(session, track_id, 1, length)

В листинге представлен основной в модуле метод main(). Данный ме-


тод вызывается как обработчик сообщения, отправленного из очереди сооб-
щений «track-fingerprint». При получении очередного сообщения с иденти-
фикатором аудиозаписи, хранящемся в реляционной базе данных Post-
greSQL, выполняются шаги предыдущих пунктов. Далее обновляется статус
для записи, обозначающий о завершении процедуры создания отпечатка и
готовности к анализу записи.
Таким образом, следование предыдущим пунктам позволяет получить
в Redis хранилище примерно следующий вид отпечатков аудиозаписей (ли-
стинг 11):

41
Листинг 11 – Пример содержимого отпечатков hash-value в Redis
{
‘3d27085b5c1f9596e71a2a92b6871945’: {
‘1092’: 764.2187381,
‘82’: 21.3123123,
‘2402’: 102.321332
},
‘53880af179ef68fd5c0224f54180c744’: {
‘11’: 167.4564566,
‘49’: 60.3418877
},
‘e6d46a50df6ca22a9ffe53cb6c68a5f0’: {
‘9’: 54.345312
}
}

3.4. Реализация модуля выполнения анализа


Основным средством реализации модуля выполнения анализа явля-
ется язык программирования Python 3.8 и аналогичные библиотеки, исполь-
зуемые для модуля создания отпечатка. Также используется хранилище
«ключ-значение» Redis для получения отпечатков.
Согласованность во времени
В предыдущих пунктах было заполнено hash-value хранилище, в ко-
тором ключ – это захэшированный массив, содержащий значение частоты
опорной точки, значение частоты целевой точки и разницу в секундах
между опорной точкой и целевой, поле в значении ключа – это идентифика-
тор аудиозаписи в реляционной базе данных, а значение конкретного поля –
это абсолютное время в данной аудиозаписи данной опорной точки. В соот-
ветствии с алгоритмом из пункта 1.4 реализуется нахождение дельт времени
для согласованности.
Пример содержимого в хранилище Redis в листинге 11 демонстри-
рует, что в рамках одного ключа возможны несколько полей, то есть не-
сколько аудиозаписей, в которых целевая точка имеет похожее расположе-
ние относительно опорной, а значит, это первый шаг к нахождению похо-
жих аудиозаписей (кандидатов на схожие аудиозаписи). Следовательно,
сначала отбираются все треки из хранилища Redis, которые имеют те же
ключи, что и интересующий трек. А далее вычисляется разница во времени

42
между абсолютным значением времени опорной точки кандидата и интере-
сующей записи в рамках одного ключа. Так как у кандидата и интересую-
щего трека может быть множество точек с одинаковым ключом, то инфор-
мация о разнице во времени сохраняется в памяти в hash-value таблицу, где
ключ – это идентификатор кандидата, а значение – это массив кортежей с
информацией о разнице во времени (временной дельте) и количества появ-
ления данной разницы (дельты). Возможная хэш-таблица представлена в ли-
стинге 12.
Листинг 12 – Получение всех дельт согласованности во времени
интересующей записи и сравниваемых (в рамках одинаковых ключей)
{'17283': [(1.51, 19),
(0.56, 13),
(0.19, 13),
(1.41, 12),
(0.09, 11),
(1.78, 10),
(-1.6, 10),
(10, 20)],
'34563': [(0.37, 84),
(0.0, 74),
(74.09, 61),
(0.74, 38),
(-1.71, 37),
(-50, 27),
(0.49, 33),
(-0.35, 30)]}

В листинге 12 представлена хэш-таблица, где ключ – это идентифика-


тор сравниваемой аудиозаписи, у которой существовал одинаковый ключ в
хранилище с интересующей записью. Значение в таблице – это массив, эле-
менты которого это кортежи, определяющие дельту и количество раз полу-
чения данной дельты у данной сравниваемой записью с интересующей.
Листинг 13 – Метод получения дельт согласованности
def syncTime(song_fingerprint, track_id):
full_delta_hash = {}

for hash_value in song_fingerprint:


other_tracks_time_sum = {}
if redis_instance.hexists(hash_value, track_id) == 1:
current_song_average_time = redis_instance.hget(hash_value,
track_id)
for song_id in redis_instance.hkeys(hash_value):
if song_id != track_id:

43
delta = round(float(current_song_average_time) -
float(redis_instance.hget(hash_value, song_id)), 2)
if full_delta_hash.get(song_id) is not None:
if full_delta_hash[song_id].get(delta) is not None:
full_delta_hash[song_id][delta] =
full_delta_hash[song_id][delta] + 1
else:
full_delta_hash[song_id][delta] = 1
else:
full_delta_hash[song_id] = {delta: 1}

for track in full_delta_hash:


full_delta_hash[track] =
dict(sorted(full_delta_hash[track].items(), key=lambda item: item[1], re-
verse=True))
full_delta_hash[track] =
list(full_delta_hash[track].items())[:DELTA_SIZE]
return full_delta_hash

Метод, определенный в листинге 13, выполняет процедуру для согла-


сования по времени из пункта 1.4.
Отбрасывание выбросов и аномалий
Согласно пункту 1.5 необходимо выполнить отбрасывание выбросов
и аномалий. В листинге 14 представлен код для вызова метода предыдущего
пункта и выполнения отбрасывания выбросов. В представленном методе
вызывается метод из листинга 13, который возвращает количество дельт со-
гласованности (временных дельт) с каждым похожим треком. Далее каждая
дельта согласованности проверяется на попадание в промежуток трех сигм
в рамках одной сравниваемого трека.
Увеличивая диапазон сигм, будет увеличиваться диапазон значений,
удаленных от среднего. При тестировании данного подхода в удалении вы-
бросов было обнаружено, что две и три сигмы не являются достаточно оп-
тимальными в отличие от одной сигмы в данной задаче (рисунок 19).
Таким образом, после удаления выбросов останутся значения дельт в
диапазоне [Xср –1ϭ; Xср +1ϭ].

44
Рисунок 19 – Правило трех сигм

Листинг 14 – Выполнение статистического удаления выбросов


def findDeltaForRecord(record_finger_print, track_id):
full_audio_delta_hash = syncTime(record_finger_print, track_id)
for track_deltas in full_audio_delta_hash:
deltas = np.array(full_audio_delta_hash[track_del-
tas]).T.tolist()[0]
mean = np.mean(deltas)
std = np.std(deltas)
for iter, delta in enumerate(full_audio_delta_hash[track_deltas]):
if abs(delta[0] - mean) / std > 1:
full_audio_delta_hash[track_deltas].pop(iter)
return full_audio_delta_hash

Ранжирование схожих аудиозаписей


Необходимо ранжировать список сравниваемых записей между собой
от наиболее к наименее схожим трекам интересующей аудиозаписи. В рам-
ках работы использовалось два подхода: вычисление среднеквадратиче-
ского отклонения для кандидатов или ранжирование по количеству дельт.
Вычисление среднеквадратического отклонения
На данном моменте анализа присутствует хэш-таблица, например, как
в листинге 12. К тому же были отброшены выбросы. В идеале абсолютно
одинаковая с интересующей записью сравниваемая аудиозапись будет
иметь одну дельту со значением 0,0 и с большим количеством ее встречи.

45
Соответственно, можно ожидать, что чем сильнее отличается сравниваемая
запись от интересующей, тем больше различных дельт будет присутство-
вать.
Таким образом, можно попробовать ранжировать сравниваемые за-
писи по разбросу значений дельт, то есть использовать вычисление диспер-
сии и СКО для массива временных дельт (листинг 15).
Листинг 15 – Поиск и ранжирование схожих с помощью СКО
dispersion_dict = {}
for delta_hash in full_audio_delta_hash:
delta_arr = []
for delta_value in full_audio_delta_hash[delta_hash]:
delta_arr.extend([delta_value[0]] * delta_value[1])
dispersion_dict[delta_hash] = np.var(delta_arr)
dispersion_dict
= dict(sorted(dispersion_dict.items(), key=lambda item: item[1]))

К сожалению, в рамках локальных тестов данный подход показывал


неудовлетворительный результат. Одна из причин – данный подход не учи-
тывает размеры сравниваемых записей. Одна большая запись может яв-
ляться аналогом сравниваемой, но из-за изначального большего размера, а
соответственно и большей энтропии дельт, может выдавать достаточно
большие по модулю значения дисперсии и СКО.
Подсчет дельт согласованности
Второй способ является более на практике успешным. Сначала выпол-
няется ранжирование дельт сравниваемой аудиозаписи по количеству появ-
ления от большего к меньшему. Затем вычисляется среднее из первых N
дельт. Далее суммируются количества появлений только тех дельт, которые
располагаются в заданной окрестности среднего значения, вычисленного
ранее. В работе значение окрестности равно 1 секунде. Данное значение яв-
ляется лишь эмпирически подобранным значением при тестировании. Со-
ответственно, чем больше сумма дельт у сравниваемой записи, тем больше
интересующая аудиозапись должна быть похожа на сравниваемую (ли-
стинг 16).

46
Листинг 16 – Поиск и ранжирование похожих записей через количество
дельт
full_audio_delta_hash_max = {}
for music in full_audio_delta_hash:
if operation == '0':
user_id = get_track_user_id(session, int(music))
if user_id is None or str(user_id) != message_user_id:
continue
top_3_deltas = np.array(full_audio_delta_hash[mu-
sic]).T.tolist()[0][:3]
mean = np.mean(top_3_deltas)
full_delta_count = 0
for delta_tuple in full_audio_delta_hash[music]:
if delta_tuple[0] != 0 and (delta_tuple[0] > (mean - 1) or
delta_tuple[0] < (mean + 1)):
full_delta_count = full_delta_count + delta_tuple[1]
# Запись во временную хэш таблицу значения количества дельт для
определенной записи по ИД
full_audio_delta_hash_max[int(music)] = full_delta_count

Интегрирование методов для анализа


Модуль анализа отпечатков аудиозаписи кроме названных выше ме-
тодов использует методы из модуля создания отпечатка. Конечно, отпеча-
ток интересующей аудиозаписи уже хранится в хранилище и его можно за-
брать, но на практике данный процесс будет на порядки дольше, чем созда-
ние в режиме реального времени.
Листинг 17 – Интегрирование методов для анализа
def process(message_params: []):
track_id = int(message_params[0])
operation = message_params[1]

message_user_id = '0'
if operation == '0':
message_user_id = message_params[2]

filename, content, current_len = get_track_content_by_id(session,


track_id)
Xdb = getXdb(filename, content)
max_list = getMaxList(Xdb)
max_over_average = getMaxOverAverage(max_list)
maxima_array = getMaxCoordArray(max_over_average)
song_finger_print = getFingerPrint(maxima_array, track_id)

full_audio_delta_hash = findDeltaForRecord(song_finger_print, track_id)


# Сохраняем список похожих треков в формате json в отдельной колонке
update_track_compare_list(session, track_id, json.dumps(full_au-
dio_delta_hash_max))

47
В листинге 17 описан метод, в котором сначала получено сообщение
строчного типа формата «trackId-operationType-userId», где trackId – иден-
тификатор аудиозаписи, operationType – код типа операции (0 – сравнение
аудиозаписи в рамках библиотеки пользователя, 1 – сравнение в рамках всех
открытых треков сообщества), userId – идентификатор пользователя. Если
необходим анализ в рамках библиотеки пользователя, то сравниваемые
треки – это аудиозаписи, загруженные самим пользователем.
После выполнения создания отпечатка интересующей записи, испол-
няются методы анализа и ранжирования, описанные ранее. Далее будет по-
лучен массив, содержащий значения идентификаторов схожих аудиозапи-
сей и ранжированный по критерию количества дельт. Для хранения резуль-
тата массив сериализуется в формат JSON и сохраняется в поле таблицы
Track реляционной базы данных. Статус выполнения анализа изменяется в
записи в таблице Track.
Далее при необходимости получить информацию о схожих треках для
данной аудиозаписи информация из поля будет десериализована из формата
JSON и выведена на пользовательский экран.

3.4. Реализация модуля Rest-сервер


Для реализации модуля Rest-сервера выбран язык программирования
Java и фреймворк Java Spring Boot. Данный выбор обусловлен наличием
множества библиотек и документаций для работы с брокерами сообщений,
хранилищем Redis и реляционной базой данных PostgreSQL. К тому сооб-
щество Java Spring Boot уже определило изрядное количество лучших прак-
тик для взаимодействия с хранилищем на данной технологии.
Задачи модуля и конечные точки
Rest-сервер должен принимать запросы от фронт-энд приложения, об-
рабатывать и, при необходимости, отправлять сообщения в очередь или об-
ращаться к реляционной базе данных.

48
В таблице 8 перечислены основные конечные точки (endpoints), к ко-
торым может обращаться внешний участник.
Таблица 8 – Конечные точки для взаимодействия с аудиозаписями
Путь (api/tracks/) HTTP метод Краткое описание
bytes/{trackId} GET Получение записи трека в байтах
?userId={}&pageable={} GET Получение списка аудиозаписей
upload POST Загрузка аудиозаписи
{trackId} DELETE Удаление аудиозаписи
fingerprint/{trackId} GET Создание отпечатка для аудиоза-
писи
analyze/{trackId} GET Выполнения анализа для аудиоза-
писи
analyze/list/{trackId} GET Получение списка похожих аудио-
записей

Всего в модуле 2 базовых класса: AuthService и TrackService. Первый


класс содержит методы для авторизации пользователя в системе, второй
обеспечивает получение/изменение записей таблицы Track.
Конфигурации JWT
Для авторизации пользователя в системе используется JWT (JSON
Web Token). JSON Web Token – это открытый стандарт (RFC 7519) для со-
здания токенов доступа, основанный на формате JSON. Как правило, ис-
пользуется для передачи данных для аутентификации в клиент-серверных
приложениях. Токены создаются сервером, подписываются секретным клю-
чом и передаются клиенту, который в дальнейшем использует данный токен
для подтверждения своей личности [7].
В исходном коде модуля имеются как минимум два класса необходи-
мых для работы с JWT. В листинге 18 представлен метод, в котором JWT
генерируется (при логине). Время жизни токена должно быть ограничено –
за это отвечает переменная jwtExpiration, которая может задаваться из пере-
менных среды.
При получении запроса с недействительным токеном (истечение
срока жизни или неверный формат заголовка) запрос будет отклонен серве-
ром.

49
Листинг 18 – Класс для генерации JWT токена
public String generateJwtToken(Authentication authentication) {
UserDetails userPrincipal = (UserDetails) authentication.getPrinci-
pal();
Date now = new Date();
return Jwts.builder()
.setSubject((userPrincipal.getUsername()))
.setIssuedAt(now)
.setExpiration(new Date((now).getTime() + jwtExpiration))
.signWith(Keys.hmacShaKeyFor(jwtSecret.getBytes()), SignatureAl-
gorithm.HS512).compact();
}

Исходный код в листинге 19 содержит метод, выполняемый при по-


лучении каждого запроса на ресурсы. Метод doFilterInternal() обрабатывает
значение заголовка Authorization из HTTP запроса, получает JWT токен и
определяет его корректность. Если токен корректный, то по токену сервер
может определить пользователя и его роль в системе. При истечении срока
жизни токена клиент может снова выполнить авторизацию, получить новый
токен и выполнить запросы на получение ресурсов с сервера.
Листинг 19 – Метод для фильтрации запросов на ресурсы
@Override
protected void doFilterInternal(HttpServletRequest request, HttpS-
ervletResponse response, FilterChain filterChain) throws ServletException,
IOException {
try {
String jwt = getJwt(request);
if (jwt != null && tokenProvider.validateJwtToken(jwt)) {
String username = tokenProvider.getUserNameFromJwtTo-
ken(jwt);

UserDetails userDetails = userDetailsSer-


vice.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new
UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetails-
Source().buildDetails(request));

SecurityContextHolder.getContext().setAuthentication(au-
thentication);
}
} catch (Exception e) {
logger.error("Can NOT set user authentication -> Message: {}",
e);
SecurityContextHolder.clearContext();
} filterChain.doFilter(request, response);}

50
3.5. Реализация модуля SPA
В качестве фреймворка для фронт-энд части приложения был выбран
Vue.js. Данная технология имеет обширную документацию даже на русском
языке, большое сообщество и широкий выбор библиотек компонентов (ком-
поненты ввода, загрузки, выпадающего меню и т.п.).
Для задачи создания первоначальной версии приложения необходима
какая-либо из библиотек компонент. Такой библиотекой выбрана Quasar.
Реализация веб-оформления
Одностраничное приложение (single page application, SPA) – это веб-
приложение или веб-сайт, использующий единственный HTML-доку-
мент как оболочку для всех веб-страниц и организующий взаимодействие с
пользователем через динамически подгружаемые HTML, CSS, JavaScript,
обычно посредством AJAX [10].
В модуле SPA существует лишь один HTML документ. Бизнес-логика
приложения располагается в однофайловых компонентах .vue. Такой файл
хранит сразу шаблон компонента, javascript исходный код и CSS стили.
После входа в приложение пользователю будет отображаться основ-
ное меню (рисунок 20), из которого можно перейти в другие страницы (или
через боковое меню).

Рисунок 20 – Основное меню

51
На странице «Мои треки» (рисунок 21) представлен список загружен-
ных пользователем аудиозаписей. Справа находится окно для загрузки но-
вых треков. В левой части окна расположено быстрое меню для перехода на
основные страницы приложения. В центре пользователь может запускать
прослушивание треков, создание отпечатков или анализ трека на схожесть
с другими.

Рисунок 21 – Страница «Мои треки»

На рисунке 22 представлена подсказка при наведении на оранжевый


знак вопроса. Для данных аудиозаписей не созданы отпечатки в системе.
При нажатии на данную кнопку будет отправлен запрос на отправку сооб-
щения в соответствующую очередь, а статус аудиозаписи перейдет в «ожи-
дание создания отпечатка» (рисунок 23).

Рисунок 22 – Статус о невыполненном создании отпечатка

52
Рисунок 23 – Ожидание создания отпечатка

После создания отпечатка напротив аудиозаписи появится меню с вы-


бором анализа: сравнения аудиозаписи локально с треками библиотеки
пользователя или с открытыми треками сообщества (рисунок 24). Второй
способ выполняет сравнение только с теми треками, которые имеют опре-
деленный статус, установленный пользователем, загрузившем в систему.

Рисунок 24 – Меню запуска анализа отпечатка

Если анализ еще не закончился, пользователь должен увидеть соот-


ветствующий статус о текущем выполнении анализа как на рисунке 25 (Ана-
лиз отпечатка в процессе выполнения). Операция выполнения анализа не
является очень быстрой, требуется время на получение отпечатков и син-
хронизацию по времени с похожими. Но из-за асинхронного выполнения
операций за счет очереди сообщений пользователь способен продолжать ис-
пользовать систему, например, загрузить еще несколько аудиозаписей.

53
Рисунок 25 – Статус о процессе выполнения анализа

После окончания выполнения будет доступен переход на страничку с


ранжированным списком схожих треков (рисунок 26).

Рисунок 26 – Окончание выполнение анализа

Также пользователи могут перейти на страничку с отображением всех


открытых аудиозаписей пользователей (рисунок 27).

Рисунок 27 – Страница аудиозаписей сообщества

Страничка с обзором открытых аудиозаписей доступна и для неавто-


ризованных в системе пользователям, но при переходе на страницу «Мои
треки» (рисунок 21) будет автоматически открыто окно логина/регистра-
ции.

54
Рисунок 28 – Страница схожих треков ремикса «Турецкий марш»

На рисунке 28 представлена страница с ранжированным списком схо-


жих аудиозаписей ремикса известного произведения В.А. Моцарта «Турец-
кий марш». На данной странице, например, первое место в ранжированном
списке схожих занимает аудиозапись оригинала «Турецкий марш», а второй
ремикс в библиотеки пользователя на оригинальное произведение нахо-
дится на четвертом месте. К сожалению, выполненный поиск может выдать
неявные схожие аудиозаписи. Это может быть связано с одинаковыми сэм-
плами или иными повторяющимися часто нотами в разных треках.
Пользователь может здесь же прослушать как и интересующий для
сравнения трек, так и сравниваемые композиции.

55
4. ТЕСТИРОВАНИЕ
Тестирование веб-приложения для определения степени схожести му-
зыкальных треков разделено на модульное тестирование, функциональное
тестирование и эксперимент по качеству нахождения схожих записей.
Данные формы тестирования проводились на оборудовании с ви-
деокартой NVIDIA GeForce GTX 1660 SUPER, ОЗУ 16 Гб, процессором
AMD Ryzen 5 3600 6 × 3600 МГц.

4.1. Модульное тестирование


Модульное тестирование (юнит-тестирование) – тестирование, заклю-
чающееся в изолированной проверке каждого отдельного элемента путем
запуска тестов в искусственной среде [16].
Модульное тестирование было применено к методам компонентов
«Модуль создания отпечатков» и «Модуль выполнения анализа». Данные
методы используются в двух данных компонентах, что было описано в тре-
тьей главе. Для тестирования на языке Python 3.8 была использована биб-
лиотека unittest, которая поддерживает автоматизацию тестов.
Пример метода тестирования продемонстрирован в листинге 20. В ка-
честве аргументов для метода во время тестирования подбирается удобно
читаемый объект (массив, строка или примитивный тип). Значения парамет-
ров размера окна быстрого преобразования Фурье и сдвига, а также частоты
дискретизации были установлены аналогично значениям в рабочем исход-
ном коде. Результат, полученный из метода, сравнивается с эталонным. Для
сравнения десятичных значений до определенной точности библиотека во
многих функциях предоставляет параметр delta. Если вычисляемое значе-
ние равна эталонному в рамках заданной точности, то тест считается прой-
денным.
Все модульные тесты для методов, представленные в таблице 9, явля-
лись успешными.

56
Листинг 20 – Пример модульного тестирования
# Модульное тестирование метода frameIndexToTime
def test_frameIndexToTime(self):
FRAME_SIZE = 2048
HOP_SIZE = 512
SR = 22100

index_40 = frameIndexToTime(40, SR, HOP_SIZE, FRAME_SIZE)


index_500 = frameIndexToTime(500, SR, HOP_SIZE, FRAME_SIZE)
index_1000 = frameIndexToTime(1000, SR, HOP_SIZE, FRAME_SIZE)
index_6000 = frameIndexToTime(6000, SR, HOP_SIZE, FRAME_SIZE)
index_20000 = frameIndexToTime(20000, SR, HOP_SIZE, FRAME_SIZE)

self.assertAlmostEqual(index_40, 0.97303, delta=0.001)


self.assertAlmostEqual(index_500, 11.630, delta=0.001)
self.assertAlmostEqual(index_1000, 23.2137, delta=0.001)
self.assertAlmostEqual(index_6000, 139.0508, delta=0.001)
self.assertAlmostEqual(index_20000, 463.3947, delta=0.001)

Таблица 9 – Модульное тестирование методов для анализа отпечатков


№ Тестируемый метод Краткое описание метода Результат
тестирования
1 getMaxList Метод получения максималь- Пройден
ных по амплитуде значений в
срезе одного временного бига
для каждого из диапазонов
частотных бинов.
2 getMaxOverAverage Метод для создания меток Пройден
для тех частот, которые
меньше среднего значения в
срезе одного временного бина
среди максимальных частот,
полученных в результате ме-
тода getMaxList.
3 getMaxCoordArray Метод для трансформирова- Пройден
ния массива тройной вложен-
ности, полученной на выходе
getMaxOverAverage, в массив
двойной вложенности с уда-
лением информации об ам-
плитуде частоты.
4 frameIndexToTime Метод для перевода значения Пройден
индекса временного бина в
действительное время в се-
кундах
5 freqBinToFreqVal Метод для перевода значения Пройден
индекса частотного бина в
действительное значение ча-
стоты в Герцах

57
4.2. Функциональное тестирование
Функциональное тестирование заключается в проверке факта кор-
ректной работы функционала, заявленных в требованиях к системе, реали-
зованных на базе спроектированных модулей. Функциональные тесты прой-
дены успешно. Система выполняет асинхронное выполнение трудоемких
операций успешно. Система является горизонтально и вертикально масшта-
бируемой. Детальные результаты тестирования приведены в таблице 10.
Таблица 10 – Функциональное тестирование веб-приложения
№ Функционал Ожидаемый результат Результат
тестирова-
ния
1 Регистрация пользователя Запись пользователя корректно Пройден
занесена в базу данных. Пользо-
ватель перенаправляется на
страницу логина
2 Авторизация пользователя с Переход на главную домашнюю Пройден
корректным логином и па- страницу веб-приложения
ролем
3 Авторизация пользователя с Появления предупреждения о Пройден
некорректным логином и некорректно заполняемых полях
паролем
4 Загрузка аудиозаписей че- Запись успешно загружена. По- Пройден
рез пользовательский ин- явление новой строчки в списке
терфейс аудиозаписей пользователя
5 Выполнение создания «от- Появление меню напротив за- Пройден
печатка» аудиозаписи фор- писи о возможности выполнить
матов .mp3, .ogg, .wav. поиск похожих аудиозаписей
6 Выполнение поиска схожих Появление меню напротив за- Пройден
аудиозаписей писи о возможности просмотра
похожих аудиозаписей в ранжи-
рованном формате
7 Выполнение очередного по- Появление меню напротив за- Пройден
вторного поиска схожих писи о возможности просмотра
аудиозаписей похожих аудиозаписей в ранжи-
рованном формате
8 Просмотр схожих аудиоза- Появление интерфейса с наиме- Пройден
писей нованием интересующей аудио-
записи и ранжированным спис-
ком похожих к интересующей
аудиозаписей
9 Прослушивание аудиоза- Появление звука данной аудио- Пройден
писи записи. Аудиоплеер браузера
показывает корректное время за-
писи

58
Окончание таблицы 10
10 Создание десяти заявок на Система отображает для записей Пройден
выполнение создание «от- с заявками статус «В процессе
печатка» создания отпечатка». Система
выполняет иной другой функци-
онал без ожидания выполнения
заявок
11 Создание десяти заявок на Система отображает для записей Пройден
поиск схожих аудиозаписей с заявками статус «В процессе
анализа». Система выполняет
иной другой функционал без
ожидания выполнения заявок

4.3. Проверка качества поиска схожих треков


Для проверки качества поиска схожих треков было загружено в си-
стему авторизованным тестовым пользователем 102 аудиозаписи. Данный
набор аудиозаписей содержит в равных размерах аудиозаписи следующих
жанров: блюз, джаз, кантри, классическая музыка, латиноамериканская му-
зыка, поп-музыка, рок-музыка, хип-хоп, электронная музыка. Такой разброс
по жанрам в равных пропорциях был сделан для тестирования алгоритма
нахождения схожих аудиозаписей среди песен разной тональности, ритма,
мелодичности и т.п.
Для первого эксперимента были загружены 4 исследуемых ремикса
для четырех аудиозаписей из ранее полученных ста двух. Ремикс представ-
ляет собой версию музыкального произведения, записанную позже ориги-
нальной версии и, как правило, с более современным вариантом аранжи-
ровки [20].
Ремикс может повторять основной музыкальный мотив оригинала, в
следствие чего человек определяет сходство. При этом похожие отрывки
могут располагаться в хаотичном порядке следования и с иными музыкаль-
ными инструментами (и/или электронными звучаниями).
Цель данного эксперимента – определить место ремикса в ранжиро-
ванном списке похожих аудиозаписей оригинала среди всех 102 записей

59
различных жанров и направлений. Результаты такого тестирования пред-
ставлены в таблице 11.
Таблица 11 – Проверка качества поиска схожих треков
№ Наименование ориги- Место реми- Примечание
нала кса в списке
схожих
1 В.А. Моцарт, «Турецкий 1 Иные классические произведения
марш» располагаются по 5 место
2 В.Р. Вагнер, «Полет валь- 2 На первом месте симфония № 40
кирий» В.А. Моцарта
3 Людвиг ван Бетховен, 1 «Турецкий марш» Моцарта на 2-ом
Bagatelle no 25 «К Элизе» месте. По 5 место поп-песни или
песни жанра кантри
4 Queen, «We are the cham- 1 Большинство песен из первых 10
pions» мест – это поп-песни с выделяющи-
мися гитарными звучаниями

Можно сделать вывод, что для осовремененных классических произ-


ведений система успешно ставит ремиксы оригиналов на наиболее по рангу
сходства высокие места для соответствующего произведения. Данные реми-
ксы не являются точными или почти точными копиями оригиналов. Си-
стема справляется сопоставлять переработанное произведение с оригина-
лом. Но по данному эксперименту можно заметить, что помимо непосред-
ственно оригинала в первые строчки по схожести попадают аудиозаписи из
совсем других жанров, которые для человека могут быть совсем не похо-
жими на исследуемый. Можно учесть, что в похожих поп-песнях выделя-
ются музыкальные инструменты, которые есть и в классических.
Второй эксперимент заключался в том, что были соединены две поло-
вины ремикс треков «К Элизе» Бетховена и «We are the champions» группы
Queen, а полученный трек, названный «К Элизе – We are the champions», был
загружен в систему для последующего получения отпечатка.
Далее был проведен поиск похожих аудиозаписей на данный трек, со-
зданный вручную. Стоит заметить, что данный поиск производится также
среди ранее загруженных более 100 аудиозаписей, среди которых есть как
две оригинальных аудиозаписи, так и два ремикса, на основе которых была

60
создана аудиозапись, анализируемая на данном шаге. Кроме того, была за-
гружена аудиозапись («We are the champions – К Элизе»), созданная анало-
гично анализируемой, но с обратным порядком соединения двух ремиксов –
в первой половине «We are the champions», во второй половине «К Элизе».
Результат полученных наиболее похожих аудиозаписей для послед-
него созданного вручную трека «К Элизе – We are the champions» представ-
лен в таблице 12.
Таблица 12 – Схожие аудиозаписи для «К Элизе – We are the champions»
№ Наименование аудиозаписи Место аудиозаписи
в списке схожих
1 Людвиг ван Бетховен, Bagatelle no 25 «К Элизе» 1
(ремикс)
2 «We are the champions – К Элизе» 2
3 Queen, «We are the champions» (ремикс) 3
4 Людвиг ван Бетховен, Bagatelle no 25 «К Элизе» 4
5 Queen, «We are the champions» 5
6 Maluma, «Que Chimba» 6
7 В.А. Моцарт, «Турецкий марш» 7
8 Matt Stell, «That ain`t Me No More» 8

Таким образом, система успешно справилась с поиском как непосред-


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

61
ЗАКЛЮЧЕНИЕ
Цель данной работы состояла в разработке веб-приложения для опре-
деления степени сходства музыкальных треков. Поставленная цель была до-
стигнута.
В ходе выполнения работы были решены следующие задачи.
1. Проведен анализ существующих алгоритмов определения схожих
треков и выполнен обзор аналогов.
2. Выполнено проектирование архитектуры приложения.
3. Осуществлен выбор средств реализации задачи.
4. Организована структура баз данных и очередей сообщений.
5. Реализован модуль системы поиска схожих записей.
6. Реализованы серверная и клиентская части веб-приложения.
7. Протестировано разработанное веб-приложение.
Направления дальнейших исследований
В дальнейшей работе по данному проекту планируется добавить авто-
матическое определение музыкального жанра, используя MFCC (Mel-
frequency cepstral coefficients, Мел-кепстральные коэффициенты), а также
повысить качество определения схожих аудиозаписей с помощью жанровой
принадлежности.

62
ЛИТЕРАТУРА
1. An Industrial –Strength Audio Search Algorithm. [Электронный ре-
сурс] URL: https://www.ee.columbia.edu/~dpwe/papers/Wang03-shazam.pdf
(дата обращения: 24.04.2021 г.).
2. An Interactive Guide To The Fourier Transform. [Электронный ре-
сурс] URL: https://betterexplained.com/articles/an-interactive-guide-to-the-fou-
rier-transform/ (дата обращения: 24.04.2021 г.).
3. Audio Fingerprint Extraction Based on Locally Linear Embedding for
Audio Retrieval System. [Электронный ресурс] URL:
https://www.mdpi.com/2079-9292/9/9/1483 (дата обращения: 22.04.2021 г.).
4. Ayanoglu E., Aytas Y., Nahum D. Mastering RabbitMQ. – Packt Pub-
lishing, 2015. – P. 286.
5. How does Shazam work. [Электронный ресурс] URL: http://coding-
geek.com/how-shazam-works/ (дата обращения: 26.04.2021 г.).
6. Interpret FFT, complex DFT, frequency bins & FFTShift. [Электрон-
ный ресурс] URL: https://www.gaussianwaves.com/2015/11/interpreting-fft-
results-complex-dft-frequency-bins-and-fftshift (дата обращения:
24.04.2021 г.).
7. JSON Web Tokens. [Электронный ресурс] URL: https://jwt.io/intro-
duction (дата обращения: 24.04.2021 г.).
8. PostgreSQL 10.16 Documentation. [Электронный ресурс] URL:
https://www.postgresql.org/files/documentation/pdf/10/postgresql-10-A4.pdf
(дата обращения: 24.04.2021 г.).
9. RabbitMQ. Documentation. [Электронный ресурс] URL:
https://www.rabbitmq.com/documentation.html (дата обращения:
24.04.2021 г.).
10. SPA (Single-page Application). [Электронный ресурс] URL:
https://developer.mozilla.org/en-US/docs/Glossary/SPA (дата обращения:
25.04.2021 г.).

63
11. What is a spectrogram? [Электронный ресурс] URL: https://vibra-
tionresearch.com/blog/what-is-a-spectrogram/ (дата обращения: 24.04.2021 г.).
12. Whitepaper Review: How Shazam Works – Part 2. [Электронный
ресурс] URL: https://www.mcand.ru/how-shazam-works-part-2 (дата обраще-
ния: 24.04.2021 г.).
13. Звук: немного теории. [Электронный ресурс] URL: http://web-
sound.ru/articles/theory/sound-theory.htm (дата обращения: 24.04.2021 г.).
14. Звуковые волны. [Электронный ресурс] URL:
http://msk.edu.ua/ivk/Fizika/Konspekt/Zvuk.php (дата обращения:
26.04.2021 г.).
15. Котельников В.А. О пропускной способности эфира и прово-
локи в электросвязи – Всесоюзный энергетический комитет. – М.: Управ-
ление связи РККА, 1933. – С. 762 – 770.
16. Модульное тестирование. Зачем, как и кто. [Электронный ре-
сурс] URL: http://citforum.ru/SE/testing/unit_testing/ (дата обращения:
21.04.2021 г.).
17. Нуссбаумер Г. Быстрое преобразование Фурье и алгоритмы вы-
числения сверток. – М.: Радио и связь, 1985. – 248 с.
18. Плохотников К.Э. Статистика // К.Э. Плохотников, С.В. Кол-
ков – М.: ФЛИНТА, 2012. – 288 с.
19. Понятно о кодировании аудио. [Электронный ресурс] URL:
http://websound.ru/articles/technologies/clarification_r.htm (дата обращения:
24.04.2021 г.).
20. Что такое ремикс, ремейк и кавер. [Электронный ресурс] URL:
http://www.as-workshop.ru/articles/276-remix (дата обращения:
24.04.2021 г.).
21. Шенинг Г. Ю. PostgreSQL 11 Мастерство разработки. / пер. с
англ. А.А. Слинкина. – М.: ДМК Пресс, 2019. – 352 с.

64

Вам также может понравиться