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];