annotate 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
rev   line source
bleeck@3 1 % This external file is included as part of the 'aim-mat' distribution package
bleeck@3 2 % (c) 2011, University of Southampton
bleeck@3 3 % Maintained by Stefan Bleeck (bleeck@gmail.com)
bleeck@3 4 % download of current version is on the soundsoftware site:
bleeck@3 5 % http://code.soundsoftware.ac.uk/projects/aimmat
bleeck@3 6 % documentation and everything is on http://www.acousticscale.org
tomwalters@0 7 % function to generate an artificial vowel
tomwalters@0 8 function sig=gen_frog(sig,options)
tomwalters@0 9 % vowel,pitch,scale,halflifeconstant,onsettimeconstant,pitch_jitter,formant_jitter,formant_jitter_bw);%
tomwalters@0 10
tomwalters@0 11 if nargin < 2
tomwalters@0 12 options=[];
tomwalters@0 13 end
tomwalters@0 14
tomwalters@0 15
tomwalters@0 16 % the rise of a damped sinusoid is not instantaneous, but like a gamma
tomwalters@0 17 % functin with the following power of t:
tomwalters@0 18 if isfield(options,'onsettimeconstant')
tomwalters@0 19 onsettimeconstant=options.onsettimeconstant;
tomwalters@0 20 else
tomwalters@0 21 onsettimeconstant=0.5;
tomwalters@0 22 end% halflife of each formant is calculated by dividing this number by the
tomwalters@0 23 % formant frequency:
tomwalters@0 24 % if halflifeconstant<=0, then fixed to 4 ms
tomwalters@0 25 if isfield(options,'halflifeconstant')
tomwalters@0 26 halflifeconstant=options.halflifeconstant;
tomwalters@0 27 else
tomwalters@0 28 halflifeconstant=3;
tomwalters@0 29 end
tomwalters@0 30 % scaling = 1: normal speaker
tomwalters@0 31 if isfield(options,'scale')
tomwalters@0 32 scale=options.scale;
tomwalters@0 33 else
tomwalters@0 34 scale=1;
tomwalters@0 35 end
tomwalters@0 36 % f0
tomwalters@0 37 if isfield(options,'pitch')
tomwalters@0 38 pitch=options.pitch;
tomwalters@0 39 else
tomwalters@0 40 pitch=100;
tomwalters@0 41 end
tomwalters@0 42 % how long the decay should continue longer then the reprate
tomwalters@0 43 if isfield(options,'carry_decay')
tomwalters@0 44 carry_decay_parameter=options.carry_decay;
tomwalters@0 45 else
tomwalters@0 46 carry_decay_parameter=1;
tomwalters@0 47 end
tomwalters@0 48 % normal or is it the octave? In this case, we jump over each second
tomwalters@0 49 if isfield(options,'do_octave')
tomwalters@0 50 do_octave=options.do_octave;
tomwalters@0 51 else
tomwalters@0 52 do_octave=0;
tomwalters@0 53 end
tomwalters@0 54 % type of vowel: 'a','e','i','o','u'
tomwalters@0 55 if isfield(options,'vowel')
tomwalters@0 56 vowel=options.vowel;
tomwalters@0 57 else
tomwalters@0 58 vowel='a';
tomwalters@0 59 end
tomwalters@0 60
tomwalters@0 61
tomwalters@0 62
tomwalters@0 63 if nargin < 1
tomwalters@0 64 sig=signal(0.5,16000);
tomwalters@0 65 end
tomwalters@0 66 sr=getsr(sig);
tomwalters@0 67 dur_time=getlength(sig);
tomwalters@0 68
tomwalters@0 69
tomwalters@0 70 nr_formants=4;
tomwalters@0 71
tomwalters@0 72 for i=1:nr_formants
tomwalters@0 73 formfre(i)=pitch*i;
tomwalters@0 74 end
tomwalters@0 75 level(1)=0;
tomwalters@0 76 % level(2)=-18;
tomwalters@0 77 % level(3)=-30;
tomwalters@0 78 % level(4)=-38;
tomwalters@0 79
tomwalters@0 80 level(2)=-4;
tomwalters@0 81 level(3)=-6;
tomwalters@0 82 level(4)=-9;
tomwalters@0 83
tomwalters@0 84
tomwalters@0 85
tomwalters@0 86 % % fix all formants to the nearest harmonic of the fundamental
tomwalters@0 87 % if isfield(options,'adjust_to_nearest_harmonic')
tomwalters@0 88 % if options.adjust_to_nearest_harmonic==1
tomwalters@0 89 % f0=options.pitch;
tomwalters@0 90 % for formant=1:nr_formants
tomwalters@0 91 % fre=formfre(formant);
tomwalters@0 92 % newfre=round(fre/f0)*f0;
tomwalters@0 93 % formfre(formant)=newfre;
tomwalters@0 94 % end
tomwalters@0 95 % end
tomwalters@0 96 % end
tomwalters@0 97
tomwalters@0 98
tomwalters@0 99 formfre=formfre.*scale;
tomwalters@0 100 dur_samp=dur_time.*sr; %length of vowel defined in sample points
tomwalters@0 101 sgpp=1/pitch; %standard glottal pulse period.
tomwalters@0 102 pitch_jitter=0;
tomwalters@0 103 t=[0:1/sr:(dur_time-(1/sr))]; %our time sequence
tomwalters@0 104 dur_samp=dur_time.*sr; %length of vowel defined in sample points
tomwalters@0 105
tomwalters@0 106
tomwalters@0 107 %we now generate a sequence, specified in sample points, which
tomwalters@0 108 %define the spacing of glottal pulses. With zero pitch_jitter the sequence
tomwalters@0 109 %is regular (1/pitch). With a pitch_jitter value of 1 the spacing of glottal
tomwalters@0 110 %pulses fall in a range with an upper limit of double the period of
tomwalters@0 111 %the pitch and a lower limit of 1/sampling rate.
tomwalters@0 112 %The average spacing of glottal pulses is approx 1/pitch
tomwalters@0 113 lwr_pth_jit=0.5-(pitch_jitter/2);
tomwalters@0 114 upr_pth_jit=0.5+(pitch_jitter/2);
tomwalters@0 115
tomwalters@0 116 gp=cell(nr_formants,1); %for each formant will store pulse time
tomwalters@0 117 for formant=1:nr_formants
tomwalters@0 118 enough_pulses=0;
tomwalters@0 119 pulse_number=0;
tomwalters@0 120 while enough_pulses==0
tomwalters@0 121 pulse_number=pulse_number+1;
tomwalters@0 122 pulse_spacing(pulse_number)=max(1,floor(sr.*(sgpp.*2.*(lwr_pth_jit+(upr_pth_jit-lwr_pth_jit)*rand(1)))));
tomwalters@0 123 pulse_time(pulse_number)=sum(pulse_spacing)-pulse_spacing(1)+1;
tomwalters@0 124 if pulse_time(pulse_number)>=dur_samp
tomwalters@0 125 pulse_time=pulse_time(1:pulse_number-1);
tomwalters@0 126 pulse_number=pulse_number-1;
tomwalters@0 127 enough_pulses=1;
tomwalters@0 128 else
tomwalters@0 129 end
tomwalters@0 130 end
tomwalters@0 131
tomwalters@0 132 gp{formant}=pulse_time;
tomwalters@0 133 clear pulse_time;
tomwalters@0 134 clear pulse_spacing;
tomwalters@0 135 no_pulses(formant)=length(gp{formant});
tomwalters@0 136 pulse_times{formant}=gp{formant};
tomwalters@0 137 end%formant
tomwalters@0 138
tomwalters@0 139 formant_jitter=0;
tomwalters@0 140
tomwalters@0 141 % if no gamma tone, then precalculate the damping function once for all
tomwalters@0 142 % if onsettimeconstant <= 0 && halflifeconstant==0
tomwalters@0 143 hl=0.04;
tomwalters@0 144 damping=exp(t.*log(0.5)/hl); %this decays to 0.5 after hl seconds
tomwalters@0 145 damping=damping/max(damping);
tomwalters@0 146 % end
tomwalters@0 147
tomwalters@0 148 onsettimes=power(t,onsettimeconstant);
tomwalters@0 149
tomwalters@0 150 formant_jitter_bw=0;
tomwalters@0 151 %--------------------------------------------------------------------------
tomwalters@0 152 for formant=1:nr_formants
tomwalters@0 153 lw_log(formant)=max(log10(150), (log10(formfre(formant))- ((formant_jitter_bw.*.3)/2) ) ); %cannot go below 150Hz
tomwalters@0 154 lw_log_adj(formant)=log10(formfre(formant))-((log10(formfre(formant))-lw_log(formant)).*formant_jitter);
tomwalters@0 155 up_log(formant)=min(log10(4500),log10(formfre(formant))+ ((formant_jitter_bw.*.3)/2)) ;
tomwalters@0 156 up_log_adj(formant)=log10(formfre(formant))+((up_log(formant)-log10(formfre(formant))).*formant_jitter);
tomwalters@0 157 end
tomwalters@0 158
tomwalters@0 159
tomwalters@0 160 % if we want to generate the octave, we take exactly the same pulses and
tomwalters@0 161 % frequencies, but only every second one:
tomwalters@0 162 if do_octave
tomwalters@0 163 pulse_step=2;
tomwalters@0 164 else
tomwalters@0 165 pulse_step=1;
tomwalters@0 166 end
tomwalters@0 167
tomwalters@0 168 nr_points=length(t);
tomwalters@0 169 final_wave=zeros(dur_samp,nr_formants);
tomwalters@0 170 for formant=1:nr_formants
tomwalters@0 171 for count=1:pulse_step:no_pulses(formant)-1
tomwalters@0 172 oneortwo=randperm(2);
tomwalters@0 173 if oneortwo(1)==1
tomwalters@0 174 freq=10.^((lw_log_adj(formant)+(log10(formfre(formant))-lw_log_adj(formant))*rand(1))); %lower range
tomwalters@0 175 else
tomwalters@0 176 freq=10.^((log10(formfre(formant))+(up_log_adj(formant)-log10(formfre(formant)))*rand(1))); %upper range
tomwalters@0 177 end
tomwalters@0 178
tomwalters@0 179 % if freq>1000
tomwalters@0 180 % no_octave=((log10(freq)-3))/.3;
tomwalters@0 181 % lev=-12.*no_octave;
tomwalters@0 182 % else
tomwalters@0 183 % lev=0;
tomwalters@0 184 % end
tomwalters@0 185 % amp=10.^(lev/20);
tomwalters@0 186
tomwalters@0 187 lev=level(formant);
tomwalters@0 188 amp=10.^(lev/20);
tomwalters@0 189
tomwalters@0 190 if halflifeconstant<=0
tomwalters@0 191 hl=0.004;
tomwalters@0 192 else
tomwalters@0 193 hl=halflifeconstant/freq;
tomwalters@0 194 end
tomwalters@0 195
tomwalters@0 196 nr_relevant_points=pulse_times{formant}(count+1)-pulse_times{formant}(count);
tomwalters@0 197
tomwalters@0 198 nr_relevant_points=nr_relevant_points*carry_decay_parameter;
tomwalters@0 199
tomwalters@0 200 if onsettimeconstant > 0
tomwalters@0 201 damping=zeros(nr_relevant_points,1);
tomwalters@0 202 for jj=1:nr_relevant_points
tomwalters@0 203 damping(jj)=onsettimes(jj)*exp(t(jj)*log(0.5)/hl); %this decays to 0.5 after hl seconds
tomwalters@0 204 end
tomwalters@0 205 damping=damping/max(damping);
tomwalters@0 206 end
tomwalters@0 207 grafix=0;
tomwalters@0 208 if grafix==1
tomwalters@0 209 figure(234)
tomwalters@0 210 plot(damping);
tomwalters@0 211 end
tomwalters@0 212
tomwalters@0 213 this_formant=zeros(nr_relevant_points,1);
tomwalters@0 214 for jj=1:nr_relevant_points
tomwalters@0 215 sinsin=sin(2*pi*freq*t(jj));
tomwalters@0 216 this_formant(jj)=amp*sinsin*damping(jj);
tomwalters@0 217 end
tomwalters@0 218 start_nr=pulse_times{formant}(count);
tomwalters@0 219 stop_nr=start_nr+nr_relevant_points-1;
tomwalters@0 220
tomwalters@0 221 if stop_nr> nr_points
tomwalters@0 222 nr_new=nr_points-start_nr+1;
tomwalters@0 223 this_formant=this_formant(1:nr_new);
tomwalters@0 224 stop_nr=nr_points;
tomwalters@0 225 final_wave(start_nr:stop_nr,formant)= final_wave(start_nr:stop_nr,formant)+this_formant;
tomwalters@0 226 else
tomwalters@0 227 final_wave(start_nr:stop_nr,formant)= final_wave(start_nr:stop_nr,formant)+this_formant;
tomwalters@0 228 end
tomwalters@0 229 end
tomwalters@0 230 end
tomwalters@0 231 final_wave_total=zeros(dur_samp,1);
tomwalters@0 232 for formant=1:nr_formants
tomwalters@0 233 final_wave_total=final_wave_total+final_wave(:,formant);
tomwalters@0 234 end
tomwalters@0 235
tomwalters@0 236 % sig=signal(final_wave_total,sr);
tomwalters@0 237
tomwalters@0 238 if isfield(options,'rise_time')
tomwalters@0 239 rise_time=options.rise_time;
tomwalters@0 240 else
tomwalters@0 241 rise_time=0.015;
tomwalters@0 242 end
tomwalters@0 243
tomwalters@0 244 if isfield(options,'fall_time')
tomwalters@0 245 fall_time=options.fall_time;
tomwalters@0 246 else
tomwalters@0 247 fall_time=0.1;
tomwalters@0 248 end
tomwalters@0 249
tomwalters@0 250 % sigvals=
tomwalters@0 251 final_wave_total=gate_on_off(rise_time,fall_time,final_wave_total,sr);
tomwalters@0 252 sig=signal(final_wave_total,sr);
tomwalters@0 253 %
tomwalters@0 254 % hold_time=length(sig)-rise_time-fall_time;
tomwalters@0 255 % attack=linspace(0,1,round(rise_time*sr));
tomwalters@0 256 %
tomwalters@0 257 % hold=ones(1,round(hold_time*sr));
tomwalters@0 258 % release=linspace(1,0,round(fall_time*sr));
tomwalters@0 259 % envelope=[attack hold release];
tomwalters@0 260 % envelope=envelope(1:getnrpoints(sig));
tomwalters@0 261 % envelope=signal(envelope,sr);
tomwalters@0 262 % sig=sig*envelope;
tomwalters@0 263
tomwalters@0 264
tomwalters@0 265 function amp=calc_level(freq);
tomwalters@0 266 %determines the level of a signal at a given frequency after it
tomwalters@0 267 %has been filtered with a low-pass filter of 12dB/octave at 1kHz
tomwalters@0 268 %first calculate if frequency is above 1kHz and if so by how many octaves
tomwalters@0 269 %then multiply by slope.
tomwalters@0 270 if freq>1000
tomwalters@0 271 no_octave=((log10(freq)-3))/.3;
tomwalters@0 272 lev=-12.*no_octave;
tomwalters@0 273 else
tomwalters@0 274 lev=0;
tomwalters@0 275 end
tomwalters@0 276 amp=10.^(lev/20);
tomwalters@0 277
tomwalters@0 278
tomwalters@0 279
tomwalters@0 280 function output=gate_on_off(onset,offset,input,sr)
tomwalters@0 281 %check duration of signal is large enough for both the onset and offset
tomwalters@0 282 %values.
tomwalters@0 283
tomwalters@0 284 sig_length_samp=length(input);
tomwalters@0 285 onset_length_samp=floor(onset.*sr);
tomwalters@0 286 offset_length_samp=floor(offset.*sr);
tomwalters@0 287
tomwalters@0 288 if (onset_length_samp+offset_length_samp)>sig_length_samp
tomwalters@0 289 output=0;
tomwalters@0 290 disp('---ERROR--- onset and offset duration too large for signal');
tomwalters@0 291 return
tomwalters@0 292 else end
tomwalters@0 293
tomwalters@0 294
tomwalters@0 295 %generate onset and offset amplitudes
tomwalters@0 296 n_on=onset_length_samp;
tomwalters@0 297 k=[1:1:n_on];
tomwalters@0 298 onset_win=(1-cos(2.*pi.*(k./(2.*(n_on-1)))))./2;
tomwalters@0 299
tomwalters@0 300 n_off=offset_length_samp;
tomwalters@0 301 k=[1:1:n_off];
tomwalters@0 302 offset_win=0.5+((cos(2.*pi.*(k./(2.*(n_off-1)))))./2);
tomwalters@0 303
tomwalters@0 304
tomwalters@0 305
tomwalters@0 306 total_window=ones(sig_length_samp,1);
tomwalters@0 307 total_window(1:onset_length_samp)=onset_win;
tomwalters@0 308 total_window(sig_length_samp-offset_length_samp+1:sig_length_samp)=offset_win;
tomwalters@0 309
tomwalters@0 310
tomwalters@0 311
tomwalters@0 312 output=input.*total_window;
tomwalters@0 313
tomwalters@0 314 return