zynaddsubfx

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

commit bb5bb4e36131198e25e9d80f1b18e859417d558d
parent b97d2037fd02e7b88b4047b857992fb80b2953f6
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Mon, 16 Jun 2014 15:10:23 -0400

Add Overtone Support to SUBsynth

Allow for non-harmonicly placed filters
Part of the Christopher Oliver patch set

Diffstat:
Msrc/Params/SUBnoteParameters.cpp | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Params/SUBnoteParameters.h | 9+++++++++
Msrc/Synth/SUBnote.cpp | 7++++---
Msrc/UI/SUBnoteUI.fl | 144++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
4 files changed, 202 insertions(+), 38 deletions(-)

diff --git a/src/Params/SUBnoteParameters.cpp b/src/Params/SUBnoteParameters.cpp @@ -23,6 +23,7 @@ #include "../globals.h" #include "SUBnoteParameters.h" #include <stdio.h> +#include <cmath> SUBnoteParameters::SUBnoteParameters():Presets() { @@ -63,6 +64,12 @@ void SUBnoteParameters::defaults() PFreqEnvelopeEnabled = 0; PBandWidthEnvelopeEnabled = 0; + POvertoneSpread.type = 0; + POvertoneSpread.par1 = 0; + POvertoneSpread.par2 = 0; + POvertoneSpread.par3 = 0; + updateFrequencyMultipliers(); + for(int n = 0; n < MAX_SUB_HARMONICS; ++n) { Phmag[n] = 0; Phrelbw[n] = 64; @@ -127,6 +134,10 @@ void SUBnoteParameters::add2XML(XMLwrapper *xml) xml->addpar("detune", PDetune); xml->addpar("coarse_detune", PCoarseDetune); + xml->addpar("overtone_spread_type", POvertoneSpread.type); + xml->addpar("overtone_spread_par1", POvertoneSpread.par1); + xml->addpar("overtone_spread_par2", POvertoneSpread.par2); + xml->addpar("overtone_spread_par3", POvertoneSpread.par3); xml->addpar("detune_type", PDetuneType); xml->addpar("bandwidth", Pbandwidth); @@ -166,6 +177,66 @@ void SUBnoteParameters::add2XML(XMLwrapper *xml) xml->endbranch(); } + + +void SUBnoteParameters::updateFrequencyMultipliers(void) { + float par1 = POvertoneSpread.par1 / 255.0f; + float par1pow = powf(10.0f, + -(1.0f - POvertoneSpread.par1 / 255.0f) * 3.0f); + float par2 = POvertoneSpread.par2 / 255.0f; + float par3 = 1.0f - POvertoneSpread.par3 / 255.0f; + float result; + float tmp = 0.0f; + int thresh = 0; + + for(int n = 0; n < MAX_SUB_HARMONICS; ++n) { + float n1 = n + 1.0f; + switch(POvertoneSpread.type) { + case 1: + thresh = (int)(100.0f * par2 * par2) + 1; + if (n1 < thresh) + result = n1; + else + result = n1 + 8.0f * (n1 - thresh) * par1pow; + break; + case 2: + thresh = (int)(100.0f * par2 * par2) + 1; + if (n1 < thresh) + result = n1; + else + result = n1 + 0.9f * (thresh - n1) * par1pow; + break; + case 3: + tmp = par1pow * 100.0f + 1.0f; + result = powf(n / tmp, 1.0f - 0.8f * par2) * tmp + 1.0f; + break; + case 4: + result = n * (1.0f - par1pow) + + powf(0.1f * n, 3.0f * par2 + 1.0f) * + 10.0f * par1pow + 1.0f; + break; + + case 5: + result = n1 + 2.0f * sinf(n * par2 * par2 * PI * 0.999f) * + sqrt(par1pow); + break; + case 6: + tmp = powf(2.0f * par2, 2.0f) + 0.1f; + result = n * powf(par1 * powf(0.8f * n, tmp) + 1.0f, tmp) + + 1.0f; + break; + + case 7: + result = (n1 + par1) / (par1 + 1); + break; + default: + result = n1; + } + float iresult = floor(result + 0.5f); + POvertoneFreqMult[n] = iresult + par3 * (result - iresult); + } +} + void SUBnoteParameters::getfromXML(XMLwrapper *xml) { Pnumstages = xml->getpar127("num_stages", Pnumstages); @@ -203,6 +274,15 @@ void SUBnoteParameters::getfromXML(XMLwrapper *xml) PDetune = xml->getpar("detune", PDetune, 0, 16383); PCoarseDetune = xml->getpar("coarse_detune", PCoarseDetune, 0, 16383); + POvertoneSpread.type = + xml->getpar127("overtone_spread_type", POvertoneSpread.type); + POvertoneSpread.par1 = + xml->getpar("overtone_spread_par1", POvertoneSpread.par1, 0, 255); + POvertoneSpread.par2 = + xml->getpar("overtone_spread_par2", POvertoneSpread.par2, 0, 255); + POvertoneSpread.par3 = + xml->getpar("overtone_spread_par3", POvertoneSpread.par3, 0, 255); + updateFrequencyMultipliers(); PDetuneType = xml->getpar127("detune_type", PDetuneType); Pbandwidth = xml->getpar127("bandwidth", Pbandwidth); diff --git a/src/Params/SUBnoteParameters.h b/src/Params/SUBnoteParameters.h @@ -38,6 +38,7 @@ class SUBnoteParameters:public Presets void add2XML(XMLwrapper *xml); void defaults(); void getfromXML(XMLwrapper *xml); + void updateFrequencyMultipliers(void); //Parameters //AMPLITUDE PARAMETRERS @@ -74,6 +75,14 @@ class SUBnoteParameters:public Presets if this parameter is 64, 1 MIDI halftone -> 1 frequency halftone */ unsigned char PfixedfreqET; + // Overtone spread parameters + struct { + unsigned char type; + unsigned char par1; + unsigned char par2; + unsigned char par3; + } POvertoneSpread; + float POvertoneFreqMult[MAX_SUB_HARMONICS]; //how many times the filters are applied unsigned char Pnumstages; diff --git a/src/Synth/SUBnote.cpp b/src/Synth/SUBnote.cpp @@ -101,12 +101,13 @@ void SUBnote::setup(float freq, GlobalFilterEnvelope = NULL; } - //select only harmonics that desire to compute int harmonics = 0; + + //select only harmonics that desire to compute for(int n = 0; n < MAX_SUB_HARMONICS; ++n) { if(pars->Phmag[n] == 0) continue; - if(n * basefreq > synth->samplerate_f / 2.0f) + if(basefreq * pars->POvertoneFreqMult[n] > synth->samplerate_f / 2.0f) break; //remove the freqs above the Nyquist freq pos[harmonics++] = n; } @@ -136,7 +137,7 @@ void SUBnote::setup(float freq, float reduceamp = 0.0f; for(int n = 0; n < numharmonics; ++n) { - float freq = basefreq * (pos[n] + 1); + float freq = basefreq * pars->POvertoneFreqMult[pos[n]]; //the bandwidth is not absolute(Hz); it is relative to frequency float bw = diff --git a/src/UI/SUBnoteUI.fl b/src/UI/SUBnoteUI.fl @@ -41,7 +41,7 @@ class SUBnoteharmonic {: {public Fl_Group} Function {make_window()} {private } { Fl_Window harmonic { - xywh {329 403 90 225} type Double hide + xywh {1257 22 90 305} type Double hide class Fl_Group } { Fl_Slider mag { @@ -51,7 +51,7 @@ if (Fl::event_button1() || Fl::event() == FL_MOUSEWHEEL) x=127-(int)o->value(); pars->Phmag[n]=x; if (pars->Phmag[n]==0) o->selection_color(0); else o->selection_color(222);} - tooltip {harmonic's magnitude} xywh {0 15 10 115} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 127 + tooltip {harmonic's magnitude} xywh {0 15 10 135} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 127 code0 {o->value(127-pars->Phmag[n]);} code1 {if (pars->Phmag[n]==0) o->selection_color(0);} } @@ -60,16 +60,16 @@ if (pars->Phmag[n]==0) o->selection_color(0); if (Fl::event_button1() || Fl::event() == FL_MOUSEWHEEL) x=127-(int)o->value(); else o->value(x); pars->Phrelbw[n]=x;} - tooltip {harmonic's bandwidth} xywh {0 135 10 75} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 64 + tooltip {harmonic's bandwidth} xywh {0 157 10 130} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 64 code0 {o->value(127-pars->Phrelbw[n]);} } Fl_Box {} { - xywh {10 170 5 5} box FLAT_BOX color 45 + xywh {10 219 5 5} box FLAT_BOX color 45 code0 {if (n+1==MAX_SUB_HARMONICS) o->hide();} } Fl_Box {} { label 01 - xywh {0 210 10 15} labelfont 1 labelsize 9 align 20 + xywh {0 288 10 15} labelfont 1 labelsize 9 align 20 code0 {char tmp[10];snprintf(tmp,10,"%d",n+1);o->label(strdup(tmp));} } Fl_Box {} { @@ -109,24 +109,24 @@ class SUBnoteUI {open : {public PresetsUI_} } { Fl_Window SUBparameters { label {SUBsynth Parameters} open - xywh {542 489 735 390} type Double visible + xywh {213 147 735 470} type Double visible } { Fl_Scroll {} { label scroll open - xywh {5 140 435 245} type HORIZONTAL box FLAT_BOX labeltype NO_LABEL + xywh {5 140 434 325} type HORIZONTAL box FLAT_BOX labeltype NO_LABEL } { - Fl_Pack harmonics {open - xywh {10 145 425 235} type HORIZONTAL + Fl_Pack harmonics { + xywh {5 145 430 325} type HORIZONTAL code0 {for (int i=0;i<MAX_SUB_HARMONICS;i++){h[i]=new SUBnoteharmonic(0,0,15,o->h(),"");h[i]->init(pars,i);}} } {} } Fl_Button {} { label Close callback {SUBparameters->hide();} - xywh {625 365 105 20} box THIN_UP_BOX labelfont 1 labelsize 11 + xywh {625 446 105 20} box THIN_UP_BOX labelfont 1 labelsize 11 } Fl_Group {} { - label AMPLITUDE + label AMPLITUDE open xywh {5 5 215 135} box UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 align 17 } { Fl_Value_Slider vol { @@ -156,18 +156,18 @@ class SUBnoteUI {open : {public PresetsUI_} } {} } Fl_Group {} { - xywh {495 325 235 35} box UP_FRAME + xywh {495 406 235 35} box UP_FRAME } { Fl_Counter filterstages { label {Filter Stages} callback {pars->Pnumstages=(int) o->value();} - tooltip {How many times the noise is filtered} xywh {515 340 45 15} type Simple labelfont 1 labelsize 10 align 1 minimum 1 maximum 5 step 1 textsize 10 + tooltip {How many times the noise is filtered} xywh {515 421 45 15} type Simple labelfont 1 labelsize 10 align 1 minimum 1 maximum 5 step 1 textsize 10 code0 {o->value(pars->Pnumstages);} } Fl_Choice magtype { label {Mag.Type} callback {pars->Phmagtype=(int) o->value();} - xywh {585 340 65 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 1 textsize 11 + xywh {585 421 65 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 1 textsize 11 code0 {o->value(pars->Phmagtype);} } { MenuItem {} { @@ -194,7 +194,7 @@ class SUBnoteUI {open : {public PresetsUI_} Fl_Choice start { label Start callback {pars->Pstart=(int) o->value();} open - xywh {670 340 50 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 1 textsize 11 + xywh {670 421 50 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 1 textsize 11 code0 {o->value(pars->Pstart);} } { MenuItem {} { @@ -212,12 +212,12 @@ class SUBnoteUI {open : {public PresetsUI_} } } Fl_Group freqsettingsui { - label FREQUENCY - xywh {440 5 290 135} box UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 align 17 + label FREQUENCY open + xywh {440 5 295 146} box UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 align 17 } { Fl_Group freqenvelopegroup { label {SUBsynth - Frequency Envelope} open - xywh {445 65 205 70} box FLAT_BOX color 51 align 144 + xywh {445 75 205 70} box FLAT_BOX color 51 align 144 code0 {o->init(pars->FreqEnvelope);} code1 {if (pars->PFreqEnvelopeEnabled==0) o->deactivate();} class EnvelopeUI @@ -229,7 +229,7 @@ if (o->value()==0) freqenvelopegroup->deactivate(); else freqenvelopegroup->activate(); o->show(); freqsettingsui->redraw();} - xywh {445 68 55 15} down_box DOWN_BOX labelfont 1 labelsize 10 + xywh {445 77 55 15} down_box DOWN_BOX labelfont 1 labelsize 10 code0 {o->value(pars->PFreqEnvelopeEnabled);} } Fl_Counter octave { @@ -238,7 +238,7 @@ freqsettingsui->redraw();} if (k<0) k+=16; pars->PCoarseDetune = k*1024+ pars->PCoarseDetune%1024;} - tooltip Octave xywh {670 50 45 15} type Simple labelsize 10 align 1 minimum -8 maximum 7 step 1 textfont 1 textsize 11 + tooltip Octave xywh {670 58 45 15} type Simple labelsize 10 align 1 minimum -8 maximum 7 step 1 textfont 1 textsize 11 code0 {int k=pars->PCoarseDetune/1024;if (k>=8) k-=16;} code2 {o->value(k);} } @@ -248,7 +248,7 @@ pars->PCoarseDetune = k*1024+ if (k<0) k+=1024; pars->PCoarseDetune = k+ (pars->PCoarseDetune/1024)*1024;} - tooltip {Coarse Detune} xywh {655 115 60 20} labelsize 10 align 1 minimum -64 maximum 63 step 1 textfont 1 textsize 11 + tooltip {Coarse Detune} xywh {655 125 60 20} labelsize 10 align 1 minimum -64 maximum 63 step 1 textfont 1 textsize 11 code0 {int k=pars->PCoarseDetune%1024;if (k>=512) k-=1024;} code2 {o->value(k);} code3 {o->lstep(10);} @@ -256,13 +256,13 @@ pars->PCoarseDetune = k+ Fl_Slider detune { callback {pars->PDetune=(int)o->value()+8192; detunevalueoutput->do_callback();} - tooltip {Fine Detune (cents)} xywh {495 25 230 15} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 + tooltip {Fine Detune (cents)} xywh {495 27 230 15} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 code0 {o->value(pars->PDetune-8192);} } Fl_Value_Output detunevalueoutput { label Detune callback {o->value(getdetune(pars->PDetuneType,0,pars->PDetune));} - xywh {448 25 45 15} labelsize 10 align 5 minimum -5000 maximum 5000 step 0.01 textfont 1 textsize 10 + xywh {448 27 45 15} labelsize 10 align 5 minimum -5000 maximum 5000 step 0.01 textfont 1 textsize 10 code0 {o->value(getdetune(pars->PDetuneType,0,pars->PDetune));} } Fl_Check_Button hz440 { @@ -271,13 +271,13 @@ detunevalueoutput->do_callback();} pars->Pfixedfreq=x; if (x==0) fixedfreqetdial->deactivate(); else fixedfreqetdial->activate();} - tooltip {set the base frequency to 440Hz} xywh {555 45 50 15} down_box DOWN_BOX labelfont 1 labelsize 10 + tooltip {set the base frequency to 440Hz} xywh {555 53 50 15} down_box DOWN_BOX labelfont 1 labelsize 10 code0 {o->value(pars->Pfixedfreq);} } Fl_Dial fixedfreqetdial { label {Eq.T.} callback {pars->PfixedfreqET=(int) o->value();} - tooltip {How the frequency varies acording to the keyboard (leftmost for fixed frequency)} xywh {610 45 15 15} box ROUND_UP_BOX labelsize 10 align 8 maximum 127 step 1 + tooltip {How the frequency varies acording to the keyboard (leftmost for fixed frequency)} xywh {610 53 15 15} box ROUND_UP_BOX labelsize 10 align 8 maximum 127 step 1 code0 {o->value(pars->PfixedfreqET);} code1 {if (pars->Pfixedfreq==0) o->deactivate();} class WidgetPDial @@ -286,15 +286,15 @@ if (x==0) fixedfreqetdial->deactivate(); label {Detune Type} callback {pars->PDetuneType=(int) o->value()+1; detunevalueoutput->do_callback();} open - xywh {655 85 70 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10 + xywh {655 94 70 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10 code0 {o->add("L35cents");o->add("L10cents");o->add("E100cents");o->add("E1200cents");} code1 {o->value(pars->PDetuneType-1);} } {} } Fl_Check_Button stereo { label Stereo - callback {pars->Pstereo=(int) o->value();} selected - xywh {440 325 55 35} box THIN_UP_BOX down_box DOWN_BOX labelsize 10 + callback {pars->Pstereo=(int) o->value();} + xywh {440 406 55 35} box THIN_UP_BOX down_box DOWN_BOX labelsize 10 code0 {o->value(pars->Pstereo);} } Fl_Button {} { @@ -308,7 +308,7 @@ detunevalueoutput->do_callback();} open pars->Phmag[0]=127; h[0]->mag->value(0); SUBparameters->redraw();} - tooltip {Clear the harmonics} xywh {445 365 70 20} box THIN_UP_BOX labelfont 1 labelsize 11 + tooltip {Clear the harmonics} xywh {445 446 70 20} box THIN_UP_BOX labelfont 1 labelsize 11 } Fl_Group bandwidthsettingsui { label BANDWIDTH @@ -346,18 +346,18 @@ bandwidthsettingsui->redraw();} } Fl_Group globalfiltergroup { label FILTER - xywh {440 140 290 185} box UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 labelsize 13 align 17 + xywh {440 221 290 185} box UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 align 17 code0 {if (pars->PGlobalFilterEnabled==0) o->deactivate();} } { Fl_Group filterenv { label {SUBsynth - Filter Envelope} open - xywh {445 250 275 70} box FLAT_BOX color 51 align 144 + xywh {445 331 275 70} box FLAT_BOX color 51 align 144 code0 {o->init(pars->GlobalFilterEnvelope);} class EnvelopeUI } {} Fl_Group filterui { label {SUBsynthl - Filter} open - xywh {445 165 275 75} box FLAT_BOX color 50 align 144 + xywh {445 246 275 75} box FLAT_BOX color 50 align 144 code0 {o->init(pars->GlobalFilter,&pars->PGlobalFilterVelocityScale,&pars->PGlobalFilterVelocityScaleFunction);} class FilterUI } {} @@ -369,18 +369,87 @@ if (o->value()==0) globalfiltergroup->deactivate(); else globalfiltergroup->activate(); o->show(); globalfiltergroup->redraw();} - xywh {445 145 85 20} down_box DOWN_BOX labelfont 1 labelsize 11 + xywh {445 226 85 20} down_box DOWN_BOX labelfont 1 labelsize 11 code0 {o->value(pars->PGlobalFilterEnabled);} } Fl_Button {} { label C callback {presetsui->copy(pars);} - xywh {540 370 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7 + xywh {540 451 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7 } Fl_Button {} { label P callback {presetsui->paste(pars,this);} - xywh {570 370 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7 + xywh {570 451 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7 + } + Fl_Group {} { + label OVERTONES open + xywh {440 151 220 70} box UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 align 17 + } { + Fl_Choice spreadtype { + label OvertonesPosition + callback {pars->POvertoneSpread.type = (int)o->value(); +pars->updateFrequencyMultipliers();} open + xywh {450 190 80 20} down_box BORDER_BOX labelsize 10 align 5 textsize 10 + code0 {o->value(pars->POvertoneSpread.type);} + } { + MenuItem {} { + label Harmonic + xywh {0 0 34 20} labelfont 1 labelsize 11 + } + MenuItem {} { + label ShiftU + xywh {10 10 34 20} labelfont 1 labelsize 11 + } + MenuItem {} { + label ShiftL + xywh {20 20 34 20} labelfont 1 labelsize 11 + } + MenuItem {} { + label PowerU + xywh {20 20 34 20} labelfont 1 labelsize 11 + } + MenuItem {} { + label PowerL + xywh {30 30 34 20} labelfont 1 labelsize 11 + } + MenuItem {} { + label Sine + xywh {40 40 34 20} labelfont 1 labelsize 11 + } + MenuItem {} { + label Power + xywh {50 50 34 20} labelfont 1 labelsize 11 + } + MenuItem {} { + label Shift selected + xywh {20 20 34 20} labelfont 1 labelsize 11 + } + } + Fl_Dial spreadpar1 { + label Par1 + callback {pars->POvertoneSpread.par1 = o->value(); +pars->updateFrequencyMultipliers();} + xywh {548 173 30 30} box ROUND_UP_BOX labelsize 10 maximum 255 step 1 + code0 {o->value(pars->POvertoneSpread.par1);} + class WidgetPDial + } + Fl_Dial spreadpar2 { + label Par2 + callback {pars->POvertoneSpread.par2 = o->value(); +pars->updateFrequencyMultipliers();} + xywh {583 173 30 30} box ROUND_UP_BOX labelsize 10 maximum 255 step 1 + code0 {o->value(pars->POvertoneSpread.par2);} + class WidgetPDial + } + Fl_Dial spreadpar3 { + label ForceH + callback {pars->POvertoneSpread.par3 = o->value(); +pars->updateFrequencyMultipliers();} + xywh {618 173 30 30} box ROUND_UP_BOX labelsize 10 maximum 255 step 1 + code0 {o->value(pars->POvertoneSpread.par3);} + class WidgetPDial + } } } } @@ -400,6 +469,11 @@ bwee->show(); bandwidthsettingsui->redraw(); detunevalueoutput->value(getdetune(pars->PDetuneType,0,pars->PDetune)); +spreadtype->value(pars->POvertoneSpread.type); +spreadpar1->value(pars->POvertoneSpread.par1); +spreadpar2->value(pars->POvertoneSpread.par2); +spreadpar3->value(pars->POvertoneSpread.par3); + freqee->value(pars->PFreqEnvelopeEnabled); if (pars->PFreqEnvelopeEnabled==0) freqenvelopegroup->deactivate(); else freqenvelopegroup->activate();