Mercurial > hg > aimmat
view aim-mat/tools/@signal/gen_frog.m @ 4:537f939baef0 tip
various bug fixes and changed copyright message
author | Stefan Bleeck <bleeck@gmail.com> |
---|---|
date | Tue, 16 Aug 2011 14:37:17 +0100 |
parents | 20ada0af3d7d |
children |
line wrap: on
line source
% This external file is included as part of the 'aim-mat' distribution package % (c) 2011, University of Southampton % Maintained by Stefan Bleeck (bleeck@gmail.com) % download of current version is on the soundsoftware site: % http://code.soundsoftware.ac.uk/projects/aimmat % documentation and everything is on http://www.acousticscale.org % function to generate an artificial vowel function sig=gen_frog(sig,options) % vowel,pitch,scale,halflifeconstant,onsettimeconstant,pitch_jitter,formant_jitter,formant_jitter_bw);% if nargin < 2 options=[]; end % the rise of a damped sinusoid is not instantaneous, but like a gamma % functin with the following power of t: if isfield(options,'onsettimeconstant') onsettimeconstant=options.onsettimeconstant; else onsettimeconstant=0.5; end% halflife of each formant is calculated by dividing this number by the % formant frequency: % if halflifeconstant<=0, then fixed to 4 ms if isfield(options,'halflifeconstant') halflifeconstant=options.halflifeconstant; else halflifeconstant=3; end % scaling = 1: normal speaker if isfield(options,'scale') scale=options.scale; else scale=1; end % f0 if isfield(options,'pitch') pitch=options.pitch; else pitch=100; end % how long the decay should continue longer then the reprate if isfield(options,'carry_decay') carry_decay_parameter=options.carry_decay; else carry_decay_parameter=1; end % normal or is it the octave? In this case, we jump over each second if isfield(options,'do_octave') do_octave=options.do_octave; else do_octave=0; end % type of vowel: 'a','e','i','o','u' if isfield(options,'vowel') vowel=options.vowel; else vowel='a'; end if nargin < 1 sig=signal(0.5,16000); end sr=getsr(sig); dur_time=getlength(sig); nr_formants=4; for i=1:nr_formants formfre(i)=pitch*i; end level(1)=0; % level(2)=-18; % level(3)=-30; % level(4)=-38; level(2)=-4; level(3)=-6; level(4)=-9; % % fix all formants to the nearest harmonic of the fundamental % if isfield(options,'adjust_to_nearest_harmonic') % if options.adjust_to_nearest_harmonic==1 % f0=options.pitch; % for formant=1:nr_formants % fre=formfre(formant); % newfre=round(fre/f0)*f0; % formfre(formant)=newfre; % end % end % end formfre=formfre.*scale; dur_samp=dur_time.*sr; %length of vowel defined in sample points sgpp=1/pitch; %standard glottal pulse period. pitch_jitter=0; t=[0:1/sr:(dur_time-(1/sr))]; %our time sequence dur_samp=dur_time.*sr; %length of vowel defined in sample points %we now generate a sequence, specified in sample points, which %define the spacing of glottal pulses. With zero pitch_jitter the sequence %is regular (1/pitch). With a pitch_jitter value of 1 the spacing of glottal %pulses fall in a range with an upper limit of double the period of %the pitch and a lower limit of 1/sampling rate. %The average spacing of glottal pulses is approx 1/pitch lwr_pth_jit=0.5-(pitch_jitter/2); upr_pth_jit=0.5+(pitch_jitter/2); gp=cell(nr_formants,1); %for each formant will store pulse time for formant=1:nr_formants enough_pulses=0; pulse_number=0; while enough_pulses==0 pulse_number=pulse_number+1; pulse_spacing(pulse_number)=max(1,floor(sr.*(sgpp.*2.*(lwr_pth_jit+(upr_pth_jit-lwr_pth_jit)*rand(1))))); pulse_time(pulse_number)=sum(pulse_spacing)-pulse_spacing(1)+1; if pulse_time(pulse_number)>=dur_samp pulse_time=pulse_time(1:pulse_number-1); pulse_number=pulse_number-1; enough_pulses=1; else end end gp{formant}=pulse_time; clear pulse_time; clear pulse_spacing; no_pulses(formant)=length(gp{formant}); pulse_times{formant}=gp{formant}; end%formant formant_jitter=0; % if no gamma tone, then precalculate the damping function once for all % if onsettimeconstant <= 0 && halflifeconstant==0 hl=0.04; damping=exp(t.*log(0.5)/hl); %this decays to 0.5 after hl seconds damping=damping/max(damping); % end onsettimes=power(t,onsettimeconstant); formant_jitter_bw=0; %-------------------------------------------------------------------------- for formant=1:nr_formants lw_log(formant)=max(log10(150), (log10(formfre(formant))- ((formant_jitter_bw.*.3)/2) ) ); %cannot go below 150Hz lw_log_adj(formant)=log10(formfre(formant))-((log10(formfre(formant))-lw_log(formant)).*formant_jitter); up_log(formant)=min(log10(4500),log10(formfre(formant))+ ((formant_jitter_bw.*.3)/2)) ; up_log_adj(formant)=log10(formfre(formant))+((up_log(formant)-log10(formfre(formant))).*formant_jitter); end % if we want to generate the octave, we take exactly the same pulses and % frequencies, but only every second one: if do_octave pulse_step=2; else pulse_step=1; end nr_points=length(t); final_wave=zeros(dur_samp,nr_formants); for formant=1:nr_formants for count=1:pulse_step:no_pulses(formant)-1 oneortwo=randperm(2); if oneortwo(1)==1 freq=10.^((lw_log_adj(formant)+(log10(formfre(formant))-lw_log_adj(formant))*rand(1))); %lower range else freq=10.^((log10(formfre(formant))+(up_log_adj(formant)-log10(formfre(formant)))*rand(1))); %upper range end % if freq>1000 % no_octave=((log10(freq)-3))/.3; % lev=-12.*no_octave; % else % lev=0; % end % amp=10.^(lev/20); lev=level(formant); amp=10.^(lev/20); if halflifeconstant<=0 hl=0.004; else hl=halflifeconstant/freq; end nr_relevant_points=pulse_times{formant}(count+1)-pulse_times{formant}(count); nr_relevant_points=nr_relevant_points*carry_decay_parameter; if onsettimeconstant > 0 damping=zeros(nr_relevant_points,1); for jj=1:nr_relevant_points damping(jj)=onsettimes(jj)*exp(t(jj)*log(0.5)/hl); %this decays to 0.5 after hl seconds end damping=damping/max(damping); end grafix=0; if grafix==1 figure(234) plot(damping); end this_formant=zeros(nr_relevant_points,1); for jj=1:nr_relevant_points sinsin=sin(2*pi*freq*t(jj)); this_formant(jj)=amp*sinsin*damping(jj); end start_nr=pulse_times{formant}(count); stop_nr=start_nr+nr_relevant_points-1; if stop_nr> nr_points nr_new=nr_points-start_nr+1; this_formant=this_formant(1:nr_new); stop_nr=nr_points; final_wave(start_nr:stop_nr,formant)= final_wave(start_nr:stop_nr,formant)+this_formant; else final_wave(start_nr:stop_nr,formant)= final_wave(start_nr:stop_nr,formant)+this_formant; end end end final_wave_total=zeros(dur_samp,1); for formant=1:nr_formants final_wave_total=final_wave_total+final_wave(:,formant); end % sig=signal(final_wave_total,sr); if isfield(options,'rise_time') rise_time=options.rise_time; else rise_time=0.015; end if isfield(options,'fall_time') fall_time=options.fall_time; else fall_time=0.1; end % sigvals= final_wave_total=gate_on_off(rise_time,fall_time,final_wave_total,sr); sig=signal(final_wave_total,sr); % % hold_time=length(sig)-rise_time-fall_time; % attack=linspace(0,1,round(rise_time*sr)); % % hold=ones(1,round(hold_time*sr)); % release=linspace(1,0,round(fall_time*sr)); % envelope=[attack hold release]; % envelope=envelope(1:getnrpoints(sig)); % envelope=signal(envelope,sr); % sig=sig*envelope; function amp=calc_level(freq); %determines the level of a signal at a given frequency after it %has been filtered with a low-pass filter of 12dB/octave at 1kHz %first calculate if frequency is above 1kHz and if so by how many octaves %then multiply by slope. if freq>1000 no_octave=((log10(freq)-3))/.3; lev=-12.*no_octave; else lev=0; end amp=10.^(lev/20); function output=gate_on_off(onset,offset,input,sr) %check duration of signal is large enough for both the onset and offset %values. sig_length_samp=length(input); onset_length_samp=floor(onset.*sr); offset_length_samp=floor(offset.*sr); if (onset_length_samp+offset_length_samp)>sig_length_samp output=0; disp('---ERROR--- onset and offset duration too large for signal'); return else end %generate onset and offset amplitudes n_on=onset_length_samp; k=[1:1:n_on]; onset_win=(1-cos(2.*pi.*(k./(2.*(n_on-1)))))./2; n_off=offset_length_samp; k=[1:1:n_off]; offset_win=0.5+((cos(2.*pi.*(k./(2.*(n_off-1)))))./2); total_window=ones(sig_length_samp,1); total_window(1:onset_length_samp)=onset_win; total_window(sig_length_samp-offset_length_samp+1:sig_length_samp)=offset_win; output=input.*total_window; return