function gfa(action,in1,in2);
%   possible actions:
%     'start'
%	  'setFilename'
%     'setAnalysisPeriod'
%     'setLowestFreq'
%     'setGateThreshold'
%	  'setFilterOn'
%     'setShowStatistics'
%	  'setDebug'
%	  'spiele'
%	  'analysiere'
%	  'stop'
%cd('c:\Dokumente und Einstellungen\Juanjo Burred\Eigene Dateien\SS 02\MMS\GFA\samples');


% ------ Einige Variablen, die den Benutzer vielleicht interessieren wuerden. ------
% Tiefpassfilter:
cutOffFreq = 60;				% bei dieser Frequenz ist die VerstŠrkung ist 3dB unter 1+extra
extra = 2.5;					% VerstŠrkung bei 0Hz ist 1+extra

% groesse der FFT:
fftSize = 8192;	
% Anzahl der Abtastwerte, die zur FFT geliefert werden, die mit Null ersetzt werden sollen:
zeroPadding = 4096;

% Statistik
memoryLen = 5;					% Wie viele Werte man in die Vergangenheit guckt - 1. Sinnvolle Werte: [1 10]
maximumVariance = 0.2;			% minimale Varianz um ein Ergebnis zu akzeptieren
% ----------------------------------------------------------------------------------


% Default-, Minimale-Werte und Maximale-Werte fuer die durch die Oberflaeche einstellbaren Variablen
defAnalysisPeriod = 40;
minAnalysisPeriod = 3;
maxAnalysisPeriod = 370;

defLowestFreq = 80;
minLowestFreq = 10;
maxLowestFreq = 2000;

defGateThreshold = 0.04;
minGateThreshold = 0.0;
maxGateThreshold = 1.0;

defFilterOn = 0;
defShowStatistics = 1;
defDebug = 0;

global sample
global Fs

if nargin<1,
    action='start';
end;

global filename
global filename_field
global analysisPeriod
global analysisPeriod_field
global lowestFreq
global lowestFreq_field
global gateThreshold
global gateThreshold_field
global filterOn
global filterOn_popup
global showStatistics
global showStatistics_popup
global debug
global debug_popup
global currentNote_text
global currentNote_field
global stop
global analyseButton

