Code covered by the BSD License  

Highlights from
3-Band Parametric Equalizer

image thumbnail

3-Band Parametric Equalizer

by

 

15 Jul 2002 (Updated )

Simulink model of a 3-band parametric equalizer controlled by a user-friendly GUI.

GraphicGUI(state);
function GraphicGUI(state);

warning off MATLAB:divideByZero;

persistent Fs Frame Owner NdB

% All inputs to the blocks are either in dBs or rads/seconds. Hence any
%value sent as inputs to the parEq blocks in the model should be converted
%to these or created as rads/sec.

% When calling PEQ.M, all gain values can be sent as absolute dB and freq
%values sent as rads/seconds; This way the program is kept independent of
%the incoming audio's sampling frequency. Only for the display absolute
%frequencies are displayed; but graphically chosen values are kept as
%rads/sec

% This gets the Frame variable and defines it locally;  
  




color1 = [255 0 0]/255;     % Red
color2 = [0 0 255]/255;     % Blue 
color3 = [0 0 0]/255;       % Black
axisColor = [159 188 191]/255;
figColor = [211 226 226]/255;


if nargin==0 | strcmp(state,'reset')
    
    Owner=gcs; 
    NdB = str2num(get_param([Owner '/band1'],'NdB'));
    %Get NdB value from the model
   % This sets the Frame persistent variable 
    eval(get_param(Owner, 'PreLoadFcn')); 
    % This sets the Fs sampling rate variable persistent 
    [y,Fs,bits] = wavread(get_param([Owner,'/From Wave File'],'FileName'),[1 100]); 
    load GraphicEQ_state
    
    
    bandw1 = eq_state.BandWidth1;
    centerfreq1 =eq_state.CenterFreq1;
    pk1= eq_state.peakgain1;
    
    bandw2= eq_state.BandWidth2;
    centerfreq2 = eq_state.CenterFreq2;
    pk2=eq_state.peakgain2;
    
    bandw3 =eq_state.BandWidth3;
    centerfreq3 = eq_state.CenterFreq3;
    pk3=eq_state.peakgain3;
    
    %Initial Creation of the filters
    %Filter1
     [b1 a1] = peq(0,pk1,centerfreq1,bandw1,NdB);
   % [b1 a1] = peq(0,14.5,centerfreq1,bandw1,NdB);
      
    [h1,w1] = freqz(b1,a1);
    %Filter2
    [b2 a2] = peq(0,pk2,centerfreq2,bandw2,NdB);
    [h2,w2] = freqz(b2,a2);
    %Filter3 
    [b3 a3] = peq(0,pk3,centerfreq3,bandw3,NdB);
    [h3,w3] = freqz(b3,a3);
    
    %Convert back to dB
    h1 = 20*log10(abs(h1));
    h2 = 20*log10(abs(h2));
    h3 = 20*log10(abs(h3));
         
    %-------------------BAND ONE-----------------------------------------
    %Create the plot
    if 1
        line1 = semilogx(w1,h1,'tag','line1'); hold on;
    else
        line1 = plot(w1,h1,'tag','line1'); hold on;  %  ENABLE THIS to
    % compare with xfer function in model
    end;
    
    set(line1,'color',color1);
    %axis off;
    grid on;
    xlim(([0 1])*pi);
    ylim([-15 15]);
    
    %Customize the looks of the Figure Window
    set(gcf,'menubar','none');
    
    % and the axis
    xlabels=[.01  .02  .05  .1 .2 .5 ];   % setup 1 2 5 sequence for xlabels
    set(gca,'xtick',xlabels*pi);
    
    for k=1:length(xlabels)
        xstring{k} = sprintf('%3.0f',(xlabels(k)*Fs/2));
    end;
    set(gca,'xticklabel',xstring)
     
    
    set(gcf,'color',figColor);
    set(gca,'color',axisColor);
    ScreenSize = get(0,'screensize');
    if ( exist('state') & ~strcmp(state,'reset')) | (nargin==0)
        set(gcf,'position',[ScreenSize(3)/3 ScreenSize(4)/2 516 350]);
    end
    set(gca,'position',[0.1000    0.1500    0.8150    0.6150]);
    set(gcf,'resize','off');
    set(gca,'xcolor','k','ycolor','k');

    %set(get(gca,'xlabel'),'String','Frequency in Hz','color','k','position',[.5,-2.2],'fontangle','italic');
    set(get(gca,'ylabel'),'String','Gain in dB','color','k','fontangle','italic');
    
    %Create Help Text at the top of the Figure Window
    htext = text(0.5,.5,'Click and drag on the Round Markers or the Lines');
    set(htext,'color','k','fontangle','oblique','fontweight','bold','tag','text1','position',[.0055 23.4028],...
        'EdgeColor','black','BackgroundColor','y');
    
    %Create Text box for Parameter Value display
    freqText = text(0.0057,19.6528,'Center Frequency:','color',figColor,'tag','freqText');

    peakText = text(0.0856,19.7917,'Peak Value:','color',figColor,'tag','peakText');

    bandwText = text(0.6207,19.9306,'Band Width:','color',figColor,'tag','bandwText');
    
    %Create the Note Text
    noteText = text(0.0036,-20.2083,'The overall response (yellow dashed line) is centered at 0dB.',...
        'color','k','tag','noteText','fontweight','demi','fontangle','italic',...
        'EdgeColor','black','BackgroundColor',[.7 .9 .7]);
    
    %Create a Reset Button
    reset = uicontrol(gcf);
    set(reset,'position',[460 5 50 15],'string','Reset');
    set(reset,'callback','GraphicGUI(''reset'')');
    %% ------------------ BAND 1 -------------------------------------------
    %Set parameters in the Simulink Model
    set_param([Owner,'/PeakGain1'],'value',num2str(pk1) );
    set_param([Owner,'/CenterFreq1'],'value',num2str(centerfreq1));
    set_param([Owner,'/BandWidth1'],'value',num2str(bandw1) );

    %Add Markers that will be used for manipulating the parameters
    if pk1>0
       [h1max,indexh1] = max(h1); 
   else
       [h1max,indexh1] = min(h1); 
   end
    
    w1max = w1(indexh1);
    % the marker is plotted as a line object
    gain1 = line(w1max,h1max,'Marker','o','MarkerEdgeColor','k', ...
        'MarkerFaceColor',color1,'tag','peakgain1','LineStyle','none','markersize',6);
    %-------------------END CODE FOR BAND ONE--------------------------------------
    
    %-------------------BAND TWO--------------------------------------------------
    
    %Create the plot
    %line2 = plot(w2*fs/(2*pi),h2,'b','tag','line2');
    line2 = semilogx(w2,h2,'tag','line2');
    set(line2,'color',color2);

    %Set parameters in the Simulink Model
    set_param([Owner,'/PeakGain2'],'value',num2str(pk2) );
    set_param([Owner,'/CenterFreq2'],'value',num2str(centerfreq2) );
    set_param([Owner,'/BandWidth2'],'value',num2str(bandw2) );
    
    %Add Markers that will be used for manipulating the parameters
    if pk2>0
        [h2max,indexh2] = max(h2);    % this does not work, it can be a max or a min!
    else
        [h2max,indexh2] = min(h2);    % this does not work, it can be a max or a min!
    end;
    
    
    w2max = w2(indexh2);
    % the marker is plotted as a line object
    gain2 = line(w2max,h2max,'Marker','o','MarkerEdgeColor','k', ...
        'MarkerFaceColor',color2,'tag','peakgain2','LineStyle','none','markersize',6);
    %-------------------END CODE FOR BAND TWO--------------------------------------

    %--------------------------BAND THREE------------------------------------------
    %Create the plot
    %line3 = plot(w3*fs/(2*pi),h3,'m','tag','line3');
    line3 = semilogx(w3,h3,'tag','line3');
    set(line3,'color',color3);
    %Set parameters in the Simulink Model
    set_param([Owner,'/PeakGain3'],'value',num2str(pk3));
    set_param([Owner,'/CenterFreq3'],'value',num2str(centerfreq3) );
    set_param([Owner,'/BandWidth3'],'value',num2str(bandw3));
        
    %Add Markers that will be used for manipulating the parameters
    if pk3>0
       [h3max,indexh3] = max(h3);
    else
       [h3max,indexh3] = min(h3);
    end
    w3max = w3(indexh3);
    % the marker is plotted as a line object
    gain3 = line(w3max,h3max,'Marker','o','MarkerEdgeColor','k', ...
        'MarkerFaceColor',color3,'tag','peakgain3','LineStyle','none','markersize',6);
    %-------------------END CODE FOR BAND THREE--------------------------------------
    
    sumH = h1+h2+h3;
    %Normalize the sum of responses to value bet -15 & +15
    normSumH = sumNorm(sumH);
    %Plot sum of all responses
    line4 = plot(w2,normSumH,'y--','tag','line4','linewidth',2,'hittest','off');
    hold off;
    
    %Store sum of all response in GCF to display sum of responses
    allH = normSumH; 
    setappdata(gcf,'allH', allH);
    
    %Also save the equalizer responses and current parameters in a
    %structure: eqData.H ,eqData.centerFreq, eqData.bandW
    eqData.H = [h1 h2 h3];
    eqData.centerFreq = [centerfreq1 centerfreq2 centerfreq3];
    eqData.bandW = [bandw1 bandw2 bandw3];
    setappdata(gcf,'eqData', eqData);
    
    %Set the button down function
    set(gcf,'WindowButtonDownFcn','GraphicGUI(''down'')');
    
    %Eliminate flicker
    set(gcf,'DoubleBuffer','on');       
    
    %Set the mouse move while button down function
    set(gcf,'WindowButtonMotionFcn','','WindowButtonUpFcn','');

    % Execute the WindowButtonDownFcn
