exponenta event banner

Генерация гитарных аккордов с помощью алгоритма Karplus-Strong

В этом примере показано, как генерировать реалистичные гитарные аккорды с помощью Karplus-Strong Algorithm и дискретно-временных фильтров.

Установка

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

Fs       = 44100;
A        = 110; % The A string of a guitar is normally tuned to 110 Hz
Eoffset  = -5;
Doffset  = 5;
Goffset  = 10;
Boffset  = 14;
E2offset = 19;

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

F = linspace(1/Fs, 1000, 2^12);

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

x = zeros(Fs*4, 1);

Воспроизведение заметки в открытой строке

Когда гитарная строка выщипывается или ударяется, она производит звуковую волну с пиками в частотной области, которые равномерно разнесены. Они называются гармониками и придают каждой ноте полный звук. Мы можем генерировать звуковые волны с этими гармониками с дискретно-временными фильтрующими объектами.

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

delay = round(Fs/A);

Создайте фильтр IIR, полюса которого аппроксимируют гармоники строки A. Нули добавляются для тонкого формирования частотной области.

b  = firls(42, [0 1/delay 2/delay 1], [0 0 1 1]);
a  = [1 zeros(1, delay) -0.5 -0.5];

Показать амплитудную характеристику фильтра.

[H,W] = freqz(b, a, F, Fs);
plot(W, 20*log10(abs(H)));
title('Harmonics of an open A string');
xlabel('Frequency (Hz)');
ylabel('Magnitude (dB)');

Figure contains an axes. The axes with title Harmonics of an open A string contains an object of type line.

Для генерации 4-секундной синтетической ноты сначала создадим вектор состояний со случайными числами. Затем мы фильтруем нули, используя эти начальные состояния. Это вынуждает случайные состояния выходить из фильтра, сформированного в гармоники.

zi = rand(max(length(b),length(a))-1,1);
note = filter(b, a, x, zi);

Нормализуйте звук для аудиоплайера.

note = note-mean(note);
note = note/max(abs(note));

% To hear, type: hplayer = audioplayer(note, Fs); play(hplayer)

Воспроизведение заметки на фреттовой строке

Каждый лад вдоль шеи гитары позволяет игроку играть на половину тона выше, или ноту, первая гармоника которой выше на 21/12.

fret  = 4;
delay = round(Fs/(A*2^(fret/12)));

b  = firls(42, [0 1/delay 2/delay 1], [0 0 1 1]);
a  = [1 zeros(1, delay) -0.5 -0.5];

[H,W] = freqz(b, a, F, Fs);
hold on
plot(W, 20*log10(abs(H)));
title('Harmonics of the A string');
legend('Open A string', 'A string on the 4th fret');

Figure contains an axes. The axes with title Harmonics of the A string contains 2 objects of type line. These objects represent Open A string, A string on the 4th fret.

Заполните состояния случайными числами.

zi = rand(max(length(b),length(a))-1,1);

Создайте 4-секундную заметку.

note = filter(b, a, x, zi);

Нормализуйте звук для аудиоплайера.

note = note-mean(note);
note = note/max(note);

% To hear, type: hplayer = audioplayer(note, Fs); play(hplayer)

Играть аккорд

Аккорд - это группа нот, сыгранных вместе, гармоники которых усиливают друг друга. Это происходит, когда имеется небольшое целочисленное отношение между двумя нотами, например, отношение 2/3 будет означать, что третья гармоника первых банкнот выровнена со второй гармоникой вторых банкнот.

Определите лады для основного аккорда G.

fret = [3 2 0 0 0 3];

Получайте задержки для каждой заметки на основе ладов и смещений строк.

delay = [round(Fs/(A*2^((fret(1)+Eoffset)/12))), ...
    round(Fs/(A*2^(fret(2)/12))), ...
    round(Fs/(A*2^((fret(3)+Doffset)/12))), ...
    round(Fs/(A*2^((fret(4)+Goffset)/12))), ...
    round(Fs/(A*2^((fret(5)+Boffset)/12))), ...
    round(Fs/(A*2^((fret(6)+E2offset)/12)))];

  
b = cell(length(delay),1);
a = cell(length(delay),1);
H = zeros(length(delay),4096);
note = zeros(length(x),length(delay));
for indx = 1:length(delay)
    
    % Build a cell array of numerator and denominator coefficients.
    b{indx} = firls(42, [0 1/delay(indx) 2/delay(indx) 1], [0 0 1 1]).';
    a{indx} = [1 zeros(1, delay(indx)) -0.5 -0.5].';
    
    % Populate the states with random numbers and filter the input zeros.
    zi = rand(max(length(b{indx}),length(a{indx}))-1,1);
    
    note(:, indx) = filter(b{indx}, a{indx}, x, zi);
    
    % Make sure that each note is centered on zero.
    note(:, indx) = note(:, indx)-mean(note(:, indx));
    
    [H(indx,:),W] = freqz(b{indx}, a{indx}, F, Fs);
end

Отображение величины для всех примечаний в хорде.

hline = plot(W,20*log10(abs(H.')));
title('Harmonics of a G major chord');
xlabel('Frequency (Hz)');
ylabel('Magnitude (dB)');
legend(hline,'G','B','D','G','B','G2');

Figure contains an axes. The axes with title Harmonics of a G major chord contains 8 objects of type line. These objects represent Open A string, A string on the 4th fret, G, B, D, G2.

Объедините заметки и нормализуйте их.

combinedNote = sum(note,2);
combinedNote = combinedNote/max(abs(combinedNote));

% To hear, type: hplayer = audioplayer(combinedNote, Fs); play(hplayer)

Добавление эффекта Strumming

Чтобы добавить эффект ударения, мы просто смещаем каждую ранее созданную заметку.

Определите смещение между строками как 50 миллисекунд.

offset = 50; 
offset = ceil(offset*Fs/1000);

Добавьте 50 миллисекунд между каждой заметкой путем добавления нулей.

for indx = 1:size(note, 2)
    note(:, indx) = [zeros(offset*(indx-1),1); ...
                note((1:end-offset*(indx-1)), indx)];
end

combinedNote = sum(note,2);
combinedNote = combinedNote/max(abs(combinedNote));

% To hear, type: hplayer = audioplayer(combinedNote, Fs); play(hplayer)

См. также

|