www.gusucode.com > 声音的处理有:LPC,FFT,共振峰,频谱源码程序 > siganlandsystemusingMatlab/SSUM/physmodel/ksstring/ksstringexpofn.m

    function ksksstringexpofn(action, datastruct)

    if nargin < 1
        action='init';
    end

	name = mfilename;
	figname = [name(1:end-2) '_fig'];
	f=findobj('Tag',figname);
    handles = get(f,'UserData');
    
    switch action
		case 'help'
			display_help(figname);
		case 'init'
				setdefaults;
				set(handles.loss_text,'Enable','inactive');
				%movegui(f,'center');

				set(handles.play,'Visible','off');
				set(handles.notestart_text,'Visible','off');
				set(handles.noteend_text,'Visible','off');
				set(handles.transpose_text,'Visible','off');
				set(handles.pianoroll,'Visible','off');
				set(handles.wetness_inst,'Visible','off');
				set(handles.wetness_room,'Visible','off');
		case 'resize'
				movegui(f,'onscreen');
		case 'play'
            if isfield(handles, 'audiodata');
                
                audiodata = handles.audiodata;
                if max(abs(audiodata.data)) > 0.9
                    audiodata.data = normalize(audiodata.data);
                end
                if (max(abs(audiodata.data)) > 1.0)
                    audiodata.data = normalize(audiodata.data);
                end
                play_audiodata(audiodata, handles.play);
            end

		case 'synthesize'
            if isfield(handles, 'mididata')
                startnote = str2num(get(handles.notestart_text,'String'));
                endnote = str2num(get(handles.noteend_text,'String'));
                
                if startnote > endnote
                    endnote = startnote;
                    set(handles.noteend_text,'String',num2str(endnote));
                end
                
                %numnotes = endnote - startnote + 1;
                Fs = str2num(get(handles.Fs_text,'String'));
                tempo = str2num(get(handles.tempo_text,'String'));
                temposcale = handles.mididata.tempo/tempo;
                
                set(handles.play,'Visible','off');
                %(delta time,absolute time, midi note number, note
                % duration, note velocity, channel)
                synth = [];
                
                % resample impulse responses
                if isfield(handles,'impulse_inst')
                    if handles.impulse_inst.Fs ~= Fs
                        impulse = resample(handles.impulse_inst.data,Fs,handles.impulse_inst.Fs);
                    else
                        impulse = handles.impulse_inst.data;
                    end
                    handles.impulse_instdata = impulse;
                end
                
                if isfield(handles,'impulse_room')
                    if handles.impulse_room.Fs ~= Fs
                        impulse = resample(handles.impulse_room.data,Fs,handles.impulse_room.Fs);
                    else
                        impulse = handles.impulse_room.data;
                    end
                    handles.impulse_roomdata = impulse;
                end
        
                handles.msgbox = waitbar(0,'Synthesizing...');
                for i=startnote:endnote
                    freq = 440*2^((handles.mididata.data(i,3)-69)/12);
                    set(handles.frequency_text,'String',num2str(freq));
                    amp = handles.mididata.data(i,5)/128/2;
                    set(handles.amplitude_text,'String',num2str(amp));
                    dur = handles.mididata.data(i,4)* ...
                        handles.mididata.ms_per_tick/1000*temposcale;
                    set(handles.duration_text,'String',num2str(dur));
                    if (dur > 0)
                        handles = synthesize(handles);
                        y = handles.audiodata.data;

                        starttime = (handles.mididata.data(i,2) - ...
                            handles.mididata.data(startnote,2))* ...
                            handles.mididata.ms_per_tick/1000*temposcale;
                        startindex = floor(starttime*Fs)+1;
                        endindex = startindex + size(y,1) - 1;
                        if size(synth,1) < endindex
                            synth = [synth; zeros(endindex-size(synth,1),size(y,2))];
                        end

                        synth(startindex:endindex,:) = ...
                            synth(startindex:endindex,:) + y;
                    end
                    waitbar((i-startnote+1)/(endnote-startnote+1),handles.msgbox);
                end
                close(handles.msgbox);
                handles.audiodata.data = synth;
                handles.audiodata.Fs = str2num(get(handles.Fs_text,'String'));
                set(handles.play,'Visible','on');
            else
                handles.msgbox = waitbar(0,'Synthesizing...');
                set(handles.play,'Visible','off');
                handles = synthesize(handles);
                set(handles.play,'Visible','on');
                waitbar(100,handles.msgbox);
                close(handles.msgbox);
            end
        case 'instmenu'
            contents = get(handles.instmenu,'String');
            switch contents{get(handles.instmenu,'Value')}
                case 'None'
                    if isfield(handles,'impulse_inst')
                        handles = rmfield(handles,'impulse_inst');
                        set(handles.infobox_inst,'String',{''});
                    end
                case 'Load'
                    handles.impulse_inst = load_audiodata;

                    filename = handles.impulse_inst.filenamepath;
                    [t,r] = strtok(filename,'/');
                    while ~isempty(r)
                        [t,r] = strtok(r,'/');
                    end
                    info = {...
                        ['Name: ' t]; ...
                        ['Fs: ' num2str(handles.impulse_inst.Fs)]; ...
                        ['Length: ' num2str(size(handles.impulse_inst.data,1))]; ...
                        ['Channels: ' num2str(size(handles.impulse_inst.data,2))]};
                    set(handles.infobox_inst,'String', info);
                    set(handles.wetness_inst,'Visible','on');
            
            end
        case 'roommenu'
            contents = get(handles.roommenu,'String');
            switch contents{get(handles.roommenu,'Value')}
                case 'None'
                    if isfield(handles,'impulse_room')
                        handles = rmfield(handles,'impulse_room');
                        set(handles.infobox_room,'String','');
                    end
                case 'Load'
                    handles.impulse_room = load_audiodata;

                    filename = handles.impulse_room.filenamepath;
                    [t,r] = strtok(filename,'/');
                    while ~isempty(r)
                        [t,r] = strtok(r,'/');
                    end
                    info = {...
                        ['Name: ' t]; ...
                        ['Fs: ' num2str(handles.impulse_room.Fs)]; ...
                        ['Length: ' num2str(size(handles.impulse_room.data,1))]; ...
                        ['Channels: ' num2str(size(handles.impulse_room.data,2))]};
                    set(handles.infobox_room,'String', info);
                    set(handles.wetness_room,'Visible','on');
            end
        case 'synthmenu'
            contents = get(handles.synthmenu,'String');
            switch contents{get(handles.synthmenu,'Value')}
                case 'Load'
                    savedir = pwd;
                    cd([ssumroot, 'data/MIDI']);
                    [filename,path] = uigetfile({'*.mid','MIDI (*.mid)';'*.*',...
                        'All files (*.*)'}, 'Select a MIDI file');
                    filenamepath = [path filename];
                    cd(savedir);

                    % Load MIDI data
                    [midi,info,ext,ms_per_quarter,ms_per_tick] ...
                        = midird3(filenamepath);
                    % Merge all tracks to one
                    midi = MergeTracks(midi);
                    %(delta time,absolute time, midi note number, note duration, note velocity, channel)
                    handles.mididata.data = midi;
                    handles.mididata.ms_per_tick = ms_per_tick;
                    handles.mididata.filename = filename;
                    duration = handles.mididata.data(end,2)*ms_per_tick/1000;
                    numnotes = size(handles.mididata.data,1);
                    handles.mididata.tempo = 1/(ms_per_quarter/1000)*60;
                    info = {...
                        ['Name: ' filename]; ...
                        ['Number of notes: ' num2str(numnotes)]; ...
                        ['Duration: ' num2str(duration) ' s']; ...
                        ['Tempo: ' num2str(handles.mididata.tempo)]};
                    set(handles.infobox_synth,'String', info);
                    set(handles.tempo_text,'String',num2str(handles.mididata.tempo));
                    set(handles.noteend_text,'String',num2str(numnotes));
                    
                    set(handles.notestart_text,'Visible','on');
                    set(handles.noteend_text,'Visible','on');
                    set(handles.tempo_text,'Visible','on');
                    set(handles.pianoroll,'Visible','on');
                    set(handles.transpose_text,'Visible','on');
                    set(handles.duration_text,'Enable','inactive');
                    set(handles.frequency_text,'Enable','inactive');
                    set(handles.amplitude_text,'Enable','inactive');
                case 'Note'
                    if isfield(handles,'mididata')
                        handles = rmfield(handles,'mididata');
                        set(handles.infobox_synth,'String','');
                    end
                    set(handles.notestart_text,'Visible','off');
                    set(handles.noteend_text,'Visible','off');
                    set(handles.tempo_text,'Visible','off');
                    set(handles.pianoroll,'Visible','off');
                    set(handles.transpose_text,'Visible','off');
                    set(handles.duration_text,'Enable','on');
                    set(handles.frequency_text,'Enable','on');
                    set(handles.amplitude_text,'Enable','on');
            end
        case {'fourierexpo', 'sonoexpo','reverbexpo'}
            if isfield(handles,'audiodata')
                audiodata = handles.audiodata;
                switch action
                    case 'fourierexpo'
                        fourierexpogui(audiodata);
                    case 'sonoexpo'
                        sonoexpogui(audiodata);
                    case 'reverbexpo'
                        reverbexpogui(audiodata);
                end
            end
        case 'pianoroll'
            if isfield(handles, 'mididata');
                startnote = str2num(get(handles.notestart_text,'String'));
                endnote = str2num(get(handles.noteend_text,'String'));
                if startnote > endnote
                    endnote = startnote;
                    set(handles.noteend_text,'String',num2str(endnote));
                end
                pianoroll(handles.mididata,1,startnote,endnote)
            end
        case 'fourier_room'
            if isfield(handles,'impulse_room'),
                fourierexpogui(handles.impulse_room);
            end
        case 'fourier_inst'
            if isfield(handles,'impulse_inst'),
                fourierexpogui(handles.impulse_inst);
            end
        case 'save'
            if isfield(handles,'audiodata')
                save_audiodata(handles.audiodata);
            end
		case 'print'
			print_figure(f);
		case 'close'
			close_figure(f,figname(1:end-4));
			return;
	end
	set(f,'UserData',handles);
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ud = synthesize(ud)
    % Taken in large part from Julius Smith's paper in CMJ
    Fs = str2num(get(ud.Fs_text,'String'));
    duration = str2num(get(ud.duration_text,'String'));
    transpose = str2num(get(ud.transpose_text,'String')); % General volume scaling
    
    amp = str2num(get(ud.duration_text,'String'));
    freq = transpose*str2num(get(ud.frequency_text,'String'));
    delay_length = round(Fs/freq/2);
    if delay_length < 1
        delay_length = 1;
    end

    % For later, design fractional delay allpass
    %[num,den] = designAllpass(Fs/freq/2+1);

    excite_position = str2num(get(ud.excitepos_text,'String'));
    loss = 1.0 - str2num(get(ud.loss_text,'String'));
    pickups = floor(str2num(get(ud.pickups_text,'String')).*delay_length);
    numsamples = ceil(Fs*duration);

    % Initialize string

    excitepos = floor(delay_length*excite_position+1);
    if excitepos > delay_length
        excitepos = delay_length-1;
    end
    y = zeros(delay_length,1);

    excite_contents = get(ud.excite_menu,'String');
    switch excite_contents{get(ud.excite_menu,'Value')}
        case 'Pluck'
            y(1:excitepos) = amp/excitepos*[0:excitepos-1];
            y(excitepos+1:end) = amp/(1-excitepos)*([excitepos:delay_length-1]-excitepos)+amp;
        case 'Strike'
						% Y is velocity, not stace
            hammerl = floor(delay_length/5);
            if excitepos+hammerl > delay_length,
                excitepos = delay_length-hammerl-1;
            end
            y(excitepos:excitepos+hammerl) = amp;
        case 'Noise'
            sig = 0.5 - rand(1,delay_length-2);
            % lowpass filter
            [N, Wn] = ellipord(0.05,0.1,1,40);
            [B,A] = ellip(N,1,40,Wn,'low');
            sig = filter(B,A,sig);
            sig = amp*sig./max(sig);
            y(2:end-1) = sig;
        case 'Bow'
            y(1:excitepos) = amp/excitepos*[0:excitepos-1];
            y(excitepos+1:end) = amp/(1-excitepos)*([excitepos:delay_length-1]-excitepos)+amp;
            temp = resample(y,1,5);
            excitelen = size(temp,1);
            %bowshape = [zeros(excitepos,1); temp; zeros(size(y,1)-size(temp,1)-excitepos,1)];
            bowshape = y;
            % Should be based on bow velocity
            tablelength = 1000;
            finc = floor(tablelength*0.9);  % samples spent increasing pull
            fdec = tablelength - finc;  % samples spent flying back
            forcetable = [linspace(0,amp,finc)'; linspace(amp,0,fdec)'];
            y = zeros(delay_length,1);
            clear temp;
    end

    udl = y/2;
    ldl = y/2;
    

    % Now simulate
    y = zeros(numsamples,1);

    switch excite_contents{get(ud.excite_menu,'Value')}
        case 'Bow'
            contents = get(ud.model_menu,'String');
            switch contents{get(ud.model_menu,'Value')}
                case {'Ideal','Lossy'}
                    for i=1:numsamples
                        % Move one sample from ldl to udl, and vice versa
                        tempval = udl(end);
                        udl = [-loss*ldl(1); udl(1:end-1)];
                        ldl = [ldl(2:end); -loss*tempval];
                        for j = 1:length(pickups)
                            y(i) = y(i) + udl(pickups(j)) + ldl(pickups(j));
                        end
                        udl = udl + (bowshape/2)*forcetable(mod(i,tablelength)+1);
                        ldl = ldl + (bowshape/2)*forcetable(mod(i,tablelength)+1);
                    end
                case {'Loss(f)'}
                    for i=1:numsamples
                        % Move one sample from ldl to udl, and vice versa
                        tempval = udl(end);
                        udl = [-loss*ldl(1); udl(1:end-1)];
                        % Lowpass filter
                        newval = (tempval+udl(end))/2;
                        ldl = [ldl(2:end); -loss*newval];
                        for j = 1:length(pickups)
                            y(i) = y(i) + udl(pickups(j)) + ldl(pickups(j));
                        end
                        udl = udl + (bowshape/2)*forcetable(mod(i,tablelength)+1);
                        ldl = ldl + (bowshape/2)*forcetable(mod(i,tablelength)+1);
                    end
						end
				case 'Strike'
					contents = get(ud.model_menu,'String');
					switch contents{get(ud.model_menu,'Value')}
							case {'Ideal','Lossy'}
									for i=2:numsamples
											% Move one sample from ldl to udl, and vice versa
											tempval = udl(end);
											udl = [-loss*ldl(1); udl(1:end-1)];
