zynaddsubfx

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

commit db383ede318baa8f10a1955ec9b959f7175ccf31
parent 6baafe64de55619ce701034da5937a17eb41a742
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Tue, 19 Feb 2013 11:30:57 -0500

OscilGen UI uses OSC transportation

The Oscillator Waveforms and spectra are now transported over OSC.
This commit is a bit of a mixed bag, as after reading more of the OscilGen
source it has become obvious that it is not a RT structure at all and similar to
PADnoteParameters it needs to be migrated to some middle layer structure.
Getting the samples is expensive and so is preparing the oscillator to the point
that even one operation in the RT thread can be enough to force it to miss its
deadline (not to mention it generates quite a few memory allocations when
adaptive harmonics are enabled).

With that said once the storage aspect of moving stuff to the middleware layer
is done, reworking the DSP code should be fairly straightforward.
All operations required to get samples for ADnote are linear transformations of
the data generated by prepare and as far as I can see only one operation depends
upon the chosen frequency (adaptive harmonics).
Thus it should be possible to reorder all other computations and place them at
the prepare() stage, thus leaving some simple math with ~4 Ptype-parameters and
one fft behind to get executed in every get() call.

As per what has been added/done in this commit:

- Multimap of paths to widgets has been created to track UI updates
- Memory leak in OscilGenUI fixed
- Ports added all over the place to get access to the locations of the
  oscillators
- OSC panes/groups introduced as a location specifying shorthand
- OSC widget types introduced in conjunction with the multimap
- Undefined behavior of vumeters fixed (uninitialized values)
- Oscilloscope waveform and spectrum widgets are separated out now as directly
  editing them in fluid is too time consuming
  (some additional refactoring could be done here)
- some parts of OscilGen have been refactored
- Large parts of the UI now either have a osc or osc_i member which contains the
  UI's OSC interface
  If multiple copies of the UI are generated, it should be possible to
  manipulate this along with the base path to direct events wherever you might
  want them

Diffstat:
Msrc/Misc/Master.cpp | 41+++++++++++++++++++++++++++++++++++++++--
Msrc/Misc/Part.cpp | 2++
Msrc/Misc/Util.cpp | 7++++++-
Msrc/Misc/Util.h | 59+++++++++++++++++++++++++++++++++++++++--------------------
Msrc/Params/ADnoteParameters.cpp | 24++++++++++++++++++++++++
Msrc/Params/ADnoteParameters.h | 5+++++
Msrc/Params/PADnoteParameters.cpp | 1+
Msrc/Params/SUBnoteParameters.cpp | 7+++++++
Msrc/Params/SUBnoteParameters.h | 2+-
Msrc/Synth/OscilGen.cpp | 109++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/Synth/OscilGen.h | 2++
Msrc/UI/ADnoteUI.fl | 218+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/UI/Connection.cpp | 19++++++++++++++-----
Msrc/UI/Fl_Osc_Interface.h | 11++++++++---
Asrc/UI/Fl_Osc_Pane.H | 25+++++++++++++++++++++++++
Asrc/UI/Fl_Osc_Widget.H | 20++++++++++++++++++++
Asrc/UI/Fl_OscilSpectrum.h | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/Fl_Oscilloscope.h | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/UI/MasterUI.fl | 16++++++++--------
Msrc/UI/OscilGenUI.fl | 414+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/UI/PADnoteUI.fl | 31++++++++++++++++++++-----------
Msrc/UI/PartUI.fl | 47++++++++++++++++++++++++++++++-----------------
Msrc/UI/VuMasterMeter.h | 10+++++++---
Msrc/UI/VuPartMeter.h | 2+-
Msrc/main.cpp | 55+++++++++++++++++++++++++++++++++++++++++++++++--------
25 files changed, 938 insertions(+), 434 deletions(-)

diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -332,6 +332,36 @@ void Master::partonoff(int npart, int what) } } +class DataObj:public rtosc::RtData +{ + public: + DataObj(char *loc_, size_t loc_size_, void *obj_, rtosc::ThreadLink *bToU_) + { + memset(loc_, 0, sizeof(loc_size_)); + loc = loc_; + loc_size = loc_size_; + obj = obj_; + bToU = bToU_; + } + + virtual void reply(const char *path, const char *args, ...) + { + va_list va; + va_start(va,args); + char *buffer = bToU->buffer(); + rtosc_vmessage(buffer,bToU->buffer_size(),path,args,va); + bToU->raw_write(buffer); + } + virtual void reply(const char *msg) + { + bToU->raw_write(msg); + } + //virtual void broadcast(const char *path, const char *args, ...){(void)path;(void)args;}; + //virtual void broadcast(const char *msg){(void)msg;}; + private: + rtosc::ThreadLink *bToU; +}; + /* * Master audio out (the final sound) */ @@ -339,8 +369,15 @@ void Master::AudioOut(float *outl, float *outr) { //Handle user events TODO move me to a proper location char loc_buf[1024]; - while(uToB->hasNext()) - ports.dispatch(loc_buf, 1024, uToB->read()+1, this); + DataObj d{loc_buf, 1024, this, bToU}; + int events = 0; + while(uToB->hasNext()) { + ports.dispatch(uToB->read()+1, d); + events++; + //printf("backend: '%s'\n", uToB->peak()); + } + if(events>1) + fprintf(stderr, "backend: %d events per cycle\n",events); //Swaps the Left channel with Right Channel if(swaplr) diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -47,6 +47,8 @@ static Ports partPorts = { static Ports kitPorts = { RECURP(Part::Kit, PADnoteParameters, padpars, padpars, "Padnote parameters"), + RECURP(Part::Kit, ADnoteParameters, adpars, adpars, "Adnote parameters"), + RECURP(Part::Kit, SUBnoteParameters, subpars, subpars, "Adnote parameters"), }; Ports &Part::Kit::ports = kitPorts; diff --git a/src/Misc/Util.cpp b/src/Misc/Util.cpp @@ -160,6 +160,11 @@ typedef pool_t::iterator pool_itr_t; pool_t pool; +static unsigned max(unsigned a, unsigned b) +{ + return a>b?a:b; +} + float *getTmpBuffer() { for(pool_itr_t itr = pool.begin(); itr != pool.end(); ++itr) @@ -169,7 +174,7 @@ float *getTmpBuffer() } pool_entry p; //Extend Pool p.free = false; - p.dat = new float[synth->buffersize]; + p.dat = new float[max(synth->buffersize, synth->oscilsize)]; pool.push_back(p); return p.dat; diff --git a/src/Misc/Util.h b/src/Misc/Util.h @@ -72,6 +72,12 @@ std::string stringFrom(T x) } template<class T> +std::string to_s(T x) +{ + return stringFrom(x); +} + +template<class T> T stringTo(const char *x) { std::string str = x != NULL ? x : "0"; //should work for the basic float/int @@ -81,6 +87,8 @@ T stringTo(const char *x) return ans; } + + template<class T> T limit(T val, T min, T max) { @@ -142,40 +150,51 @@ const char *message_snip(const char *m); ///floating point parameter - with lookup code #define PARAMF(type, var, name, scale, _min, _max, desc) \ {#name"::f", #scale "," # _min "," #_max ":'parameter':" desc, 0, \ - [](const char *m, RtData d) { \ + [](const char *m, rtosc::RtData &d) { \ if(rtosc_narguments(m)==0) {\ - bToU->write("/display", "sf", d.loc, ((type*)d.obj)->var); \ + d.reply(d.loc, "f", ((type*)d.obj)->var); \ } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='f') {\ ((type*)d.obj)->var = limit<float>(_min,_max,rtosc_argument(m,0).f); \ - bToU->write(d.loc, "f", ((type*)d.obj)->var);}}} + d.broadcast(d.loc, "f", ((type*)d.obj)->var);}}} + +///character parameter - with lookup code +#define PARAMC(type, var, name, desc) \ +{#name"::c", ":'old-param':" desc, 0, \ + [](const char *m, rtosc::RtData &d) { \ + if(rtosc_narguments(m)==0) {\ + d.reply(d.loc, "c", ((type*)d.obj)->var); \ + } else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='c') {\ + ((type*)d.obj)->var = limit<char>(0,127,rtosc_argument(m,0).i); \ + d.broadcast(d.loc, "c", ((type*)d.obj)->var);}}} ///Recur - perform a simple recursion #define RECUR(type, cast, name, var, desc) \ -{#name"/", ":'recursion':" desc, &cast::ports, [](const char *m, RtData d){\ - cast::ports.dispatch(d.loc, d.loc_size, message_snip(m),\ - &(((type*)d.obj)->var));}} +{#name"/", ":'recursion':" desc, &cast::ports, [](const char *m, rtosc::RtData &d){\ + d.obj = &(((type*)d.obj)->var); \ + cast::ports.dispatch(message_snip(m), d);}} ///Recurs - perform a ranged recursion #define RECURS(type, cast, name, var, length, desc) \ -{#name "#" #length "/", ":'recursion':" desc, &cast::ports, [](const char *m, RtData d){ \ - const char *mm = m; \ - while(!isdigit(*mm))++mm; \ - cast::ports.dispatch(d.loc, d.loc_size, message_snip(m), \ - &(((type*)d.obj)->var)[atoi(mm)]);}} +{#name "#" #length "/", ":'recursion':" desc, &cast::ports, \ + [](const char *m, rtosc::RtData &d){ \ + const char *mm = m; \ + while(!isdigit(*mm))++mm; \ + d.obj = &(((type*)d.obj)->var)[atoi(mm)]; \ + cast::ports.dispatch(message_snip(m), d);}} ///Recur - perform a simple recursion (on pointer member) #define RECURP(type, cast, name, var, desc) \ -{#name"/", ":'recursion':" desc, &cast::ports, [](const char *m, RtData d){\ - cast::ports.dispatch(d.loc, d.loc_size, message_snip(m),\ - (((type*)d.obj)->var));}} +{#name"/", ":'recursion':" desc, &cast::ports, [](const char *m, rtosc::RtData &d){\ + d.obj = (((type*)d.obj)->var); \ + cast::ports.dispatch(message_snip(m), d);}} ///Recurs - perform a ranged recursion (on pointer array member) #define RECURSP(type, cast, name, var, length, desc) \ -{#name "#" #length "/", ":'recursion':" desc, &cast::ports, [](const char *m, RtData d){ \ - const char *mm = m; \ - while(!isdigit(*mm))++mm; \ - cast::ports.dispatch(d.loc, d.loc_size, message_snip(m), \ - (((type*)d.obj)->var)[atoi(mm)]);}} - +{#name "#" #length "/", ":'recursion':" desc, &cast::ports, \ + [](const char *m, rtosc::RtData &d){ \ + const char *mm = m; \ + while(!isdigit(*mm))++mm; \ + d.obj = (((type*)d.obj)->var)[atoi(mm)]; \ + cast::ports.dispatch(message_snip(m), d);}} #endif diff --git a/src/Params/ADnoteParameters.cpp b/src/Params/ADnoteParameters.cpp @@ -33,6 +33,30 @@ #include "../Synth/Resonance.h" #include "FilterParams.h" +#include <rtosc/ports.h> +using rtosc::Ports; +using rtosc::RtData; + +#define EXPAND(x) x + +static Ports voicePorts = { + RECURP(ADnoteVoiceParam, OscilGen, oscil, OscilSmp, "Primary Oscillator"), + RECURP(ADnoteVoiceParam, OscilGen, oscil-mod, FMSmp, "Modulating Oscillator"), +}; + +static Ports globalPorts = { + PARAMC(ADnoteGlobalParam, PPanning, panning, "Panning (0 random, 1 left, 127 right)") +}; + +static Ports adPorts = {//XXX 16 should not be hard coded + RECURS(ADnoteParameters, ADnoteVoiceParam, voice, VoicePar, 16, "Voice Parameters"), + RECUR(ADnoteParameters, ADnoteGlobalParam, global, GlobalPar, "Adnote Parameters"), +}; + +Ports &ADnoteParameters::ports = adPorts; +Ports &ADnoteVoiceParam::ports = voicePorts; +Ports &ADnoteGlobalParam::ports = globalPorts; + int ADnote_unison_sizes[] = {1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 0}; diff --git a/src/Params/ADnoteParameters.h b/src/Params/ADnoteParameters.h @@ -111,6 +111,8 @@ struct ADnoteGlobalParam { //how the randomness is applied to the harmonics on more voices using the same oscillator unsigned char Hrandgrouping; + + static rtosc::Ports &ports; }; @@ -283,6 +285,8 @@ struct ADnoteVoiceParam { /* Frequency Envelope of the Modullator */ unsigned char PFMAmpEnvelopeEnabled; EnvelopeParams *FMAmpEnvelope; + + static rtosc::Ports &ports; }; class ADnoteParameters:public PresetsArray @@ -302,6 +306,7 @@ class ADnoteParameters:public PresetsArray float getUnisonFrequencySpreadCents(int nvoice); int get_unison_size_index(int nvoice); void set_unison_size_index(int nvoice, int index); + static rtosc::Ports &ports; private: void defaults(int n); //n is the nvoice diff --git a/src/Params/PADnoteParameters.cpp b/src/Params/PADnoteParameters.cpp @@ -28,6 +28,7 @@ static rtosc::Ports localPorts = { + RECURP(PADnoteParameters, OscilGen, oscil, oscilgen, "Oscillator"), {"sample#64:ifb", "::Nothing to see here", 0, [](const char *m, rtosc::RtData d) { diff --git a/src/Params/SUBnoteParameters.cpp b/src/Params/SUBnoteParameters.cpp @@ -24,6 +24,13 @@ #include "SUBnoteParameters.h" #include <stdio.h> +#include <rtosc/ports.h> + +static rtosc::Ports localPorts = { +}; + +rtosc::Ports &SUBnoteParameters::ports = localPorts; + SUBnoteParameters::SUBnoteParameters():Presets() { setpresettype("Psubsyth"); diff --git a/src/Params/SUBnoteParameters.h b/src/Params/SUBnoteParameters.h @@ -96,7 +96,7 @@ class SUBnoteParameters:public Presets //how the harmonics start("0"=0,"1"=random,"2"=1) unsigned char Pstart; - + static rtosc::Ports &ports; private: }; diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -28,6 +28,73 @@ #include <math.h> #include <stdio.h> +#include <rtosc/ports.h> + +static rtosc::Ports localPorts = { + {"prepare:", "::Ensures Output of Oscillator is in sync with parameters", + NULL, [](const char *m, rtosc::RtData &d) { + ((OscilGen*)d.obj)->prepare(); + }}, + {"convert2sine:", "::Translates waveform into FS", + NULL, [](const char *m, rtosc::RtData &d) { + ((OscilGen*)d.obj)->convert2sine(); + }}, + {"phase#128::c", "::Sets harmonic phase", + NULL, [](const char *m, rtosc::RtData &d) { + const char *mm = m; + while(*mm && !isdigit(*mm)) ++mm; + unsigned char &phase = ((OscilGen*)d.obj)->Phphase[atoi(mm)]; + if(!rtosc_narguments(m)) + d.reply(d.loc, "c", phase); + else + phase = rtosc_argument(m,0).i; + }}, + {"magnitude#128::c", "::Sets harmonic magnitude", + NULL, [](const char *m, rtosc::RtData &d) { + const char *mm = m; + while(*mm && !isdigit(*mm)) ++mm; + unsigned char &mag = ((OscilGen*)d.obj)->Phmag[atoi(mm)]; + if(!rtosc_narguments(m)) + d.reply(d.loc, "c", mag); + else + mag = rtosc_argument(m,0).i; + }}, + {"base-spectrum:", "::Returns spectrum of base waveshape", + NULL, [](const char *m, rtosc::RtData &d) { + const unsigned n = synth->oscilsize / 2; + float *spc = getTmpBuffer(); + ((OscilGen*)d.obj)->getspectrum(n,spc,1); + d.reply(d.loc, "b", n*sizeof(float), spc); + returnTmpBuffer(spc); + }}, + {"base-waveform:", "::Returns base waveshape points", + NULL, [](const char *m, rtosc::RtData &d) { + const unsigned n = synth->oscilsize; + float *smps = getTmpBuffer(); + ((OscilGen*)d.obj)->getcurrentbasefunction(smps); + d.reply(d.loc, "b", n*sizeof(float), smps); + returnTmpBuffer(smps); + }}, + {"spectrum:", "::Returns spectrum of waveform", + NULL, [](const char *m, rtosc::RtData &d) { + const unsigned n = synth->oscilsize / 2; + float *spc = getTmpBuffer(); + ((OscilGen*)d.obj)->getspectrum(n,spc,0); + d.reply(d.loc, "b", n*sizeof(float), spc); + returnTmpBuffer(spc); + }}, + {"waveform:", "::Returns waveform points", + NULL, [](const char *m, rtosc::RtData &d) { + const unsigned n = synth->oscilsize; + float *smps = getTmpBuffer(); + ((OscilGen*)d.obj)->get(smps,-1.0); + d.reply(d.loc, "b", n*sizeof(float), smps); + returnTmpBuffer(smps); + }}, +}; + +rtosc::Ports &OscilGen::ports = localPorts; + //operations on FFTfreqs inline void clearAll(fft_t *freqs) @@ -659,6 +726,11 @@ void OscilGen::prepare() oscilprepared = 1; } +fft_t operator*(float a, fft_t b) +{ + return std::complex<float>(a*b.real(), a*b.imag()); +} + void OscilGen::adaptiveharmonic(fft_t *f, float freq) { if(Padaptiveharmonics == 0 /*||(freq<1.0f)*/) @@ -687,41 +759,22 @@ void OscilGen::adaptiveharmonic(fft_t *f, float freq) } for(int i = 0; i < synth->oscilsize / 2 - 2; ++i) { - float h = i * rap; - int high = (int)(i * rap); - float low = fmod(h, 1.0f); + const int high = (int)(i * rap); + const float low = fmod(i * rap, 1.0f); if(high >= (synth->oscilsize / 2 - 2)) break; - else { - if(down) { - f[high] = - std::complex<float>(f[high].real() + inf[i].real() * (1.0f - low), - f[high].imag() + inf[i].imag() * (1.0f - low)); - f[high + 1] = std::complex<float>(f[high + 1].real() + inf[i].real() * low, - f[high + 1].imag() + inf[i].imag() * low); - } - else { - hc = inf[high].real() - * (1.0f - low) + inf[high + 1].real() * low; - hs = inf[high].imag() - * (1.0f - low) + inf[high + 1].imag() * low; - } - if(fabs(hc) < 0.000001f) - hc = 0.0f; - if(fabs(hs) < 0.000001f) - hs = 0.0f; + if(down) { + f[high] += (1.0f - low) * inf[i]; + f[high + 1] += low * inf[i]; } - - if(!down) { - if(i == 0) { //corect the aplitude of the first harmonic - hc *= rap; - hs *= rap; - } - f[i] = fft_t(hc, hs); + else { + f[i] = (1.0f - low) * inf[high] + low * inf[high + 1]; } } + if(!down)//corect the aplitude of the first harmonic + f[0] *= rap; f[1] += f[0]; clearDC(f); diff --git a/src/Synth/OscilGen.h b/src/Synth/OscilGen.h @@ -110,6 +110,8 @@ class OscilGen:public Presets bool ADvsPAD; //if it is used by ADsynth or by PADsynth + static rtosc::Ports &ports; + private: //This array stores some termporary data and it has OSCIL_SIZE elements float *tmpsmps; diff --git a/src/UI/ADnoteUI.fl b/src/UI/ADnoteUI.fl @@ -1,53 +1,62 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0110 +version 1.0300 header_name {.h} code_name {.cc} -decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {} +decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {private local +} -decl {//License: GNU GPL version 2 or later} {} +decl {//License: GNU GPL version 2 or later} {private local +} -decl {\#include "../Params/ADnoteParameters.h"} {public +decl {\#include "../Params/ADnoteParameters.h"} {public local } -decl {\#include "../Misc/Util.h"} {public +decl {\#include "../Misc/Util.h"} {public local } -decl {\#include "../Misc/Master.h"} {public +decl {\#include "../Misc/Master.h"} {public local } -decl {\#include "ResonanceUI.h"} {public +decl {\#include "ResonanceUI.h"} {public local } -decl {\#include <FL/Fl_Box.H>} {public +decl {\#include <FL/Fl_Box.H>} {public local } -decl {\#include <FL/Fl_Group.H>} {public +decl {\#include <FL/Fl_Group.H>} {public local } -decl {\#include <math.h>} {} +decl {\#include <math.h>} {private local +} + +decl {\#include <stdio.h>} {private local +} -decl {\#include <stdio.h>} {} +decl {\#include <stdlib.h>} {private local +} -decl {\#include <stdlib.h>} {} +decl {\#include <string.h>} {private local +} -decl {\#include <string.h>} {} +decl {\#include "WidgetPDial.h"} {public local +} -decl {\#include "WidgetPDial.h"} {public +decl {\#include "Fl_Oscilloscope.h"} {public local } -decl {\#include "EnvelopeUI.h"} {public +decl {\#include "EnvelopeUI.h"} {public local } -decl {\#include "LFOUI.h"} {public +decl {\#include "LFOUI.h"} {public local } -decl {\#include "FilterUI.h"} {public +decl {\#include "FilterUI.h"} {public local } -decl {\#include "OscilGenUI.h"} {public +decl {\#include "OscilGenUI.h"} {public local } -decl {\#include "PresetsUI.h"} {public +decl {\#include "PresetsUI.h"} {public local } class ADvoicelistitem {open : {public Fl_Group} @@ -55,10 +64,10 @@ class ADvoicelistitem {open : {public Fl_Group} Function {make_window()} {open private } { Fl_Window ADnoteVoiceListItem {open - private xywh {262 736 615 100} type Double box UP_FRAME + private xywh {310 881 615 100} type Double box UP_FRAME class Fl_Group visible } { - Fl_Group voicelistitemgroup { + Fl_Group voicelistitemgroup {open private xywh {50 0 570 25} code0 {if (pars->VoicePar[nvoice].Enabled==0) o->deactivate();} } { @@ -85,9 +94,10 @@ class ADvoicelistitem {open : {public Fl_Group} } Fl_Group voiceoscil {open xywh {60 5 30 20} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 - code0 {osc=new Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} - code1 {osc->init(pars->VoicePar[nvoice].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master);} - code2 {if (pars->VoicePar[nvoice].Pextoscil != -1) {osc->init(pars->VoicePar[pars->VoicePar[nvoice].Pextoscil].OscilSmp,master);}} + code0 {osc=new Fl_Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {voiceoscil->osc=osc_i;voiceoscil->pane_name=loc;osc->init(false);//osc->init(pars->VoicePar[nvoice].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master);} + code2 {if (pars->VoicePar[nvoice].Pextoscil != -1) {/*osc->init(pars->VoicePar[pars->VoicePar[nvoice].Pextoscil].OscilSmp,master);*/ osc->init(false);}} + class Fl_Osc_Group } {} Fl_Value_Output detunevalueoutput { callback {o->value(getdetune((pars->VoicePar[nvoice].PDetuneType==0)?(pars->GlobalPar.PDetuneType) : (pars->VoicePar[nvoice].PDetuneType),0,pars->VoicePar[nvoice].PDetune)*pars->getBandwidthDetuneMultiplier());} @@ -133,19 +143,27 @@ o->redraw();} } } } - Function {ADvoicelistitem(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + Function {ADvoicelistitem(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {open + } { code {nvoice=0; pars=NULL;} {} } - Function {init(ADnoteParameters *parameters,int nvoice_,Master *master_)} {} { - code {pars=parameters; + Function {init(ADnoteParameters *parameters,int nvoice_,Master *master_, std::string loc_, Fl_Osc_Interface *osc_)} {open + } { + code {assert(osc_); +assert(!loc_.empty()); + +pars=parameters; nvoice=nvoice_; master=master_; +osc_i = osc_; +loc = loc_; make_window(); ADnoteVoiceListItem->show(); end();} {} } - Function {refreshlist()} {} { + Function {refreshlist()} {open + } { code {voiceenabled->value(pars->VoicePar[nvoice].Enabled); voiceresonanceenabled->value(pars->VoicePar[nvoice].Presonance); voicevolume->value(pars->VoicePar[nvoice].PVolume); @@ -153,9 +171,12 @@ voicedetune->value(pars->VoicePar[nvoice].PDetune-8192); voicepanning->value(pars->VoicePar[nvoice].PPanning); voicelfofreq->value(pars->VoicePar[nvoice].FreqLfo->Pintensity); if (pars->VoicePar[nvoice].Pextoscil != -1) { - osc->init(pars->VoicePar[pars->VoicePar[nvoice].Pextoscil].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master); -} else - osc->init(pars->VoicePar[nvoice].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master); + //osc->init(pars->VoicePar[pars->VoicePar[nvoice].Pextoscil].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master); + osc->init(false); +} else { + //osc->init(pars->VoicePar[nvoice].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master); + osc->init(false); +} if (pars->VoicePar[nvoice].Enabled==0) voicelistitemgroup->deactivate(); else voicelistitemgroup->activate(); detunevalueoutput->do_callback(); @@ -166,10 +187,18 @@ ADnoteVoiceListItem->redraw();} {} code {ADnoteVoiceListItem->hide(); //delete(ADnoteVoiceListItem);} {} } - decl {ADnoteParameters *pars;} {} - decl {int nvoice;} {} - decl {Oscilloscope *osc;} {} - decl {Master *master;} {} + decl {ADnoteParameters *pars;} {private local + } + decl {int nvoice;} {private local + } + decl {Fl_Oscilloscope *osc;} {private local + } + decl {Master *master;} {private local + } + decl {Fl_Osc_Interface *osc_i;} {private local + } + decl {std::string loc;} {private local + } } class ADvoiceUI {open : {public Fl_Group} @@ -178,7 +207,7 @@ class ADvoiceUI {open : {public Fl_Group} } { Fl_Window ADnoteVoiceParameters { label Voice open - xywh {84 305 765 590} type Double box NO_BOX + xywh {502 391 765 590} type Double box NO_BOX class Fl_Group visible } { Fl_Group voiceparametersgroup {open @@ -302,9 +331,11 @@ o->redraw();} } { Fl_Group fmoscil {open xywh {535 440 220 140} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 - code0 {oscFM=new Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} - code1 {int nv=nvoice; if (pars->VoicePar[nvoice].PextFMoscil>=0) nv=pars->VoicePar[nvoice].PextFMoscil;} - code2 {oscFM->init(pars->VoicePar[nv].FMSmp,0,pars->VoicePar[nvoice].PFMoscilphase,master);} + code0 {oscFM=new Fl_Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {//int nv=nvoice; if (pars->VoicePar[nvoice].PextFMoscil>=0) nv=pars->VoicePar[nvoice].PextFMoscil;} + code2 {fmoscil->pane_name = loc+"oscil-mod/";fmoscil->osc = osc_i;//oscFM->init(pars->VoicePar[nv].FMSmp,0,pars->VoicePar[nvoice].PFMoscilphase,master);} + code3 {oscFM->parent(fmoscil);oscFM->init(false);oscFM->update();} + class Fl_Osc_Group } {} Fl_Box {} { label {Mod.Oscillator} @@ -317,7 +348,7 @@ o->redraw();} int nv=nvoice; if (pars->VoicePar[nvoice].PextFMoscil>=0) nv=pars->VoicePar[nvoice].PextFMoscil; -oscedit=new OscilEditor(pars->VoicePar[nv].FMSmp,fmoscil,NULL,NULL,master);} +oscedit=new OscilEditor(pars->VoicePar[nv].FMSmp,fmoscil,NULL,NULL,loc+"oscil-mod/", osc_i);} xywh {700 380 55 15} box THIN_UP_BOX labelfont 1 labelsize 11 code0 {if (pars->VoicePar[nvoice].PextFMoscil>=0) o->labelcolor(FL_BLUE);} } @@ -333,10 +364,12 @@ fmoscil->redraw();} label Use callback {pars->VoicePar[nvoice].PextFMoscil=(int)o->value()-1; if ((int) o->value() != 0) { - oscFM->init(pars->VoicePar[(int) o->value()-1].FMSmp,master); + //oscFM->init(pars->VoicePar[(int) o->value()-1].FMSmp,master); + oscFM->init(false); changeFMoscilbutton->labelcolor(FL_BLUE); } else { - oscFM->init(pars->VoicePar[nvoice].FMSmp,master); + //oscFM->init(pars->VoicePar[nvoice].FMSmp,master); + oscFM->init(false); changeFMoscilbutton->labelcolor(FL_BLACK); }; voiceFMparametersgroup->redraw();} open @@ -497,9 +530,11 @@ detunevalueoutput->do_callback();} open } Fl_Group voiceoscil { xywh {80 390 445 145} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 - code0 {osc=new Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} - code1 {int nv=nvoice; if (pars->VoicePar[nvoice].Pextoscil>=0) nv=pars->VoicePar[nvoice].Pextoscil;} - code2 {osc->init(pars->VoicePar[nv].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master);} + code0 {osc=new Fl_Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {voiceoscil->pane_name = loc+"oscil/";//int nv=nvoice; if (pars->VoicePar[nvoice].Pextoscil>=0) nv=pars->VoicePar[nvoice].Pextoscil;} + code2 {voiceoscil->osc = osc_i;//osc->init(pars->VoicePar[nv].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master);} + code3 {osc->parent(voiceoscil); osc->init(false);} + class Fl_Osc_Group } {} Fl_Button changevoiceoscilbutton { label Change @@ -508,7 +543,7 @@ detunevalueoutput->do_callback();} open int nv=nvoice; if (pars->VoicePar[nvoice].Pextoscil>=0) nv=pars->VoicePar[nvoice].Pextoscil; -oscedit=new OscilEditor(pars->VoicePar[nv].OscilSmp,voiceoscil,NULL,NULL,master);} +oscedit=new OscilEditor(pars->VoicePar[nv].OscilSmp,voiceoscil,NULL,NULL,loc+"oscil/", osc_i);} xywh {5 490 65 20} box THIN_UP_BOX labelfont 1 labelsize 11 code0 {if (pars->VoicePar[nvoice].Pextoscil>=0) o->labelcolor(FL_BLUE);} } @@ -534,10 +569,12 @@ voiceoscil->redraw();} label {Use Oscil.} callback {pars->VoicePar[nvoice].Pextoscil=(int)o->value()-1; if ((int) o->value() != 0) { - osc->init(pars->VoicePar[(int) o->value()-1].OscilSmp,master); + //osc->init(pars->VoicePar[(int) o->value()-1].OscilSmp,master); + osc->init(false); changevoiceoscilbutton->labelcolor(FL_BLUE); } else { - osc->init(pars->VoicePar[nvoice].OscilSmp,master); + //osc->init(pars->VoicePar[nvoice].OscilSmp,master); + osc->init(false); changevoiceoscilbutton->labelcolor(FL_BLACK); }; @@ -780,11 +817,15 @@ o->redraw();} pars=NULL; oscedit=NULL;} {} } - Function {init(ADnoteParameters *parameters,int nvoice_,Master *master_)} {open + Function {init(ADnoteParameters *parameters,int nvoice_,Master *master_, std::string loc_, Fl_Osc_Interface *osc_)} {open } { - code {pars=parameters; + code {assert(osc_); +assert(!loc_.empty()); +pars=parameters; nvoice=nvoice_; master=master_; +loc=loc_; +osc_i=osc_; make_window(); end(); ADnoteVoiceParameters->show();} {} @@ -793,17 +834,26 @@ ADnoteVoiceParameters->show();} {} } { code {ADnoteVoiceParameters->hide(); hide(); -if (oscedit!=NULL) { - delete(oscedit); -}; -//delete (ADnoteVoiceParameters);} {} +delete(oscedit); +//delete (ADnoteVoiceParameters);} {selected + } + } + decl {int nvoice;} {private local + } + decl {ADnoteParameters *pars;} {private local + } + decl {OscilEditor *oscedit;} {private local + } + decl {Fl_Oscilloscope *osc;} {private local + } + decl {Fl_Oscilloscope *oscFM;} {private local + } + decl {Master *master;} {private local + } + decl {std::string loc;} {private local + } + decl {Fl_Osc_Interface *osc_i;} {private local } - decl {int nvoice;} {} - decl {ADnoteParameters *pars;} {} - decl {OscilEditor *oscedit;} {} - decl {Oscilloscope *osc;} {} - decl {Oscilloscope *oscFM;} {} - decl {Master *master;} {} } class ADnoteUI {open : {public PresetsUI_} @@ -812,7 +862,7 @@ class ADnoteUI {open : {public PresetsUI_} } { Fl_Window ADnoteGlobalParameters { label {ADsynth Global Parameters of the Instrument} open - xywh {457 319 540 430} type Double visible + xywh {505 551 540 430} type Double visible } { Fl_Group {} { label FREQUENCY open @@ -956,7 +1006,7 @@ for (int i=0;i<NUM_VOICES;i++){ } } Fl_Group {} { - label FILTER open selected + label FILTER open xywh {250 5 285 265} box UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 labelsize 13 align 17 } { Fl_Group filterenv { @@ -1021,11 +1071,11 @@ resui->resonancewindow->show();} } Fl_Window ADnoteVoice { label {ADsynth Voice Parameters} open - xywh {512 361 765 620} type Double visible + xywh {4 361 765 620} type Double visible } { - Fl_Group advoice { + Fl_Group advoice {open xywh {0 0 765 585} - code0 {o->init(pars,nvoice,master);} + code0 {o->init(pars,nvoice,master,loc+"voice"+to_s(nvoice)+"/", osc);} code1 {o->show();} class ADvoiceUI } {} @@ -1042,7 +1092,7 @@ ADnoteVoice->remove(advoice); delete advoice; advoice=new ADvoiceUI(0,0,765,585); ADnoteVoice->add(advoice); -advoice->init(pars,nvoice,master); +advoice->init(pars,nvoice,master,loc+"voice"+to_s(nvoice)+"/", osc); advoice->show(); ADnoteVoice->redraw();} xywh {10 590 130 25} type Simple labelfont 1 align 8 minimum 0 maximum 2 step 1 value 1 textfont 1 textsize 13 @@ -1060,7 +1110,7 @@ ADnoteVoice->redraw();} } } Fl_Window ADnoteVoiceList { - label {ADsynth Voices list} + label {ADsynth Voices list} open xywh {32 266 650 260} type Double hide } { Fl_Text_Display {} { @@ -1097,16 +1147,22 @@ ADnoteVoice->redraw();} } { Fl_Pack {} {open xywh {0 20 620 210} - code0 {for (int i=0;i<NUM_VOICES;i++){voicelistitem[i]=new ADvoicelistitem(0,0,620,25,"");voicelistitem[i]->init(pars,i,master);}} + code0 {for (int i=0;i<NUM_VOICES;i++){voicelistitem[i]=new ADvoicelistitem(0,0,620,25,"");voicelistitem[i]->init(pars,i,master,loc+"voice"+to_s(i)+"/oscil/",osc);}} } {} } } } - Function {ADnoteUI(ADnoteParameters *parameters,Master *master_)} {} { - code {pars=parameters; + Function {ADnoteUI(ADnoteParameters *parameters,Master *master_, std::string loc_, Fl_Osc_Interface *osc_)} {open + } { + code {assert(osc_); +assert(!loc_.empty()); + +pars=parameters; master=master_; nvoice=0; resui=new ResonanceUI(pars->GlobalPar.Reson); +loc=loc_; +osc=osc_; make_window();} {} } Function {~ADnoteUI()} {} { @@ -1118,7 +1174,8 @@ delete(ADnoteGlobalParameters); delete(ADnoteVoice); delete(resui);} {} } - Function {refresh()} {} { + Function {refresh()} {open + } { code {volume->value(pars->GlobalPar.PVolume); vsns->value(pars->GlobalPar.PAmpVelocityScaleFunction); pan->value(pars->GlobalPar.PPanning); @@ -1154,9 +1211,18 @@ for (int i=0;i<NUM_VOICES;i++) voicelistitem[i]->refreshlist(); resui->refresh(); currentvoicecounter->do_callback();} {} } - decl {ADnoteParameters *pars;} {} - decl {ResonanceUI *resui;} {} - decl {Master *master;} {} - decl {int nvoice;} {} - decl {ADvoicelistitem *voicelistitem[NUM_VOICES];} {} + decl {ADnoteParameters *pars;} {private local + } + decl {ResonanceUI *resui;} {private local + } + decl {Master *master;} {private local + } + decl {int nvoice;} {private local + } + decl {ADvoicelistitem *voicelistitem[NUM_VOICES];} {private local + } + decl {std::string loc;} {private local + } + decl {Fl_Osc_Interface *osc;} {private local + } } diff --git a/src/UI/Connection.cpp b/src/UI/Connection.cpp @@ -77,10 +77,10 @@ void GUI::destroyUi(ui_handle_t ui) #define BEGIN(x) {x,"",NULL,[](const char *m, rtosc::RtData d){ \ MasterUI *ui = static_cast<MasterUI*>(d.obj); \ - rtosc_arg_t a0 = rtosc_argument(m,0); \ - rtosc_arg_t a1 = rtosc_argument(m,1); \ - rtosc_arg_t a2 = rtosc_argument(m,2); \ - rtosc_arg_t a3 = rtosc_argument(m,3); + rtosc_arg_t a0 = rtosc_argument(m,0); + //rtosc_arg_t a1 = rtosc_argument(m,1); \ + //rtosc_arg_t a2 = rtosc_argument(m,2); \ + //rtosc_arg_t a3 = rtosc_argument(m,3); #define END }}, //DSL based ports @@ -106,6 +106,7 @@ static rtosc::Ports ports = { ui->do_load_master(a0.s); } END BEGIN("vu-meter:bb") { + rtosc_arg_t a1 = rtosc_argument(m,1); if(a0.b.len == sizeof(vuData) && a1.b.len == sizeof(float)*NUM_MIDI_PARTS) { //Refresh the primary VU meters @@ -121,8 +122,16 @@ static rtosc::Ports ports = { void GUI::raiseUi(ui_handle_t gui, const char *message) { + MasterUI *mui = (MasterUI*)gui; + mui->osc->tryLink(message); + //printf("got message for UI '%s'\n", message); char buffer[1024]; - ports.dispatch(buffer, sizeof(buffer), message+1, gui); + memset(buffer, 0, sizeof(buffer)); + rtosc::RtData d; + d.loc = buffer; + d.loc_size = 1024; + d.obj = gui; + ports.dispatch(message+1, d); } void GUI::raiseUi(ui_handle_t gui, const char *dest, const char *args, ...) diff --git a/src/UI/Fl_Osc_Interface.h b/src/UI/Fl_Osc_Interface.h @@ -8,14 +8,19 @@ class Fl_Osc_Interface public: //It is assumed that you want to have a registry for all of these //elements - virtual void createLink(string s, class Fl_Osc_Widget*){printf("linking %s...\n", s.c_str());}; + virtual void createLink(string s, class Fl_Osc_Widget *w) + {printf("linking %s (%p)...\n", s.c_str(), w);}; virtual void renameLink(string,string,class Fl_Osc_Widget*){}; - virtual void removeLink(string,class Fl_Osc_Widget*){}; + virtual void removeLink(string s,class Fl_Osc_Widget*){printf("removing '%s'...\n", s.c_str());}; + //and to be able to give them events + virtual void tryLink(const char *msg){}; //Communication link - virtual void requestValue(string){}; + virtual void requestValue(string s) { printf("request: '%s'...\n", s.c_str()); }; virtual void writeValue(string s, float f){printf("%s -> %f\n",s.c_str(), f); }; + virtual void writeValue(string s, char c){printf("%s->%d\n", s.c_str(), c);}; virtual void writeValue(string, int){}; virtual void writeValue(string, bool){}; virtual void writeValue(string, string){}; + virtual void write(string s, const char *, ...) {};//{printf("write: '%s'\n", s.c_str());}; }; diff --git a/src/UI/Fl_Osc_Pane.H b/src/UI/Fl_Osc_Pane.H @@ -0,0 +1,25 @@ +#pragma once +#include <FL/Fl_Group.H> +#include <string> + +class Fl_Osc_Pane +{ + public: + class Fl_Osc_Interface *osc; + std::string pane_name; +}; + +class Fl_Osc_Group:public Fl_Osc_Pane, public Fl_Group +{ + public: + Fl_Osc_Group(int x, int y, int w, int h, const char *L=0) + :Fl_Group(x,y,w,h,L) + { + if(auto *p = dynamic_cast<Fl_Osc_Pane*>(parent())) { + osc = p->osc; + pane_name = p->pane_name; + } + }; +}; + + diff --git a/src/UI/Fl_Osc_Widget.H b/src/UI/Fl_Osc_Widget.H @@ -0,0 +1,20 @@ +#pragma once +#include <string> +#include <cstring> +#include <cmath> +#include <FL/Fl_Group.H> + +class Fl_Osc_Widget +{ + public: + Fl_Osc_Widget(void) {} + virtual ~Fl_Osc_Widget(void){}; + + virtual void OSC_value(float) {} + virtual void OSC_value(bool) {} + virtual void OSC_value(int) {} + virtual void OSC_value(unsigned,void*) {} + + std::string loc; + class Fl_Osc_Interface *osc; +}; diff --git a/src/UI/Fl_OscilSpectrum.h b/src/UI/Fl_OscilSpectrum.h @@ -0,0 +1,119 @@ +#include <cassert> + +//consider merging with Fl_Oscilloscope +class Fl_OscilSpectrum : public Fl_Box, Fl_Osc_Widget +{ + public: + Fl_OscilSpectrum(int x,int y, int w, int h, const char *label=0) + :Fl_Box(x,y,w,h,label), nsamples(0), spc(NULL) + {} + + ~Fl_OscilSpectrum(void) + { + delete[] spc; + osc->removeLink(loc, (Fl_Osc_Widget*) this); + } + + void init(bool base_spectrum_p) + { + Fl_Group *g = dynamic_cast<Fl_Group*>(parent()); + Fl_Osc_Group *og = dynamic_cast<Fl_Osc_Group*>(g); + assert(og); + + loc = og->pane_name + (base_spectrum_p ? "base-spectrum": "spectrum"); + osc = og->osc; + assert(osc); + + osc->createLink(loc, (Fl_Osc_Widget*) this); + osc->requestValue(loc); + } + + void update(void) + { + osc->write(loc, "i", nsamples); + } + + void OSC_value(unsigned N, void *data) override + { + assert(!(N%4)); + const size_t new_samples = N / 4; + + //resize buffer if needed + if(new_samples != nsamples) { + delete [] spc; + spc = new float[new_samples]; + nsamples = new_samples; + } + + memcpy(spc, data, N); + + //normalize + float max=0; + for (unsigned i=0; i<nsamples; i++){ + float x=fabs(spc[i]); + if (max<x) max=x; + } + if (max<0.000001) max=1.0; + max=max*1.05; + + for(unsigned i=0; i<nsamples; ++i) + spc[i]/=max; + + //Get widget to redraw new data + redraw(); + } + + void draw(void) + { + const int ox=x(),oy=y(),lx=w(),ly=h(); + const int maxdb=60;//must be multiple of 10 + const int GX=2; + int n=lx/GX-1; + if (n>synth->oscilsize/2) + n=synth->oscilsize/2; + + //draw + if(this->active_r()) + fl_color(this->parent()->labelcolor()); + else + fl_color(this->parent()->color()); + fl_line_style(FL_DOT); + + for(int i=1; i<maxdb/10; i++){ + const int ky=((int)((float)i*ly*10.0/maxdb)/2)*2; + fl_line(ox,oy+ky-1,ox+lx-2,oy+ky-1); + } + + for(int i=2; i<n; i++){ + int tmp=i*GX-2; + if(i%10==1) + fl_line_style(0); + else + fl_line_style(FL_DOT); + fl_line(ox+tmp,oy+2,ox+tmp,oy+ly-2); + } + + if (this->active_r()) + fl_color(this->parent()->selection_color()); + else + fl_color(this->parent()->color()); + fl_line_style(0); + + if(!spc) + return; + //draws the spectrum + for(int i=0; i<n; i++){ + int tmp=i*GX+2; + float x=spc[i]; + + if (x>dB2rap(-maxdb)) x=rap2dB(x)/maxdb+1; + else x=0; + + int val=(int) ((ly-2)*x); + if (val>0) fl_line(ox+tmp,oy+ly-2-val,ox+tmp,oy+ly-2); + } + } + private: + size_t nsamples; + float *spc; +}; diff --git a/src/UI/Fl_Oscilloscope.h b/src/UI/Fl_Oscilloscope.h @@ -0,0 +1,126 @@ +#pragma once + +#include "Fl_Osc_Pane.H" +#include <FL/Fl_Box.H> +#include <FL/fl_draw.H> +#include "Fl_Osc_Widget.H" +#include "Fl_Osc_Pane.H" +#include "Fl_Osc_Interface.h" +#include "common.H" +#include <cassert> +#include <cstdio> + +class Fl_Osc_Group; +//Consider merging in Fl_OscilSpectrum +class Fl_Oscilloscope : public Fl_Box, Fl_Osc_Widget +{ + public: + Fl_Oscilloscope(int x,int y, int w, int h, const char *label=0) + :Fl_Box(x,y,w,h,label) + { + smps = new float[synth->oscilsize]; + memset(smps, 0, synth->oscilsize*sizeof(float)); + phase=64; + box(FL_FLAT_BOX); + } + + ~Fl_Oscilloscope(void) + { + delete[] smps; + osc->removeLink(loc, this); + } + + void init(bool base_waveform_p) + { + Fl_Group *g = dynamic_cast<Fl_Group*>(parent()); + Fl_Osc_Group *og = dynamic_cast<Fl_Osc_Group*>(g); + assert(og); + + loc = og->pane_name + (base_waveform_p ? "base-waveform": "waveform"); + osc = og->osc; + assert(osc); + + osc->createLink(loc, this); + osc->requestValue(loc); + } + + void update(void) + { + osc->requestValue(loc); + } + + void OSC_value(unsigned N, void *data) override + { + assert(N==(unsigned)(synth->oscilsize*4)); + + memcpy(smps, data, N); + + //normalize + float max=0; + for (int i=0;i<synth->oscilsize;i++) + if(max<fabs(smps[i])) + max=fabs(smps[i]); + if (max<0.00001) max=1.0; + max *= -1.05; + + for(int i=0; i < synth->oscilsize; ++i) + smps[i] /= max; + + //Get widget to redraw new data + redraw(); + } + + void draw(void) + { + int ox=x(),oy=y(),lx=w(),ly=h()-1; + + if (damage()!=1){ + fl_color( fl_color_average( FL_BLACK, FL_BACKGROUND_COLOR, 0.5 )); + fl_rectf(ox,oy,lx,ly); + } + + //draw + fl_line_style(FL_DASH); + if (this->active_r()) fl_color(this->parent()->labelcolor()); + else fl_color(this->parent()->color()); + + int GX=16;if (lx<GX*3) GX=-1; + for (int i=1;i<GX;i++){ + int tmp=(int)(lx/(float)GX*i); + fl_line(ox+tmp,oy+2,ox+tmp,oy+ly-2); + } + + int GY=8; if (ly<GY*3) GY=-1; + for (int i=1;i<GY;i++){ + int tmp=(int)(ly/(float)GY*i); + fl_line(ox+2,oy+tmp,ox+lx-2,oy+tmp); + } + + //draw the function + fl_line_style(0,1); + fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2); + if (this->active_r()) fl_color(this->parent()->selection_color()); + else fl_color(this->parent()->labelcolor()); + + fl_color( fl_color_add_alpha( fl_color(), 127 ) ); + + int lw=2; + fl_line_style(FL_SOLID,lw); + fl_begin_line(); + double ph=((phase-64.0)/128.0*synth->oscilsize+synth->oscilsize); + for (int i=1;i<lx;i++){ + int k2=(synth->oscilsize*i/lx)+ph; + double y2=smps[k2%synth->oscilsize]; + fl_vertex(i+ox,y2*ly/2.0+oy+ly/2); + } + fl_end_line(); + + fl_line_style(FL_SOLID,0); + } + + //allows UI to manipuate phase of displayed waveform + int phase; + + private: + float *smps; +}; diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl @@ -123,7 +123,7 @@ class Panellistitem {open : {public Fl_Group} Function {make_window()} {open private } { Fl_Window panellistitem {open - private xywh {620 721 100 260} type Double box NO_BOX + private xywh {623 721 100 260} type Double box NO_BOX class Fl_Group visible } { Fl_Group panellistitemgroup {open @@ -261,7 +261,7 @@ if (( *exitprogram=1; }; \#endif} - xywh {92 456 390 525} type Double xclass zynaddsubfx visible + xywh {95 456 390 525} type Double xclass zynaddsubfx visible } { Fl_Menu_Bar mastermenu { xywh {-5 0 690 25} @@ -530,7 +530,7 @@ pthread_mutex_unlock(&master->mutex);} } { Fl_Group partui {open xywh {0 310 383 175} - code0 {o->init(master->part[0],"/part0/", master,0,bankui);} + code0 {o->init(master->part[0],"/part0/", master,0,bankui,"/part0/", osc);} code1 {o->show();} class PartUI } {} @@ -808,7 +808,7 @@ partui=new PartUI(0,0,765,525); partuigroup->add(partui); char buffer[1024]; snprintf(buffer, 1024, "/part%d/", nval); -partui->init(master->part[nval], buffer, master, nval, bankui); +partui->init(master->part[nval], buffer, master, nval, bankui, "/part"+to_s(nval)+"/", osc); partui->redraw(); o->redraw(); npart=nval; @@ -901,7 +901,7 @@ GNU General Public License for details.} } Fl_Window panelwindow { label {ZynAddSubFX Panel} open - xywh {95 105 630 635} type Double visible + xywh {98 128 630 635} type Double visible } { Fl_Scroll {} {open xywh {0 5 570 310} type HORIZONTAL box THIN_UP_BOX @@ -941,7 +941,7 @@ if (fl_choice("Exit and leave the unsaved data?","No","Yes",NULL)) { *exitprogram=1; }; \#endif} - xywh {295 354 600 335} type Double visible + xywh {298 377 600 335} type Double visible } { Fl_Menu_Bar simplemastermenu { xywh {0 0 690 25} @@ -1705,10 +1705,10 @@ bankui->hide();} {} } decl {char masterwindowlabel[100];} {private local } - decl {Panellistitem *panellistitem[NUM_MIDI_PARTS];} {selected public local + decl {Panellistitem *panellistitem[NUM_MIDI_PARTS];} {public local } decl {NioUI nioui;} {private local } - decl {class Fl_Osc_Interface *osc;} {private local + decl {class Fl_Osc_Interface *osc;} {selected public local } } diff --git a/src/UI/OscilGenUI.fl b/src/UI/OscilGenUI.fl @@ -1,135 +1,77 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0110 +version 1.0300 header_name {.h} code_name {.cc} -decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {} +decl {//Copyright (c) 2002-2005 Nasca Octavian Paul} {private local +} -decl {//License: GNU GPL version 2 or later} {} +decl {//License: GNU GPL version 2 or later} {private local +} -decl {\#include "../Synth/OscilGen.h"} {public +decl {\#include "../Synth/OscilGen.h"} {public local } -decl {\#include "../Misc/Util.h"} {public +decl {\#include "../Misc/Util.h"} {public local } -decl {\#include "../Misc/Master.h"} {public +decl {\#include "../Misc/Master.h"} {public local } -decl {\#include "ResonanceUI.h"} {public +decl {\#include "ResonanceUI.h"} {public local } -decl {\#include <FL/Fl_Box.H>} {public +decl {\#include "Fl_Oscilloscope.h"} {public local } -decl {\#include <FL/Fl_Group.H>} {public +decl {\#include "Fl_OscilSpectrum.h"} {public local } -decl {\#include <FL/Fl_Slider.H>} {public +decl {\#include "Fl_Osc_Interface.h"} {public local } -decl {\#include <math.h>} {} +decl {\#include <FL/Fl_Box.H>} {public local +} -decl {\#include <stdio.h>} {} +decl {\#include <FL/Fl_Group.H>} {public local +} -decl {\#include <stdlib.h>} {} +decl {\#include <FL/Fl_Slider.H>} {public local +} -decl {\#include <string.h>} {} +decl {\#include <math.h>} {private local +} -decl {\#include "WidgetPDial.h"} {public +decl {\#include <stdio.h>} {private local } -decl {\#include "EnvelopeUI.h"} {public +decl {\#include <stdlib.h>} {private local } -decl {\#include "LFOUI.h"} {public +decl {\#include <string.h>} {private local } -decl {\#include "FilterUI.h"} {public +decl {\#include "WidgetPDial.h"} {public local } -decl {\#include "PresetsUI.h"} {public +decl {\#include "Fl_Osc_Pane.H"} {public local } -decl {\#include <FL/fl_draw.H>} {public +decl {\#include "EnvelopeUI.h"} {public local } -class OscilSpectrum {: {public Fl_Box} -} { - Function {OscilSpectrum(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { - code {oscil=NULL;} {} - } - Function {init(OscilGen *oscil_,int oscbase_,Master *master_)} {} { - code {oscil=oscil_; -oscbase=oscbase_; -master=master_;} {} - } - Function {draw()} {} { - code {int ox=x(),oy=y(),lx=w(),ly=h(),i; -const int maxdb=60;//must be multiple of 10 -int GX=2; -int n=lx/GX-1; -if (n>synth->oscilsize/2) n=synth->oscilsize/2; - -float x; -float* spc=new float[n]; -for (i=0;i<n;i++) spc[i]=0.0; - -pthread_mutex_lock(&master->mutex); -if (oscbase==0) oscil->getspectrum(n,spc,0); - else oscil->getspectrum(n,spc,1); -pthread_mutex_unlock(&master->mutex); - -//normalize -float max=0; -for (i=0;i<n;i++){ - x=fabs(spc[i]); - if (max<x) max=x; -} -if (max<0.000001) max=1.0; -max=max*1.05; - -//draw - -if (this->active_r()) fl_color(this->parent()->selection_color()); - else fl_color(this->parent()->color()); -fl_line_style(FL_DOT); - -for (i=1;i<maxdb/10;i++){ - int ky=(int)((float)i*ly*10.0/maxdb)/2; - ky*=2; - fl_line(ox,oy+ky-1,ox+lx-2,oy+ky-1); -}; +decl {\#include "LFOUI.h"} {public local +} -for (i=2;i<n;i++){ - int tmp=i*GX-2; - if (i%10==1) fl_line_style(0); - else fl_line_style(FL_DOT); - fl_line(ox+tmp,oy+2,ox+tmp,oy+ly-2); -} - -if (this->active_r()) fl_color(this->parent()->labelcolor()); - else fl_color(this->parent()->color()); -fl_line_style(0); - -//draws the spectrum -for (i=0;i<n;i++){ - int tmp=i*GX+2; - x=spc[i]/max; - - if (x>dB2rap(-maxdb)) x=rap2dB(x)/maxdb+1; - else x=0; - - int val=(int) ((ly-2)*x); - if (val>0) fl_line(ox+tmp,oy+ly-2-val,ox+tmp,oy+ly-2); -} -delete [] spc;} {} - } - decl {OscilGen *oscil;} {} - decl {int oscbase;} {} - decl {Master *master;} {} +decl {\#include "FilterUI.h"} {public local +} + +decl {\#include "PresetsUI.h"} {public local +} + +decl {\#include <FL/fl_draw.H>} {public local } -class PSlider {: {public Fl_Slider} +class PSlider {open : {public Fl_Slider} } { Function {PSlider(int x,int y, int w, int h, const char *label=0):Fl_Slider(x,y,w,h,label)} {} { code {;} {} @@ -157,105 +99,19 @@ if (!Fl::event_inside(X,Y,W,H)) { return(1);} {} } -} - -class Oscilloscope {open : {public Fl_Box} -} { - Function {Oscilloscope(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {open - } { - code {oscil=NULL; -phase=64; -oscbase=0; -box(FL_FLAT_BOX);} {} - } - Function {init(OscilGen *oscil_,Master *master_)} {} { - code {oscil=oscil_; -master=master_;} {} - } - Function {init(OscilGen *oscil_,int oscbase_,Master *master_)} {} { - code {oscil=oscil_; -oscbase=oscbase_; -master=master_;} {} - } - Function {init(OscilGen *oscil_,int oscbase_,int phase_,Master *master_)} {} { - code {oscil=oscil_; -oscbase=oscbase_; -phase=phase_; -master=master_;} {} - } - Function {draw()} {open - } { - code {int ox=x(),oy=y(),lx=w(),ly=h()-1,i; -float smps[synth->oscilsize]; -pthread_mutex_lock(&master->mutex); -if (oscbase==0) oscil->get(smps,-1.0); - else oscil->getcurrentbasefunction(smps); -pthread_mutex_unlock(&master->mutex); - -if (damage()!=1){ - fl_color( fl_color_average( FL_BLACK, FL_BACKGROUND_COLOR, 0.5 )); - fl_rectf(ox,oy,lx,ly); -}; - -//normalize -float max=0; -for (i=0;i<synth->oscilsize;i++) - if (max<fabs(smps[i])) max=fabs(smps[i]); -//fprintf(stderr,"%.4f\\n",max); -if (max<0.00001) max=1.0; -max=-max*1.05; - -//draw -fl_line_style(FL_DASH); -if (this->active_r()) fl_color(this->parent()->labelcolor()); - else fl_color(this->parent()->color()); -int GX=16;if (lx<GX*3) GX=-1; -for (i=1;i<GX;i++){ - int tmp=(int)(lx/(float)GX*i); - fl_line(ox+tmp,oy+2,ox+tmp,oy+ly-2); -}; -int GY=8;if (ly<GY*3) GY=-1; -for (i=1;i<GY;i++){ - int tmp=(int)(ly/(float)GY*i); - fl_line(ox+2,oy+tmp,ox+lx-2,oy+tmp); -}; - -//draw the function -fl_line_style(0,1); -fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2); -if (this->active_r()) fl_color(this->parent()->selection_color()); - else fl_color(this->parent()->labelcolor()); - -fl_color( fl_color_add_alpha( fl_color(), 127 ) ); - -int lw=2; -//if ((lx<135)||(ly<135)) lw=1; -fl_line_style(FL_SOLID,lw); -fl_begin_line(); -double ph=((phase-64.0)/128.0*synth->oscilsize+synth->oscilsize); -for (i=1;i<lx;i++){ - int k2=(synth->oscilsize*i/lx)+ph; - double y2=smps[k2%synth->oscilsize]/max; - fl_vertex(i+ox,y2*ly/2.0+oy+ly/2); -}; -fl_end_line(); - -fl_line_style(FL_SOLID,0);} {} + decl {std::string loc;} {public local } - decl {OscilGen *oscil;} {} - decl {int oscbase;} {} - decl {int phase;} {public + decl {Fl_Osc_Interface *osc} {public local } - decl {Master *master;} {} } -class Oscilharmonic {: {public Fl_Group} +class Oscilharmonic {open : {public Fl_Group} } { Function {make_window()} {open private } { Fl_Window harmonic {open - private xywh {338 259 100 225} type Double box NO_BOX - class Fl_Group visible + private xywh {392 673 100 225} type Double box NO_BOX + class Fl_Osc_Group visible } { Fl_Slider mag { callback {int x=64; @@ -264,14 +120,14 @@ if (Fl::event_button3()) o->value(x); if (x==64) o->selection_color(0); else o->selection_color(222); -pthread_mutex_lock(&master->mutex); - oscil->Phmag[n]=x; + o->osc->writeValue(o->loc+"magnitude"+to_s(n), (char)x); if (x==64) { - oscil->Phphase[n]=64; + o->osc->writeValue(o->loc+"phase"+to_s(n), (char)64); phase->value(64); - }; - oscil->prepare(); -pthread_mutex_unlock(&master->mutex); + } + o->osc->requestValue(o->loc+"prepare"); + o->osc->requestValue(o->loc+"spectrum"); + o->osc->requestValue(o->loc+"waveform"); display->redraw(); oldosc->redraw(); @@ -281,8 +137,8 @@ if (cbwidget!=NULL) { applybutton->redraw(); };} xywh {0 15 15 115} type {Vert Knob} box NO_BOX selection_color 222 maximum 127 step 1 value 64 - code0 {o->value(127-oscil->Phmag[n]);} - code1 {if (oscil->Phmag[n]==64) o->selection_color(0);} + code0 {//o->value(127-oscil->Phmag[n]);} + code1 {//if (oscil->Phmag[n]==64) o->selection_color(0);} class PSlider } Fl_Slider phase { @@ -290,10 +146,10 @@ if (cbwidget!=NULL) { if (Fl::event_button3()) o->value(x); else x=(int)o->value(); -pthread_mutex_lock(&master->mutex); - oscil->Phphase[n]=x; - oscil->prepare(); -pthread_mutex_unlock(&master->mutex); +o->osc->writeValue(o->loc+"phase"+to_s(n), (char) x); +o->osc->requestValue(o->loc+"prepare"); +o->osc->requestValue(o->loc+"spectrum"); +o->osc->requestValue(o->loc+"waveform"); display->redraw(); oldosc->redraw(); @@ -303,7 +159,7 @@ if (cbwidget!=NULL) { applybutton->redraw(); };} xywh {0 135 15 75} type {Vert Knob} box NO_BOX selection_color 222 maximum 127 step 1 value 64 - code0 {o->value(oscil->Phphase[n]);} + code0 {//o->value(oscil->Phphase[n]);} class PSlider } Fl_Box {} { @@ -326,39 +182,57 @@ if (cbwidget!=NULL) { } Function {Oscilharmonic(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { code {n=0; -oscil=NULL; display=NULL; applybutton=NULL; cbwidget=NULL;} {} } - Function {init(OscilGen *oscil_,int n_,Fl_Group *display_,Fl_Widget *oldosc_,Fl_Widget *cbwidget_,Fl_Widget *applybutton_, Master *master_)} {} { - code {oscil=oscil_; + Function {init(int n_,Fl_Group *display_,Fl_Widget *oldosc_,Fl_Widget *cbwidget_,Fl_Widget *applybutton_, std::string loc_, Fl_Osc_Interface *osc_)} {open + } { + code {assert(osc_); +assert(!loc_.empty()); + n=n_; display=display_; -master=master_; oldosc=oldosc_; cbwidget=cbwidget_; applybutton=applybutton_; +osc = osc_; +loc = loc_; make_window(); +mag->osc = osc; +mag->loc = loc; +phase->osc = osc; +phase->loc = loc; + +//osc->requestValue(loc+"magnitude"+to_s(n)); +//osc->requestValue(loc+"phase"+to_s(n)); end(); harmonic->show();} {} } - Function {refresh()} {} { - code {mag->value(127-oscil->Phmag[n]); -phase->value(oscil->Phphase[n]); + Function {refresh()} {open + } { + code {osc->requestValue(loc+"magnitude"+to_s(n));//mag->value(127-oscil->Phmag[n]); +osc->requestValue(loc+"phase"+to_s(n));//phase->value(oscil->Phphase[n]); -if (oscil->Phmag[n]==64) mag->selection_color(0); - else mag->selection_color(222);} {} +if (mag->value()==64) + mag->selection_color(0); +else + mag->selection_color(222);} {} } Function {~Oscilharmonic()} {} { code {harmonic->hide(); //delete(harmonic);} {} } - decl {OscilGen *oscil;} {} - decl {Fl_Group *display;} {} - decl {int n;} {} - decl {Fl_Widget *oldosc,*cbwidget,*applybutton;} {} - decl {Master *master;} {} + decl {Fl_Group *display;} {private local + } + decl {int n;} {private local + } + decl {Fl_Widget *oldosc,*cbwidget,*applybutton;} {private local + } + decl {Fl_Osc_Interface *osc;} {private local + } + decl {std::string loc;} {private local + } } class OscilEditor {open : {public PresetsUI_} @@ -367,9 +241,15 @@ class OscilEditor {open : {public PresetsUI_} } { Fl_Window osceditUI { label {ADsynth Oscillator Editor} open - xywh {542 193 735 595} type Double + xywh {341 339 735 595} type Double code0 {if (oscil->ADvsPAD) o->label("PADsynth Harmonic Content Editor");} visible } { + Fl_Group dummy {open selected + xywh {25 25 15 15} color 32 selection_color 71 labelcolor 179 + code0 {dummy->pane_name = loc;} + code1 {dummy->osc = osc;} + class Fl_Osc_Group + } {} Fl_Button applybutton { label Apply callback {applybutton->color(FL_GRAY); @@ -382,13 +262,14 @@ if (cbapplywidget!=NULL) { xywh {300 280 60 20} box THIN_UP_BOX labelfont 1 code0 {if (!oscil->ADvsPAD) o->hide();} } - Fl_Group oscildisplaygroup { + Fl_Group oscildisplaygroup {open xywh {5 5 360 300} box UP_FRAME } { Fl_Group {} {open xywh {10 85 350 190} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 - code0 {Oscilloscope *osc=new Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} - code1 {osc->init(oscil,master);} + code0 {oscilo=new Fl_Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {oscilo->parent(dummy);oscilo->init(false);} + code2 {oscilo->activate();} } {} Fl_Box {} { label Oscillator @@ -404,8 +285,9 @@ oldosc->redraw();} } Fl_Group {} {open xywh {10 30 350 50} box THIN_DOWN_BOX color 32 selection_color 218 labelcolor 63 - code0 {OscilSpectrum *spc=new OscilSpectrum(o->x(),o->y(),o->w(),o->h(),"");} - code1 {spc->init(oscil,0,master);} + code0 {oscils=new Fl_OscilSpectrum(o->x(),o->y(),o->w(),o->h(),"");} + code1 {oscils->parent(dummy);oscils->init(false);} + code2 {oscils->activate();} } {} Fl_Group {} { xywh {246 277 115 25} box UP_FRAME @@ -436,13 +318,18 @@ oldosc->redraw();} } } } - Fl_Group basefuncdisplaygroup {open selected + Fl_Group basefuncdisplaygroup {open xywh {365 5 360 300} box UP_FRAME + code0 {o->pane_name = loc;} + code1 {o->osc = osc;} + code2 {assert(osc);} + class Fl_Osc_Group } { Fl_Group {} { xywh {370 85 350 190} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 - code0 {Oscilloscope *osc=new Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} - code1 {osc->init(oscil,1,master);} + code0 {oscilo_base=new Fl_Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {oscilo_base->parent(dummy);oscilo_base->init(true);} + code2 {oscilo_base->activate();} } {} Fl_Dial bfslider { callback {oscil->Pbasefuncpar=(int)o->value()+64; @@ -535,8 +422,9 @@ if ((oscil->Pcurrentbasefunc==0)||(oscil->Pcurrentbasefunc==127)) basefuncmodula } Fl_Group {} {open xywh {370 30 350 50} box THIN_DOWN_BOX color 32 selection_color 218 labelcolor 63 - code0 {OscilSpectrum *spc=new OscilSpectrum (o->x(),o->y(),o->w(),o->h(),"");} - code1 {spc->init(oscil,1,master);} + code0 {oscils_base=new Fl_OscilSpectrum (o->x(),o->y(),o->w(),o->h(),"");} + code1 {oscils_base->parent(dummy);oscils_base->init(true);} + code2 {oscils_base->activate();} } {} Fl_Value_Output bfparval { label {Par.} @@ -646,13 +534,13 @@ if (autoclearbutton->value()){ sabutton->do_callback(); }; -pthread_mutex_lock(&master->mutex); +//pthread_mutex_lock(&master->mutex); for (int i=0;i<MAX_AD_HARMONICS;i++){ if (oscil->Phmag[i]==64) h[i]->mag->selection_color(0); else h[i]->mag->selection_color(222); }; - oscil->prepare(); -pthread_mutex_unlock(&master->mutex); + osc->requestValue(loc+"prepare"); +//pthread_mutex_unlock(&master->mutex); basefuncdisplaygroup->redraw(); redrawoscil();} @@ -682,11 +570,7 @@ for (int i=0;i<MAX_AD_HARMONICS;i++){ }; //harmonics->redraw(); - -pthread_mutex_lock(&master->mutex); - oscil->prepare(); -pthread_mutex_unlock(&master->mutex); - +osc->requestValue(loc+"prepare"); redrawoscil();} xywh {670 505 55 15} box THIN_UP_BOX labelfont 1 labelsize 11 } @@ -1039,9 +923,7 @@ redrawoscil();} label Sine callback {if (!fl_choice("Convert to SINE?","No","Yes",NULL)) return; -pthread_mutex_lock(&master->mutex); - oscil->convert2sine(); -pthread_mutex_unlock(&master->mutex); +osc->requestValue(loc+"convert2sine"); redrawoscil(); refresh();} @@ -1057,34 +939,51 @@ refresh();} callback {presetsui->paste(oscil,this);} xywh {700 545 25 15} box THIN_UP_BOX color 179 labelfont 1 labelsize 11 labelcolor 7 } - Fl_Scroll _this_has_to_be_the_last { + Fl_Scroll _this_has_to_be_the_last {open xywh {5 340 660 250} type HORIZONTAL box FLAT_BOX } { Fl_Pack harmonics {open xywh {10 345 650 225} type HORIZONTAL - code0 {for (int i=0;i<MAX_AD_HARMONICS;i++){h[i]=new Oscilharmonic(0,0,20,o->h(),"");h[i]->init(oscil,i,oscildisplaygroup,oldosc,cbwidget,applybutton,master);}} + code0 {for (int i=0;i<MAX_AD_HARMONICS;i++){h[i]=new Oscilharmonic(0,0,20,o->h(),"");h[i]->init(i,oscildisplaygroup,oldosc,cbwidget,applybutton,loc,osc);}} } {} } } } - Function {OscilEditor(OscilGen *oscil_,Fl_Widget *oldosc_,Fl_Widget *cbwidget_,Fl_Widget *cbapplywidget_,Master *master_)} {} { - code {oscil=oscil_; + Function {OscilEditor(OscilGen *oscil_,Fl_Widget *oldosc_,Fl_Widget *cbwidget_,Fl_Widget *cbapplywidget_, std::string loc_, Fl_Osc_Interface *osc_)} {open + } { + code {assert(osc_); +assert(!loc_.empty()); + +oscil=oscil_; oldosc=oldosc_; cbwidget=cbwidget_; cbapplywidget=cbapplywidget_; -master=master_; +osc = osc_; +loc = loc_; + +oscilo = NULL; +oscilo_base = NULL; +oscils = NULL; +oscils_base = NULL; make_window(); refresh(); osceditUI->show();} {} } - Function {~OscilEditor()} {} { + Function {~OscilEditor()} {open + } { code {osceditUI->hide(); //for (int i=0;i<MAX_AD_HARMONICS;i++) delete (h[i]); + +delete oscilo; +delete oscilo_base; +delete oscils; +delete oscils_base; delete (osceditUI);} {} } - Function {refresh()} {} { + Function {refresh()} {open + } { code {magtype->value(oscil->Phmagtype); rndslider->value(oscil->Prand-64); @@ -1127,15 +1026,20 @@ adhrtype->value(oscil->Padaptiveharmonicspar); for (int i=0;i<MAX_AD_HARMONICS;i++) h[i]->refresh(); -pthread_mutex_lock(&master->mutex); - oscil->prepare(); -pthread_mutex_unlock(&master->mutex); +osc->requestValue(loc+"prepare"); basefuncdisplaygroup->redraw(); redrawoscil();} {} } - Function {redrawoscil()} {} { - code {oscildisplaygroup->redraw(); + Function {redrawoscil()} {open + } { + code {//get data from backend +oscilo->update(); +oscils->update(); +oscilo_base->update(); +oscils_base->update(); + +oscildisplaygroup->redraw(); oldosc->redraw(); if (cbwidget!=NULL) { cbwidget->do_callback(); @@ -1143,8 +1047,18 @@ if (cbwidget!=NULL) { applybutton->redraw(); };} {} } - decl {OscilGen *oscil;} {} - decl {Fl_Widget *oldosc,*cbwidget,*cbapplywidget;} {} - decl {Oscilharmonic *h[MAX_AD_HARMONICS];} {} - decl {Master *master;} {} + decl {OscilGen *oscil;} {private local + } + decl {Fl_Widget *oldosc,*cbwidget,*cbapplywidget;} {private local + } + decl {Oscilharmonic *h[MAX_AD_HARMONICS];} {private local + } + decl {std::string loc;} {private local + } + decl {Fl_Osc_Interface *osc;} {private local + } + decl {Fl_Oscilloscope *oscilo, *oscilo_base;} {private local + } + decl {Fl_OscilSpectrum *oscils, *oscils_base;} {private local + } } diff --git a/src/UI/PADnoteUI.fl b/src/UI/PADnoteUI.fl @@ -38,7 +38,7 @@ decl {\#include <stdlib.h>} {private local decl {\#include <string.h>} {private local } -decl {\#include <string>} {selected public local +decl {\#include <string>} {public local } decl {\#include "WidgetPDial.h"} {public local @@ -242,20 +242,25 @@ for (int i=0;i<lx;i++){ class PADnoteUI {open : {public PresetsUI_} } { - Function {PADnoteUI(PADnoteParameters *parameters, std::string location_, Master *master_)} {open + Function {PADnoteUI(PADnoteParameters *parameters, std::string location_, Fl_Osc_Interface *osc_, Master *master_)} {open } { - code {location=location_; + code {assert(osc_); +assert(!location_.empty()); + +location=location_; pars=parameters; master=master_; oscui=NULL; +osc_i = osc_; resui=new ResonanceUI(pars->resonance); -make_window();} {} +make_window();} {selected + } } Function {make_window()} {open } { Fl_Window padnotewindow { label {PAD synth Parameters} open - xywh {297 415 535 435} type Double visible + xywh {303 461 535 435} type Double visible } { Fl_Tabs {} { callback {if (o->value()!=harmonicstructuregroup) applybutton->hide(); @@ -437,15 +442,16 @@ cbwidget->do_callback();} class WidgetPDial } } - Fl_Group {} { + Fl_Group oscilgroup { xywh {100 155 270 135} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 align 6 - code0 {osc=new Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} - code1 {osc->init(pars->oscilgen,master);} + code0 {osc=new Fl_Oscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {oscilgroup->pane_name = location+"oscil/"; oscilgroup->osc = osc_i;osc->init(false);//pars->oscilgen,master);} + class Fl_Osc_Group } {} Fl_Button {} { label Change callback {if (oscui!=NULL) delete (oscui); -oscui=new OscilEditor(pars->oscilgen,osc,cbwidget,applybutton,master);} +oscui=new OscilEditor(pars->oscilgen,osc,cbwidget,applybutton,location+"oscil/",osc_i);} xywh {375 270 60 20} box THIN_UP_BOX labelfont 1 labelsize 11 } Fl_Box cbwidget { @@ -1016,7 +1022,8 @@ pars->export2wav(filename);} } } } - Function {refresh()} {} { + Function {refresh()} {open + } { code {volume->value(pars->PVolume); vsns->value(pars->PAmpVelocityScaleFunction); pan->value(pars->PPanning); @@ -1122,10 +1129,12 @@ delete(padnotewindow);} {} } decl {OscilEditor *oscui;} {public local } - decl {Oscilloscope *osc;} {public local + decl {Fl_Oscilloscope *osc;} {public local } decl {ResonanceUI *resui;} {public local } decl {std::string location;} {private local } + decl {Fl_Osc_Interface *osc_i;} {private local + } } diff --git a/src/UI/PartUI.fl b/src/UI/PartUI.fl @@ -17,7 +17,7 @@ decl {\#include <stdio.h>} {public local decl {\#include <string.h>} {public local } -decl {\#include <string>} {selected public local +decl {\#include <string>} {public local } decl {\#include "WidgetPDial.h"} {public local @@ -52,7 +52,7 @@ class PartSysEffSend {open : {public Fl_Group} Function {make_window()} {open private } { Fl_Window syseffsend { - private xywh {592 152 100 100} type Double box NO_BOX + private xywh {598 198 100 100} type Double box NO_BOX class Fl_Group visible } { Fl_Dial {} { @@ -96,7 +96,7 @@ class PartKitItem {open : {public Fl_Group} Function {make_window()} {open private } { Fl_Window partkititem { - private xywh {476 429 670 100} type Double box NO_BOX + private xywh {482 475 670 100} type Double box NO_BOX class Fl_Group visible } { Fl_Group partkititemgroup { @@ -287,7 +287,7 @@ class PartUI {open : {public Fl_Group} Function {make_window()} {open private } { Fl_Window partgroup {open - private xywh {691 287 385 180} type Double box NO_BOX + private xywh {697 333 385 180} type Double box NO_BOX class Fl_Group visible } { Fl_Group partgroupui {open @@ -465,7 +465,7 @@ if (part->Penabled==0) partgroupui->deactivate(); } Fl_Window ctlwindow { label Controllers open - private xywh {777 284 500 130} type Double box NO_BOX visible + private xywh {777 330 500 130} type Double box NO_BOX visible } { Fl_Check_Button {} { label Expr @@ -648,7 +648,7 @@ else {propta->deactivate();proptb->deactivate();}} } Fl_Window partfx { label {Part's Insert Effects} - private xywh {557 683 390 145} type Double box NO_BOX visible + private xywh {563 729 390 145} type Double box NO_BOX visible } { Fl_Counter inseffnocounter { label {FX No.} @@ -769,7 +769,7 @@ pthread_mutex_unlock(&master->mutex);} } Fl_Window instrumentkitlist { label {Instrument Kit} open - xywh {589 589 670 370} type Double box NO_BOX visible + xywh {595 611 670 370} type Double box NO_BOX visible } { Fl_Button {} { label {Close Window} @@ -850,7 +850,7 @@ if (part->Pkitmode==0) { } Fl_Window instrumenteditwindow { label {Instrument Edit} open - xywh {250 621 395 360} type Double box NO_BOX visible + xywh {256 621 395 360} type Double box NO_BOX visible } { Fl_Group {} { xywh {0 220 395 110} box UP_FRAME @@ -1026,20 +1026,27 @@ if (x==0) subeditbutton->deactivate(); } } } - Function {PartUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + Function {PartUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {open + } { code {part=NULL; adnoteui=NULL; subnoteui=NULL; padnoteui=NULL; lastkititem=-1;} {} } - Function {init(Part *part_, std::string part_path_, Master *master_,int npart_,BankUI *bankui_)} {} { - code {bankui=bankui_; - part_path = part_path_; + Function {init(Part *part_, std::string part_path_, Master *master_,int npart_,BankUI *bankui_, std::string loc_, Fl_Osc_Interface *osc_)} {open + } { + code {assert(osc_); +assert(!loc_.empty()); + +bankui=bankui_; +part_path = part_path_; part=part_; npart=npart_; master=master_; ninseff=0; +osc=osc_; +loc=loc_; make_window(); partgroup->position(this->parent()->x()+2,this->parent()->y()+2); @@ -1065,9 +1072,11 @@ while (klimits[k]!=0){ }; if (val==-1) val=k; -keylimitlist->value(val);} {} +keylimitlist->value(val);} {selected + } } - Function {showparameters(int kititem,int engine)} {} { + Function {showparameters(int kititem,int engine)} {open + } { code {if (engine==-1){//this is used if I want to clear the engine from the part if (kititem==lastkititem) kititem=-1; else kititem=lastkititem; @@ -1083,8 +1092,8 @@ if (kititem!=lastkititem){ if (kititem>=NUM_KIT_ITEMS) return;//bad kit item if (kititem<0) return; - if (part->kit[kititem].adpars!=NULL) - adnoteui=new ADnoteUI(part->kit[kititem].adpars,master); + if (part->kit[kititem].adpars!=NULL) + adnoteui=new ADnoteUI(part->kit[kititem].adpars,master, loc+"kit"+to_s(kititem)+"/adpars/", osc); if (part->kit[kititem].subpars!=NULL) subnoteui=new SUBnoteUI(part->kit[kititem].subpars); @@ -1092,7 +1101,7 @@ if (kititem!=lastkititem){ if (part->kit[kititem].padpars!=NULL) { char buffer[1024]; snprintf(buffer, 1024, "%skit%d/padpars/", part_path.c_str(), kititem); - padnoteui=new PADnoteUI(part->kit[kititem].padpars, buffer, master); + padnoteui=new PADnoteUI(part->kit[kititem].padpars, buffer, osc, master); } }; @@ -1147,4 +1156,8 @@ delete(instrumenteditwindow);} {} } decl {std::string part_path;} {private local } + decl {std::string loc;} {private local + } + decl {Fl_Osc_Interface *osc;} {private local + } } diff --git a/src/UI/VuMasterMeter.h b/src/UI/VuMasterMeter.h @@ -6,7 +6,11 @@ class VuMasterMeter: public VuMeter { public: VuMasterMeter(int x,int y, int w, int h, const char *label=0) - :VuMeter(x,y,w,h,label),osc(NULL) + :VuMeter(x,y,w,h,label), + olddbl(0.0f),olddbr(0.0f), + oldrmsdbl(0.0f),oldrmsdbr(0.0f), + dbl(0.0f),dbr(0.0f),rmsdbl(0.0f),rmsdbr(0.0f),maxdbl(0.0f),maxdbr(0.0f), + clipped(0),osc(NULL) {} void init(Fl_Osc_Interface *_osc) @@ -27,10 +31,10 @@ class VuMasterMeter: public VuMeter osc->requestValue("/reset-vu"); break; } - + return 1; } - + static void tick(void *v) { Fl::repeat_timeout(1.0/18.0,tick,v);//18 fps diff --git a/src/UI/VuPartMeter.h b/src/UI/VuPartMeter.h @@ -5,7 +5,7 @@ class VuPartMeter: public VuMeter { public: VuPartMeter(int x,int y, int w, int h, const char *label=0) - :VuMeter(x,y,w,h,label) + :VuMeter(x,y,w,h,label), db(0.0f) {} void draw(void) diff --git a/src/main.cpp b/src/main.cpp @@ -22,6 +22,7 @@ #include <iostream> +#include <map> #include <cmath> #include <cctype> #include <algorithm> @@ -49,12 +50,13 @@ extern Dump dump; //GUI System #include "UI/Fl_Osc_Interface.h" +#include "UI/Fl_Osc_Widget.H" #include "UI/Connection.h" GUI::ui_handle_t gui; //The Glue -rtosc::ThreadLink *bToU = new rtosc::ThreadLink(1024,1024); -rtosc::ThreadLink *uToB = new rtosc::ThreadLink(1024,1024); +rtosc::ThreadLink *bToU = new rtosc::ThreadLink(4096*2,1024); +rtosc::ThreadLink *uToB = new rtosc::ThreadLink(4096*2,1024); using namespace std; @@ -229,16 +231,53 @@ void initprogram(void) class UI_Interface:public Fl_Osc_Interface { - void requestValue(string s) - { - if(last_url != "GUI") { - uToB->write("/echo", "ss", "OSC_URL", "GUI"); + public: + void requestValue(string s) override + { + //Fl_Osc_Interface::requestValue(s); + if(last_url != "GUI") { + uToB->write("/echo", "ss", "OSC_URL", "GUI"); last_url = "GUI"; + } + + uToB->write(s.c_str(),""); } - uToB->write(s.c_str(),""); + void writeValue(string s, char c) + { + Fl_Osc_Interface::writeValue(s,c); + uToB->write(s.c_str(), "c", c); + } - } + void createLink(string s, class Fl_Osc_Widget*w) override + { + Fl_Osc_Interface::createLink(s,w); + map.insert(std::pair<string,Fl_Osc_Widget*>(s,w)); + } + + void removeLink(string s, class Fl_Osc_Widget*w) override + { + for(auto i = map.begin(); i != map.end(); ++i) { + if(i->first == s && i->second == w) + map.erase(i); + } + printf("[%d] removing '%s' (%p)...\n", map.size(), s.c_str(), w); + } + + virtual void tryLink(const char *msg) override + { + for(auto pair:map) { + //printf("'%s' :=> '%p'\n", pair.first.c_str(), pair.second); + if(pair.first == msg) { + //printf("Possible location for application of '%s' is '%p'\n", msg, pair.second); + if(!strcmp(rtosc_argument_string(msg), "b")) + pair.second->OSC_value(rtosc_argument(msg,0).b.len,rtosc_argument(msg,0).b.data); + } + } + }; + + private: + std::multimap<string,Fl_Osc_Widget*> map; } ui_link;