% Fuer die Initialisierung:
if strcmp(action,'start')
    %====================================
    % Graphics initialization
    oldFigNumber = watchon;
    figNumber = figure;
    set(gcf, ...
        'Position',[30 50 800 600],'NumberTitle','off', ...
        'Name','Grundfrequenzanalyse durch Maximum-Likelihood-Schaetzwert', ...
        'backingstore','off',...
        'Units','normalized');

    %====================================
    % Information for all buttons
    labelColor=192/255*[1 1 1];
    top=0.95;
    bottom=0.05;
    left=0.75;
    yInitLabelPos=0.90;
    left = 0.78;
    labelWid=0.18;
    labelHt=0.03;
    btnWid = 0.18;
    btnHt=0.035;  
	bigBtnHt=0.025;
    % Spacing between the label and the button for the same command
    btnOffset=0.003;
    % Spacing between the button and the next command's label
    spacing=0.03;
 	extraBtn=0.0;
	
    %====================================
    % The CONSOLE frame
    frmBorder=0.02;
    yPos=0.05-frmBorder;
    frmPos=[left-frmBorder yPos+2.25*btnHt btnWid+2*frmBorder 0.9+2*frmBorder-2.25*btnHt];
    h=uicontrol( ...
        'Style','frame', ...
        'Units','normalized', ...
        'Position',frmPos);
    
    %====================================
    % The filename editable text box
    btnNumber=1+extraBtn;
    yLabelPos=top-(btnNumber-1)*(btnHt+labelHt+spacing);
    labelPos=[left yLabelPos-labelHt labelWid labelHt];
    filename_text = uicontrol( ...
        'Style','text', ...
        'Units','normalized', ...
        'Position', labelPos, ...
        'String',' Dateiname:');

    btnPos=[left  yLabelPos-labelHt-2*btnHt-btnOffset ...
            0.9*btnWid+frmBorder  2*btnHt];
    filename_field = uicontrol( ...
        'Style','edit', ...
        'Units','normalized', ...
        'Position', btnPos, ...
        'BackgroundColor','w',...
        'String','',...
        'CallBack','gfa(''setFilename'')');
		
	filename = 'sample1.wav';
 	extraBtn=0.3;
	
	%====================================
    % The analysisPeriod editable text box
    btnNumber=2+extraBtn;
    yLabelPos=top-(btnNumber-1)*(btnHt+labelHt+spacing);
    labelPos=[left yLabelPos-labelHt labelWid labelHt];
    analysisPeriod_text = uicontrol( ...
        'Style','text', ...
        'Units','normalized', ...
        'Position', labelPos, ...
        'String',' Zeitliche Aufloesung (ms):');

    btnPos=[left+0.02  yLabelPos-labelHt-btnHt-btnOffset ...
            0.5*btnWid+frmBorder  btnHt];
    analysisPeriod_field = uicontrol( ...
        'Style','edit', ...
        'Units','normalized', ...
        'Position', btnPos, ...
        'BackgroundColor','w',...
        'String',num2Str(defAnalysisPeriod), ...
        'CallBack','gfa(''setAnalysisPeriod'')');
	
	analysisPeriod = defAnalysisPeriod;
	
	
	%====================================
    % The lowestFreq editable text box
    btnNumber=3+extraBtn;
    yLabelPos=top-(btnNumber-1)*(btnHt+labelHt+spacing);
    labelPos=[left yLabelPos-labelHt labelWid labelHt];
    lowestFreq_text = uicontrol( ...
        'Style','text', ...
        'Units','normalized', ...
        'Position', labelPos, ...
        'String',' Tiefste Frequenz (Hz):');

    btnPos=[left+0.02  yLabelPos-labelHt-btnHt-btnOffset ...
            0.5*btnWid+frmBorder  btnHt];
    lowestFreq_field = uicontrol( ...
        'Style','edit', ...
        'Units','normalized', ...
        'Position', btnPos, ...
        'BackgroundColor','w',...
        'String',num2Str(defLowestFreq), ...
        'CallBack','gfa(''setLowestFreq'')');
	
	lowestFreq = defLowestFreq;
	
	%====================================
    % The gateThreshold editable text box
    btnNumber=4+extraBtn;
    yLabelPos=top-(btnNumber-1)*(btnHt+labelHt+spacing);
    labelPos=[left yLabelPos-labelHt labelWid labelHt];
    gateThreshold_text = uicontrol( ...
        'Style','text', ...
        'Units','normalized', ...
        'Position', labelPos, ...
        'String',' Noisegate Threshold [0 1]:');

    btnPos=[left+0.02  yLabelPos-labelHt-btnHt-btnOffset ...
            0.5*btnWid+frmBorder  btnHt];
    gateThreshold_field = uicontrol( ...
        'Style','edit', ...
        'Units','normalized', ...
        'Position', btnPos, ...
        'BackgroundColor','w',...
        'String',num2Str(defGateThreshold), ...
        'CallBack','gfa(''setGateThreshold'')');
	
	gateThreshold = defGateThreshold;

    %====================================
    % The filterOn command popup button

    btnNumber=5+extraBtn;
    yLabelPos=top-(btnNumber-1)*(btnHt+labelHt+spacing);
    labelStr=' Tiefpassfilter anwenden?';

    % Generic label information
    labelPos=[left yLabelPos-labelHt labelWid labelHt];
    filterOn_text = uicontrol( ...
        'Style','text', ...
        'Units','normalized', ...
        'Position',labelPos, ...
        'HorizontalAlignment','left', ...
        'String',labelStr);

    btnPos=[left yLabelPos-labelHt-btnHt-btnOffset btnWid btnHt];
    filterOn_popup=uicontrol('Style','Popup','String','nein|ja',...
        'Units','normalized',...
        'Position', btnPos, ...
        'CallBack','gfa(''setFilterOn'')');
		
	filterOn = defFilterOn;	

    %====================================
    % The filter anzeigen command popup button
    btnNumber=6+extraBtn;
    yLabelPos=top-(btnNumber-1)*(btnHt+labelHt+spacing);
    labelStr=' Im Plot 2 anzeigen:';
    popupStr= ' Ausgabe vor Statistik| das Tiefpass';
	
    % Generic label information
    labelPos=[left yLabelPos-labelHt labelWid labelHt];
    showStatistics_text = uicontrol( ...
        'Style','text', ...
        'Units','normalized', ...
        'Position',labelPos, ...
        'HorizontalAlignment','left', ...
        'String',labelStr);

    % Generic popup button information
    btnPos=[left yLabelPos-labelHt-btnHt-btnOffset btnWid btnHt];
    %% das war winHndl hier:
	showStatistics_popup = uicontrol( ...
        'Style','popup', ...
        'Units','normalized', ...
        'Position',btnPos, ...
        'String',popupStr, ...
        'Callback','gfa(''setShowStatistics'')');
	
	showStatistics = defShowStatistics;

    %====================================
    % The debug popup button
    btnNumber=7+extraBtn;
    yLabelPos=top-(btnNumber-1)*(btnHt+labelHt+spacing);
    labelStr=' Debug Modus?';
    popupStr= ' nein| doch!';
	
    % Generic label information
    labelPos=[left yLabelPos-labelHt labelWid labelHt];
    debug_text = uicontrol( ...
        'Style','text', ...
        'Units','normalized', ...
        'Position',labelPos, ...
        'HorizontalAlignment','left', ...
        'String',labelStr);

    % Generic popup button information
    btnPos=[left yLabelPos-labelHt-btnHt-btnOffset btnWid btnHt];
 	debug_popup = uicontrol( ...
        'Style','popup', ...
        'Units','normalized', ...
        'Position',btnPos, ...
        'String',popupStr, ...
        'Callback','gfa(''setDebug'')');
	
	debug = defDebug;
	
	
   %====================================
    % The Sample Spielen button
	uicontrol('Style','Pushbutton', ...
		'Units','normalized',...
		'Position',[left 2.25*btnHt+bottom+(0.9*bigBtnHt)+spacing btnWid 1.5*bigBtnHt], ...
		'String','Sample Spielen', ...
      'Callback','gfa(''spiele'')','String','Spiele');
   
  	uicontrol('Style','Pushbutton', ...
		'Units','normalized',...
		'Position',[left 2.25*btnHt+bottom+(3*bigBtnHt)+spacing btnWid 1.5*bigBtnHt], ...
		'String','Hilfe', ...
		'Callback','gfa(''info'')');


   %========================================
   % The Analysiere button
    analyseButton = uicontrol('Style','Pushbutton', ...
        'Units','normalized',...
        'Position',[left 2.25*btnHt+bottom btnWid 1.5*bigBtnHt], ...
        'Callback','gfa(''analysiere'')','String','Analysiere');

		
	%====================================
    % The currentNote editable text box
    
	yLabelPos=bottom+labelHt;
    labelPos=[left-.1*labelWid yLabelPos-labelHt labelWid labelHt];
    currentNote_text = uicontrol( ...
        'Style','text', ...
        'Units','normalized', ...
        'Position', labelPos, ...
        'String','Aktuelle Note/Frequenz:');

    btnPos=[left+0.02  yLabelPos-labelHt-btnHt-btnOffset ...
            0.5*btnWid+frmBorder  btnHt];
    currentNote_field = uicontrol( ...
        'Style','text', ...
        'Units','normalized', ...
        'Position', btnPos, ...
        'BackgroundColor','w',...
        'String','', ...
        'CallBack','gfa(''setAnalysisPeriod'')');
		
	%====================================

   
    % mehr Initialisierung:
	sample = 0;
	stop = 0;

    watchoff(oldFigNumber);