%                         % Move temp val through allpass
% 
%                         if length(udl) < length(num)
%                             x =[udl; ldl(1:length(num)-length(udl))];
%                         else
%                             x = udl(end-length(num):end);
%                         end
%                             
%                         tempval = filter(num,den,x);
											ldl = [ldl(2:end); -loss*tempval(1)];
											% Leaky integrator
											for j = 1:length(pickups)
													y(i) = y(i) + udl(pickups(j)) + ldl(pickups(j)) + 0.99*y(i-1);
											end
									end
							case {'Loss(f)'}
									for i=2:numsamples
											% Move one sample from ldl to udl, and vice versa
											tempval = udl(end);
											udl = [-loss*ldl(1); udl(1:end-1)];
											% Lowpass filter
											newval = (tempval+udl(end))/2;
											ldl = [ldl(2:end); -loss*newval];
											% Leaky integrator
											for j = 1:length(pickups)
													y(i) = y(i) + udl(pickups(j)) + ldl(pickups(j)) + 0.99*y(i-1);
											end
									end
					end
        otherwise
            contents = get(ud.model_menu,'String');
            switch contents{get(ud.model_menu,'Value')}
                case {'Ideal','Lossy'}
                    for i=1:numsamples
                        % Move one sample from ldl to udl, and vice versa
                        tempval = udl(end);
                        udl = [-loss*ldl(1); udl(1:end-1)];
