diff --git a/src/PARTIE1.m b/src/PARTIE1.m new file mode 100644 index 0000000000000000000000000000000000000000..3ac99b6a92739ccf3e49b10b1376d204ee8cad91 --- /dev/null +++ b/src/PARTIE1.m @@ -0,0 +1,185 @@ +%% ======================================================================== +% PARTIE 1 — Synthese additive (Q 1.1 → Q 1.5) +% Poly « SAR – Traitements audio : partie signal » v1.0 (23 avril 2025) +% ------------------------------------------------------------------------ +% AUCUN caractere « _ » dans les noms de variables ou de fonctions. +% Les fichiers .wav peuvent garder leur nom d origine. +% ------------------------------------------------------------------------ +clear; close all; clc + +%% ------------------------------------------------------------------------ +%% Question 1.1 – Spectre et frequence fondamentale +% ------------------------------------------------------------------------- +fichiers = { ... + "wav/piano_chord.wav", ... + "wav/nylon-guitar.wav", ... + "wav/single_tone_celtic-harp-a3.wav" }; + +figure('Name','Q1-1 Spectres'); hold on +fundamentale = zeros(numel(fichiers),1); +nom = {"piano","guitare","harpe"} +for k = 1:numel(fichiers) + [x, Fe] = audioread(fichiers{k}); + x = mean(x,2); % mono + N = length(x); + X = fftshift( fft( x .* hann(N) ) ); % fenetrage Hann + f = linspace(-Fe/2, Fe/2, N); + amp = 20*log10( abs(X) + eps ); + + plot(f, amp, 'DisplayName', nom{k}); + + % premiere raie cote positif = fondamentale + [~, idx] = max( amp(f > 0) ); + posVect = find(f > 0); + idxPos = posVect(idx); + fondamentale(k) = f(idxPos); +end +grid on; xlabel('Frequence (Hz)'); ylabel('Amplitude (dB)'); +legend('Interpreter','none'); title('Q 1.1 Spectres normalises'); + +%% ------------------------------------------------------------------------ +%% Question 1.2 – Inharmonicite de deux pianos +% ------------------------------------------------------------------------- +[p1, Fe1] = audioread("wav/single_tone_piano1.wav"); +[p2, Fe2] = audioread("wav/single_tone_piano2.wav"); + +analyse = @(x, Fe) ... + struct( ... + "N", length(x), ... + "f", linspace(-Fe/2, Fe/2, length(x)), ... + "amp", 20*log10( abs( fftshift( fft( mean(x,2) ) ) ) + eps ) ); + +S1 = analyse(p1, Fe1); +S2 = analyse(p2, Fe2); + +% fondamentale de chaque piano (pic principal > 0) +[~, id1] = max( S1.amp( S1.f > 0 ) ); +[~, id2] = max( S2.amp( S2.f > 0 ) ); +idxPos1 = find(S1.f > 0); idxPos2 = find(S2.f > 0); +f1P1 = S1.f( idxPos1(id1) ); +f1P2 = S2.f( idxPos2(id2) ); + +% huit composantes dominantes +kmax = 8; +[pks1, locs1] = findpeaks( S1.amp(S1.f > 0), 'SortStr','descend', ... + 'NPeaks', kmax ); +[pks2, locs2] = findpeaks( S2.amp(S2.f > 0), 'SortStr','descend', ... + 'NPeaks', kmax ); +fMes1 = S1.f( S1.f > 0 ); +fMes1 = fMes1(locs1).'; +fMes2 = S2.f( S2.f > 0 ); +fMes2 = fMes2(locs2).'; + +fTheo1 = f1P1*(1:kmax).'; +fTheo2 = f1P2*(1:kmax).'; + +xi1 = 1200*abs( log2( fMes1 ./ fTheo1 ) ); % cents +xi2 = 1200*abs( log2( fMes2 ./ fTheo2 ) ); + +inharmTot1 = sum(xi1); +inharmTot2 = sum(xi2); + +fprintf('\nInharmonicite totale Piano 1 : %.2f cents\n', inharmTot1); +fprintf('Inharmonicite totale Piano 2 : %.2f cents\n', inharmTot2); + +figure('Name','Q1-2 Spectres pianos'); +plot(S1.f, S1.amp, 'b', S2.f, S2.amp, 'r'); grid on +xlabel('Frequence (Hz)'); ylabel('Amplitude (dB)'); +legend('Piano 1','Piano 2'); title('Q 1.2 Comparaison spectrale'); + +%% ------------------------------------------------------------------------ +%% Question 1.3 – Synthese additive (8 harmoniques) +% ------------------------------------------------------------------------- +if inharmTot1 <= inharmTot2 + fBase = f1P1; + fMes = fMes1; + ampLin = 10.^(pks1/20); + FeSynt = Fe1; + tag = 'piano1'; +else + fBase = f1P2; + fMes = fMes2; + ampLin = 10.^(pks2/20); + FeSynt = Fe2; + tag = 'piano2'; +end + +ampLin = ampLin(1:kmax); +ampLin = ampLin / max(ampLin); % normalisation + +dur = 2; % secondes +t = 0 : 1/FeSynt : dur - 1/FeSynt; +yAdd = zeros(size(t)); + +for n = 1:kmax + yAdd = yAdd + ampLin(n) * sin(2*pi*fMes(n)*t); +end +yAdd = yAdd.' / max(abs(yAdd)); % colonne + normalisation + +audiowrite("wav/" + tag + "_synth8h.wav", yAdd, FeSynt); +soundsc(yAdd, FeSynt); + +%% ------------------------------------------------------------------------ +%% Question 1.4 – Application enveloppe ADSR +% ------------------------------------------------------------------------- +clear t yAdd + +[ys, Fe] = audioread("wav/" + tag + "_synth8h.wav"); +Nsig = length(ys); + +tA = 0.03; % Attack +tD = 0.12; % Decay +sustainLvl = 0.7; +tR = 0.30; % Release + +nA = round(tA*Fe); +nD = round(tD*Fe); +nR = round(tR*Fe); +nS = max(Nsig - nA - nD - nR, 0); + +env = [ linspace(0,1,nA), ... + linspace(1,sustainLvl,nD), ... + sustainLvl*ones(1,nS), ... + linspace(sustainLvl,0,nR) ]; +env = env(1:Nsig).'; % mise a la meme taille + +yAdsr = ys .* env; +yAdsr = yAdsr / max(abs(yAdsr)); + +soundsc(yAdsr, Fe); +audiowrite("wav/" + tag + "_synth8h_ADSR.wav", yAdsr, Fe); + +figure('Name','Q1-4 ADSR'); plot((0:Nsig-1)/Fe, env); grid on +xlabel('Temps (s)'); ylabel('Amplitude'); +title('Enveloppe ADSR'); + +%% ------------------------------------------------------------------------ +%% Question 1.5 – Synthese par IFFT +% ------------------------------------------------------------------------- +clearvars -except tag FeSynt kmax fMes ampLin + +dur = 2; +Nsyn = round(dur * FeSynt); +Xspec = zeros(Nsyn,1); + +for n = 1:kmax + k = round(fMes(n) / FeSynt * Nsyn) + 1; + A = ampLin(n) / 2; + Xspec(k) = A; + Xspec(Nsyn - k + 2) = conj(A); +end + +yIdft = real( ifft( Xspec ) ); +yIdft = yIdft / max(abs(yIdft)); + +audiowrite("wav/" + tag + "_synth8h_iDFT.wav", yIdft, FeSynt); +soundsc(yIdft, FeSynt); + +% comparaison rapide +[yt, ~] = audioread("wav/" + tag + "_synth8h.wav"); +Lcmp = min(length(yt), length(yIdft)); +errMax = max( abs( yt(1:Lcmp) - yIdft(1:Lcmp) ) ); +fprintf('\nErreur max entre somme sinus et IFFT : %.3e\n', errMax); + +%% ======================================================================== +%% === Fin PARTIE 1 =======================================================