% Um filename einzustellen:
elseif strcmp(action,'setFilename'),
	filename = get(filename_field,'String');

	disp(sprintf('Versuchen %s zu oeffnen...',filename));

	if(or(exist(filename)==2,exist(strcat(filename,'.wav'))==2))
		if length(findstr(filename,'.au'))
			[sample,Fs,bits] = auread(filename);
		else
		[sample,Fs,bits] = wavread(filename);
		end

% Falls die Datei 2 oder mehr Kanaele besitzt:
	siz = size(sample);
	if siz(2:2)~=1
	sample = sum(sample')';
	end

	l = length(sample);
	if l>16383
		disp('Erfolgreich.')
		subplot('position',[0.05 0.05 0.66 0.9])
		for i=2:1000,
			shortSample(i-1) = sum(sample(floor(((i-1)/1000)*l):floor((i/1000)*l)));
		end
	plot(linspace(1,l,999)/Fs,shortSample)
	xlabel('Zeit in Sekunden')
	ylabel('Amplitude des Eingangssignales')
	else
      
   disp('Ein Fehler ist aufgetreten. Ist die Datei gueltig? Ist sie zu kurz (weniger als 16384 Abtastwerte)?')
   disp(sprintf('Die eingelesene Laenge ist %d.',length(sample)));
sample = 0;
end
else
disp(sprintf('Konnte die Datei %s leider nicht finden. Steht sie im Matlab-Pfad?', ...
	filename))
sample = 0;
end	

% Um analysisPeriod einzustellen.	
elseif strcmp(action,'setAnalysisPeriod'),
	x = str2num(get(analysisPeriod_field,'String'));
	if isempty(x),
		disp('FEHLER mit der Eingabe.')
		set(analysisPeriod_field,'String',num2str(defAnalysisPeriod));
		analysisPeriod = defAnalysisPeriod;
	else
		if x<minAnalysisPeriod,
			disp('FEHLER: Eingabe zu klein.')
			set(analysisPeriod_field,'String',num2str(minAnalysisPeriod))
			analysisPeriod = minAnalysisPeriod;
		elseif x>maxAnalysisPeriod,
			disp('FEHLER: Eingabe zu gross.')
			set(analysisPeriod_field,'String',num2str(maxAnalysisPeriod))
			analysisPeriod = maxAnalysisPeriod;
		else
			analysisPeriod = x;
		end
	end
	disp(sprintf('Es wird jede %d ms in der Datei analysiert und einen Ausgabenwert berechnet.',analysisPeriod))

% Um lowestFreq einzustellen.	
elseif strcmp(action,'setLowestFreq'),
	x = str2num(get(lowestFreq_field,'String'));
	if isempty(x),
		disp('FEHLER mit der Eingabe.')
		set(lowestFreq_field,'String',num2str(defLowestFreq));
		lowestFreq = defLowestFreq;
	else
		if x<minLowestFreq,
			disp('FEHLER: Eingabe zu klein.')
			set(lowestFreq_field,'String',num2str(minLowestFreq))
			lowestFreq = minLowestFreq;
		elseif x>maxLowestFreq,
			disp('FEHLER: Eingabe zu gross.')
			set(lowestFreq_field,'String',num2str(maxLowestFreq))
			lowestFreq = maxLowestFreq;
		else
			lowestFreq = x;
		end
	end
	disp(sprintf('Es wird nicht tiefer als %d Hz gesucht.',lowestFreq))

% Um gateThreshold einzustellen.
elseif strcmp(action,'setGateThreshold'),
	x = str2num(get(gateThreshold_field,'String'));
	if isempty(x),
		disp('FEHLER mit der Eingabe.')
		set(gateThreshold_field,'String',num2str(defGateThreshold));
		gateThreshold = defGateThreshold;
	else
		if x<minGateThreshold,
			disp('FEHLER: Eingabe zu klein.')
			set(gateThreshold_field,'String',num2str(minGateThreshold))
			gateThreshold = minGateThreshold;
		elseif x>maxLowestFreq,
			disp('FEHLER: Eingabe zu gross.')
			set(gateThreshold_field,'String',num2str(maxGateThreshold))
			gateThreshold=maxGateThreshold;
		else
			gateThreshold = x;
		end
	end
	disp(sprintf('Das Threshold des Noisegates ist %d. Sinnvoller Bereich ist [0.0 1.0].',gateThreshold))

% Um filterOn einzustellen.
elseif strcmp(action,'setFilterOn'),
	filterOn = get(filterOn_popup,'Value') - 1;
	if filterOn
		disp('Ein Tiefpassfilter wird auf das Eingangssignal angewendet.')
	else
		disp('Das Eingangssignal wird nicht gefiltert.')
	end

% Um showStatistics einzustellen.
elseif strcmp(action,'setShowStatistics'),
	showStatistics = 1 - (get(showStatistics_popup,'Value') - 1);
	if showStatistics
		disp('Im zweiten Plot werden die berechneten Grundfrequenzwerte angezeigt, vor sie selbst gefiltert werden.')
	else
		disp('Im zweiten Plot wird das Tiefpassfilter angezeigt, das auf das Eingangssignal angewendet wird.')
	end

% Um debug einzustellen.
elseif strcmp(action,'setDebug'),
	debug = get(debug_popup,'Value') - 1;
	if debug
		disp('Debugginginfos werden jetzt angezeigt.')
	else
		disp('Keine Debugginfos werden angezeigt.')
	end

% Um ein schon geoeffnetes Sample zu spielen.	
elseif strcmp(action,'spiele'),
	if length(sample)>1
		disp(sprintf('Die Datei %s wird jetzt gespielt.',filename))
		sound(sample,Fs);
	else
		disp('Welche Datei spielen? Bitte einen gueltigen zuerst Dateinamen eingeben.')
	end

% Um ein Sample zu analysieren.
% Das Sample soll schon geoeffnet sein.
elseif strcmp(action,'analysiere'),	
	if not(length(sample)>1)
		disp('Welche Datei analysieren? Bitte einen gueltigen zuerst Dateinamen eingeben.')
	else

%---- Code fuer die Analyse faengt hier an!

% Konstanten:
% -----------

% FFT Vorverarbeitung:
% --------------------
% wenn die Abtastrate des eingegebenen Files x nicht samplingRate ist, wird x neu abgetastet:
samplingRate = 11025;   	
% Abtastwerte zwischen nebeneinanderstehenden Fenstern:
stepLength = round(analysisPeriod/1000*samplingRate);
% binsToShow soll nicht mehr als die Haelfte der fftSize sein (sonst treten die negativen Frequenzen auf).
% Nur diese Bins werden in den Plots angezeigt und werden fuer den Maximum-Likelihood-Schaetzwert benutzt.
binsToShow = 2250;
% Hoehe des Spektrums im Plot 1:
fftPlotHeight = (fftSize-zeroPadding)/8192*800;
% Skalierungsfaktor: (siehe unten)
z = 800/fftPlotHeight;	
% Anzahl der gewaehlten Maxima (mit den gruenen Punkten gezeigt)
maximums = 10;				

% Fuer das Noisegate [0,1). Das Fenster wird nicht zu Ende bewertet, wenn das groesste Maximum kleiner als
% gateThreshold*fftPlotHeight ist.
myGateThreshold = gateThreshold * fftPlotHeight;

% Filter wird berechnet:
cutOffBin = round(cutOffFreq*samplingRate/fftSize);
alpha = (-1/cutOffBin)*log(1/(extra*sqrt(2)));
fFilt = 1:fftSize;
for i=1:fftSize;
	filt(i) = 1 + extra - extra *exp((-1*alpha)*(cutOffBin-fFilt(i)));
	if or(filt(i)<1,not(filterOn))
		filt(i) = 1;
	end
end


% Konstanten fuer Suche der Maxima
% Zahl der Frequenzbaender bei tiefsten Frequenzen zu ignorieren (dh, 1 + startOffset)
startOffset = round(lowestFreq/(samplingRate/fftSize));			
endOffset = 0;					% Zahl der Frequenzbaender bei hoechsten Frequenzen zu ignorieren (dh, binsToShow - endOffset)
numToSelect = 20;				% Wie viele Maxima sollen gewaehlt werden (wenn moeglich)
% Diese sind natuerlich von der Skalierung im Frequenzbereich abhŠngig: (z, siehe oben)
binsToIncrease = ceil(1/z);		% Spektrogram muss fuer wenigstens binsToIncrease Frequenzbaender steigern, bevor ein Maximum gewaehlt werden darf
binsToDecrease = ceil(1/z);		% Das Spektrogram muss dann fuer wenigstens binsToDecrease Frequenzbaender nach unten gehen, und dann hat man ein Maximum
increaseThreshold = 3/z;		% Um als eine Steigerung akzeptiert zu werden, muss es wenigstens um increaseThreshold gesteigert werden
decreaseThreshold = 3/z;		% Um als eine nach unten gehen akzeptiert zu werden, muss es wenigstens um decreaseThreshold nach unten gegangen sein

% Vorverarbeitung
% ---------------
windowFunction = hanning(fftSize-zeroPadding)';           % Berechnung der Fensterfunktion (fuer Zeitbereichanwendungen)


if Fs~=samplingRate
	disp(sprintf('Bitte warten: Abtastrate %d -> %d',Fs,samplingRate));

	sample = resample(sample,samplingRate,Fs,30);
	Fs = samplingRate;
	% Das letzte Parameter ist normalerweise 10; hoehere Werte dauern laenger...	
end
sampleLength = length(sample);
numFrames=floor((sampleLength-(fftSize-zeroPadding))/stepLength);

% Analysiere Button wird Aufhoeren Button:
set(analyseButton,'Callback','gfa(''stop'')','String','Aufhoeren');
stop = 0;

% Um die Plots einzustellen:
plot1Rect = [0.07 0.68 0.64 0.21];
plot2Rect = [0.07 0.4 0.64 0.19];
plot3Rect = [0.07 0.06 0.64 0.28];

subplot('position',plot1Rect);
hold off
plot(0,0,'b');
axis([0 (binsToShow-1)*samplingRate/fftSize 0 fftPlotHeight]);

subplot('position',plot2Rect);
hold off
if (showStatistics==0)
	% Das Filter muss nur ein mal gezeichnet werden.
	% Es wird nicht geaendert.
	plot(fFilt(1:binsToShow)*samplingRate/fftSize,filt(1:binsToShow));
   	axis([0 (binsToShow-1)*samplingRate/fftSize 0 1+extra])
	ylabel('Verstaerkung');
	xlabel('Frequenz in Hz');
else
	plot(0,0,'b');
	axis([0 numFrames*stepLength/samplingRate 0 127]); grid on;
    ylabel('MIDI in blau (Frequenz in rot)');
   	xlabel('Zeit in Sekunden');
end

subplot('position',plot3Rect);
hold off
plot(0,0,'b');
axis([0 numFrames*stepLength/samplingRate 0 127]); grid on;
ylabel('Gefiltertes MIDI');
xlabel('Zeit in Sekunden');


% Programmschleife
% ----------------
i=1;
memory = zeros(1,memoryLen);
frame=0;
while (i+(fftSize-zeroPadding)) < sampleLength;
	% Aufhoeren, im Fall dass der Benutzer 'Aufhoeren' geklickt hat.
	if stop
		stop=0;
		break;
	end
	
	% Fenster auswaehlen
	currentFrame = [(sample(i:i+(fftSize-zeroPadding)-1)' .* windowFunction) zeros(1,zeroPadding)];
	freqDomain = (abs(fft(currentFrame)));

	if filterOn
		freqDomain = freqDomain .* filt;
	end
	
	zoom on; 
	
	% nur die erste binsToShow anzeigen lassen
	subplot('position',plot1Rect);
	plot(linspace(0,(binsToShow-1)*samplingRate/fftSize,binsToShow),(freqDomain(1:binsToShow)));	
	axis([0 (binsToShow-1)*samplingRate/fftSize 0 fftPlotHeight])		% Dimensionen fuer das Spektrogram
    ylabel('Relative Amplituden');
    xlabel('Frequenz in Hz');
	
	
	% Die Suche nach Maxima
	% ---------------------
	increasedBins = 0;
	wereIncreasedBins = 0;
	decreasedBins = 0;
	lastValue = 0;
	outputCounter = 1;
	outputFreq = 0;
	outputAmp = 0;
	for j=1+startOffset:binsToShow-endOffset,
		if freqDomain(j) > (lastValue + increaseThreshold)
			increasedBins = increasedBins + 1;
			decreasedBins = 0;
		elseif freqDomain(j) < (lastValue - decreaseThreshold)
			decreasedBins = decreasedBins + 1;
			if increasedBins~=0
				wereIncreasedBins = increasedBins;
			end
			increasedBins = 0;
		end
		
		if (wereIncreasedBins >= binsToIncrease) & (decreasedBins >= binsToDecrease)
			% Maximum gefunden!
			outputFreq(outputCounter) = (j-decreasedBins-1)*samplingRate/(fftSize);   % Frequenz des gewählten Maximums
			outputAmp(outputCounter) = freqDomain(j-decreasedBins);
			
			outputCounter = outputCounter + 1;
			wereIncreasedBins = 0;
			increasedBins = 0;
			decreasedBins = 0;
		end
		
		lastValue = freqDomain(j);
	end
	outputCounter = outputCounter - 1;						% outputCounter vertritt jetzt die Anzahl der im 1. Schritt gefundenen Maxima
   
	if outputCounter>0
		hold on
		plot(outputFreq,outputAmp,'mo');   					% Maxima zum Plot hinzufügen
		hold off
	end

	% Reduzieren der Maxima auf die Anzahl von <numToSelect>
	% --------------------------------------------------------
	% Es koennte beschleunigt werden, falls wir uns nicht mit diesem ampThreshold beschaeftigen woellen
	% Dann koennten wir das ganze unten in einem "if" stecken, wobei
	% if outputCounter <= numToSelect
	% 	selectedFreq = outputFreq;
	%	selectedAmp = outputAmp;
	% else
	%	<das ganze hier unten>
    % end

	ampThresholdRatio = 0.1;
	ampThreshold=max(freqDomain)*ampThresholdRatio;
   
	selectedFreq = 0;
	selectedAmp = 0;
	numActuallySelected = 0;
	for k=1:numToSelect,
		if k>outputCounter									% falls alle Maxima schon untersucht wurden
			break;
		else
			[theAmp, thePos] = max(outputAmp);				% sonst den nächsten groessten finden
		end
		
		if theAmp < ampThreshold							% die Amplitude muß gross genug sein
			break;
		else
			numActuallySelected = numActuallySelected + 1;	
			selectedAmp(k) = theAmp;						% zu der neuen Liste hinzufuegen
			selectedFreq(k) = outputFreq(thePos);
			outputAmp(thePos) = 0;
		end
	end
	
	if numActuallySelected>0
		hold on
		plot(selectedFreq,selectedAmp,'g*');
		hold off
	end	

   
   
	% Maximum-Likelihood-Schaetzwert
	% -----------------------------
	%
	% ML = summe( A + T + N )
	%
	% A : Parameter abhaengig von der Amplitude des i-ten Maximums 
	% T : Parameter abhaengig vom Frequenzabstand zwischen erkanntem und theoretischem Maximum
	% N : Parameter abhaengig vom Frequenzabstand zwischen erkanntem Maximum und Grundfrequenz
	ML=zeros(1,numActuallySelected);
	
	if and(numActuallySelected>0,ampThreshold/ampThresholdRatio>myGateThreshold)	% "Noise Gate"
		for l=1:numActuallySelected
			if debug
				disp('******************************************************************');
				disp(sprintf('Untersuchtes Maximum: %f3',selectedFreq(l)));
				disp('------------------------------------------------------------------');
			end   
			for m=1:numActuallySelected
         		if selectedFreq(m)>=selectedFreq(l)
            		% Parameter A
            		A = 100*log(selectedAmp(m));
            
            		% Parameter T
            		lastDist=inf;
            		harmonic=selectedFreq(l);
            		maxFreq=max(selectedFreq);
            		while harmonic<=maxFreq
               			dist=abs(harmonic-selectedFreq(m));
               			if dist<lastDist
                  			lastDist=dist;
               			end
               			harmonic=harmonic+selectedFreq(l);
            		end
					T=169*exp(-.05*(lastDist*lastDist));
					
					% Andere moegliche Funktionen fuer T:
					%T=10*(10+log(1/(lastDist+0.001)));
            		%T=1/(lastDist+0.001);
            
            		% Parameter N
            		N=10/exp(selectedFreq(m)/1000);
            
           		 	product=A*T*N;
            		if debug
               			disp(sprintf('Anderes Maximum: %f3   A=%f  T=%f N=%f product=%f',selectedFreq(m),A,T,N,product));
            		end
            		ML(l)=ML(l)+product;
				end
			end
      		if debug
				disp(sprintf('Likelihood= %f',ML(l)));   
			end
		end
		[val,index]=max(ML);
   
   		GF=selectedFreq(index);
   		[MIDI,note]=freq2note(GF);
   
		% gewaehltes Maximum ausgeben, falls Debugging angeschaltet ist.
		if debug
			disp(sprintf('Frequenz: %f  MIDI Nr.: %d  Note: %s',GF,MIDI,note));
		end
		
		% gewaehltes Maximum als schwarzes Rechteck anzeigen lassen:
		subplot('position',plot1Rect);
   		hold on
   		plot(GF,selectedAmp(index),'ks');
   		hold off;
		drawnow;
		   
		% Zeige die Ausgabe vom Algorithmus vor dem statistischen Filter an, falls das Filter
		% im Plot 2 nicht angezeigt wird.
    	if showStatistics
    		subplot('position',plot2Rect);
			hold on;
   			plot(frame*stepLength/samplingRate,GF/4000*127,'r.');%drawnow;
   			plot(frame*stepLength/samplingRate,MIDI,'b.');%drawnow;
   			axis([0 numFrames*stepLength/samplingRate 0 127]); grid on;
		end	
   
   		% statistisches Filter: liefere ein Ergebnis nur, wenn die Varianz von den letzten memoryLen Werte
		% kleiner als maximumVariance ist
		if memoryLen > 1   
   			for memCount=2:memoryLen,
				memory(memCount-1) = memory(memCount);
			end
		end
		memory(memoryLen) = MIDI;
		avg = sum(memory)/memoryLen;
		variance = sum((memory-avg).*(memory-avg))/memoryLen;
		
		if variance < maximumVariance
   			subplot('position',plot3Rect)
			hold on;
			plot(frame*stepLength/samplingRate,avg,'b.');
			axis([0 numFrames*stepLength/samplingRate 0 127]); grid on;
			% Das Ergebnis liefern:
			set(currentNote_field,'String',strcat(note,'/',num2str(round(GF))))
		else
			variance;
			% keine Note gefunden, dh. kein Ergebnis liefern:
			set(currentNote_field,'String','')
		end
	else
		% vom Noisegate ausgefiltert, dh. kein Ergebnis liefern:
		set(currentNote_field,'String','')
	end
   
	if debug
   		r = input('<return> druecken fuer das naechste Fenster (0 eingeben, um aufzuhoeren)');
   		if not(isempty(r))
			if (r==0)
	   			break;
			end
   		end
	end

    frame=frame+1;
	i=i+stepLength;
end 

% Aufhoeren Button wird Analysieren Button:
set(analyseButton,'Callback','gfa(''analysiere'')','String','Analysieren');


%---- Analysecode endet hier.
	end

% Falls der Benutzer stop klickt:
elseif strcmp(action,'stop'),
	stop=1;
%end


elseif strcmp(action,'info'),
    ttlStr = 'Grundfrequenzanalyse musikalischer Signale'; 

    hlpStr1= ...                                              
        ['                                                '
         ' Eingabefelder:                                 '  
         ' ===========                                    '  
         '                                                '  
         ' Dateiname:                                     '  
         '  Damit die Dateien gelesen werden, muss        '  
         '  Ihr Ordner im MATLAB-Path definiert sein      '  
         '  WAV Dateien:                                  '  
         '       Name mit oder ohne ".wav" Endung eingeben'  
         '  AU Dateien:                                   '  
         '       Name mit ".au" Endung eingeben           '  
         '                                                '  
         ' Zeitliche Aufloesung (ms):                     '  
         '  Zeitintervall zwischen zwei Kurzzeitanalysen  '  
         '  Geeignete Werte: 5-40 ms                      '
         '                                                '
         ' Tiefste Frequenz (Hz):                         '
         '  Je nach Instrument: 20-400 Hz                 '
         '                                                '
         ' Noisegate Threshold:                           '
         '  Zwischen 0.0 und 1.0                          '
         '                                                '];

    hlpStr2= ...                                               
        [' Tiefpassfilter anwenden?                        '  
         '  Tiefpassfilter geeignet fuer Instrumente mit   '  
         '  besonderem schwaechen Grundfrequenz in tiefen  '  
         '  Frequenzbereichen (z.B. Klavier)               '  
         '                                                 '  
         ' Im Plot 2 anzeigen:                             '  
         '  Ausgabe vor Statistik:                         '  
         '    Durch das "Varianzfilter" nicht gefilterte   '
         '    Grundfrequenzen zeigen                       '  
         '  Tiefpass:                                      '  
         '    Frequenzgang des TP-Filters anzeigen         '  
         '                                                 '  
         ' Debug Modus:                                    '  
         '  Wenn ein, das Programm stoppt nach der Analyse '  
         '  jedes Fensters und zeigt im MATLAB Command     '  
         '  Window die berechneten Maximum-Likelihood      '
         '  Parameter fuer jedes untersuchtes Maximum      '  
         '                                                 '];

	    hlpStr3= ...                                               
        [' GFA: Grundfrequenzanalyse durch Maximum-        '  
         '      Likelihood Schatezwert                     '  
         ' ---------------------------                     '  
         ' Edgar Berdahl (thatguy@uclink.berkeley.edu)     '  
         ' Juan Jose Burred (jjburred@hotmail.com)         '  
         '                                                 '  
         ' Fuer genauere Informationen siehe:              '  
         '    "Grundfrequenzanalyse musikalischer Signale" '
         '    Endbericht des Seminars                      '  
         '    "Moderne Methoden der Signalanalse"          '  
         '    TU Berlin, Sommersemester 2002               '  
         '                                                 '  
         '                                                 '];

     helpfunk(ttlStr, hlpStr1, hlpStr2, hlpStr3);

end


