В рамках проекта "fun-at-home-research-project" я пытаюсь найти способ уменьшить/преобразовать песню в гудение, как аудиосигнал (основная мелодия, которую мы, люди, воспринимаем, когда слушаем песню). Прежде чем я расскажу о своей попытке решить эту проблему, я хотел бы упомянуть, что я совершенно не знаком с аудиоанализом, хотя у меня есть большой опыт анализа изображений и видео.
После того, как я немного поработал, я нашел кучу алгоритмов извлечения мелодии. Учитывая полифонический аудиосигнал песни (например:.wav файл), они выводят трек основного тона --- в каждый момент времени они оценивают доминирующий шаг (исходящий от голоса певца или какого-то инструмента для создания мелодии) и отслеживают доминирующее шаг с течением времени.
Я прочитал несколько статей, и они, похоже, вычислили короткое преобразование Фурье песни, а затем сделают некоторый анализ на спектрограмме, чтобы получить и отследить доминирующий шаг. Извлечение мелодии - это всего лишь компонент в системе, которую я пытаюсь разработать, поэтому я не против использовать какой-либо алгоритм, который доступен, насколько он подходит для моих аудиофайлов, и код доступен. Поскольку я новичок в этом, я был бы рад услышать любые предложения, по которым известно, что алгоритмы работают хорошо, и где я могу найти его код.
Я нашел два алгоритма:
Я выбрал Melodia, поскольку результаты в разных музыкальных жанрах выглядели довольно впечатляюще. Пожалуйста, проверьте чтобы увидеть его результаты. Гудение, которое вы слышите для каждой части музыки, по сути, меня интересует.
"Это поколение этого жужжания для любой произвольной песни, о которой я хочу помочь в этом вопросе".
Алгоритм (доступен как плагин vamp) выводит звуковую дорожку --- [time_stamp, pitch/frequency] --- матрицу Nx2, где в первом столбце находится метка времени (в секундах) и вторая колонка является доминирующим шагом, обнаруженным на соответствующей отметке времени. Ниже приведена визуализация тональной дорожки, полученной из алгоритма, наложенного фиолетовым цветом, с сигналом во временной области (см. Выше) и его спектрограммой/кратковременным увеличением. Отрицательные значения шага/частоты представляют собой алгоритмы доминантной оценки шага для незвуковых/не-мелодических сегментов. Поэтому все оценки тонa >= 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
Основополагающая логика этого кода такова: на каждой отметке времени я синтезирую короткоживущую волну (скажем, синусоидальную) с частотой, равной обнаруженной доминирующей частоте/частоте на этой отметке времени для продолжительность равна его разрыву со следующей отметкой времени во входной матрице мелодии. Я только задаюсь вопросом, правильно ли я делаю это.
Затем я беру аудиосигнал, который я получаю от этой функции, и воспроизвожу его с оригинальной песней (мелодия на левом канале и оригинальная песня на правом канале). Хотя сгенерированный аудиосигнал, похоже, довольно хорошо сегментирует источники генерации мелодии (голос/ведущий-intstrument) - его активность, когда голос и нуль повсюду - сам сигнал далеко не гудит (я получаю что-то вроде beep beep beeeeep beep beeep beeeeeeeep), которые авторы показывают на своем веб-сайте. В частности, ниже представлена визуализация, показывающая сигнал временной области входной композиции в нижней части и сигнал временной области мелодии, генерируемой с использованием моей функции.
Одна из основных проблем - хотя мне дается частота волны для генерации при каждой отметке времени, а также продолжительности, я не знаю, как установить амплитуду волны. На данный момент я устанавливаю амплитуду как плоское/постоянное значение, и я подозреваю, что это проблема.
Есть ли у кого-нибудь предложения по этому поводу? Я приветствую предложения на любом языке программирования (желательно MATLAB, python, С++), но я думаю, мой вопрос здесь более общий --- Как генерировать волну при каждой отметке времени?
Несколько идей/исправлений в моем сознании:
- Установите амплитуду, получив усредненную/максимальную оценку амплитуды от сигнала временной области исходной песни.
- Полностью изменить мой подход - вычислить спектральное/короткое преобразование Фурье звукового сигнала песни. отсекают с трудом/нулевой или мягко все остальные частоты, кроме тех, что у меня на тангаже (или близки к моему тангажу). А затем вычислите обратное кратковременное преобразование Фурье, чтобы получить сигнал во временной области.