elseif strcmp(state,'down')
    
    %Get the current complete info on filter responses
    EqData = getappdata(gcf,'eqData');
    cfreq = EqData.centerFreq;
    
    %Identify the Band that was clicked
    htype = get(gco,'type');
    
    %If Line is clicked, then set the Point Down information in the Figure
    if strcmp(htype,'line')
        tag = get(gco,'tag');
        tagIndex = eval(tag(end));
        
        set(gcf,'WindowButtonMotionFcn','GraphicGUI(''move'')', ...
            'WindowButtonUpFcn','GraphicGUI(''up'')');  
        
        cp = get(gca,'CurrentPoint');
        xDown = cp(1,1);
        yDown = cp(1,2);
        
        setappdata(gcf,'pointDown',[xDown cfreq(tagIndex)]); 
        
        text1 = findobj(gcf,'tag','text1');
        line4 = findobj(gcf,'tag','line4');
        if strcmp(tag,'peakgain1')|strcmp(tag,'peakgain2')|strcmp(tag,'peakgain3') 
            set(text1,'string','Drag to move the peak around');
        elseif strcmp(tag,'line1')|strcmp(tag,'line2')|strcmp(tag,'line3')
            set(text1,'string','Drag to change the bandwidth');
        elseif strcmp(tag,'line4')
            set(text1,'string','This is the actual response. Change this by moving individual bands');
        end
    end
    
