function varargout = ita_tonality(varargin) %ITA_TONALITY - TONALITY ref. DIN 45681 (2002) % This function gives: % TONALITY ref. DIN 45681 (2002) % tonh_max = Maximum Tonal Audibility [dB]. Der Maximale Wert aller DL % ist nach DIN 45681(2002) maßgeblich für die Tonhaltigkeit % tonh_maxf = Frequency [Hz] of this maximum % info = Information Matrix like in DIN paper % Syntax: % audioObjOut = ita_tonality(audioObjIn) % % Example: % audioObjOut = ita_tonality(audioObjIn) % % See also: % ita_toolbox_gui, ita_read, ita_write, ita_generate % % Reference page in Help browser % doc ita_tonality % % This file is part of the application Psychoacoustics for the ITA-Toolbox. All rights reserved. % You can find the license for this m-file in the application folder. % % Author: Daniel Cragg -- Email: daniel.cragg@akustik.rwth-aachen.de % Created: 22-Jun-2010 %% Get Function String thisFuncStr = [upper(mfilename) ':']; %Use to show warnings or infos in this functions %% Initialization and Input Parsing % all fixed inputs get fieldnames with posX_* and dataTyp % optonal inputs get a default value ('comment','test', 'opt1', true) % please see the documentation for more details sArgs = struct('pos1_data','itaAudio'); [input,sArgs] = ita_parse_arguments(sArgs,varargin); %#ok %% +++Body - Your Code here+++ 'input' is an audioObj and is given back sig=input; sig_t=sig.time; % Frequenzgrenzen der Auswertung. ACHTUNG: Das sind die % FFT-Punkte, Frequenz durch Deltaf dividiert! 50 = (100 Hz/2 Hz) anfang = 50; % 100 Hz ende = 4096; % 8192 Hz Nf = 22050; % Anzahl Samplepunkte sampfrq = 44100; freq = 2:2:22050; k_max = round(Nf*0.5); clear L_pt L_pn f_max merker(1:22050) = 0; % Signal muss Spalte sein: Zeilenvektor wird transponiert if size(sig_t,1) == 1 sig_t = sig_t.'; end % ---------------- self-averaging ----------------- num_av = floor((length(sig_t)-2050)/10000 - 1); % überlappend nach 10.000 for i = [1:num_av] a = i*10000; sig_t1 = sig_t((a-9999):a+12050); Sig_tmp = abs(fft(sig_t1.*hanning(Nf))).'; Sig_f(i,:) = (Sig_tmp(1:round(Nf/2)).*sqrt(2)/(2e-5*Nf)).^ 2; end pegel = 10 * log10 (mean(Sig_f)); figure(1) plot(freq(1:2000),pegel(1:2000)) axis([0 2500 -20 80]) text(20,70,['Averages: ' num2str(num_av)]) % ---------------- Anfang und Ende des Untersuchungsbereiches bestimmen i = 1; start = 1; delta_L(anfang:ende) = 0; freq_anfang = freq(anfang); freq_ende = freq(ende); % ---------------- Linienbreite bestimmen linienbreite = freq(2) - freq(1); % ---------------- Falls Spektrum nicht A-bewertet, A-Bewertung vornehmen % hier: KEINE A-Bewertung for i = start:ende pegel(i) = pegel(i) + 165.5 + 20*log10(freq(i)^4 / (freq(i)^2 + 20.6^2) / (freq(i)^2 + 12200^2) / sqrt(freq(i)^2 + 107.7^2) / sqrt(freq(i)^2 + 737.9^2)); end % ---------------- Frequenzgruppenbreite sowie Unter- und Obergrenzen bestimmen j1alt = 2; j2alt = 2; % ---------------- schleife = 1 for i = anfang:ende delta_f_c(i) = 25 + 75 * (1 + 1.4 * (freq(i) / 1000)^2)^0.69; % delta_f_c f1(i) = freq(i) - 0.5 * delta_f_c(i); % f1 f2(i) = freq(i) + 0.5 * delta_f_c(i); % f2 % index fgi1 der Frequenzgruppenuntergrenze bestimmen j = j1alt; while freq(j) < f1(i) & j < ende j = j + 1; end fgi1(i) = j; j1alt = j; % index fgi2 der Frequenzgruppenobergrenze bestimmen j = j2alt; while freq(j) < f2(i) & j <= ende j = j + 1; end fgi2(i) = j - 1; j2alt = j; end % ---------------- Töne suchen % ---------------- schleife = 2 for i = anfang:ende % alle Linien des Spektrums in aufsteig. Reihenfolge untersuchen % mittleren Schmalbandpegel LS bestimmen merker(i) = 1; linien = 1000; vorwert = 0; LS(i) = 1000; % Beginn der iterationsschleife while linien > 9 & vorwert ~= LS(i) % Abbruch, wenn LS sich nicht mehr ändert % oder weniger als 10 Linien zur Bestimmung % von LS übriggeblieben sind % --------------NEU: vektorisiert merker_tmp = zeros(length(fgi1(i):fgi2(i)),1); merker_tmp(pegel(fgi1(i):fgi2(i)) > LS(i) + 6) = 2; % die mehr als 6 dB über LS liegen merker(fgi1(i):fgi2(i))=merker_tmp; % --------------ENDE NEU vorwert = LS(i); % LS(i) = 0; % linien = 0; % --------------NEU: vektorisiert k_vector = find(merker(fgi1(i):fgi2(i))==0) + fgi1(i) - 1; LS(i) = sum(10.^(pegel(k_vector)/10)); linien = length(k_vector); % --------------ENDE NEU if linien > 0 LS(i) = 10 * log10(LS(i) / linien) - 1.76; % LS berechnen end end % Ende der Iterationsschleife if linien < 10 % Falls Iteration wegen Unterschreitung der LS(i) = vorwert; % Mindestzahl an Linien beendet wurde, end % letzten LS mit Anzahl > 10 wählen % for j = fgi1(i):fgi2(i) % verwendete Hilfsmerker rücksetzen % merker(j) = 0; % end merker(fgi1(i):fgi2(i)) = 0; end % ---------------- alle Linien des Spektrums in aufsteig. Reihenfolge untersuchen % ---------------- schleife = 3 for i = anfang:ende if pegel(i) >= LS(i) + 6 % potenziellen Ton als ununterbrochenen D_S = pegel(i)-LS(i); maximum = i; % Bereich mit Pegel > LS + 6 dB suchen maxpegel = pegel(i); kmax = i + 1; while pegel(kmax) >= LS(kmax) + 6 if pegel(kmax) > maxpegel maxpegel = pegel(kmax); % und Frequenz der Spektrallinie mit maximum = kmax; % maximalem Pegel als Frequenz des end % potenziellen Tonesermitteln kmax = kmax + 1; end % !!! mkl NEU: ohne diese Zeilen geht's nicht! (Anfang) ------------------ kmax = i - 1; while pegel(kmax) >= LS(kmax) + 6 if pegel(kmax) > maxpegel maxpegel = pegel(kmax); % maximum = kmax; % end % kmax = kmax - 1; end if maximum>=anfang i = maximum; % sonst unter 100 Hz! end % !!! mkl NEU: ohne diese Zeilen geht's nicht! (Ende) ------------------ % ---------------- Tonpegel des potenziellen Tones bestimmen LT(i) = 10^(pegel(i) / 10); merker(i) = 0; TonLinien(i) = 1; % ---------------- zu kleinen Frequenzen hin Nebenlinien des Tones suchen j = i - 1; while pegel(j) >= LS(i) + 6 & pegel(j) >= pegel(i) - 10 LT(i) = LT(i) + 10^(pegel(j) / 10); merker(i) = 3; TonLinien(i) = TonLinien(i) + 1; j = j - 1; end if j < i - 1 % Flankensteilheit der unteren Flanke berechnen untereFlanke(i) = (pegel(i) - pegel(j)) * freq(i) / sqrt(2) / (freq(i) - freq(j)); else untereFlanke(i) = 100; end % ---------------- zu hohen Frequenzen hin Nebenlinien des Tones suchen j = i + 1; while pegel(j) >= LS(i) + 6 & pegel(j) >= pegel(i) - 10 LT(i) = LT(i) + 10^(pegel(j) / 10); merker(i) = 3; TonLinien(i) = TonLinien(i) + 1; j = j + 1; end if j > i + 1 % Flankensteilheit der oberen Flanke berechnen obereFlanke(i) = (pegel(i) - pegel(j)) * freq(i) / sqrt(2) / (freq(j) - freq(i)); else obereFlanke(i) = 100; end LT(i) = 10 * log10(LT(i)); if merker(i) == 3 % wenn Nebenlinien addiert wurden, LT(i) = LT(i) - 1.76; % Korrektur für Hanning-Fenster vornehmen end % ---------------- Prüfung ob Ton, dann Tonzuschlag berechnen LG(i) = LS(i) + 10 * log10(delta_f_c(i) / linienbreite); av(i) = -2 - log10(1 + (freq(i) / 502)^2.5); delta_L(i) = LT(i) - LG(i) - av(i); % ---------------- Kriterium Ausgeprägtheit: % kein Ton, wenn er breiter als 18 * (1 + 0.001 *fT) der Frequenzgruppe % oder Flankensteilheit kleiner 24/Oktave ist % if (TonLinien(i) * linienbreite > 18 * (1 + 0.001 * freq(i)) | untereFlanke(i) < 24 | obereFlanke(i) < 24) & antwortS ~= 'vbYes' if (TonLinien(i) * linienbreite > 18 * (1 + 0.001 * freq(i)) | untereFlanke(i) < 24 | obereFlanke(i) < 24) delta_L(i) = 0; end for j = fgi1(i):fgi2(i) % verwendete Hilfsmerker rücksetzen merker(j) = 0; end i = kmax - 1; % im oben untersuchten Bereich nicht weiter suchen % ??????? WIE GEHT DAS ?????? end end % ---------------- Töne in einer Frequenzgruppe addieren % ---------------- schleife = 4 for i = ende:-1:anfang if delta_L(i) > 0 % wenn Ton gefunden LT_FG(i) = 10^(LT(i)/10); for j = (i - 1):-1:fgi1(i) % zu tiefen Frequenzen hin prüfen, if delta_L(j) > 0 % ob in der Frequenzgruppe ein weiterer Ton liegt LT_FG(i) = LT_FG(i) + 10^(LT(j) / 10); merker(i) = 4; end end for j = (i + 1):fgi2(i) % zu hohen Frequenzen hin prüfen, if delta_L(j) > 0 % ob in der Frequenzgruppe ein weiterer Ton liegt LT_FG(i) = LT_FG(i) + 10^(LT(j) / 10); merker(i) = 4; end end if merker(i) == 4 % wenn mindestens 2 Töne in der Frequenzgruppe LT_FG(i) = 10 * log10(LT_FG(i)); delta_L_FG(i) = LT_FG(i) - LG(i) - av(i); else LT_FG(i) = 0; end end end % ---------------- Töne anzeigen und maximalen Zuschlag bestimmen maxzuschlag = 0; j = 1; DL(i)=delta_L(i); DLF(i) = DL(i); for i = anfang:ende if delta_L(i) > 0 DL(i)=delta_L(i); DLF(i) = DL(i); if merker(i) == 4 DLF(i) = delta_L_FG(i); end info(j,1) = freq(i); info(j,2) = delta_f_c(i); info(j,3) = LS(i); info(j,4) = LT(i); info(j,5) = LG(i); info(j,6) = av(i); info(j,7) = DL(i); info(j,8) = merker(i); info(j,9) = LT_FG(i); info(j,10) = DLF(i); j = j + 1; end end tonh_max = max(DL,DLF); tonh_maxfreq = find(tonh_max==max(tonh_max)); tonh_maxf = freq(tonh_maxfreq); tonh_max = max(tonh_max); % sample use of the ita warning/ informing function % ita_verbose_info([thisFuncStr 'Testwarning'],0); %% Add history line input = ita_metainfo_add_historyline(input,mfilename,varargin); %% Set Output varargout(1) = {tonh_max}; varargout (2)= {tonh_maxf}; varargout (3) = {info}; %end function end