bleeck@3
|
1 % method of class @signal
|
bleeck@3
|
2 % function sig=genharmonicstim(sig,varargin)
|
bleeck@3
|
3 % INPUT VALUES:
|
bleeck@3
|
4 % sig: @signal with length and samplerate
|
bleeck@3
|
5 % varargin must have several parameters:
|
bleeck@3
|
6 % fundamental (default 128) = periodicity
|
bleeck@3
|
7 % min_fre (128) = lowest possible frequency
|
bleeck@3
|
8 % max_fre (10000) = highest possible frequency
|
bleeck@3
|
9 %
|
bleeck@3
|
10 % envelope of amplitudes
|
bleeck@3
|
11 % either
|
bleeck@3
|
12 % filterprop ([256,256,1024,512]) = fc, df1, bandwidth, df2 (in Hz)
|
bleeck@3
|
13 % default values: fc=3500;
|
bleeck@3
|
14 % df1=256;
|
bleeck@3
|
15 % bandwidth=1024;
|
bleeck@3
|
16 % df2=512;
|
bleeck@3
|
17 % the amplitdes can also be given by cf and two slopes for
|
bleeck@3
|
18 % higher and lower frequencies:
|
bleeck@3
|
19 % eg 'cf',1000,'lowslope',25,'highslope',38
|
bleeck@3
|
20 % the highest and lowest possible allowed harmonic are given
|
bleeck@3
|
21 % in either case by giving 'lowestharmonic' and
|
bleeck@3
|
22 % 'highestharmonic' (default value: 1 and inf)
|
bleeck@3
|
23 %
|
bleeck@3
|
24 % type = which type (default none)
|
bleeck@3
|
25 % filtered,
|
bleeck@3
|
26 % decreaseoddamplitude,
|
bleeck@3
|
27 % decreaseoddphase
|
bleeck@3
|
28 % shiftallcomponents
|
bleeck@3
|
29 % mistunedharmonic
|
bleeck@3
|
30 % decrease_amplitude_linear
|
bleeck@3
|
31 % changeby = value, that the odd harmonics shall vary (degree or dB or whatever)
|
bleeck@3
|
32 % phases must be in degrees!
|
bleeck@3
|
33 % RETURN VALUE:
|
bleeck@3
|
34 % sig: @signal
|
bleeck@3
|
35 %
|
bleeck@3
|
36 % examples:
|
bleeck@3
|
37 % create a stimulus with certain filtercharacteristic with random
|
bleeck@3
|
38 % phase, and every second harmonic reduced by an amount
|
bleeck@3
|
39 % tone(i)=genharmonics(sig,'fundamental',chroma,...
|
bleeck@3
|
40 % 'filterprop',[toneheight,handles.df1,handles.bw,handles.df2],...
|
bleeck@3
|
41 % 'phase','random',...
|
bleeck@3
|
42 % 'type','decreaseoddamplitude',...
|
bleeck@3
|
43 % 'changeby',octheight...
|
bleeck@3
|
44 % );
|
bleeck@3
|
45 %
|
bleeck@3
|
46 %
|
bleeck@3
|
47 %
|
bleeck@3
|
48 % create a signal with a mistuned harmonic
|
bleeck@3
|
49 % s=signal(0.1,16000);
|
bleeck@3
|
50 % clear p
|
bleeck@3
|
51 % p{1}='fundamental';
|
bleeck@3
|
52 % p{2}=100;
|
bleeck@3
|
53 % p{3}='type';
|
bleeck@3
|
54 % p{4}='mistunedharmonic';
|
bleeck@3
|
55 % p{5}='changeby';
|
bleeck@3
|
56 % p{6}=10;
|
bleeck@3
|
57 % p{7}='min_fre';
|
bleeck@3
|
58 % p{8}=500;
|
bleeck@3
|
59 % p{9}='max_fre';
|
bleeck@3
|
60 % p{10}=2000;
|
bleeck@3
|
61 % p{11}='harmonicnumber';
|
bleeck@3
|
62 % p{12}='12';
|
bleeck@3
|
63 % s=genharmonics(s,p{1},p{2},p{3},p{4},p{5},p{6},p{7},p{8},p{9},p{10},p{11},p{12})
|
bleeck@3
|
64
|
bleeck@3
|
65 % create a harmonic signal with lots of harmonics
|
bleeck@3
|
66 % s=signal(0.1,16000);
|
bleeck@3
|
67 % clear p
|
bleeck@3
|
68 % p{1}='fundamental';
|
bleeck@3
|
69 % p{2}=250;
|
bleeck@3
|
70 % p{3}='min_fre';
|
bleeck@3
|
71 % p{4}=499;
|
bleeck@3
|
72 % p{5}='max_fre';
|
bleeck@3
|
73 % p{6}=5001;
|
bleeck@3
|
74 % s=genharmonics(s,p{1},p{2},p{3},p{4},p{5},p{6})
|
bleeck@3
|
75 %
|
bleeck@3
|
76
|
bleeck@3
|
77
|
bleeck@3
|
78
|
bleeck@3
|
79 % This external file is included as part of the 'aim-mat' distribution package
|
bleeck@3
|
80 % (c) 2011, University of Southampton
|
bleeck@3
|
81 % Maintained by Stefan Bleeck (bleeck@gmail.com)
|
bleeck@3
|
82 % download of current version is on the soundsoftware site:
|
bleeck@3
|
83 % http://code.soundsoftware.ac.uk/projects/aimmat
|
bleeck@3
|
84 % documentation and everything is on http://www.acousticscale.org
|
bleeck@3
|
85
|
bleeck@3
|
86 function sig=genharmonics(sig,varargin)
|
bleeck@3
|
87
|
bleeck@3
|
88 if mod(nargin,2)==0
|
bleeck@3
|
89 disp('odd number of parameters - please input a full set of parameters and arguments');
|
bleeck@3
|
90 return;
|
bleeck@3
|
91 end
|
bleeck@3
|
92 str_fundamental=getargument(varargin ,'fundamental');
|
bleeck@3
|
93 str_type=getargument(varargin,'type');
|
bleeck@3
|
94 str_harmnr=getargument(varargin,'harmonicnumber');
|
bleeck@3
|
95 str_changeby=getargument(varargin,'changeby');
|
bleeck@3
|
96 str_filterprop=getargument(varargin,'filterprop');
|
bleeck@3
|
97 str_fc=getargument(varargin,'fc');
|
bleeck@3
|
98 str_lowslope=getargument(varargin,'lowslope');
|
bleeck@3
|
99 str_highslope=getargument(varargin,'highslope');
|
bleeck@3
|
100 str_lowestharmonic=getargument(varargin,'lowestharmonic');
|
bleeck@3
|
101 str_highestharmonic=getargument(varargin,'highestharmonic');
|
bleeck@3
|
102 str_bw=getargument(varargin,'bw');
|
bleeck@3
|
103 str_phase=getargument(varargin,'phase');
|
bleeck@3
|
104 str_min_fre=getargument(varargin,'min_fre');
|
bleeck@3
|
105 str_max_fre=getargument(varargin,'max_fre');
|
bleeck@3
|
106
|
bleeck@3
|
107 str_which_harmonics=getargument(varargin,'which harmonics');
|
bleeck@3
|
108
|
bleeck@3
|
109 % defaultvalues:
|
bleeck@3
|
110 if strcmp(str_filterprop,'') && isempty(str_max_fre{1})
|
bleeck@3
|
111 if strcmp(str_changeby,'')
|
bleeck@3
|
112 str_filterprop{1}=[256,256,1024,512];
|
bleeck@3
|
113 fc=256;
|
bleeck@3
|
114 df1=256;
|
bleeck@3
|
115 bandwidth=1024;
|
bleeck@3
|
116 df2=512;
|
bleeck@3
|
117 else
|
bleeck@3
|
118 min_fre=str_min_fre{1};
|
bleeck@3
|
119 max_fre=str_max_fre{1};
|
bleeck@3
|
120 df1=1;
|
bleeck@3
|
121 df2=1;
|
bleeck@3
|
122 fc=min_fre;
|
bleeck@3
|
123 bandwidth=max_fre-min_fre;
|
bleeck@3
|
124 end
|
bleeck@3
|
125 elseif isempty(str_max_fre{1})
|
bleeck@3
|
126 %eval(sprintf('filterprop=%s;',str_filterprop{1}));
|
bleeck@3
|
127 fc=str_filterprop{1}(1);
|
bleeck@3
|
128 df1=str_filterprop{1}(2);
|
bleeck@3
|
129 bandwidth=str_filterprop{1}(3);
|
bleeck@3
|
130 df2=str_filterprop{1}(4);
|
bleeck@3
|
131 end
|
bleeck@3
|
132 if strcmp(str_changeby,'')
|
bleeck@3
|
133 else
|
bleeck@3
|
134 if isnumeric(str_changeby{1})
|
bleeck@3
|
135 changeby=str_changeby{1};
|
bleeck@3
|
136 else
|
bleeck@3
|
137 eval(sprintf('changeby=%f;',str_changeby{1}));
|
bleeck@3
|
138 end
|
bleeck@3
|
139 end
|
bleeck@3
|
140
|
bleeck@3
|
141 % different method of defining envelope: center frequency is the
|
bleeck@3
|
142 % highest point, highslope and lowslope define the amplitude on both
|
bleeck@3
|
143 % sides for each harmonic
|
bleeck@3
|
144 if ~strcmp(str_lowslope,'') && ~strcmp(str_highslope,'')
|
bleeck@3
|
145 lowslope=str_lowslope{1};
|
bleeck@3
|
146 highslope=str_highslope{1};
|
bleeck@3
|
147 calculate_amplitude_with_slopes=1;
|
bleeck@3
|
148
|
bleeck@3
|
149 % test with
|
bleeck@3
|
150 % plot(powerspectrum(genharmonics(signal(0.1,16000),'fc',2000,'lowslope',30,'highslope',40,'fundamental',250)))
|
bleeck@3
|
151 else
|
bleeck@3
|
152 calculate_amplitude_with_slopes=0;
|
bleeck@3
|
153 end
|
bleeck@3
|
154
|
bleeck@3
|
155 if strcmp(str_type,'')
|
bleeck@3
|
156 str_type{1}='';
|
bleeck@3
|
157 type='';
|
bleeck@3
|
158 else
|
bleeck@3
|
159 type=str_type{1};
|
bleeck@3
|
160 end
|
bleeck@3
|
161
|
bleeck@3
|
162 if strcmp(str_phase,'')
|
bleeck@3
|
163 setphase='cosine';
|
bleeck@3
|
164 else
|
bleeck@3
|
165 setphase=str_phase{1};
|
bleeck@3
|
166 end
|
bleeck@3
|
167
|
bleeck@3
|
168 if strcmp(str_fundamental,'')
|
bleeck@3
|
169 str_fundamental{1}='128';
|
bleeck@3
|
170 fundamental=128;
|
bleeck@3
|
171 else
|
bleeck@3
|
172 if isnumeric(str_fundamental{1})
|
bleeck@3
|
173 fundamental=str_fundamental{1};
|
bleeck@3
|
174 else
|
bleeck@3
|
175 eval(sprintf('fundamental=%s;',str_fundamental{1}));
|
bleeck@3
|
176 end
|
bleeck@3
|
177 end
|
bleeck@3
|
178
|
bleeck@3
|
179 if strcmp(str_lowestharmonic,'')
|
bleeck@3
|
180 lowestharmonic=1;
|
bleeck@3
|
181 else
|
bleeck@3
|
182 if isnumeric(str_lowestharmonic{1})
|
bleeck@3
|
183 lowestharmonic=str_lowestharmonic{1};
|
bleeck@3
|
184 else
|
bleeck@3
|
185 eval(sprintf('lowestharmonic=%s;',lowestharmonic{1}));
|
bleeck@3
|
186 end
|
bleeck@3
|
187 end
|
bleeck@3
|
188 if strcmp(str_highestharmonic,'')
|
bleeck@3
|
189 highestharmonic=inf;
|
bleeck@3
|
190 else
|
bleeck@3
|
191 if isnumeric(str_highestharmonic{1})
|
bleeck@3
|
192 highestharmonic=str_highestharmonic{1};
|
bleeck@3
|
193 else
|
bleeck@3
|
194 eval(sprintf('highestharmonic=%s;',highestharmonic{1}));
|
bleeck@3
|
195 end
|
bleeck@3
|
196 end
|
bleeck@3
|
197
|
bleeck@3
|
198 if strcmp(str_fc{1},'')
|
bleeck@3
|
199 else
|
bleeck@3
|
200 if isnumeric(str_fc{1})
|
bleeck@3
|
201 fc=str_fc{1};
|
bleeck@3
|
202 else
|
bleeck@3
|
203 eval(sprintf('fc=%s;',str_fc{1}));
|
bleeck@3
|
204 end
|
bleeck@3
|
205 end
|
bleeck@3
|
206
|
bleeck@3
|
207 if strcmp(str_bw{1},'')
|
bleeck@3
|
208 else
|
bleeck@3
|
209 if isnumeric(str_bw{1})
|
bleeck@3
|
210 bandwidth=str_bw{1};
|
bleeck@3
|
211 else
|
bleeck@3
|
212 eval(sprintf('bandwidth=%s;',str_bw{1}));
|
bleeck@3
|
213 end
|
bleeck@3
|
214 end
|
bleeck@3
|
215
|
bleeck@3
|
216 if strcmp(str_which_harmonics,'')
|
bleeck@3
|
217 str_which_harmonics{1}='all';
|
bleeck@3
|
218 end
|
bleeck@3
|
219
|
bleeck@3
|
220 samplerate=sig.samplerate;
|
bleeck@3
|
221 length=getlength(sig);
|
bleeck@3
|
222
|
bleeck@3
|
223
|
bleeck@3
|
224 % begin!
|
bleeck@3
|
225
|
bleeck@3
|
226 % if isempty(str_max_fre)
|
bleeck@3
|
227 if isempty(str_max_fre{1})
|
bleeck@3
|
228 max_fre=fc+bandwidth+df2;
|
bleeck@3
|
229 min_fre=fc-df1;
|
bleeck@3
|
230 else
|
bleeck@3
|
231 min_fre=str_min_fre{1};
|
bleeck@3
|
232 max_fre=str_max_fre{1};
|
bleeck@3
|
233 end
|
bleeck@3
|
234
|
bleeck@3
|
235 if (min_fre<0) %squeese df1 to go from 0 to fc
|
bleeck@3
|
236 df1=df1-abs(min_fre);
|
bleeck@3
|
237 % disp('df1 was reduced')
|
bleeck@3
|
238 end
|
bleeck@3
|
239
|
bleeck@3
|
240 if fundamental > max_fre
|
bleeck@3
|
241 disp('error: genharmonics: fundamental must be smaller then highest frequency');
|
bleeck@3
|
242 return;
|
bleeck@3
|
243 end
|
bleeck@3
|
244
|
bleeck@3
|
245 s=signal(length,samplerate);
|
bleeck@3
|
246 if max_fre>1000
|
bleeck@3
|
247 s=setname(s,sprintf('Harmonic Signal - f0=%4.1f Hz, type: %s (from %2.2f kHz to %2.2f kHz)',fundamental,type,min_fre/1000,max_fre/1000));
|
bleeck@3
|
248 else
|
bleeck@3
|
249 s=setname(s,sprintf('Harmonic Signal - f0=%4.1f Hz, type: %s (from %3.0 Hz to %3.0f Hz)',fundamental,type,min_fre,max_fre));
|
bleeck@3
|
250 end
|
bleeck@3
|
251
|
bleeck@3
|
252 if calculate_amplitude_with_slopes
|
bleeck@3
|
253 s=setname(s,sprintf('Harmonic Signal - modfre=%4.1f Hz, type: %s (cf: %2.2f kHz, low slope: %3.0f dB/oct, high slope %3.0f dB/oct)',fundamental,type,fc/1000,lowslope,highslope));
|
bleeck@3
|
254 end
|
bleeck@3
|
255
|
bleeck@3
|
256 % in case of sloped amplitudes, we dont want a limit on harmonics
|
bleeck@3
|
257 if calculate_amplitude_with_slopes
|
bleeck@3
|
258 max_fre=getsr(sig)/2;
|
bleeck@3
|
259 min_fre=0;
|
bleeck@3
|
260 end
|
bleeck@3
|
261
|
bleeck@3
|
262 % if limit of harmonics is explicitly given
|
bleeck@3
|
263 if ~strcmp(str_highestharmonic,'')
|
bleeck@3
|
264 max_fre=highestharmonic*fundamental;
|
bleeck@3
|
265 end
|
bleeck@3
|
266 if ~strcmp(str_lowestharmonic,'')
|
bleeck@3
|
267 min_fre=lowestharmonic*fundamental;
|
bleeck@3
|
268 end
|
bleeck@3
|
269
|
bleeck@3
|
270 fre=fundamental;
|
bleeck@3
|
271 count_partials=1;
|
bleeck@3
|
272 while fre <= max_fre
|
bleeck@3
|
273 if fre >= min_fre
|
bleeck@3
|
274 temp=signal(length,samplerate);
|
bleeck@3
|
275 amplitude=1;
|
bleeck@3
|
276 phase=0;
|
bleeck@3
|
277 offset=0;
|
bleeck@3
|
278 if strcmp(type,'mistunedharmonic') % in %
|
bleeck@3
|
279 eval(sprintf('nr=%s;',str_harmnr{1}));
|
bleeck@3
|
280 if count_partials==nr
|
bleeck@3
|
281 offset=fundamental*changeby/100;
|
bleeck@3
|
282 amplitude=1;
|
bleeck@3
|
283 phase=0;
|
bleeck@3
|
284 end
|
bleeck@3
|
285 end
|
bleeck@3
|
286 if strcmp(type,'shiftallcomponents') % in Hz
|
bleeck@3
|
287 offset=changeby;
|
bleeck@3
|
288 amplitude=1;
|
bleeck@3
|
289 phase=0;
|
bleeck@3
|
290 end
|
bleeck@3
|
291 if strcmp(type,'decreaseoddphase')
|
bleeck@3
|
292 % phase must be given in degree!
|
bleeck@3
|
293 if mod(count_partials,2)==1
|
bleeck@3
|
294 amplitude=1;
|
bleeck@3
|
295 phase=changeby;
|
bleeck@3
|
296 end
|
bleeck@3
|
297 end
|
bleeck@3
|
298
|
bleeck@3
|
299 if strcmp(type,'decrease_amplitude_linear')
|
bleeck@3
|
300 % the amount must be given in changeby!
|
bleeck@3
|
301 amplitude=1*power(10,(-changeby*count_partials)/20);
|
bleeck@3
|
302 ampscale=1;
|
bleeck@3
|
303 elseif ~isempty(str_type{1})
|
bleeck@3
|
304 ampscale=filterbandamp(fre+offset,amplitude,fc,df1,bandwidth,df2);
|
bleeck@3
|
305 else
|
bleeck@3
|
306 ampscale=1;
|
bleeck@3
|
307 end
|
bleeck@3
|
308 amplitude=amplitude*ampscale;
|
bleeck@3
|
309
|
bleeck@3
|
310
|
bleeck@3
|
311 % stattdessen mit Slopes:
|
bleeck@3
|
312 if calculate_amplitude_with_slopes
|
bleeck@3
|
313 % calculate the distance from cf (in octaves)
|
bleeck@3
|
314 % and from this the attenuation
|
bleeck@3
|
315 % distance=log2(fre/fc);
|
bleeck@3
|
316 distance=fre/fc;
|
bleeck@3
|
317 % if distance >= 0
|
bleeck@3
|
318 if distance >= 1
|
bleeck@3
|
319 atten=distance*highslope;
|
bleeck@3
|
320 else
|
bleeck@3
|
321 atten=100;
|
bleeck@3
|
322 end
|
bleeck@3
|
323 amplitude=1*power(10,-atten/20);
|
bleeck@3
|
324 p=0;
|
bleeck@3
|
325 end
|
bleeck@3
|
326
|
bleeck@3
|
327 if strcmp(type,'decreaseoddamplitude')
|
bleeck@3
|
328 if mod(count_partials,2)==1
|
bleeck@3
|
329 amplitude=amplitude*power(10,changeby/20);
|
bleeck@3
|
330 end
|
bleeck@3
|
331 end
|
bleeck@3
|
332 if strcmp(type,'decreaseevenamplitude')
|
bleeck@3
|
333 if mod(count_partials,2)==0
|
bleeck@3
|
334 amplitude=amplitude*power(10,changeby/20);
|
bleeck@3
|
335 end
|
bleeck@3
|
336 end
|
bleeck@3
|
337
|
bleeck@3
|
338
|
bleeck@3
|
339 switch str_which_harmonics{1}
|
bleeck@3
|
340 case 'all'
|
bleeck@3
|
341 case 'only odd'
|
bleeck@3
|
342 if mod(count_partials,2)==0
|
bleeck@3
|
343 amplitude=0;
|
bleeck@3
|
344 end
|
bleeck@3
|
345 case 'only even'
|
bleeck@3
|
346 if mod(count_partials,2)==1
|
bleeck@3
|
347 amplitude=0;
|
bleeck@3
|
348 end
|
bleeck@3
|
349 end
|
bleeck@3
|
350
|
bleeck@3
|
351 % degree2rad
|
bleeck@3
|
352 switch setphase
|
bleeck@3
|
353 case 'random'
|
bleeck@3
|
354 piphase=rand(1)*2*pi+pi;
|
bleeck@3
|
355 case 'cosine'
|
bleeck@3
|
356 piphase=phase*(pi/180)+pi/2;
|
bleeck@3
|
357 case 'sine'
|
bleeck@3
|
358 piphase=phase*(pi/180);
|
bleeck@3
|
359
|
bleeck@3
|
360 end
|
bleeck@3
|
361 % disp(sprintf('fre: %3.2f amp:%2.1f',fre,amplitude*100));
|
bleeck@3
|
362 % amplitude
|
bleeck@3
|
363 % fre
|
bleeck@3
|
364 temp=generatesinus(temp,fre+offset,amplitude,piphase);
|
bleeck@3
|
365
|
bleeck@3
|
366 % add them up!
|
bleeck@3
|
367 s=s+temp;
|
bleeck@3
|
368 end
|
bleeck@3
|
369 fre=fre+fundamental;
|
bleeck@3
|
370 count_partials=count_partials+1;
|
bleeck@3
|
371 end
|
bleeck@3
|
372
|
bleeck@3
|
373 sig=s;
|