mirror of
https://github.com/LMMS/lmms.git
synced 2026-03-11 02:26:19 -04:00
Bandwidth effect on Reverb
(cherry picked from commit cefe2b53d04b1d5de3b51e0f977abcd5d8528619)
This commit is contained in:
@@ -934,3 +934,6 @@
|
||||
25 Sep 2009 (Mark McCurry)
|
||||
- Allowed for XMLwrapper to retrieve strings stored in mxml TEXT
|
||||
fields
|
||||
29 Sep 2009 (Paul Nasca)
|
||||
- Remove the old (FFT based) Bandwidth effect to Reverb and started rewrite it (based on multivoice chorus/unison effect)
|
||||
|
||||
@@ -4,6 +4,7 @@ set(zynaddsubfx_dsp_SRCS
|
||||
Filter.cpp
|
||||
FormantFilter.cpp
|
||||
SVFilter.cpp
|
||||
Unison.cpp
|
||||
)
|
||||
|
||||
add_library(zynaddsubfx_dsp STATIC
|
||||
|
||||
@@ -73,7 +73,7 @@ void Unison::update_parameters(){
|
||||
};
|
||||
|
||||
#warning compute unison_amplitude_samples in functie de centi
|
||||
unison_amplitude_samples=20.0;
|
||||
unison_amplitude_samples=200.0;
|
||||
|
||||
if (unison_amplitude_samples>=max_delay-1) unison_amplitude_samples=max_delay-2;
|
||||
|
||||
@@ -96,7 +96,7 @@ void Unison::process(int bufsize,REALTYPE *inbuf,REALTYPE *outbuf){
|
||||
xpos+=xpos_step;
|
||||
REALTYPE in=inbuf[i],out=0.0;
|
||||
|
||||
|
||||
REALTYPE sign=1.0;
|
||||
for (int k=0;k<unison_size;k++){
|
||||
REALTYPE vpos=uv[k].realpos1*(1.0-xpos)+uv[k].realpos2*xpos;//optimize
|
||||
REALTYPE pos=delay_k+max_delay-vpos-1.0;//optimize
|
||||
@@ -105,7 +105,8 @@ void Unison::process(int bufsize,REALTYPE *inbuf,REALTYPE *outbuf){
|
||||
F2I(pos,posi);//optimize!
|
||||
if (posi>=max_delay) posi-=max_delay;
|
||||
posf=pos-floor(pos);
|
||||
out+=(1.0-posf)*delay_buffer[posi]+posf*delay_buffer[posi+1];
|
||||
out+=((1.0-posf)*delay_buffer[posi]+posf*delay_buffer[posi+1])*sign;
|
||||
sign=-sign;
|
||||
};
|
||||
outbuf[i]=out*volume;
|
||||
// printf("%d %g\n",i,outbuf[i]);
|
||||
@@ -129,8 +130,7 @@ void Unison::update_unison_data(){
|
||||
pos=1.0;
|
||||
step=-step;
|
||||
};
|
||||
//REALTYPE vibratto_val=pos-0.35*pos*pos*pos;//make the vibratto lfo smoother
|
||||
REALTYPE vibratto_val=(pos+1);
|
||||
REALTYPE vibratto_val=pos-0.35*pos*pos*pos;//make the vibratto lfo smoother
|
||||
REALTYPE newval=1.0+0.5*(vibratto_val+1.0)*unison_amplitude_samples;
|
||||
|
||||
if (first_time){
|
||||
@@ -146,21 +146,4 @@ void Unison::update_unison_data(){
|
||||
if (first_time) first_time=false;
|
||||
|
||||
};
|
||||
/*
|
||||
int main(){
|
||||
srand(time(NULL));
|
||||
Unison unison(10,0.2);
|
||||
//unison.set_base_frequency(1.0);
|
||||
|
||||
|
||||
int bufsize=100;
|
||||
REALTYPE in[bufsize],out[bufsize];
|
||||
ZERO_REALTYPE (in,bufsize);
|
||||
ZERO_REALTYPE (out,bufsize);
|
||||
in[20]=1;
|
||||
for (int i=0;i<100000;i++) unison.process(bufsize,in,out);
|
||||
for (int i=0;i<bufsize;i++) printf("%.3g ",out[i]);printf("\n");
|
||||
|
||||
return 1;
|
||||
};
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#ifndef UNISON_H
|
||||
#define UNISON_H
|
||||
#include <stdlib.h>
|
||||
#include "../globals.h"
|
||||
|
||||
|
||||
@@ -31,6 +32,8 @@ class Unison{
|
||||
|
||||
void set_size(int new_size);
|
||||
void set_base_frequency(REALTYPE freq);
|
||||
void set_bandwidth(REALTYPE bandwidth_cents){
|
||||
};
|
||||
|
||||
void process(int bufsize,REALTYPE *inbuf,REALTYPE *outbuf=NULL);
|
||||
|
||||
@@ -44,7 +47,7 @@ class Unison{
|
||||
REALTYPE step,position;//base LFO
|
||||
REALTYPE realpos1,realpos2; //the position regarding samples
|
||||
int lin_ipos,lin_ifreq;
|
||||
#error sa calculez frecventa si pozitia a.i. la inceput sa fie realpos1 si la final sa fie realpos2
|
||||
//#error sa calculez frecventa si pozitia a.i. la inceput sa fie realpos1 si la final sa fie realpos2
|
||||
REALTYPE lin_fpos,lin_ffreq;
|
||||
UnisonVoice(){
|
||||
position=RND*1.8-0.9;
|
||||
|
||||
@@ -25,114 +25,6 @@
|
||||
|
||||
/**\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)
|
||||
{
|
||||
@@ -269,6 +161,7 @@ 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;
|
||||
};
|
||||
|
||||
if (idelay!=NULL) {
|
||||
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
|
||||
//Initial delay r
|
||||
@@ -276,11 +169,13 @@ void Reverb::out(REALTYPE *smps_l, REALTYPE *smps_r)
|
||||
inputbuf[i]=idelay[idelayk];
|
||||
idelay[idelayk]=tmp;
|
||||
idelayk++;
|
||||
if (idelayk>=idelaylen) idelayk=0;
|
||||
if (idelayk>=idelaylen) {
|
||||
idelayk=0;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
if (bandwidth) bandwidth->process(inputbuf);
|
||||
if (bandwidth) bandwidth->process(SOUND_BUFFER_SIZE,inputbuf);
|
||||
|
||||
if (lpf!=NULL) lpf->filterout(inputbuf);
|
||||
if (hpf!=NULL) hpf->filterout(inputbuf);
|
||||
@@ -458,11 +353,10 @@ void Reverb::settype(unsigned char Ptype)
|
||||
if (bandwidth) delete bandwidth;
|
||||
bandwidth=NULL;
|
||||
if (Ptype==2){//bandwidth
|
||||
|
||||
#warning sa calculez numarul optim de buffere
|
||||
bandwidth=new ReverbBandwidth(SOUND_BUFFER_SIZE,32);
|
||||
|
||||
|
||||
bandwidth=new Unison(SOUND_BUFFER_SIZE/4+1,0.5);
|
||||
bandwidth->set_size(50);
|
||||
bandwidth->set_base_frequency(1.0);
|
||||
#warning sa schimb size-ul
|
||||
};
|
||||
};
|
||||
|
||||
@@ -479,7 +373,7 @@ void Reverb::setroomsize(const unsigned char &Proomsize)
|
||||
|
||||
void Reverb::setbandwidth(const unsigned char &Pbandwidth){
|
||||
this->Pbandwidth=Pbandwidth;
|
||||
if (bandwidth) bandwidth->set_bandwidth(Pbandwidth/127.0);
|
||||
if (bandwidth) bandwidth->set_bandwidth(Pbandwidth/127.0*200.0);
|
||||
};
|
||||
|
||||
void Reverb::setpreset(unsigned char npreset)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "../globals.h"
|
||||
#include "../DSP/AnalogFilter.h"
|
||||
#include "../DSP/FFTwrapper.h"
|
||||
#include "../DSP/Unison.h"
|
||||
#include "Effect.h"
|
||||
|
||||
#define REV_COMBS 8
|
||||
@@ -34,122 +35,6 @@
|
||||
|
||||
/**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:
|
||||
@@ -218,14 +103,14 @@ private:
|
||||
void setbandwidth(const unsigned char &Pbandwidth);
|
||||
|
||||
REALTYPE pan,erbalance;
|
||||
//Parametrii 2
|
||||
//Parameters
|
||||
int lohidamptype;/**<0=disable,1=highdamp(lowpass),2=lowdamp(highpass)*/
|
||||
int idelaylen,rdelaylen;
|
||||
int idelayk;
|
||||
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;
|
||||
Unison *bandwidth;
|
||||
|
||||
//Internal Variables
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ extern int OSCIL_SIZE;
|
||||
#define RND (rand()/(RAND_MAX+1.0))
|
||||
|
||||
#define ZERO(data,size) {char *data_=(char *) data;for (int i=0;i<size;i++) data_[i]=0;};
|
||||
#define ZERO_REALTYPE(data,size) {REALTYPE *data_=(REALTYPE *) data;for (int i=0;i<size;i++) data_[i]=0.0;};
|
||||
|
||||
enum ONOFFTYPE {OFF=0,ON=1};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user