paulstretch_cpp

PaulStretch
Log | Files | Refs | LICENSE

ProcessedStretch.cpp (14228B)


      1 /*
      2   Copyright (C) 2009 Nasca Octavian Paul
      3   Author: Nasca Octavian Paul
      4 
      5   This program is free software; you can redistribute it and/or modify
      6   it under the terms of version 2 of the GNU General Public License 
      7   as published by the Free Software Foundation.
      8 
      9   This program is distributed in the hope that it will be useful,
     10   but WITHOUT ANY WARRANTY; without even the implied warranty of
     11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12   GNU General Public License (version 2) for more details.
     13 
     14   You should have received a copy of the GNU General Public License (version 2)
     15   along with this program; if not, write to the Free Software Foundation,
     16   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     17 */
     18 
     19 #include <math.h>
     20 #include <stdlib.h>
     21 #include <stdio.h>
     22 #include "ProcessedStretch.h"
     23 
     24 void ProcessParameters::add2XML(XMLwrapper *xml){
     25 
     26 	xml->addparbool("pitch_shift.enabled",pitch_shift.enabled);
     27 	xml->addparreal("pitch_shift.cents",pitch_shift.cents);
     28 
     29 	xml->addparbool("octave.enabled",octave.enabled);
     30 	xml->addparreal("octave.om2",octave.om2);
     31 	xml->addparreal("octave.om1",octave.om1);
     32 	xml->addparreal("octave.o0",octave.o0);
     33 	xml->addparreal("octave.o1",octave.o1);
     34 	xml->addparreal("octave.o15",octave.o15);
     35 	xml->addparreal("octave.o2",octave.o2);
     36 
     37 	xml->addparbool("freq_shift.enabled",freq_shift.enabled);
     38 	xml->addparreal("freq_shift.Hz",freq_shift.Hz);
     39 
     40 	xml->addparbool("compressor.enabled",compressor.enabled);
     41 	xml->addparreal("compressor.power",compressor.power);
     42 
     43 	xml->addparbool("filter.enabled",filter.enabled);
     44 	xml->addparbool("filter.stop",filter.stop);
     45 	xml->addparreal("filter.low",filter.low);
     46 	xml->addparreal("filter.high",filter.high);
     47 	xml->addparreal("filter.hdamp",filter.hdamp);
     48 
     49 	xml->addparbool("harmonics.enabled",harmonics.enabled);
     50 	xml->addparreal("harmonics.freq",harmonics.freq);
     51 	xml->addparreal("harmonics.bandwidth",harmonics.bandwidth);
     52 	xml->addpar("harmonic.nharmonics",harmonics.nharmonics);
     53 
     54 	xml->addparbool("harmonics.gauss",harmonics.gauss);
     55 
     56 	xml->addparbool("spread.enabled",spread.enabled);
     57 	xml->addparreal("spread.bandwidth",spread.bandwidth);
     58 	
     59 	xml->addparbool("tonal_vs_noise.enabled",tonal_vs_noise.enabled);
     60 	xml->addparreal("tonal_vs_noise.bandwidth",tonal_vs_noise.bandwidth);
     61 	xml->addparreal("tonal_vs_noise.preserve",tonal_vs_noise.preserve);
     62 
     63 	xml->beginbranch("FREE_FILTER");
     64 	free_filter.add2XML(xml);
     65 	xml->endbranch();
     66 
     67 	xml->beginbranch("STRETCH_MULTIPLIER");
     68 	stretch_multiplier.add2XML(xml);
     69 	xml->endbranch();
     70 
     71 };
     72 
     73 void ProcessParameters::getfromXML(XMLwrapper *xml){
     74 	pitch_shift.enabled=xml->getparbool("pitch_shift.enabled",pitch_shift.enabled);
     75 	pitch_shift.cents=xml->getparreal("pitch_shift.cents",pitch_shift.cents);
     76 
     77 	octave.enabled=xml->getparbool("octave.enabled",octave.enabled);
     78 	octave.om2=xml->getparreal("octave.om2",octave.om2);
     79 	octave.om1=xml->getparreal("octave.om1",octave.om1);
     80 	octave.o0=xml->getparreal("octave.o0",octave.o0);
     81 	octave.o1=xml->getparreal("octave.o1",octave.o1);
     82 	octave.o15=xml->getparreal("octave.o15",octave.o15);
     83 	octave.o2=xml->getparreal("octave.o2",octave.o2);
     84 
     85 	freq_shift.enabled=xml->getparbool("freq_shift.enabled",freq_shift.enabled);
     86 	freq_shift.Hz=xml->getparreal("freq_shift.Hz",freq_shift.Hz);
     87 
     88 	compressor.enabled=xml->getparbool("compressor.enabled",compressor.enabled);
     89 	compressor.power=xml->getparreal("compressor.power",compressor.power);
     90 
     91 	filter.enabled=xml->getparbool("filter.enabled",filter.enabled);
     92 	filter.stop=xml->getparbool("filter.stop",filter.stop);
     93 	filter.low=xml->getparreal("filter.low",filter.low);
     94 	filter.high=xml->getparreal("filter.high",filter.high);
     95 	filter.hdamp=xml->getparreal("filter.hdamp",filter.hdamp);
     96 
     97 	harmonics.enabled=xml->getparbool("harmonics.enabled",harmonics.enabled);
     98 	harmonics.freq=xml->getparreal("harmonics.freq",harmonics.freq);
     99 	harmonics.bandwidth=xml->getparreal("harmonics.bandwidth",harmonics.bandwidth);
    100 	harmonics.nharmonics=xml->getpar("harmonic.nharmonics",harmonics.nharmonics,1,100);
    101 
    102 	harmonics.gauss=xml->getparbool("harmonics.gauss",harmonics.gauss);
    103 
    104 	spread.enabled=xml->getparbool("spread.enabled",spread.enabled);
    105 	spread.bandwidth=xml->getparreal("spread.bandwidth",spread.bandwidth);
    106 	
    107 	tonal_vs_noise.enabled=xml->getparbool("tonal_vs_noise.enabled",tonal_vs_noise.enabled);
    108 	tonal_vs_noise.preserve=xml->getparreal("tonal_vs_noise.preserve",tonal_vs_noise.bandwidth);
    109 	tonal_vs_noise.bandwidth=xml->getparreal("tonal_vs_noise.bandwidth",tonal_vs_noise.bandwidth);
    110 
    111 
    112 	if (xml->enterbranch("FREE_FILTER")){
    113 		free_filter.getfromXML(xml);
    114 		xml->exitbranch();
    115 	};
    116 	if (xml->enterbranch("STRETCH_MULTIPLIER")){
    117 		stretch_multiplier.getfromXML(xml);
    118 		xml->exitbranch();
    119 	};
    120 };
    121 
    122 ProcessedStretch::ProcessedStretch(REALTYPE rap_,int in_bufsize_,FFTWindow w,bool bypass_,REALTYPE samplerate_,int stereo_mode_):Stretch(rap_,in_bufsize_,w,bypass_,samplerate_,stereo_mode_){
    123 	nfreq=bufsize;
    124 	infreq=new REALTYPE[nfreq];
    125 	sumfreq=new REALTYPE[nfreq];
    126 	tmpfreq1=new REALTYPE[nfreq];
    127 	tmpfreq2=new REALTYPE[nfreq];
    128 	//fbfreq=new REALTYPE[nfreq];
    129 	free_filter_freqs=new REALTYPE[nfreq];
    130 	for (int i=0;i<nfreq;i++) {
    131 		free_filter_freqs[i]=1.0;
    132 	//	fbfreq[i]=0.0;
    133 	};
    134 };
    135 ProcessedStretch::~ProcessedStretch(){
    136 	delete [] infreq;
    137 	delete [] sumfreq;
    138 	delete [] tmpfreq1;
    139 	delete [] tmpfreq2;
    140 	delete [] free_filter_freqs;
    141 //	delete [] fbfreq;
    142 };
    143 
    144 void ProcessedStretch::set_parameters(ProcessParameters *ppar){
    145 	pars=*ppar;
    146 	update_free_filter();
    147 };
    148 
    149 
    150 void ProcessedStretch::copy(REALTYPE *freq1,REALTYPE *freq2){
    151 	for (int i=0;i<nfreq;i++) freq2[i]=freq1[i];
    152 };
    153 
    154 void ProcessedStretch::add(REALTYPE *freq2,REALTYPE *freq1,REALTYPE a){
    155 	for (int i=0;i<nfreq;i++) freq2[i]+=freq1[i]*a;
    156 };
    157 
    158 void ProcessedStretch::mul(REALTYPE *freq1,REALTYPE a){
    159 	for (int i=0;i<nfreq;i++) freq1[i]*=a;
    160 };
    161 
    162 void ProcessedStretch::zero(REALTYPE *freq1){
    163 	for (int i=0;i<nfreq;i++) freq1[i]=0.0;
    164 };
    165 
    166 REALTYPE ProcessedStretch::get_stretch_multiplier(REALTYPE pos_percents){
    167 	REALTYPE result=1.0;
    168 	if (pars.stretch_multiplier.get_enabled()){
    169 		result*=pars.stretch_multiplier.get_value(pos_percents);
    170 	};
    171 	///REALTYPE transient=pars.get_transient(pos_percents);
    172 	///printf("\n%g\n",transient);
    173 	///REALTYPE threshold=0.05;
    174 	///REALTYPE power=1000.0;
    175 	///transient-=threshold;
    176 	///if (transient>0){
    177 	///	transient*=power*(1.0+power);
    178 	///	result/=(1.0+transient);
    179 	///};
    180 	///printf("tr=%g\n",result);
    181 	return result;
    182 };
    183 
    184 void ProcessedStretch::process_spectrum(REALTYPE *freq){
    185 	if (pars.harmonics.enabled) {
    186 		copy(freq,infreq);
    187 		do_harmonics(infreq,freq);
    188 	};
    189 
    190 	if (pars.tonal_vs_noise.enabled){
    191 		copy(freq,infreq);
    192 		do_tonal_vs_noise(infreq,freq);
    193 	};
    194 
    195 	if (pars.freq_shift.enabled) {
    196 		copy(freq,infreq);
    197 		do_freq_shift(infreq,freq);
    198 	};
    199 	if (pars.pitch_shift.enabled) {
    200 		copy(freq,infreq);
    201 		do_pitch_shift(infreq,freq,pow(2.0,pars.pitch_shift.cents/1200.0));
    202 	};
    203 	if (pars.octave.enabled){
    204 		copy(freq,infreq);
    205 		do_octave(infreq,freq);
    206 	};
    207 
    208 
    209 	if (pars.spread.enabled){
    210 		copy(freq,infreq);
    211 		do_spread(infreq,freq);
    212 	};
    213 
    214 
    215 	if (pars.filter.enabled){
    216 		copy(freq,infreq);
    217 		do_filter(infreq,freq);
    218 	};
    219 	
    220 	if (pars.free_filter.get_enabled()){
    221 		copy(freq,infreq);
    222 		do_free_filter(infreq,freq);
    223 	};
    224 
    225 	if (pars.compressor.enabled){
    226 		copy(freq,infreq);
    227 		do_compressor(infreq,freq);
    228 	};
    229 
    230 };
    231 
    232 //void ProcessedStretch::process_output(REALTYPE *smps,int nsmps){
    233 //};
    234 
    235 
    236 REALTYPE profile(REALTYPE fi, REALTYPE bwi){
    237 	REALTYPE x=fi/bwi;
    238 	x*=x;
    239 	if (x>14.71280603) return 0.0;
    240 	return exp(-x);///bwi;
    241 
    242 };
    243 
    244 void ProcessedStretch::do_harmonics(REALTYPE *freq1,REALTYPE *freq2){
    245 	REALTYPE freq=pars.harmonics.freq;
    246 	REALTYPE bandwidth=pars.harmonics.bandwidth;
    247 	int nharmonics=pars.harmonics.nharmonics;
    248 
    249 	if (freq<10.0) freq=10.0;
    250 
    251 	REALTYPE *amp=tmpfreq1;
    252 	for (int i=0;i<nfreq;i++) amp[i]=0.0;
    253 
    254 	for (int nh=1;nh<=nharmonics;nh++){//for each harmonic
    255 		REALTYPE bw_Hz;//bandwidth of the current harmonic measured in Hz
    256 		REALTYPE bwi;
    257 		REALTYPE fi;
    258 		REALTYPE f=nh*freq;
    259 
    260 		if (f>=samplerate/2) break;
    261 
    262 		bw_Hz=(pow(2.0,bandwidth/1200.0)-1.0)*f;
    263 		bwi=bw_Hz/(2.0*samplerate);
    264 		fi=f/samplerate;
    265 
    266 		REALTYPE sum=0.0;
    267 		REALTYPE max=0.0;
    268 		for (int i=1;i<nfreq;i++){//todo: optimize here
    269 			REALTYPE hprofile;
    270 			hprofile=profile((i/(REALTYPE)nfreq*0.5)-fi,bwi);
    271 			amp[i]+=hprofile;
    272 			if (max<hprofile) max=hprofile;
    273 			sum+=hprofile;
    274 		};
    275 	};
    276 
    277 	REALTYPE max=0.0;
    278 	for (int i=1;i<nfreq;i++){
    279 		if (amp[i]>max) max=amp[i];
    280 	};
    281 	if (max<1e-8) max=1e-8;
    282 
    283 	for (int i=1;i<nfreq;i++){
    284 		REALTYPE c,s;
    285 		REALTYPE a=amp[i]/max;
    286 		if (!pars.harmonics.gauss) a=(a<0.368?0.0:1.0);
    287 		freq2[i]=freq1[i]*a;
    288 	};
    289 
    290 };
    291 
    292 
    293 void ProcessedStretch::do_freq_shift(REALTYPE *freq1,REALTYPE *freq2){
    294 	zero(freq2);
    295 	int ifreq=(int)(pars.freq_shift.Hz/(samplerate*0.5)*nfreq);
    296 	for (int i=0;i<nfreq;i++){
    297 		int i2=ifreq+i;
    298 		if ((i2>0)&&(i2<nfreq)) freq2[i2]=freq1[i];
    299 	};
    300 };
    301 void ProcessedStretch::do_pitch_shift(REALTYPE *freq1,REALTYPE *freq2,REALTYPE rap){
    302 	zero(freq2);
    303 	if (rap<1.0){//down
    304 		for (int i=0;i<nfreq;i++){
    305 			int i2=(int)(i*rap);
    306 			if (i2>=nfreq) break;
    307 			freq2[i2]+=freq1[i];
    308 		};
    309 	};
    310 	if (rap>=1.0){//up
    311 		rap=1.0/rap;
    312 		for (int i=0;i<nfreq;i++){
    313 			freq2[i]=freq1[(int)(i*rap)];
    314 		};
    315 
    316 	};
    317 };
    318 void ProcessedStretch::do_octave(REALTYPE *freq1,REALTYPE *freq2){
    319 	zero(sumfreq);
    320 	if (pars.octave.om2>1e-3){
    321 		do_pitch_shift(freq1,tmpfreq1,0.25);
    322 		add(sumfreq,tmpfreq1,pars.octave.om2);
    323 	};
    324 	if (pars.octave.om1>1e-3){
    325 		do_pitch_shift(freq1,tmpfreq1,0.5);
    326 		add(sumfreq,tmpfreq1,pars.octave.om1);
    327 	};
    328 	if (pars.octave.o0>1e-3){
    329 		add(sumfreq,freq1,pars.octave.o0);
    330 	};
    331 	if (pars.octave.o1>1e-3){
    332 		do_pitch_shift(freq1,tmpfreq1,2.0);
    333 		add(sumfreq,tmpfreq1,pars.octave.o1);
    334 	};
    335 	if (pars.octave.o15>1e-3){
    336 		do_pitch_shift(freq1,tmpfreq1,3.0);
    337 		add(sumfreq,tmpfreq1,pars.octave.o15);
    338 	};
    339 	if (pars.octave.o2>1e-3){
    340 		do_pitch_shift(freq1,tmpfreq1,4.0);
    341 		add(sumfreq,tmpfreq1,pars.octave.o2);
    342 	};
    343 
    344 	REALTYPE sum=0.01+pars.octave.om2+pars.octave.om1+pars.octave.o0+pars.octave.o1+pars.octave.o15+pars.octave.o2;
    345 	if (sum<0.5) sum=0.5;
    346 	for (int i=0;i<nfreq;i++) freq2[i]=sumfreq[i]/sum;    
    347 };
    348 
    349 void ProcessedStretch::do_filter(REALTYPE *freq1,REALTYPE *freq2){
    350 	REALTYPE low=0,high=0;
    351 	if (pars.filter.low<pars.filter.high){//sort the low/high freqs
    352 		low=pars.filter.low;
    353 		high=pars.filter.high;
    354 	}else{
    355 		high=pars.filter.low;
    356 		low=pars.filter.high;
    357 	};
    358 	int ilow=(int) (low/samplerate*nfreq*2.0);
    359 	int ihigh=(int) (high/samplerate*nfreq*2.0);
    360 	REALTYPE dmp=1.0;
    361 	REALTYPE dmprap=1.0-pow(pars.filter.hdamp*0.5,4.0);
    362 	for (int i=0;i<nfreq;i++){
    363 		REALTYPE a=0.0;
    364 		if ((i>=ilow)&&(i<ihigh)) a=1.0;
    365 		if (pars.filter.stop) a=1.0-a;
    366 		freq2[i]=freq1[i]*a*dmp;
    367 		dmp*=dmprap+1e-8;
    368 	};
    369 };
    370 
    371 void ProcessedStretch::update_free_filter(){
    372 	pars.free_filter.update_curve();
    373 	if (pars.free_filter.get_enabled()) {
    374 		for (int i=0;i<nfreq;i++){
    375 			REALTYPE freq=(REALTYPE)i/(REALTYPE) nfreq*samplerate*0.5;
    376 			free_filter_freqs[i]=pars.free_filter.get_value(freq);
    377 		};
    378 	}else{
    379 		for (int i=0;i<nfreq;i++){
    380 			free_filter_freqs[i]=1.0;
    381 		};
    382 	};
    383 };
    384 void ProcessedStretch::do_free_filter(REALTYPE *freq1,REALTYPE *freq2){
    385 	for (int i=0;i<nfreq;i++){
    386 		freq2[i]=freq1[i]*free_filter_freqs[i];
    387 	};
    388 };
    389 
    390 void ProcessedStretch::do_spread(REALTYPE *freq1,REALTYPE *freq2){
    391 	spread(freq1,freq2,pars.spread.bandwidth);
    392 };
    393 
    394 void ProcessedStretch::spread(REALTYPE *freq1,REALTYPE *freq2,REALTYPE spread_bandwidth){
    395 	//convert to log spectrum
    396 	REALTYPE minfreq=20.0;
    397 	REALTYPE maxfreq=0.5*samplerate;
    398 
    399 	REALTYPE log_minfreq=log(minfreq);
    400 	REALTYPE log_maxfreq=log(maxfreq);
    401 		
    402 	for (int i=0;i<nfreq;i++){
    403 		REALTYPE freqx=i/(REALTYPE) nfreq;
    404 		REALTYPE x=exp(log_minfreq+freqx*(log_maxfreq-log_minfreq))/maxfreq*nfreq;
    405 		REALTYPE y=0.0;
    406 		int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1;
    407 		int x1=x0+1; if (x1>=nfreq) x1=nfreq-1;
    408 		REALTYPE xp=x-x0;
    409 		if (x<nfreq){
    410 			y=freq1[x0]*(1.0-xp)+freq1[x1]*xp;
    411 		};
    412 		tmpfreq1[i]=y;
    413 	};
    414 
    415 	//increase the bandwidth of each harmonic (by smoothing the log spectrum)
    416 	int n=2;
    417 	REALTYPE bandwidth=spread_bandwidth;
    418 	REALTYPE a=1.0-pow(2.0,-bandwidth*bandwidth*10.0);
    419 	a=pow(a,8192.0/nfreq*n);
    420 
    421 	for (int k=0;k<n;k++){                                                  
    422 		tmpfreq1[0]=0.0;
    423 		for (int i=1;i<nfreq;i++){                                       
    424 			tmpfreq1[i]=tmpfreq1[i-1]*a+tmpfreq1[i]*(1.0-a);
    425 		};                                                              
    426 		tmpfreq1[nfreq-1]=0.0;                                               
    427 		for (int i=nfreq-2;i>0;i--){                                     
    428 			tmpfreq1[i]=tmpfreq1[i+1]*a+tmpfreq1[i]*(1.0-a);                    
    429 		};                                                              
    430 	};                                                                      
    431 
    432 	freq2[0]=0;
    433 	REALTYPE log_maxfreq_d_minfreq=log(maxfreq/minfreq);
    434 	for (int i=1;i<nfreq;i++){
    435 		REALTYPE freqx=i/(REALTYPE) nfreq;
    436 		REALTYPE x=log((freqx*maxfreq)/minfreq)/log_maxfreq_d_minfreq*nfreq;
    437 		REALTYPE y=0.0;
    438 		if ((x>0.0)&&(x<nfreq)){
    439 			int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1;
    440 			int x1=x0+1; if (x1>=nfreq) x1=nfreq-1;
    441 			REALTYPE xp=x-x0;
    442 			y=tmpfreq1[x0]*(1.0-xp)+tmpfreq1[x1]*xp;
    443 		};
    444 		freq2[i]=y;
    445 	};
    446 
    447 
    448 };
    449 
    450 
    451 void ProcessedStretch::do_compressor(REALTYPE *freq1,REALTYPE *freq2){
    452 	REALTYPE rms=0.0;
    453 	for (int i=0;i<nfreq;i++) rms+=freq1[i]*freq1[i];
    454 	rms=sqrt(rms/nfreq)*0.1;
    455 	if (rms<1e-3) rms=1e-3;
    456 
    457 	REALTYPE rap=pow(rms,-pars.compressor.power);
    458 	for (int i=0;i<nfreq;i++) freq2[i]=freq1[i]*rap;
    459 };
    460 
    461 void ProcessedStretch::do_tonal_vs_noise(REALTYPE *freq1,REALTYPE *freq2){
    462 	spread(freq1,tmpfreq1,pars.tonal_vs_noise.bandwidth);
    463 
    464 	if (pars.tonal_vs_noise.preserve>=0.0){
    465 		REALTYPE mul=(pow(10.0,pars.tonal_vs_noise.preserve)-1.0);
    466 		for (int i=0;i<nfreq;i++) {
    467 			REALTYPE x=freq1[i];
    468 			REALTYPE smooth_x=tmpfreq1[i]+1e-6;
    469 
    470 			REALTYPE result=0.0;
    471 			result=x-smooth_x*mul;
    472 			if (result<0.0) result=0.0;
    473 			freq2[i]=result;
    474 		};
    475 	}else{
    476 		REALTYPE mul=(pow(5.0,1.0+pars.tonal_vs_noise.preserve)-1.0);
    477 		for (int i=0;i<nfreq;i++) {
    478 			REALTYPE x=freq1[i];
    479 			REALTYPE smooth_x=tmpfreq1[i]+1e-6;
    480 
    481 			REALTYPE result=0.0;
    482 			result=x-smooth_x*mul+0.1*mul;
    483 			if (result<0.0) result=x;
    484 			else result=0.0;
    485 
    486 			freq2[i]=result;
    487 		};
    488 	};
    489 
    490 };
    491