% Execute the WindowButtonMotionFcn    
elseif strcmp(state,'move')
    
    %Get the current complete info on filter responses
    EqData = getappdata(gcf,'eqData');
    cfreq = EqData.centerFreq;
    H = EqData.H;
    bandw = EqData.bandW;
    
    %Find handles of blocks in Simulink Model whose value is set here
    text1 = findobj(gcf,'tag','text1');
    
    line1 = findobj(gcf,'tag','line1');
    gain1 = findobj(gcf,'tag','peakgain1');

    line2 = findobj(gcf,'tag','line2');
    gain2 = findobj(gcf,'tag','peakgain2');
    
    line3 = findobj(gcf,'tag','line3');
    gain3 = findobj(gcf,'tag','peakgain3');
    
    line4 = findobj(gcf,'tag','line4');
   
    freqText = findobj(gcf,'tag','freqText');
    peakText = findobj(gcf,'tag','peakText');
    bandwText = findobj(gcf,'tag','bandwText');
     
    cp = get(gca,'CurrentPoint');

    %-----------------------------------
    %If the user drags the point out of the axis reset
    %the corresponding point to the axis limits
    x = cp(1,1); xlims = get(gca,'xlim'); 
    %if x<xlims(1), x = xlims(1);end;
    if x<(45*2*pi/Fs), x = (45*2*pi/Fs) ;end; % Center frequency cannot be lower than 45 Hz
    if x>xlims(2), x = xlims(2);end;
    
    y = cp(1,2); ylims = get(gca,'ylim'); 
    if y<ylims(1), y = ylims(1);end;
    if y>ylims(2), y = ylims(2);end;
    %------------------------------------
    
    tag = get(gco,'tag');
    tagIndex = eval(tag(end));
    switch tag(end)
        case '1'
            col = color1;
        case '2' 
            col = color2;
        case '3' 
            col = color3;
    end
    %Get the original ButtonDown x,y coordinates
    xyDown = getappdata(gcf,'pointDown');
    allH = getappdata(gcf,'allH');
    
    %IF THE GAIN POINT IS MOVED ====>>>
    if strcmp(tag,'peakgain1')|strcmp(tag,'peakgain2')|strcmp(tag,'peakgain3') 
        set(text1,'string','Change the Center Frequency and Peak Gain of the frequency band');
        myH = H(:,tagIndex);
        
        %Change the Shape and color of Marker while it's moving
        set(eval(['gain' tag(end)]),'xdata',x,'ydata',y,'marker','diamond','markersize',12,'markerfacecolor','y');
        [newb, newa] = peq(0,y,x,bandw(tagIndex),NdB);
        [newh,neww] = freqz(newb,newa);
        newh = 20*log10(abs(newh));
        [watever maxW] = max(newh);
        
        set(eval(['line' tag(end)]),'ydata',newh,'xdata',neww,'linewidth',2);
        H(:,tagIndex) = newh;
        
        %Update the sum response plot to improve readability
        allH = sumNorm(sum(H,2));
        set(line4,'ydata',allH,'xdata',neww);

        %Set the new parameters for the modified band
        EqData.H = H;
        cfreq(tagIndex) = x; 
        EqData.centerFreq = cfreq;
        EqData.bandW = bandw;
        setappdata(gcf,'eqData',EqData);
        setappdata(gcf,'allH',allH);
        
        %Display the parameters as the user moves the UIobjects
        numFreq = numFormat(x,Fs);
        numBandw = numFormat(bandw(tagIndex),Fs);
        peakVal = sprintf('%0.1f',y);
        set(freqText,'string',['Center Frequency: ',numFreq],'color',col,'fontangle','italic');
        set(peakText,'string',['Peak Value: ',peakVal,'dB'],'color',col,'fontangle','italic');
        set(bandwText,'string',['Bandwidth: ',numBandw],'color',col,'fontangle','italic');
        
        drawnow
    
    %IF THE LINE (Bandwidth) IS MOVED ====>>>    
    elseif strcmp(tag,'line1')|strcmp(tag,'line2')|strcmp(tag,'line3')
        set(text1,'string','Dragging the colored lines changes the bandwidth of the frequency band ');
        %Get the response of the current band
        myH = H(:,tagIndex);
        %Change the Shape and color of line while it's moving
        set(eval(['line' tag(end)]),'color','c','linewidth',3);
        
        %Get the value of the peak gain
        peakG = get(eval(['gain' tag(end)]),'ydata');
        
        %Compute new Bandwidth
        %bwDiff = sign(xyDown(1)-xyDown(2)) * (x-xyDown(1));
        %Difference between current pressed x and centerFreq of that band
        
        bwDiff = (x-xyDown(2));
        bandww = 2*abs(bwDiff);
        if bandww<50*2*pi/Fs
            bandww = 50*2*pi/Fs; %Minimum Bandwidth allowed is 50 hertz
        elseif bandww>(20000*2*pi/Fs) %Maximum Bandwidth allowed is 20000 hertz
            bandww = 20000*2*pi/Fs;
        end
        bandw(tagIndex) = bandww; 
        
        %Center Frequency cfreq doesnt change
        
        %Compute New Filter parameters
        [newb, newa] = peq(0,peakG,cfreq(tagIndex),bandww,NdB);
        [newh,neww] = freqz(newb,newa);
        newh = 20*log10(abs(newh));
        
        %Update Line for the chosen band
        set(eval(['line' tag(end)]),'ydata',newh,'xdata',neww);
        set(eval(['gain' tag(end)]),'Marker','o','MarkerEdgeColor','k',...
             'MarkerFaceColor',col,'LineStyle','none','markersize',6);
        
         
        %Update the sum response plot along with a bias to improve
        %readability

        H(:,tagIndex) = newh;
        EqData.H = H;
        %EqData.centerFreq = cfreq;
        EqData.bandW = bandw;
        setappdata(gcf,'eqData',EqData);
        
        allH = sumNorm(sum(H,2));
        setappdata(gcf,'allH',allH);
        set(line4,'ydata',allH,'xdata',neww);
         
        peakVal = sprintf('%.1f',peakG);
        numFreq = numFormat(cfreq(tagIndex),Fs);
        numBandw = numFormat(bandw(tagIndex),Fs);
        
        set(freqText,'string',['Center Frequency: ',numFreq],'color',col,'fontangle','italic');
        set(peakText,'string',['Peak Value: ',peakVal,' dB'],'color',col,'fontangle','italic');
        set(bandwText,'string',['Bandwidth: ',numBandw],'color',col,'fontangle','italic');
        
        drawnow
    end;
    
