zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit ac9ca5fc289fe8c0a7edd0e10918bc32a32a18f0
parent 1f30a453df88c9a508bd54b0b9d06192a0c10ddc
Author: Paul <nop@nop-desktop.(none)>
Date:   Thu, 24 Sep 2009 23:06:17 +0300

Started to implement Bandwidth to the Reverb effect.

Diffstat:
MChangeLog | 6++++--
Msrc/Effects/Reverb.cpp | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/Effects/Reverb.h | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/UI/EffUI.fl | 42+++++++++++++++++++++++++-----------------
4 files changed, 318 insertions(+), 45 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -906,4 +906,6 @@ - bugfixes: Voice Amplitude Envelope and FM 24 Sep 2009 (Paul Nasca) - - Small enhancements and bugfixes to Unison -\ No newline at end of file + - Small enhancements and bugfixes to Unison + - Started to implement Bandwidth to the Reverb effect + +\ No newline at end of file diff --git a/src/Effects/Reverb.cpp b/src/Effects/Reverb.cpp @@ -25,11 +25,121 @@ /**\todo: EarlyReflections,Prdelay,Perbalance */ +ReverbBandwidth::ReverbBandwidth (int small_buffer_size_,int n_small_buffers_per_half_big_buffer_): + OverlapAdd (small_buffer_size_,n_small_buffers_per_half_big_buffer_){ + bandwidth=0.1; + fft=new FFTwrapper(big_buffer_size); + newFFTFREQS(&freqs,half_big_buffer_size); + srcfreq=new REALTYPE[half_big_buffer_size]; + destfreq=new REALTYPE[half_big_buffer_size]; + tmpfreq=new REALTYPE[half_big_buffer_size]; + window=new REALTYPE[big_buffer_size]; + ZERO(srcfreq,half_big_buffer_size); + ZERO(destfreq,half_big_buffer_size); + ZERO(tmpfreq,half_big_buffer_size); + + for (int i=0;i<big_buffer_size;i++) window[i]=0.5*(1.0-cos(2*M_PI*i/(big_buffer_size-1.0))); +}; + +ReverbBandwidth::~ReverbBandwidth(){ + delete fft; + deleteFFTFREQS(&freqs); + delete []srcfreq; + delete []destfreq; + delete []tmpfreq; + delete []window; +}; + +void ReverbBandwidth::do_process_big_buffer(){ + + for (int i=0;i<big_buffer_size;i++) big_buffer[i]*=window[i]; + + fft->smps2freqs(big_buffer,freqs); + for (int i=0;i<half_big_buffer_size;i++){ + srcfreq[i]=sqrt(freqs.c[i]*freqs.c[i]+freqs.s[i]*freqs.s[i])/half_big_buffer_size; + }; + + + //spread + do_spread(half_big_buffer_size,srcfreq,destfreq,bandwidth); + + unsigned int rand_seed=rand(); + REALTYPE inv_2p15_2pi=1.0/16384.0*M_PI; + freqs.c[0]=freqs.s[0]=0.0; + for (int i=1;i<half_big_buffer_size;i++) { + rand_seed=(rand_seed*1103515245+12345); + unsigned int rand=(rand_seed>>16)&0x7fff; + REALTYPE phase=rand*inv_2p15_2pi; + freqs.c[i]=destfreq[i]*cos(phase); + freqs.s[i]=destfreq[i]*sin(phase); + }; + + + fft->freqs2smps(freqs,big_buffer); + for (int i=0;i<big_buffer_size;i++) big_buffer[i]*=window[i]; +}; + +void ReverbBandwidth::do_spread(int nfreq,REALTYPE *freq1,REALTYPE *freq2,REALTYPE bandwidth){ + //convert to log spectrum + REALTYPE minfreq=20.0; + REALTYPE maxfreq=0.5*SAMPLE_RATE; + + REALTYPE log_minfreq=log(minfreq); + REALTYPE log_maxfreq=log(maxfreq); + + for (int i=0;i<nfreq;i++){ + REALTYPE freqx=i/(REALTYPE) nfreq; + REALTYPE x=exp(log_minfreq+freqx*(log_maxfreq-log_minfreq))/maxfreq*nfreq; + REALTYPE y=0.0; + int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1; + int x1=x0+1; if (x1>=nfreq) x1=nfreq-1; + REALTYPE xp=x-x0; + if (x<nfreq){ + y=freq1[x0]*(1.0-xp)+freq1[x1]*xp; + }; + tmpfreq[i]=y; + }; + + //increase the bandwidth of each harmonic (by smoothing the log spectrum) + int n=2; + REALTYPE a=1.0-pow(2.0,-bandwidth*bandwidth*10.0); + a=pow(a,8192.0/nfreq*n); + + for (int k=0;k<n;k++){ + tmpfreq[0]=0.0; + for (int i=1;i<nfreq;i++){ + tmpfreq[i]=tmpfreq[i-1]*a+tmpfreq[i]*(1.0-a); + }; + tmpfreq[nfreq-1]=0.0; + for (int i=nfreq-2;i>0;i--){ + tmpfreq[i]=tmpfreq[i+1]*a+tmpfreq[i]*(1.0-a); + }; + }; + + freq2[0]=0; + REALTYPE log_maxfreq_d_minfreq=log(maxfreq/minfreq); + for (int i=1;i<nfreq;i++){ + REALTYPE freqx=i/(REALTYPE) nfreq; + REALTYPE x=log((freqx*maxfreq)/minfreq)/log_maxfreq_d_minfreq*nfreq; + REALTYPE y=0.0; + if ((x>0.0)&&(x<nfreq)){ + int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1; + int x1=x0+1; if (x1>=nfreq) x1=nfreq-1; + REALTYPE xp=x-x0; + y=tmpfreq[x0]*(1.0-xp)+tmpfreq[x1]*xp; + }; + freq2[i]=y; + }; +}; + + Reverb::Reverb(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_) :Effect(insertion_,efxoutl_,efxoutr_,NULL,0) { inputbuf=new REALTYPE[SOUND_BUFFER_SIZE]; + bandwidth=NULL; + //defaults Pvolume=48; Ppan=64; @@ -43,6 +153,7 @@ Reverb::Reverb(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_) Plohidamp=80; Ptype=1; Proomsize=64; + Pbandwidth=30; roomsize=1.0; rs=1.0; @@ -80,6 +191,7 @@ Reverb::~Reverb() for (i=0;i<REV_COMBS*2;i++) delete [] comb[i]; delete [] inputbuf; + if (bandwidth) delete bandwidth; }; /* @@ -156,15 +268,19 @@ void Reverb::out(REALTYPE *smps_l, REALTYPE *smps_r) for (i=0;i<SOUND_BUFFER_SIZE;i++) { inputbuf[i]=(smps_l[i]+smps_r[i])/2.0; - //Initial delay r - if (idelay!=NULL) { - REALTYPE tmp=inputbuf[i]+idelay[idelayk]*idelayfb; - inputbuf[i]=idelay[idelayk]; - idelay[idelayk]=tmp; - idelayk++; - if (idelayk>=idelaylen) idelayk=0; - }; - }; + }; + if (idelay!=NULL) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + //Initial delay r + REALTYPE tmp=inputbuf[i]+idelay[idelayk]*idelayfb; + inputbuf[i]=idelay[idelayk]; + idelay[idelayk]=tmp; + idelayk++; + if (idelayk>=idelaylen) idelayk=0; + }; + }; + + if (bandwidth) bandwidth->process(inputbuf); if (lpf!=NULL) lpf->filterout(inputbuf); if (hpf!=NULL) hpf->filterout(inputbuf); @@ -288,17 +404,21 @@ void Reverb::setlpf(const unsigned char &Plpf) void Reverb::settype(unsigned char Ptype) { - const int NUM_TYPES=2; + const int NUM_TYPES=3; int combtunings[NUM_TYPES][REV_COMBS]={ //this is unused (for random) {0,0,0,0,0,0,0,0}, //Freeverb by Jezar at Dreampoint + {1116,1188,1277,1356,1422,1491,1557,1617}, + //Freeverb by Jezar at Dreampoint //duplicate {1116,1188,1277,1356,1422,1491,1557,1617} }; int aptunings[NUM_TYPES][REV_APS]={ //this is unused (for random) {0,0,0,0}, //Freeverb by Jezar at Dreampoint + {225,341,441,556}, + //Freeverb by Jezar at Dreampoint (duplicate) {225,341,441,556} }; @@ -335,6 +455,15 @@ void Reverb::settype(unsigned char Ptype) }; settime(Ptime); cleanup(); + if (bandwidth) delete bandwidth; + bandwidth=NULL; + if (Ptype==2){//bandwidth + +#warning sa calculez numarul optim de buffere + bandwidth=new ReverbBandwidth(SOUND_BUFFER_SIZE,32); + + + }; }; void Reverb::setroomsize(const unsigned char &Proomsize) @@ -348,37 +477,42 @@ void Reverb::setroomsize(const unsigned char &Proomsize) settype(Ptype); }; +void Reverb::setbandwidth(const unsigned char &Pbandwidth){ + this->Pbandwidth=Pbandwidth; + if (bandwidth) bandwidth->set_bandwidth(Pbandwidth/127.0); +}; + void Reverb::setpreset(unsigned char npreset) { - const int PRESET_SIZE=12; + const int PRESET_SIZE=13; const int NUM_PRESETS=13; unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ //Cathedral1 - {80,64,63,24,0,0,0,85,5,83,1,64}, + {80,64,63,24,0,0,0,85,5,83,1,64,0}, //Cathedral2 - {80,64,69,35,0,0,0,127,0,71,0,64}, + {80,64,69,35,0,0,0,127,0,71,0,64,0}, //Cathedral3 - {80,64,69,24,0,0,0,127,75,78,1,85}, + {80,64,69,24,0,0,0,127,75,78,1,85,0}, //Hall1 - {90,64,51,10,0,0,0,127,21,78,1,64}, + {90,64,51,10,0,0,0,127,21,78,1,64,0}, //Hall2 - {90,64,53,20,0,0,0,127,75,71,1,64}, + {90,64,53,20,0,0,0,127,75,71,1,64,0}, //Room1 - {100,64,33,0,0,0,0,127,0,106,0,30}, + {100,64,33,0,0,0,0,127,0,106,0,30,0}, //Room2 - {100,64,21,26,0,0,0,62,0,77,1,45}, + {100,64,21,26,0,0,0,62,0,77,1,45,0}, //Basement - {110,64,14,0,0,0,0,127,5,71,0,25}, + {110,64,14,0,0,0,0,127,5,71,0,25,0}, //Tunnel - {85,80,84,20,42,0,0,51,0,78,1,105}, + {85,80,84,20,42,0,0,51,0,78,1,105,0}, //Echoed1 - {95,64,26,60,71,0,0,114,0,64,1,64}, + {95,64,26,60,71,0,0,114,0,64,1,64,0}, //Echoed2 - {90,64,40,88,71,0,0,114,0,88,1,64}, + {90,64,40,88,71,0,0,114,0,88,1,64,0}, //VeryLong1 - {90,64,93,15,0,0,0,114,0,77,0,95}, + {90,64,93,15,0,0,0,114,0,77,0,95,0}, //VeryLong2 - {90,64,111,30,0,0,0,114,90,74,1,80} + {90,64,111,30,0,0,0,114,90,74,1,80,0} }; if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; @@ -425,6 +559,9 @@ void Reverb::changepar(const int &npar,const unsigned char &value) case 11: setroomsize(value); break; + case 12: + setbandwidth(value); + break; }; }; @@ -465,6 +602,9 @@ unsigned char Reverb::getpar(const int &npar)const case 11: return(Proomsize); break; + case 12: + return(Pbandwidth); + break; }; return(0);//in case of bogus "parameter" }; diff --git a/src/Effects/Reverb.h b/src/Effects/Reverb.h @@ -2,7 +2,7 @@ ZynAddSubFX - a software synthesizer Reverb.h - Reverberation effect - Copyright (C) 2002-2005 Nasca Octavian Paul + Copyright (C) 2002-2009 Nasca Octavian Paul Author: Nasca Octavian Paul This program is free software; you can redistribute it and/or modify @@ -23,15 +23,133 @@ #ifndef REVERB_H #define REVERB_H - +#include <math.h> #include "../globals.h" #include "../DSP/AnalogFilter.h" +#include "../DSP/FFTwrapper.h" #include "Effect.h" #define REV_COMBS 8 #define REV_APS 4 /**Creates Reverberation Effects*/ + +class OverlapAdd{//50% overlap + public: + OverlapAdd(int small_buffer_size_,int n_small_buffers_per_half_big_buffer_){ + small_buffer_size=small_buffer_size_; + n_small_buffers_per_half_big_buffer=n_small_buffers_per_half_big_buffer_; + half_big_buffer_size=small_buffer_size*n_small_buffers_per_half_big_buffer; + big_buffer_size=half_big_buffer_size*2; + + new_half_big_buffer_input=new REALTYPE[half_big_buffer_size]; + old_half_big_buffer_input=new REALTYPE[half_big_buffer_size]; + new_half_big_buffer_processed=new REALTYPE[half_big_buffer_size]; + half_big_buffer_output=new REALTYPE[half_big_buffer_size]; + big_buffer=new REALTYPE[big_buffer_size]; + for (int i=0;i<half_big_buffer_size;i++){ + new_half_big_buffer_input[i]=0.0; + old_half_big_buffer_input[i]=0.0; + new_half_big_buffer_processed[i]=0.0; + half_big_buffer_output[i]=0.0; + }; + for (int i=0;i<big_buffer_size;i++){ + big_buffer[i]=0.0; + }; + small_buffer_k=0; + }; + virtual ~OverlapAdd(){ + delete []new_half_big_buffer_input; + delete []old_half_big_buffer_input; + delete []new_half_big_buffer_processed; + delete []half_big_buffer_output; + delete []big_buffer; + }; + + + void process(REALTYPE *small_buffer){ + + int input_start_pos=small_buffer_size*small_buffer_k; + + for (int i=0;i<small_buffer_size;i++){ + new_half_big_buffer_input[input_start_pos+i]=small_buffer[i]; + }; + small_buffer_k++; + if (small_buffer_k>=n_small_buffers_per_half_big_buffer){ + small_buffer_k=0; + process_big_buffer(); + }; + + int output_start_pos=small_buffer_size*small_buffer_k; //check if this is correct + + for (int i=0;i<small_buffer_size;i++){ + small_buffer[i]=half_big_buffer_output[output_start_pos+i]; + }; + + + }; + protected: + int half_big_buffer_size; + int big_buffer_size; + REALTYPE *big_buffer; + + virtual void do_process_big_buffer(){//the resulting buffer must be windowed + for (int i=0;i<big_buffer_size;i++){ + big_buffer[i]*=(1.0-cos(i*M_PI*2.0/big_buffer_size))*0.5; +// big_buffer[i]*=0.5; + }; +// printf("BIG_BUFFER:\n"); for (int i=0;i<big_buffer_size;i++) printf(" %g ",big_buffer[i]); printf("\n\n"); + }; + private: + void process_big_buffer(){ + for (int i=0;i<half_big_buffer_size;i++){ + big_buffer[i]=old_half_big_buffer_input[i]; + big_buffer[i+half_big_buffer_size]=new_half_big_buffer_input[i]; + }; + + do_process_big_buffer();//process input buffer and get windowed buffer + + for (int i=0;i<half_big_buffer_size;i++){ + old_half_big_buffer_input[i]=new_half_big_buffer_input[i]; + }; + +// printf("OUT1:\n"); for (int i=0;i<half_big_buffer_size;i++) printf(" %g,%g ",big_buffer[i],new_half_big_buffer_processed[i]); printf("\n\n"); + for (int i=0;i<half_big_buffer_size;i++){ + half_big_buffer_output[i]=big_buffer[i]+new_half_big_buffer_processed[i]; + new_half_big_buffer_processed[i]=big_buffer[i+half_big_buffer_size]; + }; + + }; + + int small_buffer_size; + int n_small_buffers_per_half_big_buffer; + int small_buffer_k; + + REALTYPE *old_half_big_buffer_input,*new_half_big_buffer_input; + REALTYPE *new_half_big_buffer_processed; + + REALTYPE *half_big_buffer_output; +}; + +class ReverbBandwidth: public OverlapAdd{ + public: + ReverbBandwidth (int small_buffer_size_,int n_small_buffers_per_half_big_buffer_); + ~ReverbBandwidth(); + void do_spread(int nfreq,REALTYPE *freq1,REALTYPE *freq2, REALTYPE bandwidth); + void set_bandwidth(REALTYPE par){ + if (par<0.0) par=0.0; + if (par>1.0) par=1.0; + bandwidth=par; + }; + private: + void do_process_big_buffer(); + FFTwrapper *fft; + FFTFREQS freqs; + REALTYPE *srcfreq,*destfreq,*tmpfreq; + REALTYPE *window; + REALTYPE bandwidth; +}; + class Reverb:public Effect { public: @@ -83,6 +201,9 @@ private: /**Room Size*/ unsigned char Proomsize; + /**Bandwidth */ + unsigned char Pbandwidth; + //parameter control void setvolume(const unsigned char &Pvolume); void setpan(const unsigned char &Ppan); @@ -94,6 +215,7 @@ private: void setlpf(const unsigned char &Plpf); void settype( unsigned char Ptype); void setroomsize(const unsigned char &Proomsize); + void setbandwidth(const unsigned char &Pbandwidth); REALTYPE pan,erbalance; //Parametrii 2 @@ -103,6 +225,7 @@ private: REALTYPE lohifb,idelayfb,roomsize,rs;//rs is used to "normalise" the volume according to the roomsize int comblen[REV_COMBS*2]; int aplen[REV_APS*2]; + ReverbBandwidth *bandwidth; //Internal Variables diff --git a/src/UI/EffUI.fl b/src/UI/EffUI.fl @@ -1,5 +1,5 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0107 +version 1.0109 header_name {.h} code_name {.cc} decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {} @@ -36,7 +36,7 @@ decl {\#include "../Effects/EffectMgr.h"} {public decl {\#include "PresetsUI.h"} {public } -class EQGraph {selected : {public Fl_Box} +class EQGraph {: {public Fl_Box} } { Function {EQGraph(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { code {eff=NULL; @@ -155,7 +155,7 @@ return(log(freq/20.0)/log(1000.0));} {} decl {int maxdB;} {} } -class EffUI {: {public Fl_Group,public PresetsUI_} +class EffUI {open : {public Fl_Group,public PresetsUI_} } { Function {EffUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { code {eff=NULL; @@ -188,10 +188,11 @@ if (filterwindow!=NULL){ } } } - Function {make_reverb_window()} {} { - Fl_Window effreverbwindow { - xywh {343 337 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 hide - class Fl_Group + Function {make_reverb_window()} {open + } { + Fl_Window effreverbwindow {open + xywh {343 337 380 95} type Double box PLASTIC_UP_BOX color 221 labelfont 1 + class Fl_Group visible } { Fl_Text_Display {} { label {Reverb } @@ -259,8 +260,8 @@ refresh(eff);} } Fl_Choice revp10 { label Type - callback {eff->seteffectpar(10,(int) o->value());} - xywh {110 15 75 15} down_box BORDER_BOX color 14 labelfont 1 labelsize 10 align 5 textfont 1 textsize 10 textcolor 7 + callback {eff->seteffectpar(10,(int) o->value());} open + xywh {110 15 85 15} down_box BORDER_BOX color 14 labelfont 1 labelsize 10 align 5 textfont 1 textsize 10 textcolor 7 } { MenuItem {} { label Random @@ -270,6 +271,10 @@ refresh(eff);} label Freeverb xywh {30 30 100 20} labelfont 1 labelsize 10 labelcolor 7 } + MenuItem {} { + label Bandwidth + xywh {40 40 100 20} labelfont 1 labelsize 10 labelcolor 7 + } } Fl_Dial revp0 { label Vol @@ -301,10 +306,10 @@ refresh(eff);} tooltip {Initial Delay Feedback} xywh {155 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 maximum 127 class WidgetPDial } - Fl_Dial revp5 { - label {R.delay} - callback {eff->seteffectpar(5,(int) o->value());} - xywh {200 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 when 4 maximum 127 deactivate + Fl_Dial revp12 { + label bw + callback {eff->seteffectpar(12,(int) o->value());} + xywh {200 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 11 when 4 maximum 127 class WidgetPDial } Fl_Dial revp6 { @@ -337,7 +342,7 @@ refresh(eff);} if (Fl::event_button1()) x=(int)o->value(); else o->value(x); eff->seteffectpar(11,x);} - tooltip RoomSize xywh {190 10 25 25} box ROUND_UP_BOX labelfont 1 labelsize 8 align 8 minimum 1 maximum 127 step 1 + tooltip RoomSize xywh {200 10 25 25} box ROUND_UP_BOX labelfont 1 labelsize 8 align 8 minimum 1 maximum 127 step 1 class WidgetPDial } } @@ -1263,7 +1268,8 @@ effdynamicfilterwindow->position(px,py); refresh(eff);} {} } - Function {refresh(EffectMgr *eff_)} {} { + Function {refresh(EffectMgr *eff_)} {open + } { code {eff=eff_; this->hide(); @@ -1293,13 +1299,14 @@ switch(eff->geteffect()){ revp2->value(eff->geteffectpar(2)); revp3->value(eff->geteffectpar(3)); revp4->value(eff->geteffectpar(4)); - revp5->value(eff->geteffectpar(5)); + //revp5->value(eff->geteffectpar(5)); revp6->value(eff->geteffectpar(6)); revp7->value(eff->geteffectpar(7)); revp8->value(eff->geteffectpar(8)); revp9->value(eff->geteffectpar(9)); revp10->value(eff->geteffectpar(10)); revp11->value(eff->geteffectpar(11)); + revp12->value(eff->geteffectpar(12)); effreverbwindow->show(); break; @@ -1410,7 +1417,8 @@ switch(eff->geteffect()){ break; }; -this->show();} {} +this->show();} {selected + } } Function {refresh()} {} { code {refresh(eff);} {}