В рамках исследовательского проекта «развлечение дома» я пытаюсь найти способ уменьшить / преобразовать песню в гудящий звуковой сигнал (основная мелодия, которую мы, люди, воспринимаем, когда слушаем песню). Прежде чем продолжить описание своей попытки решить эту проблему, я хотел бы упомянуть, что я совершенно не знаком с аудиоанализом, хотя у меня большой опыт анализа изображений и видео.
Немного погуглив, я нашел кучу алгоритмов извлечения мелодий. Учитывая полифонический звуковой сигнал песни (например, файл .wav), они выводят дорожку высоты тона - в каждый момент времени они оценивают доминирующую высоту звука (исходящую от голоса певца или какого-либо инструмента, генерирующего мелодию) и отслеживают доминирующую высоту звука. шаг с течением времени.
Я прочитал несколько статей, и они, кажется, вычисляют кратковременное преобразование Фурье песни, а затем проводят некоторый анализ спектрограммы, чтобы получить и отследить доминирующую высоту тона. Извлечение мелодии - это только компонент в системе, которую я пытаюсь разработать, поэтому я не возражаю против использования любого доступного алгоритма, поскольку он хорошо справляется с моими аудиофайлами и доступен код. Поскольку я новичок в этом, я был бы рад услышать любые предложения о том, какие алгоритмы, как известно, работают хорошо, и где я могу найти его код.
Я нашел два алгоритма:
Я выбрал Мелодию, так как результаты в разных музыкальных жанрах выглядели весьма впечатляюще. Пожалуйста, проверьте это, чтобы увидеть результаты. Жужжание, которое вы слышите при каждом музыкальном произведении, - это, по сути, то, что меня интересует.
«Это поколение этого гудения для любой произвольной песни, и мне нужна ваша помощь в этом вопросе».
Алгоритм (доступный как плагин vamp) выводит дорожку высоты тона --- [time_stamp, pitch / frequency] --- матрицу Nx2, где в первом столбце - отметка времени (в секундах), а во втором столбце - преобладающий тон. обнаружен на соответствующей отметке времени. Ниже показана визуализация дорожки основного тона, полученная с помощью алгоритма, наложенного фиолетовым цветом на сигнал во временной области песни (вверху) и его спектрограмму / кратковременный фурье. Отрицательные значения основного тона / частоты представляют собой алгоритм оценки доминирующего основного тона для неголосовых / немелодических сегментов. Так что все оценки высоты тона> = 0 соответствуют мелодии, остальные для меня не важны.

Теперь я хочу преобразовать этот питч-трек обратно в гудящий звуковой сигнал - точно так же, как это есть у авторов на своих сайтах.
Ниже приведена функция MATLAB, которую я написал для этого:
function [melSignal] = melody2audio(melody, varargin)
% melSignal = melody2audio(melody, Fs, synthtype)
% melSignal = melody2audio(melody, Fs)
% melSignal = melody2audio(melody)
%
% Convert melody/pitch-track to a time-domain signal
%
% Inputs:
%
% melody - [time-stamp, dominant-frequency]
% an Nx2 matrix with time-stamp in the
% first column and the detected dominant
% frequency at corresponding time-stamp
% in the second column.
%
% synthtype - string to choose synthesis method
% passed to synth function in synth.m
% current choices are: 'fm', 'sine' or 'saw'
% default='fm'
%
% Fs - sampling frequency in Hz
% default = 44.1e3
%
% Output:
%
% melSignal -- time-domain representation of the
% melody. When you play this, you
% are supposed to hear a humming
% of the input melody/pitch-track
%
p = inputParser;
p.addRequired('melody', @isnumeric);
p.addParamValue('Fs', 44100, @(x) isnumeric(x) && isscalar(x));
p.addParamValue('synthtype', 'fm', @(x) ismember(x, {'fm', 'sine', 'saw'}));
p.addParamValue('amp', 60/127, @(x) isnumeric(x) && isscalar(x));
p.parse(melody, varargin{:});
parameters = p.Results;
% get parameter values
Fs = parameters.Fs;
synthtype = parameters.synthtype;
amp = parameters.amp;
% generate melody
numTimePoints = size(melody,1);
endtime = melody(end,1);
melSignal = zeros(1, ceil(endtime*Fs));
h = waitbar(0, 'Generating Melody Audio' );
for i = 1:numTimePoints
% frequency
freq = max(0, melody(i,2));
% duration
if i > 1
n1 = floor(melody(i-1,1)*Fs)+1;
dur = melody(i,1) - melody(i-1,1);
else
n1 = 1;
dur = melody(i,1);
end
% synthesize/generate signal of given freq
sig = synth(freq, dur, amp, Fs, synthtype);
N = length(sig);
% augment note to whole signal
melSignal(n1:n1+N-1) = melSignal(n1:n1+N-1) + reshape(sig,1,[]);
% update status
waitbar(i/size(melody,1));
end
close(h);
end
Логика, лежащая в основе этого кода, следующая: на каждой временной отметке я синтезирую короткоживущую волну (скажем, синусоидальную волну) с частотой, равной обнаруженному доминирующему тону / частоте на этой временной отметке, в течение продолжительности, равной его пробел со следующей отметкой времени во входной матрице мелодии. Мне только интересно, правильно ли я это делаю.
Затем я беру аудиосигнал, получаемый от этой функции, и воспроизводю его с исходной песней (мелодия на левом канале и исходная песня на правом канале). Хотя сгенерированный аудиосигнал, кажется, достаточно хорошо сегментирует источники, генерирующие мелодию (голос / ведущий инструмент) - он активен там, где есть голос, и ноль везде - сам сигнал далеко не гудящий (я получаю что-то вроде beep beep beeeeep beep beeep beeeeeeeep), которые авторы показывают на своих сайтах. В частности, ниже представлена визуализация, показывающая сигнал во временной области входной песни внизу и сигнал во временной области мелодии, сгенерированной с использованием моей функции.

Одна из основных проблем заключается в том, что хотя мне дается частота волны для генерации на каждой временной отметке, а также продолжительность, я не знаю, как установить амплитуду волны. На данный момент я установил для амплитуды ровное / постоянное значение и подозреваю, что проблема именно в этом.
Есть ли у кого-нибудь предложения по этому поводу? Я приветствую предложения на любом языке программы (желательно MATLAB, python, C ++), но я предполагаю, что мой вопрос здесь более общий: как сгенерировать волну на каждой временной отметке?
Несколько идей / исправлений на мой взгляд:
- Установите амплитуду, получив усредненную / максимальную оценку амплитуды сигнала во временной области исходной песни.
- Полностью изменить мой подход - вычислить спектрограмму / кратковременное преобразование Фурье звукового сигнала песни. срезать с трудом / обнулить или мягко все остальные частоты, кроме тех, что в моем питч-треке (или близки к моему питч-треку). А затем вычислите обратное кратковременное преобразование Фурье, чтобы получить сигнал во временной области.