% Execute the WindowButtonUpFcn        
elseif strcmp(state,'up')
    
    tag = get(gco,'Tag');
    tagIndex = eval(tag(end));
    switch tag(end)
        case '1', col = color1;
        case '2', col = color2;
        case '3', col = color3;
    end
    
    eqData = getappdata(gcf,'eqData');
    H = eqData.H;
    myH = H(:,tagIndex);
    hmax = max(myH);
    hmin = min(myH);
    
    if abs(hmax) < 0.00001
        hmax = hmin;
    end
    
    cf = eqData.centerFreq;
    cfreq = cf(tagIndex);
    bw = eqData.bandW;
    bandw = bw(tagIndex);

    text1 = findobj(gcf,'tag','text1');
    gain1 = findobj(gcf,'tag','peakgain1');
    line1 = findobj(gcf,'tag','line1');
    
    gain2 = findobj(gcf,'tag','peakgain2');
    line2 = findobj(gcf,'tag','line2');
    
    gain3 = findobj(gcf,'tag','peakgain3');
    line3 = findobj(gcf,'tag','line3');
    
    %Set the Change in parameters in the Simulink Model
    set_param([Owner,'/PeakGain',tag(end)],'value',num2str(hmax)) ;
    set_param([Owner,'/CenterFreq' tag(end)] ,'value',num2str(cfreq));
    set_param([Owner,'/BandWidth' tag(end)],'value',num2str(bandw));
    
    allH = getappdata(gcf,'allH');