%                         % Move temp val through allpass
% 
%                         if length(udl) < length(num)
%                             x =[udl; ldl(1:length(num)-length(udl))];
%                         else
%                             x = udl(end-length(num):end);
%                         end
%                             
%                         tempval = filter(num,den,x);
                        ldl = [ldl(2:end); -loss*tempval(1)];
                        
                        for j = 1:length(pickups)
                            y(i) = y(i) + udl(pickups(j)) + ldl(pickups(j));
                        end
                    end
                case {'Loss(f)'}
                    for i=1:numsamples
                        % Move one sample from ldl to udl, and vice versa
                        tempval = udl(end);
                        udl = [-loss*ldl(1); udl(1:end-1)];
                        % Lowpass filter
                        newval = (tempval+udl(end))/2;
                        ldl = [ldl(2:end); -loss*newval];
                        for j = 1:length(pickups)
                            y(i) = y(i) + udl(pickups(j)) + ldl(pickups(j));
                        end
                    end
            end
    end

    % Taper the first 5 milliseconds

    taperlength = ceil(Fs*5/1000);
    if (size(y,1) < 2*taperlength)
        % Taper the first 5%
        taperlength = ceil(0.05*size(y,1));
    end

    for i=1:size(y,2)
        y(1:taperlength,i) =  y(1:taperlength,i).* ...
            sin(pi*[0:taperlength-1]'/(2*taperlength));
    end

    
    % Taper the last 50 milliseconds if sound is longer than 300 ms
    if size(y,1)/Fs < 0.3
        taperlength = ceil(Fs*50/1000);
        if (size(y,1) < 2*taperlength)
            % Taper the last 20%
            taperlength = ceil(0.2*size(y,1));
        end

        for i=1:size(y,2)
            y(end-taperlength+1:end,i) = y(end-taperlength+1:end,i).* ...
                cos(pi*[0:taperlength-1]'/(2*taperlength));
        end
    else
        for i=1:size(y,2)
            y(end-taperlength+1:end,i) = y(end-taperlength+1:end,i).* ...
                cos(pi*[0:taperlength-1]'/(3*taperlength));
        end
    end
    
    
    % Apply Instrument impulse response
    if isfield(ud,'impulse_inst')
        wetness = str2num(get(ud.wetness_inst,'String'))/100;
        impulse = ud.impulse_inst.data;

        if (size(y,1) >= size(impulse,1))
            for i=1:size(impulse,2)     % For each channel
                temp(:,i) = [y; zeros(size(impulse(:,i),1),1)];
                temp(:,i) = fftfilt(impulse(:,i),temp(:,i));
            end
        else
            impulse = [impulse; zeros(size(y,1),size(impulse,2))];
            for i=1:size(impulse,2)
                temp(:,i) = fftfilt(y,impulse(:,i));
            end
        end

        temp = temp*wetness;
        for i=1:size(impulse,2),
            temp(1:size(y,1),i) = temp(1:size(y,1),i) + y.*(1-wetness)./size(impulse,2);
        end
        y = temp;
    end

    
    % Apply Room impulse response
    if isfield(ud,'impulse_room')
        wetness = str2num(get(ud.wetness_room,'String'))/100;
        impulse = ud.impulse_room.data;
        clear temp;
        
        if (size(y,1) >= size(impulse,1))
            for i=1:size(impulse,2)     % For each channel
                temp(:,i) = [y; zeros(size(impulse(:,i),1),1)];
                temp(:,i) = fftfilt(impulse(:,i),temp(:,i));
            end
        else
            impulse = [impulse; zeros(size(y,1),size(impulse,2))];
            for i=1:size(impulse,2)
                temp(:,i) = fftfilt(y,impulse(:,i));
            end
        end
        
        temp = temp*wetness;
        for i=1:size(impulse,2),
            temp(1:size(y,1),i) = temp(1:size(y,1),i) + y.*(1-wetness)./size(impulse,2);
        end
        y = temp;
    end

%     % Taper the first 10 milliseconds if no impulse
%     if ~isfield(ud,'impulse_room') & ~isfield(ud,'impulse_inst')
%         taperlength = ceil(Fs*10/1000);
%         if (size(y,1) < 2*taperlength)
%             % Taper the first 5%
%             taperlength = ceil(0.05*size(y,1));
%         end
% 
%         for i=1:size(y,2)
%             y(1:taperlength,i) =  y(1:taperlength,i).* ...
%                 sin(pi*[0:taperlength-1]'/(2*taperlength));
%         end
%     end
    
    % Taper the last 50 milliseconds
%     taperlength = ceil(Fs*50/1000);
%     if (size(y,1) < 2*taperlength)
%         % Taper the last 20%
%         taperlength = ceil(0.2*size(y,1));
%     end
%     
%     for i=1:size(y,2)
%         y(end-taperlength+1:end,i) = y(end-taperlength+1:end,i).* ...
%             cos(pi*[0:taperlength-1]'/(2*taperlength));
%     end
    
    if max(abs(y)) > 0.9
        y = normalize(y);
    end
    
    ud.audiodata.data = y;
    ud.audiodata.Fs = Fs;

    
function [num,den] = designAllpass(delay)

    N = floor(delay);

    d = zeros(1,N);
    p = zeros(1,N+1);

    for k=1:N,
        for n=0:N,
            p(n+1) = (delay-N+n)/(delay-N+k+n);
        end
        d(k) = (-1)^k*nchoosek(N,k)*prod(p);
    end

    w = linspace(0,1,500).*pi;

    % Allpass filter giving fractional delay
    num = [fliplr(d) 1];
    den = [1 d];