%     %Compute the total decibel energy in the final response, to be used for
%     %normalizing the output power
%     sumDB = trapz(allH); %Perform trapezoidal integration
%     if ~isnan(sumDB)|~isinf(sumDB)
%         gainDB = 25 + sign((4000 - sumDB))*0.7*log10(abs(4000 - sumDB)); %Compute the gain by which the output is to be muliplied
%         set_param([gcs,'/outputGain'],'db',num2str(gainDB));
%     end
    

    set(text1,'string','Click and drag on the Colored Round Markers or the Colored Lines');
    set(eval(['gain' tag(end)]),'Marker','o','MarkerEdgeColor','k',...
            'MarkerFaceColor',col,'LineStyle','none','markersize',6);
    set(eval(['line' tag(end)]),'color',col,'linewidth',1);

    set(gcf,'WindowButtonMotionFcn','');
    set(gcf,'WindowButtonUpFcn','');
    
elseif strcmp(state,'save_state') 
    eq_state.peakgain1 =  str2num(get_param([Owner,'/PeakGain1'],'value'));
    eq_state.CenterFreq1= str2num(get_param([Owner,'/CenterFreq1'],'value'));
    eq_state.BandWidth1=  str2num(get_param([Owner,'/BandWidth1'],'value'));
    
    eq_state.peakgain2   =  str2num(get_param([Owner,'/PeakGain2'],'value'));
    eq_state.CenterFreq2 =  str2num(get_param([Owner,'/CenterFreq2'],'value'));
    eq_state.BandWidth2  =  str2num(get_param([Owner,'/BandWidth2'],'value'));
    
    eq_state.peakgain3   =  str2num(get_param([Owner,'/PeakGain3'],'value'));
    eq_state.CenterFreq3 =  str2num(get_param([Owner,'/CenterFreq3'],'value'));
    eq_state.BandWidth3  =  str2num(get_param([Owner,'/BandWidth3'],'value'));
    
    eq_state.AF_Gain   =    str2num(get_param([Owner,'/AF_Gain'],'gain'));
    
   save GraphicEQ_State  eq_state
   %%save junk eq_state
    
end

function out = numFormat(x,Fs)
%This function is for formatting the display of the frequency values
x = x*Fs/(2*pi); %Convert from radians/sec to absolute frequency in Hz
if (x/1000)<1
    out = [num2str(round(x)),'Hz'];
else
    s = sprintf('%0.3g',x/1000);
    out = [s,'kHz'];
end

function normSumH = sumNorm(x)
% Look for the center of the freq response range, and force this to be 0 dB.
normSumH= x -(max(x)+min(x))/2;


    

   
    



    

Contact us