zynaddsubfx

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

commit 299a4e2dde8dce06fc95fe905c059110608d6310
parent 96f21123fe87f2c63b69542af356c5fc36c69800
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Tue, 25 Aug 2015 20:49:52 -0400

Merge branch 'master' of ssh://git.code.sf.net/p/zynaddsubfx/code

Conflicts:
	src/Misc/Master.cpp
	src/Misc/Master.h
	src/Misc/MiddleWare.cpp
	src/Misc/Part.cpp
	src/Misc/Part.h
	src/Synth/PADnote.cpp
	src/Synth/PADnote.h
	src/Tests/InstrumentStats.cpp
	src/Tests/SubNoteTest.h
	src/Tests/UnisonTest.h

Diffstat:
MHISTORY.txt | 2+-
Mdoc/adsynth.txt | 10+++++-----
Mdoc/controller.txt | 16++++++++--------
Mdoc/effects.txt | 40++++++++++++++++++++--------------------
Mdoc/getting.txt | 4++--
Mdoc/intro.txt | 4++--
Mdoc/lfo.txt | 18+++++++++---------
Msrc/CMakeLists.txt | 8++++++--
Msrc/Containers/NotePool.cpp | 1+
Msrc/DSP/Unison.cpp | 1+
Msrc/Effects/EQ.cpp | 31++++++++-----------------------
Msrc/Effects/EQ.h | 4++--
Msrc/Effects/EffectLFO.cpp | 3++-
Msrc/Effects/EffectMgr.cpp | 47++++++++++++++++++++++++++++++-----------------
Msrc/Effects/EffectMgr.h | 13+++----------
Msrc/Misc/Allocator.cpp | 18+++++++++---------
Msrc/Misc/Allocator.h | 49+++++++++++++++++++++++++++++++++++++++----------
Msrc/Misc/Bank.cpp | 16++++++++--------
Msrc/Misc/Bank.h | 5++++-
Msrc/Misc/CMakeLists.txt | 1+
Msrc/Misc/Config.cpp | 37++++++++++++++++++-------------------
Msrc/Misc/Config.h | 27+++++++++++++++++++--------
Msrc/Misc/Master.cpp | 17+++++++++++------
Msrc/Misc/Master.h | 3++-
Msrc/Misc/Microtonal.cpp | 5+++--
Msrc/Misc/Microtonal.h | 4+++-
Msrc/Misc/MiddleWare.cpp | 163+++++++++++++++++++++----------------------------------------------------------
Msrc/Misc/MiddleWare.h | 8+++++++-
Msrc/Misc/Part.cpp | 31+++++++++++++++++++------------
Msrc/Misc/Part.h | 5++++-
Msrc/Misc/PresetExtractor.cpp | 20+++++++++++---------
Asrc/Misc/TmpFileMgr.cpp | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/TmpFileMgr.h | 18++++++++++++++++++
Msrc/Misc/Util.cpp | 5+----
Msrc/Misc/Util.h | 6------
Msrc/Misc/XMLwrapper.cpp | 5++---
Msrc/Misc/XMLwrapper.h | 2+-
Msrc/Nio/EngineMgr.cpp | 11++++++-----
Msrc/Nio/EngineMgr.h | 6++++--
Msrc/Nio/Nio.cpp | 6++++--
Msrc/Nio/Nio.h | 3++-
Msrc/Nio/OssEngine.cpp | 12++++++++----
Msrc/Nio/OssEngine.h | 6+++++-
Msrc/Nio/OssMultiEngine.cpp | 8+++++---
Msrc/Nio/OssMultiEngine.h | 5++++-
Msrc/Nio/OutMgr.h | 3++-
Msrc/Output/DSSIaudiooutput.cpp | 6+-----
Msrc/Output/DSSIaudiooutput.h | 5+++--
Msrc/Params/PresetsStore.cpp | 7++++---
Msrc/Params/PresetsStore.h | 5+++--
Msrc/Synth/ADnote.cpp | 4++--
Msrc/Synth/OscilGen.cpp | 5++++-
Msrc/Synth/PADnote.cpp | 8++++----
Msrc/Synth/PADnote.h | 4+++-
Msrc/Synth/SUBnote.cpp | 4++--
Msrc/Tests/AdNoteTest.h | 14++------------
Msrc/Tests/AllocatorTest.h | 2+-
Msrc/Tests/EchoTest.h | 2+-
Msrc/Tests/InstrumentStats.cpp | 13+++++--------
Msrc/Tests/KitTest.h | 11++++-------
Msrc/Tests/MicrotonalTest.h | 8+++++---
Msrc/Tests/MiddlewareTest.h | 19++++++++++---------
Msrc/Tests/OscilGenTest.h | 7-------
Msrc/Tests/PadNoteTest.h | 16++++------------
Msrc/Tests/PluginTest.h | 9++-------
Msrc/Tests/RandTest.h | 2--
Msrc/Tests/SubNoteTest.h | 10+---------
Msrc/Tests/UnisonTest.h | 9+--------
Msrc/UI/ADnoteUI.fl | 14+++++++-------
Msrc/UI/CMakeLists.txt | 10++++++++--
Msrc/UI/EffUI.fl | 10++++++++--
Msrc/UI/EnvelopeFreeEdit.cpp | 10++++++++++
Msrc/UI/EnvelopeFreeEdit.h | 9+++++----
Msrc/UI/Fl_EQGraph.H | 4++--
Msrc/UI/Fl_EQGraph.cpp | 22+++++++++++++++-------
Msrc/UI/Fl_Osc_Dial.cpp | 12+++++++-----
Msrc/UI/Fl_Osc_DialF.H | 2+-
Msrc/UI/Fl_Osc_Output.H | 3+--
Msrc/UI/Fl_Osc_Output.cpp | 6+++---
Msrc/UI/Fl_OscilSpectrum.h | 2+-
Msrc/UI/Fl_PADnoteOvertonePosition.h | 2+-
Msrc/UI/FormantFilterGraph.H | 2+-
Msrc/UI/MasterUI.fl | 6+++---
Msrc/UI/OscilGenUI.fl | 8+++++++-
Msrc/UI/PartUI.fl | 8++++++--
Msrc/UI/SUBnoteUI.fl | 31+++++++++++++++++++++++--------
Asrc/globals.cpp | 43+++++++++++++++++++++++++++++++++++++++++++
Msrc/globals.h | 45++++++++++++++++++++++++++++++++++-----------
Msrc/main.cpp | 33++++++++++++++-------------------
Mzynaddsubfx-alsa.desktop | 1+
Mzynaddsubfx-jack.desktop | 1+
91 files changed, 740 insertions(+), 535 deletions(-)

diff --git a/HISTORY.txt b/HISTORY.txt @@ -1,4 +1,4 @@ -2.5.1 (18+ June 2015) +2.5.1 (4 July 2015) - Add Colorized CMake Configuration - Add PID option for jack - Add OSC port option diff --git a/doc/adsynth.txt b/doc/adsynth.txt @@ -17,21 +17,21 @@ image::gen/ad-note.png[scalewidth="50%",width="700"] The global level of adsynth is almost entirely composed of previously discussed elements. However a few new features appear here, this includes velocity sensing, punch, -detune options and realative bandwidth , and resonance. +detune options and relative bandwidth , and resonance. .AdSynth Global Window image::images/ad-global.png[] -Velocity sensing is simply an exponental transformation from the note's velocity +Velocity sensing is simply an exponential transformation from the note's velocity to some parameter change. -The below diagram shows how the velocity senseing controls affects this +The below diagram shows how the velocity sensing controls affects this translation over the whole range of possible note velocities. .Velocity Sensing Chart image::gen/velf.png[scalewidth="50%",width="600"] -The puch of a note in AdSynth is a constant amplification to the output at the +The punch of a note in AdSynth is a constant amplification to the output at the start of the note, with its length determined by the punch time and stretch and the amplitude being determined by the punch strength and velocity sensing. The relBW control in the frequency pane is effectively a multiplier for detuning @@ -88,7 +88,7 @@ Waveshaping can be done using the *Wsh* area in the Oscillator editor. The type of distortion has much influence on how the overtones are being placed. Sometimes, you get a "fat" bass, and sometimes, high frequencies are added, -makeing the sound "crystal clear". +making the sound "crystal clear". Atan & Sigmoid ++++++++++++++ diff --git a/doc/controller.txt b/doc/controller.txt @@ -6,13 +6,13 @@ image::./images/uicontroller.png[] General ~~~~~~~ -* *ModWh*: Modullation Wheel depth -* *Exp MWh*: Exponental Modulation Wheel (changes modulation scale to - exponental) +* *ModWh*: Modulation Wheel depth +* *Exp MWh*: Exponential Modulation Wheel (changes modulation scale to + exponential) * *BwDpth*: Bandwidth Depth -* *Exp BW*: Exponental Bandwidth (changes badwidth scale to exponental) +* *Exp BW*: Exponential Bandwidth (changes bandwidth scale to exponential) * *PanDpth*: Panning Depth -* *FltQ*: Filter Q (ressonance) depth +* *FltQ*: Filter Q (resonance) depth * *FltCut* Filter Cutoff frequency depth * *Expr*: enable/disable expression * *Vol*: enable/disable receiving volume controller @@ -27,7 +27,7 @@ Portamento * *time*: The duration of the portamento * *thresh*: The threshold of the portamento. It represents the minimum or the maximum number of halftones -(or hundried cents) required to start the portamento. +(or hundred cents) required to start the portamento. The difference is computed between the last note and current note. * *th.type*: The threshold type. Checked means that the portamento activates when the difference of frequencies @@ -37,13 +37,13 @@ NOTE: The threshold refers to the frequencies and not to MIDI notes (you should consider this if you use microtonal scales). -Proportinal Portamento +Proportional Portamento ^^^^^^^^^^^^^^^^^^^^^^ //// TODO: add graphs to explain prp.rate and prp. depth //// -* *Propt.*: If the portamento is proportinal to ratio of frequencies +* *Propt.*: If the portamento is proportional to ratio of frequencies * *Prp. Rate*: Ratio needed to double the time of portamento * *Prp. Dpth*: The divergence from diff --git a/doc/effects.txt b/doc/effects.txt @@ -1,7 +1,7 @@ Effects ------- -Effects are, generally, blackboxes that transform audio signals in a +Effects are, generally, black boxes that transform audio signals in a specified way. More exactly, the only input data for an effect in ZynAddSubFX is: @@ -123,7 +123,7 @@ electronic music, we only have an input wave and need to generate these different timbres by ourselves. ZynAddSubFX therefore simply plays the sound, pitch modulated by an LFO, and adds this to the original sound. This explains the diagram below: The multiple pitches are generated by a delayed version of -the input. This version is being pitched by an LFO. More detailled, this pitch +the input. This version is being pitched by an LFO. More detailed, this pitch is generated by varying the reading speed of the delayed sound; the variation amount is controlled by an LFO. @@ -134,8 +134,8 @@ TODO: Add LFO pointing to delay? Related effects to Chorus are Flangers. Flangers can be described as Chorus with very short LFO delay and little LFO depth. You can imagine a flanger as two -copies of a sound playing at almost the same time. This leeds to interference, -which can be clearly heared. It is popular to apply flangers to guitars, giving +copies of a sound playing at almost the same time. This leads to interference, +which can be clearly heard. It is popular to apply flangers to guitars, giving them more "character". Usage @@ -149,8 +149,8 @@ changed at all. the delay also depends on the current pitch. * After the correct element of the sound buffer is found using the LFO, the *Fb* knob lets you set how loud it shall be played. This is mostly redundant to -the *D/W* knob, but we have not applied panning and substraction yet. -* Next, the singal can be negated. If the *Substract* Checkbox is activated, +the *D/W* knob, but we have not applied panning and subtraction yet. +* Next, the signal can be negated. If the *Substract* checkbox is activated, the amplitude is multiplied by -1. * Finally, *Pan* lets you apply panning. @@ -175,7 +175,7 @@ Distortion can happen in many situations when working with audio. Often, this is not wanted. In classical music, for example, distortion does not occur naturally. However, distortion can also be a wanted effect. It is typical for Rock guitars, but also present in electronic music, mostly in Dubstep and -DrumNBass. +Drum & Bass. The basic components of distortion are mainly @@ -215,18 +215,18 @@ We explain the functionality in a diagram and list the components below. image:./gen/distort.png[width=700, title="The components of a distortion function."] -* Negation is the first thing to happen. If the *Neg* Checkbox is activated, the +* Negation is the first thing to happen. If the *Neg* checkbox is activated, the amplitude is multiplied by -1. * Panning is applied. Note, however, that you have to activate the Stereo Checkbox, labeled *St*, before. -* Pre amplification is done next. The amount can be changed using the +* Preamplification is done next. The amount can be changed using the *Drive* nob. Indeed, this is the amount of distortion. For example, if you clip a signal, the louder the input gets, the more distortion you will get. This can have different meanings for different types of distortion, as described above. * *HPF* and *LPF* are filters with 2 poles. Whether they are used before or after the waveshape, depends on the checkbox labeled *PF*. * The next step is the wave shape. This defines how the wave is -actually modified. The *Type* ComboBox lets you define how. We will discuss some +actually modified. The *Type* combo box lets you define how. We will discuss some types below. * After the wave shape, we scale the level again. This is called output amplification. You can change the value using the *Level* knob. @@ -383,7 +383,7 @@ Function As mentioned, a reverb consists of permanent echo. The reverb in ZynAddSubFX is more complex than the echo. After the delaying, comb filters and then allpass filters are being applied. These make the resulting sound more realistic. The -parameters for these filters depend on the roomsize. For details, consider the +parameters for these filters depend on the room size. For details, consider the information about https://ccrma.stanford.edu/~jos/pasp/Freeverb.html[Freeverb]. image:./gen/reverb.png[width=700, @@ -392,13 +392,13 @@ image:./gen/reverb.png[width=700, Description ^^^^^^^^^^^ -* The *Type* ComboBox lets you select a reverb type: +* The *Type* combo box lets you select a reverb type: ** *Freeverb* is a preset. It was proposed by Jezar at Dreampoint. ** *Bandwidth* has the same parameters for the comb and allpass filters, but it applies a unison before the LP/HP. The unison's bandwidth can be set using *bw*. ** Random chooses a random layout for comb and allpass each time the type or -the roomsize is being changed. -* The roomsize (*R.S.*) defines parameters only for the comb and allpass +the room size is being changed. +* The room size (*R.S.*) defines parameters only for the comb and allpass filters. * *Time* controls how long the whole reverb shall take, including how slow the volume is decreased. @@ -435,8 +435,8 @@ signal, which *preserves* the amplitude, but determines the delay time. In the end, both paths are added. The following picture describes how this works on white noise. Light blue -signalises that the frequency is not present at the current time, and dark blue -signalises the opposite. The dark blue peaks appear if the delay time is very +signalizes that the frequency is not present at the current time, and dark blue +signalizes the opposite. The dark blue peaks appear if the delay time is very short, because then, the second path almost equals the first one, which results in duplication of the signal. If the delay line is very long, then it is --- in the case of white noise --- totally at random whether the delayed signal @@ -468,7 +468,7 @@ Description For the normal phaser, first, the LFO is generated: -* There are 4 controls (*Freq*,*Rnd*,*LFO tpye*,*St.df*) that define the +* There are 4 controls (*Freq*,*Rnd*,*LFO type*,*St.df*) that define the LFO. * *Phase* and *Depth* are applied afterwards in the usual way (TODO: I don't understand the code here for the normal phase...). For the analog phaser, @@ -504,14 +504,14 @@ Function ^^^^^^^^ The way that the filter moves between the two vocals is mainly -described by an LFO. A bit easified, Paul Nasca has stated the formula (for +described by an LFO. A bit simplified, Paul Nasca has stated the formula (for latexmath:[$i^2=-1; R<1$]) as latexmath:[$fb=R*(\cos(\alpha)+i*\sin(\alpha))$] latexmath:[$y_n=y_{n-delay}*R*(\cos(\alpha)+i*\sin(\alpha))+x_n*(1-R)$]. -The input latexmath:[$x_n$] has the real part of the samples from the wavefile +The input latexmath:[$x_n$] has the real part of the samples from the wave file and the imaginary part is zero. The output of this effect is the real part of latexmath:[$y_n$]. latexmath:[$\alpha$] is the phase. @@ -519,7 +519,7 @@ Description ^^^^^^^^^^^ * *Pan* -* The following 5 controls (*Freq*,*Rnd*,*LFO tpye*,*St.df*, *Dpth*) define the +* The following 5 controls (*Freq*,*Rnd*,*LFO type*,*St.df*, *Dpth*) define the LFO. ** *Fb* diff --git a/doc/getting.txt b/doc/getting.txt @@ -5,7 +5,7 @@ Usually there are several methods to obtain a copy of ZynAddSubFX. SourceForge:: http://sourceforge.net/projects/zynaddsubfx/files/ -Distribuition:: +Distribution:: apt/yum/others Git:: git clone git://git.code.sf.net/p/zynaddsubfx/code zynaddsubfx @@ -14,7 +14,7 @@ Introduction to Git ~~~~~~~~~~~~~~~~~~~ For those who want to live on the bleeding edge or who want to assist with -making sure that the next release has fewer bugs, you will want to get aquanted +making sure that the next release has fewer bugs, you will want to get acquainted with git. Git is used to manage the source code for this project and can be used to quickly and easily get an up-to-date copy of the source code. diff --git a/doc/intro.txt b/doc/intro.txt @@ -3,7 +3,7 @@ Getting Started ZynAddSubFX is a fairly complex software synthesizer with a very large number of controls. -As such, it is not alway obvious how to use ZynAddSubFX. +As such, it is not always obvious how to use ZynAddSubFX. Many applications under Linux transport MIDI over ALSA and transmit audio over JACK. @@ -21,7 +21,7 @@ Currently the beginner interface is deprecated, so the advanced one is recommended. Now you should be able to see ZynAddSubFX's main window, from which you can -setup patches, effects, and general configurations, but more importatnly it +setup patches, effects, and general configurations, but more importantly it provides links into the parameters of the patches. ZynAddSubFX is a powerful tool with a number of base patches, but its true power lies in the ability to make your own patches. diff --git a/doc/lfo.txt b/doc/lfo.txt @@ -7,13 +7,13 @@ Introduction "LFO" means Low Frequency Oscillator. These oscillators are not used to make sounds by themselves, but they changes -somes parameters (like the frequencies, the amplitudes or the filters). +some parameters (like the frequencies, the amplitudes or the filters). -The LFOs has some basic parameters: +The LFOs have some basic parameters: * *Delay*: This parameter sets how much time takes since the start of the note to the start of the LFO -* *Start Phase*: The possition that a LFO will start at +* *Start Phase*: The position that a LFO will start at * *Frequency*: How fast the LFO is (i.e. how fast the parameter's controlled by the LFO changes) * *Depth*: The amplitude of the LFO (i.e. how much the parameter's controlled @@ -23,7 +23,7 @@ image:images/lfo0.png[] Another important LFO parameter is the shape. There are many LFO Types according to the shape. -ZynAddSubFX supports the folowing LFO shapes: +ZynAddSubFX supports the following LFO shapes: image:images/lfo1.png[] @@ -31,15 +31,15 @@ Another parameter is the LFO Randomness. It modifies the LFO amplitude or the LFO frequency at random. In ZynAddSubFX you can choose how much the LFO frequency or LFO amplitude changes by this parameter. -In the folowing images are shown some examples of randomness and how changes +In the following images are shown some examples of randomness and how changes the shape of a triangle LFO. image:images/lfo2.png[] Other parameters are: -* *Continous mode*: If this mode is used, the LFO will not start from "zero" on each new note, but it will be continuous. This is very usefull if you apply on filters to make interesting sweeps. -* *Stretch*: It controlls how much the LFO frequency changes according to the +* *Continous mode*: If this mode is used, the LFO will not start from "zero" on each new note, but it will be continuous. This is very useful if you apply on filters to make interesting sweeps. +* *Stretch*: It controls how much the LFO frequency changes according to the note's frequency. It can vary from negative stretch (the LFO frequency is decreased on higher notes) to zero (the LFO frequency will be the same on all notes) to positive @@ -52,14 +52,14 @@ In ZynAddSubFX, LFO parameters are shown as: image:images/uilfo.jpg[] -Theese parameters are: +These parameters are: * *Freq*: LFO Frequency * *Depth*: LFO Depth * *Start*: LFO Start Phase - If this knob is at the lowest value, the LFO Start Phase will be random. * *Delay*: LFO Delay -* *A.R.*: LFO Amplitude Randomnes +* *A.R.*: LFO Amplitude Randomness * *F.R.*: LFO Frequency Randomness * *C.*: LFO Continous Mode * *Str.*: LFO Stretch - in the image above the LFO stretch is set to zero diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -4,9 +4,11 @@ message(STATUS "Checking Library Path" $ENV{CMAKE_LIBRARY_PATH} ${CMAKE_LIBRARY_ #Dependency check include(CheckFunctionExists) +include(CheckIncludeFile) find_package(PkgConfig REQUIRED) find_package(zlib REQUIRED) find_package(X11) +check_include_file(X11/xpm.h HAS_XPM) pkg_check_modules(FFTW REQUIRED fftw3) pkg_check_modules(MXML REQUIRED mxml) find_package(Threads REQUIRED) @@ -267,7 +269,7 @@ if(FltkGui) set(GUI_LIBRARIES zynaddsubfx_gui ${FLTK_LIBRARIES} ${FLTK_LIBRARIES} ${OPENGL_LIBRARIES}) - if(X11_FOUND) + if(X11_FOUND AND HAS_XPM) set(GUI_LIBRARIES ${GUI_LIBRARIES} ${X11_LIBRARIES} -lXpm) endif() @@ -291,7 +293,7 @@ if(NtkGui) set(GUI_LIBRARIES zynaddsubfx_gui ${NTK_LIBRARIES} ${NTK_IMAGES_LIBRARIES} ${OPENGL_LIBRARIES}) - if(X11_FOUND) + if(X11_FOUND AND HAS_XPM) set(GUI_LIBRARIES ${GUI_LIBRARIES} ${X11_LIBRARIES} -lXpm) endif() @@ -346,6 +348,7 @@ add_subdirectory(DSP) add_subdirectory(Nio) add_library(zynaddsubfx_core STATIC + globals.cpp ../tlsf/tlsf.c Containers/NotePool.cpp ${zynaddsubfx_dsp_SRCS} @@ -385,6 +388,7 @@ if (DssiEnable) add_library(zynaddsubfx_dssi SHARED UI/ConnectionDummy.cpp Output/DSSIaudiooutput.cpp + globals.cpp ) target_link_libraries(zynaddsubfx_dssi diff --git a/src/Containers/NotePool.cpp b/src/Containers/NotePool.cpp @@ -7,6 +7,7 @@ #include <cassert> NotePool::NotePool(void) + :needs_cleaning(0) { memset(ndesc, 0, sizeof(ndesc)); memset(sdesc, 0, sizeof(ndesc)); diff --git a/src/DSP/Unison.cpp b/src/DSP/Unison.cpp @@ -24,6 +24,7 @@ #include "../Misc/Allocator.h" #include "Unison.h" +#include "globals.h" #ifndef errx #include <err.h> diff --git a/src/Effects/EQ.cpp b/src/Effects/EQ.cpp @@ -205,41 +205,26 @@ float EQ::getfreqresponse(float freq) return rap2dB(resp * outvolume); } -//full taps & three filter taps -static void convolve(float *a, const float *filter) -{ - float tmp[MAX_EQ_BANDS*2+1]; - - for(int i=0; i<MAX_EQ_BANDS*2+1; ++i) - tmp[i] = a[i]; - - //Base Case - a[0] = tmp[0]*filter[0]; - a[1] = tmp[0]*filter[1] + tmp[1]*filter[0]; - - for(int i=2; i<MAX_EQ_BANDS+1; ++i) { - a[i] = filter[0]*tmp[i] + - filter[1]*tmp[i-1] + - filter[2]*tmp[i-2]; - } -} - //Not exactly the most efficient manner to derive the total taps, but it should //be fast enough in practice void EQ::getFilter(float *a, float *b) const { a[0] = 1; b[0] = 1; + off_t off=0; for(int i = 0; i < MAX_EQ_BANDS; ++i) { auto &F = filter[i]; if(F.Ptype == 0) continue; - float Fb[3] = {F.l->coeff.c[0], F.l->coeff.c[1], F.l->coeff.c[2]}; - float Fa[3] = {1.0f, -F.l->coeff.d[1], -F.l->coeff.d[2]}; + const double Fb[3] = {F.l->coeff.c[0], F.l->coeff.c[1], F.l->coeff.c[2]}; + const double Fa[3] = {1.0f, -F.l->coeff.d[1], -F.l->coeff.d[2]}; for(int j=0; j<F.Pstages+1; ++j) { - convolve(b, Fb); - convolve(a, Fa); + for(int k=0; k<3; ++k) { + a[off] = Fa[k]; + b[off] = Fb[k]; + off++; + } } } } diff --git a/src/Effects/EQ.h b/src/Effects/EQ.h @@ -38,8 +38,8 @@ class EQ:public Effect void cleanup(void); float getfreqresponse(float freq); - void getFilter(float *a/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]*/, - float *b/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]*/) const; + void getFilter(float *a/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]*/, + float *b/*[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]*/) const; private: //Parameters unsigned char Pvolume; diff --git a/src/Effects/EffectLFO.cpp b/src/Effects/EffectLFO.cpp @@ -24,6 +24,7 @@ #include "../Misc/Util.h" #include <cmath> +#include "globals.h" EffectLFO::EffectLFO(float srate_f, float bufsize_f) :Pfreq(40), @@ -79,7 +80,7 @@ float EffectLFO::getlfoshape(float x) break; //when adding more, ensure ::updateparams() gets updated default: - out = cosf(x * 2.0f * PI); //EffectLFO_SINE + out = cosf(x * 2.0f * PI); //EffectLFO_SINE // TODO: use M_PI ? } return out; } diff --git a/src/Effects/EffectMgr.cpp b/src/Effects/EffectMgr.cpp @@ -26,12 +26,14 @@ #include "EffectMgr.h" #include "Effect.h" +#include "Alienwah.h" #include "Reverb.h" #include "Echo.h" #include "Chorus.h" #include "Distorsion.h" #include "EQ.h" #include "DynamicFilter.h" +#include "Phaser.h" #include "../Misc/XMLwrapper.h" #include "../Misc/Util.h" #include "../Params/FilterParams.h" @@ -43,7 +45,7 @@ static const rtosc::Ports local_ports = { rSelf(EffectMgr), rPaste, rRecurp(filterpars, "Filter Parameter for Dynamic Filter"), - {"parameter#64::i", rProp(alias) rDoc("Parameter Accessor"), NULL, + {"parameter#128::i", rProp(alias) rDoc("Parameter Accessor"), NULL, [](const char *msg, rtosc::RtData &d) { EffectMgr *eff = (EffectMgr*)d.obj; @@ -52,8 +54,10 @@ static const rtosc::Ports local_ports = { if(!rtosc_narguments(msg)) d.reply(d.loc, "i", eff->geteffectparrt(atoi(mm))); - else + else { eff->seteffectparrt(atoi(mm), rtosc_argument(msg, 0).i); + d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm))); + } }}, {"preset::i", rProp(alias) rDoc("Effect Preset Selector"), NULL, [](const char *msg, rtosc::RtData &d) @@ -61,8 +65,10 @@ static const rtosc::Ports local_ports = { EffectMgr *eff = (EffectMgr*)d.obj; if(!rtosc_narguments(msg)) d.reply(d.loc, "i", eff->getpreset()); - else + else { eff->changepresetrt(rtosc_argument(msg, 0).i); + d.broadcast(d.loc, "i", eff->getpreset()); + } }}, {"eq-coeffs:", rProp(internal) rDoc("Get equalizer Coefficients"), NULL, [](const char *, rtosc::RtData &d) @@ -71,8 +77,8 @@ static const rtosc::Ports local_ports = { if(eff->nefx != 7) return; EQ *eq = (EQ*)eff->efx; - float a[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]; - float b[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]; + float a[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; + float b[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); eq->getFilter(a,b); @@ -81,9 +87,10 @@ static const rtosc::Ports local_ports = { {"efftype::i", rDoc("Get Effect Type"), NULL, [](const char *m, rtosc::RtData &d) { EffectMgr *eff = (EffectMgr*)d.obj; - if(rtosc_narguments(m)) + if(rtosc_narguments(m)) { eff->changeeffectrt(rtosc_argument(m,0).i); - else + d.broadcast(d.loc, "i", eff->nefx); + } else d.reply(d.loc, "i", eff->nefx); }}, {"efftype:b", rProp(internal) rDoc("Pointer swap EffectMgr"), NULL, @@ -141,7 +148,7 @@ void EffectMgr::defaults(void) } //Change the effect -void EffectMgr::changeeffectrt(int _nefx) +void EffectMgr::changeeffectrt(int _nefx, bool avoidSmash) { cleanup(); if(nefx == _nefx && efx != NULL) @@ -185,6 +192,10 @@ void EffectMgr::changeeffectrt(int _nefx) if(efx) filterpars = efx->filterpars; + + if(!avoidSmash) + for(int i=0; i<128; ++i) + settings[i] = geteffectparrt(i); } void EffectMgr::changeeffect(int _nefx) @@ -203,8 +214,8 @@ int EffectMgr::geteffect(void) // Initialize An Effect in RT context void EffectMgr::init(void) { - changeeffectrt(nefx); - changepresetrt(preset); + changeeffectrt(nefx, true); + changepresetrt(preset, true); for(int i=0; i<128; ++i) seteffectparrt(i, settings[i]); } @@ -240,11 +251,14 @@ void EffectMgr::changepreset(unsigned char npreset) } // Change the preset of the current effect -void EffectMgr::changepresetrt(unsigned char npreset) +void EffectMgr::changepresetrt(unsigned char npreset, bool avoidSmash) { preset = npreset; if(efx) efx->setpreset(npreset); + if(!avoidSmash) + for(int i=0; i<128; ++i) + settings[i] = geteffectparrt(i); } //Change a parameter of the current effect @@ -295,8 +309,8 @@ void EffectMgr::out(float *smpsl, float *smpsr) return; } for(int i = 0; i < synth.buffersize; ++i) { - smpsl[i] += denormalkillbuf[i]; - smpsr[i] += denormalkillbuf[i]; + smpsl[i] += synth.denormalkillbuf[i]; + smpsr[i] += synth.denormalkillbuf[i]; efxoutl[i] = 0.0f; efxoutr[i] = 0.0f; } @@ -368,11 +382,10 @@ void EffectMgr::setdryonly(bool value) void EffectMgr::paste(EffectMgr &e) { - changeeffectrt(e.nefx); - changepresetrt(e.preset); - for(int i=0;i<128;++i){ + changeeffectrt(e.nefx, true); + changepresetrt(e.preset, true); + for(int i=0;i<128;++i) seteffectparrt(e.settings[i], i); - } } void EffectMgr::add2XML(XMLwrapper *xml) diff --git a/src/Effects/EffectMgr.h b/src/Effects/EffectMgr.h @@ -24,22 +24,15 @@ #include <pthread.h> -#include "Alienwah.h" -#include "Phaser.h" -#include "../Params/Presets.h" - class Effect; class FilterParams; class XMLwrapper; class Allocator; -#include "Distorsion.h" -#include "EQ.h" -#include "DynamicFilter.h" #include "../Params/FilterParams.h" #include "../Params/Presets.h" -/**Effect manager, an interface betwen the program and effects*/ +/** Effect manager, an interface between the program and effects */ class EffectMgr:public Presets { public: @@ -62,11 +55,11 @@ class EffectMgr:public Presets void kill(void) REALTIME; void cleanup(void) REALTIME; - void changeeffectrt(int nefx_) REALTIME; + void changeeffectrt(int nefx_, bool avoidSmash=false) REALTIME; void changeeffect(int nefx_) NONREALTIME; int geteffect(void); void changepreset(unsigned char npreset) NONREALTIME; - void changepresetrt(unsigned char npreset) REALTIME; + void changepresetrt(unsigned char npreset, bool avoidSmash=false) REALTIME; unsigned char getpreset(void); void seteffectpar(int npar, unsigned char value) NONREALTIME; void seteffectparrt(int npar, unsigned char value) REALTIME; diff --git a/src/Misc/Allocator.cpp b/src/Misc/Allocator.cpp @@ -7,7 +7,7 @@ #include "Allocator.h" //Used for dummy allocations -Allocator DummyAlloc; +DummyAllocator DummyAlloc; //recursive type class to avoid void *v = *(void**)v style casting struct next_t @@ -57,7 +57,7 @@ Allocator::~Allocator(void) delete impl; } -void *Allocator::alloc_mem(size_t mem_size) +void *AllocatorClass::alloc_mem(size_t mem_size) { impl->totalAlloced += mem_size; void *mem = tlsf_malloc(impl->tlsf, mem_size); @@ -66,14 +66,14 @@ void *Allocator::alloc_mem(size_t mem_size) //printf("Allocator result = %p\n", mem); return mem; } -void Allocator::dealloc_mem(void *memory) +void AllocatorClass::dealloc_mem(void *memory) { //printf("dealloc_mem(%d)\n", tlsf_block_size(memory)); tlsf_free(impl->tlsf, memory); //free(memory); } -bool Allocator::lowMemory(unsigned n, size_t chunk_size) +bool AllocatorClass::lowMemory(unsigned n, size_t chunk_size) const { //This should stay on the stack void *buf[n]; @@ -90,7 +90,7 @@ bool Allocator::lowMemory(unsigned n, size_t chunk_size) } -void Allocator::addMemory(void *v, size_t mem_size) +void AllocatorClass::addMemory(void *v, size_t mem_size) { next_t *n = impl->pools; while(n->next) n = n->next; @@ -124,7 +124,7 @@ typedef struct block_header_t static const size_t block_header_free_bit = 1 << 0; #endif -bool Allocator::memFree(void *pool) +bool Allocator::memFree(void *pool) const { size_t bh_shift = sizeof(next_t)+sizeof(size_t); //Assume that memory is free to start with @@ -145,7 +145,7 @@ bool Allocator::memFree(void *pool) return isFree; } -int Allocator::memPools() +int Allocator::memPools() const { int i = 1; next_t *n = impl->pools; @@ -156,7 +156,7 @@ int Allocator::memPools() return i; } -int Allocator::freePools() +int Allocator::freePools() const { int i = 0; next_t *n = impl->pools->next; @@ -169,7 +169,7 @@ int Allocator::freePools() } -unsigned long long Allocator::totalAlloced() +unsigned long long Allocator::totalAlloced() const { return impl->totalAlloced; } diff --git a/src/Misc/Allocator.h b/src/Misc/Allocator.h @@ -2,14 +2,17 @@ #include <cstdlib> #include <utility> +//! Allocator Base class +//! subclasses must specify allocation and deallocation class Allocator { public: Allocator(void); Allocator(const Allocator&) = delete; - ~Allocator(void); - void *alloc_mem(size_t mem_size); - void dealloc_mem(void *memory); + virtual ~Allocator(void); + + virtual void *alloc_mem(size_t mem_size) = 0; + virtual void dealloc_mem(void *memory) = 0; template <typename T, typename... Ts> T *alloc(Ts&&... ts) @@ -64,23 +67,49 @@ class Allocator } } - void addMemory(void *, size_t mem_size); + virtual void addMemory(void *, size_t mem_size) = 0; //Return true if the current pool cannot allocate n chunks of chunk_size - bool lowMemory(unsigned n, size_t chunk_size); - bool memFree(void *pool); + virtual bool lowMemory(unsigned n, size_t chunk_size) const = 0; + bool memFree(void *pool) const; //returns number of pools - int memPools(); + int memPools() const; - int freePools(); + int freePools() const; - unsigned long long totalAlloced(); + unsigned long long totalAlloced() const; struct AllocatorImpl *impl; }; -extern Allocator DummyAlloc; +//! the allocator for normal use +class AllocatorClass : public Allocator +{ + public: + void *alloc_mem(size_t mem_size); + void dealloc_mem(void *memory); + void addMemory(void *, size_t mem_size); + bool lowMemory(unsigned n, size_t chunk_size) const; + using Allocator::Allocator; +}; +typedef AllocatorClass Alloc; + +//! the dummy allocator, which does not allow any allocation +class DummyAllocator : public Allocator +{ + void not_allowed() const { + throw "(de)allocation forbidden"; // TODO: std exception + } +public: + void *alloc_mem(size_t ) { return not_allowed(), nullptr; } + void dealloc_mem(void* ) { not_allowed(); } // TODO: more functions? + void addMemory(void *, size_t ) { not_allowed(); } + bool lowMemory(unsigned , size_t ) const { return not_allowed(), true; } + using Allocator::Allocator; +}; + +extern DummyAllocator DummyAlloc; /** * General notes on Memory Allocation Within ZynAddSubFX diff --git a/src/Misc/Bank.cpp b/src/Misc/Bank.cpp @@ -46,16 +46,16 @@ using namespace std; -Bank::Bank() - :bankpos(0), defaultinsname(" ") +Bank::Bank(Config *config) + :bankpos(0), defaultinsname(" "), config(config) { clearbank(); bankfiletitle = dirname; rescanforbanks(); - loadbank(config.cfg.currentBankDir); + loadbank(config->cfg.currentBankDir); for(unsigned i=0; i<banks.size(); ++i) { - if(banks[i].dir == config.cfg.currentBankDir) { + if(banks[i].dir == config->cfg.currentBankDir) { bankpos = i; break; } @@ -270,7 +270,7 @@ int Bank::loadbank(string bankdirname) closedir(dir); if(!dirname.empty()) - config.cfg.currentBankDir = dirname; + config->cfg.currentBankDir = dirname; return 0; } @@ -281,7 +281,7 @@ int Bank::loadbank(string bankdirname) int Bank::newbank(string newbankdirname) { string bankdir; - bankdir = config.cfg.bankRootDirList[0]; + bankdir = config->cfg.bankRootDirList[0]; if(((bankdir[bankdir.size() - 1]) != '/') && ((bankdir[bankdir.size() - 1]) != '\\')) @@ -361,8 +361,8 @@ void Bank::rescanforbanks() banks.clear(); for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i) - if(!config.cfg.bankRootDirList[i].empty()) - scanrootdir(config.cfg.bankRootDirList[i]); + if(!config->cfg.bankRootDirList[i].empty()) + scanrootdir(config->cfg.bankRootDirList[i]); //sort the banks sort(banks.begin(), banks.end()); diff --git a/src/Misc/Bank.h b/src/Misc/Bank.h @@ -26,6 +26,7 @@ #include <string> #include <vector> #include "../globals.h" +#include "Config.h" //entries in a bank #define BANK_SIZE 160 @@ -35,7 +36,7 @@ class Bank { public: /**Constructor*/ - Bank(); + Bank(Config* config); ~Bank(); std::string getname(unsigned int ninstrument); std::string getnamenumbered(unsigned int ninstrument); @@ -96,6 +97,8 @@ class Bank std::string dirname; void scanrootdir(std::string rootdir); //scans a root dir for banks + + Config* const config; }; #endif diff --git a/src/Misc/CMakeLists.txt b/src/Misc/CMakeLists.txt @@ -14,6 +14,7 @@ set(zynaddsubfx_misc_SRCS Misc/MiddleWare.cpp Misc/PresetExtractor.cpp Misc/Allocator.cpp + Misc/TmpFileMgr.cpp ) diff --git a/src/Misc/Config.cpp b/src/Misc/Config.cpp @@ -28,6 +28,7 @@ #include <rtosc/port-sugar.h> #include "Config.h" +#include "../src/globals.h" #include "XMLwrapper.h" #define rStdString(name, len, ...) \ @@ -46,7 +47,7 @@ #if 1 #define rObject Config -static rtosc::Ports ports = { +static const rtosc::Ports ports = { //rString(cfg.LinuxOSSWaveOutDev), //rString(cfg.LinuxOSSSeqInDev), rParamI(cfg.SampleRate, "samples of audio per second"), @@ -145,7 +146,7 @@ static rtosc::Ports ports = { d.broadcast(d.loc, "i", (int)(log(c.cfg.OscilSize*1.0)/log(2.0))); }}, }; -rtosc::Ports &Config::ports = ::ports; +const rtosc::Ports &Config::ports = ::ports; #endif Config::Config() @@ -160,10 +161,10 @@ void Config::init() cfg.OscilSize = 1024; cfg.SwapStereo = 0; - cfg.LinuxOSSWaveOutDev = new char[MAX_STRING_SIZE]; - snprintf(cfg.LinuxOSSWaveOutDev, MAX_STRING_SIZE, "/dev/dsp"); - cfg.LinuxOSSSeqInDev = new char[MAX_STRING_SIZE]; - snprintf(cfg.LinuxOSSSeqInDev, MAX_STRING_SIZE, "/dev/sequencer"); + cfg.oss_devs.linux_wave_out = new char[MAX_STRING_SIZE]; + snprintf(cfg.oss_devs.linux_wave_out, MAX_STRING_SIZE, "/dev/dsp"); + cfg.oss_devs.linux_seq_in = new char[MAX_STRING_SIZE]; + snprintf(cfg.oss_devs.linux_seq_in, MAX_STRING_SIZE, "/dev/sequencer"); cfg.WindowsWaveOutId = 0; cfg.WindowsMidiInId = 0; @@ -228,8 +229,8 @@ void Config::init() Config::~Config() { - delete [] cfg.LinuxOSSWaveOutDev; - delete [] cfg.LinuxOSSSeqInDev; + delete [] cfg.oss_devs.linux_wave_out; + delete [] cfg.oss_devs.linux_seq_in; for(int i = 0; i < winmidimax; ++i) delete [] winmididevices[i].name; @@ -237,7 +238,7 @@ Config::~Config() } -void Config::save() +void Config::save() const { char filename[MAX_STRING_SIZE]; getConfigFileName(filename, MAX_STRING_SIZE); @@ -330,10 +331,10 @@ void Config::readConfig(const char *filename) //linux stuff xmlcfg.getparstr("linux_oss_wave_out_dev", - cfg.LinuxOSSWaveOutDev, + cfg.oss_devs.linux_wave_out, MAX_STRING_SIZE); xmlcfg.getparstr("linux_oss_seq_in_dev", - cfg.LinuxOSSSeqInDev, + cfg.oss_devs.linux_seq_in, MAX_STRING_SIZE); //windows stuff @@ -352,7 +353,7 @@ void Config::readConfig(const char *filename) cfg.OscilSize = (int) powf(2, ceil(logf(cfg.OscilSize - 1.0f) / logf(2.0f))); } -void Config::saveConfig(const char *filename) +void Config::saveConfig(const char *filename) const { XMLwrapper *xmlcfg = new XMLwrapper(); @@ -392,8 +393,8 @@ void Config::saveConfig(const char *filename) xmlcfg->addpar("interpolation", cfg.Interpolation); //linux stuff - xmlcfg->addparstr("linux_oss_wave_out_dev", cfg.LinuxOSSWaveOutDev); - xmlcfg->addparstr("linux_oss_seq_in_dev", cfg.LinuxOSSSeqInDev); + xmlcfg->addparstr("linux_oss_wave_out_dev", cfg.oss_devs.linux_wave_out); + xmlcfg->addparstr("linux_oss_seq_in_dev", cfg.oss_devs.linux_seq_in); //windows stuff xmlcfg->addpar("windows_wave_out_id", cfg.WindowsWaveOutId); @@ -401,15 +402,13 @@ void Config::saveConfig(const char *filename) xmlcfg->endbranch(); - int tmp = cfg.GzipCompression; - cfg.GzipCompression = 0; - xmlcfg->saveXMLfile(filename); - cfg.GzipCompression = tmp; + // for some reason (which one?), the gzip compression is bashed to 0 + xmlcfg->saveXMLfile(filename, 0); delete (xmlcfg); } -void Config::getConfigFileName(char *name, int namesize) +void Config::getConfigFileName(char *name, int namesize) const { name[0] = 0; snprintf(name, namesize, "%s%s", getenv("HOME"), "/.zynaddsubfxXML.cfg"); diff --git a/src/Misc/Config.h b/src/Misc/Config.h @@ -22,21 +22,32 @@ #ifndef CONFIG_H #define CONFIG_H -#include "../globals.h" + #include <string> #define MAX_STRING_SIZE 4000 #define MAX_BANK_ROOT_DIRS 100 +namespace rtosc +{ + struct Ports; +} + +class oss_devs_t +{ + public: + char *linux_wave_out, *linux_seq_in; +}; + /**Configuration file functions*/ class Config { public: - /** Constructor*/ Config(); - /** Destructor*/ + Config(const Config& ) = delete; ~Config(); + struct { - char *LinuxOSSWaveOutDev, *LinuxOSSSeqInDev; + oss_devs_t oss_devs; int SampleRate, SoundBufferSize, OscilSize, SwapStereo; int WindowsWaveOutId, WindowsMidiInId; int BankUIAutoClose; @@ -62,12 +73,12 @@ class Config void clearbankrootdirlist(); void clearpresetsdirlist(); void init(); - void save(); + void save() const; - static rtosc::Ports &ports; + static const rtosc::Ports &ports; private: void readConfig(const char *filename); - void saveConfig(const char *filename); - void getConfigFileName(char *name, int namesize); + void saveConfig(const char *filename) const; + void getConfigFileName(char *name, int namesize) const; }; #endif diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -25,6 +25,8 @@ #include "Part.h" +#include "../Misc/Stereo.h" +#include "../Misc/Util.h" #include "../Params/LFOParams.h" #include "../Effects/EffectMgr.h" #include "../DSP/FFTwrapper.h" @@ -286,13 +288,15 @@ vuData::vuData(void) rmspeakl(0.0f), rmspeakr(0.0f), clipped(0) {} -Master::Master(const SYNTH_T &synth_) -:HDDRecorder(synth_), ctl(synth_), midi(Master::ports), frozenState(false), pendingMemory(false), - synth(synth_), time(synth) +Master::Master(const SYNTH_T &synth_, Config* config) + :HDDRecorder(synth_), ctl(synth_), + microtonal(config->cfg.GzipCompression), bank(config), + midi(Master::ports), frozenState(false), pendingMemory(false), + synth(synth_), gzip_compression(config->cfg.GzipCompression), time(synth) { bToU = NULL; uToB = NULL; - memory = new Allocator(); + memory = new AllocatorClass(); swaplr = 0; off = 0; smps = 0; @@ -311,7 +315,8 @@ Master::Master(const SYNTH_T &synth_) } for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) - part[npart] = new Part(*memory, synth, time, &microtonal, fft); + part[npart] = new Part(*memory, synth, time, config->cfg.GzipCompression, + config->cfg.Interpolation, &microtonal, fft); //Insertion Effects init for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) @@ -1045,7 +1050,7 @@ int Master::saveXML(const char *filename) add2XML(xml); xml->endbranch(); - int result = xml->saveXMLfile(filename); + int result = xml->saveXMLfile(filename, gzip_compression); delete (xml); return result; } diff --git a/src/Misc/Master.h b/src/Misc/Master.h @@ -50,7 +50,7 @@ class Master { public: /** Constructor TODO make private*/ - Master(const SYNTH_T &synth); + Master(const SYNTH_T &synth, class Config *config); /** Destructor*/ ~Master(); @@ -174,6 +174,7 @@ class Master bool pendingMemory; const SYNTH_T &synth; AbsTime time; + const int& gzip_compression; //!< value from config private: float sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; float sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; diff --git a/src/Misc/Microtonal.cpp b/src/Misc/Microtonal.cpp @@ -75,7 +75,8 @@ const rtosc::Ports Microtonal::ports = { }; -Microtonal::Microtonal() +Microtonal::Microtonal(const int &gzip_compression) + : gzip_compression(gzip_compression) { defaults(); } @@ -688,7 +689,7 @@ int Microtonal::saveXML(const char *filename) const add2XML(xml); xml->endbranch(); - int result = xml->saveXMLfile(filename); + int result = xml->saveXMLfile(filename, gzip_compression); delete (xml); return result; } diff --git a/src/Misc/Microtonal.h b/src/Misc/Microtonal.h @@ -36,7 +36,7 @@ class Microtonal { public: /**Constructor*/ - Microtonal(); + Microtonal(const int& gzip_compression); /**Destructor*/ ~Microtonal(); void defaults(); @@ -131,6 +131,8 @@ class Microtonal //the real tunning is x1/x2 unsigned int x1, x2; } octave[MAX_OCTAVE_SIZE], tmpoctave[MAX_OCTAVE_SIZE]; + + const int& gzip_compression; }; #endif diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp @@ -12,7 +12,6 @@ #include <lo/lo.h> #include <unistd.h> -#include <dirent.h> #include "../UI/Connection.h" #include "../UI/Fl_Osc_Interface.h" @@ -20,6 +19,7 @@ #include <map> #include "Util.h" +#include "TmpFileMgr.h" #include "Master.h" #include "Part.h" #include "PresetExtractor.h" @@ -459,13 +459,12 @@ namespace Nio } /* Implementation */ -class MiddleWareImpl +class MiddleWareImpl : TmpFileMgr { - static constexpr const char* tmp_nam_prefix = "/tmp/zynaddsubfx_"; MiddleWare *parent; //Detect if the name of the process is 'zynaddsubfx' - bool isPlugin() + bool isPlugin() const { std::string proc_file = "/proc/" + to_s(getpid()) + "/comm"; std::ifstream ifs(proc_file); @@ -477,113 +476,11 @@ class MiddleWareImpl return true; } - //! returns file name to where UDP port is saved - std::string get_tmp_nam() const - { - return tmp_nam_prefix + to_s(getpid()); - } - - void create_tmp_file(unsigned server_port) - { - std::string tmp_nam = get_tmp_nam(); - if(0 == access(tmp_nam.c_str(), F_OK)) { - fprintf(stderr, "Error: Cannot overwrite file %s. " - "You should probably remove it.", tmp_nam.c_str()); - exit(EXIT_FAILURE); - } - FILE* tmp_fp = fopen(tmp_nam.c_str(), "w"); - if(!tmp_fp) - fprintf(stderr, "Warning: could not create new file %s.\n", - tmp_nam.c_str()); - else - fprintf(tmp_fp, "%u", server_port); - fclose(tmp_fp); - } - - void clean_up_tmp_nams() const - { - DIR *dir; - struct dirent *entry; - if ((dir = opendir ("/tmp/")) != nullptr) - { - while ((entry = readdir (dir)) != nullptr) - { - std::string name = std::string("/tmp/") + entry->d_name; - if(!name.compare(0, strlen(tmp_nam_prefix),tmp_nam_prefix)) - { - std::string pid = name.substr(strlen(tmp_nam_prefix)); - std::string proc_file = "/proc/" + std::move(pid) + - "/comm"; - - std::ifstream ifs(proc_file); - bool remove = false; - - if(!ifs.good()) - { - fprintf(stderr, "Note: trying to remove %s - the " - "process does not exist anymore.\n", - name.c_str()); - remove = true; - } - else - { - std::string comm_name; - ifs >> comm_name; - if(comm_name == "zynaddsubfx") - fprintf(stderr, "Note: detected running " - "zynaddsubfx with PID %s.\n", - name.c_str() + strlen(tmp_nam_prefix)); - else { - fprintf(stderr, "Note: trying to remove %s - the " - "PID is owned by\n another " - "process: %s\n", - name.c_str(), comm_name.c_str()); - remove = true; - } - } - - - if(remove) - { - // make sure this file contains only one unsigned - unsigned udp_port; - std::ifstream ifs2(name); - if(!ifs2.good()) - fprintf(stderr, "Warning: could not open %s.\n", - name.c_str()); - else - { - ifs2 >> udp_port; - if(ifs.good()) - fprintf(stderr, "Warning: could not remove " - "%s, \n it has not been " - "written by zynaddsubfx\n", - name.c_str()); - else - { - if(std::remove(name.c_str()) != 0) - fprintf(stderr, "Warning: can not remove " - "%s.\n", name.c_str()); - } - } - } - - /* one might want to connect to zyn here, - but it is not necessary: - lo_address la = lo_address_new(nullptr, udp_port.c_str()); - if(lo_send(la, "/echo", nullptr) <= 0) - fputs("Note: found crashed file %s\n", stderr); - lo_address_free(la);*/ - } - } - closedir (dir); - } else { - fputs("Warning: can not read /tmp.\n", stderr); - } - } - + Config* const config; + public: - MiddleWareImpl(MiddleWare *mw, SYNTH_T synth, int prefered_port); + MiddleWareImpl(MiddleWare *mw, SYNTH_T synth, Config* config, + int preferred_port); ~MiddleWareImpl(void); void warnMemoryLeaks(void); @@ -670,7 +567,11 @@ public: auto alloc = std::async(std::launch::async, [master,filename,this,npart](){ - Part *p = new Part(*master->memory, synth, master->time, &master->microtonal, master->fft); + Part *p = new Part(*master->memory, synth, + master->time, + config->cfg.GzipCompression, + config->cfg.Interpolation, + &master->microtonal, master->fft); if(p->loadXMLinstrument(filename)) fprintf(stderr, "Warning: failed to load part<%s>!\n", filename); @@ -704,7 +605,11 @@ public: { if(npart == -1) return; - Part *p = new Part(*master->memory, synth, master->time, &master->microtonal, master->fft); + Part *p = new Part(*master->memory, synth, + master->time, + config->cfg.GzipCompression, + config->cfg.Interpolation, + &master->microtonal, master->fft); p->applyparameters(); obj_store.extractPart(p, npart); kits.extractPart(p, npart); @@ -721,7 +626,7 @@ public: //structures at once... TODO error handling void loadMaster(const char *filename) { - Master *m = new Master(synth); + Master *m = new Master(synth, config); m->uToB = uToB; m->bToU = bToU; if(filename) { @@ -829,7 +734,7 @@ public: { char buffer[1024]; memset(buffer, 0, sizeof(buffer)); - DummyDataObj d(buffer, 1024, (void*)&config, this, uToB); + DummyDataObj d(buffer, 1024, (void*)config, this, uToB); strcpy(buffer, "/config/"); Config::ports.dispatch(msg+8, d); @@ -896,15 +801,20 @@ public: //Synthesis Rate Parameters const SYNTH_T synth; + + PresetsStore presetsstore; }; -MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, int prefered_port) - :parent(mw), ui(nullptr), synth(synth_) +MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, + Config* config, int preferrred_port) + :parent(mw), config(config), ui(nullptr), synth(std::move(synth_)), + presetsstore(*config) { bToU = new rtosc::ThreadLink(4096*2,1024); uToB = new rtosc::ThreadLink(4096*2,1024); - if(prefered_port != -1) - server = lo_server_new_with_proto(to_s(prefered_port).c_str(), LO_UDP, liblo_error_cb); + if(preferrred_port != -1) + server = lo_server_new_with_proto(to_s(preferrred_port).c_str(), + LO_UDP, liblo_error_cb); else server = lo_server_new_with_proto(NULL, LO_UDP, liblo_error_cb); lo_server_add_method(server, NULL, NULL, handler_function, mw); @@ -925,7 +835,7 @@ MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_, int prefered_port #ifndef PLUGINVERSION the_bToU = bToU; #endif - master = new Master(synth); + master = new Master(synth, config); master->bToU = bToU; master->uToB = uToB; osc = GUI::genOscInterface(mw); @@ -1340,8 +1250,9 @@ void MiddleWareImpl::warnMemoryLeaks(void) /****************************************************************************** * MidleWare Forwarding Stubs * ******************************************************************************/ -MiddleWare::MiddleWare(SYNTH_T synth, int prefered_port) -:impl(new MiddleWareImpl(this, synth, prefered_port)) +MiddleWare::MiddleWare(SYNTH_T synth, Config* config, + int preferred_port) +:impl(new MiddleWareImpl(this, std::move(synth), config, preferred_port)) {} MiddleWare::~MiddleWare(void) { @@ -1432,3 +1343,13 @@ const char* MiddleWare::getServerAddress(void) const { return lo_server_get_url(impl->server); } + +const PresetsStore& MiddleWare::getPresetsStore() const +{ + return impl->presetsstore; +} + +PresetsStore& MiddleWare::getPresetsStore() +{ + return impl->presetsstore; +} diff --git a/src/Misc/MiddleWare.h b/src/Misc/MiddleWare.h @@ -5,11 +5,14 @@ struct SYNTH_T; class Master; +class PresetsStore; + //Link between realtime and non-realtime layers class MiddleWare { public: - MiddleWare(SYNTH_T synth, int prefered_port = -1); + MiddleWare(SYNTH_T synth, class Config *config, + int preferred_port = -1); ~MiddleWare(void); void updateResources(Master *m); //returns internal master pointer @@ -39,6 +42,9 @@ class MiddleWare const SYNTH_T &getSynth(void) const; //liblo stuff const char* getServerAddress(void) const; + + const PresetsStore& getPresetsStore() const; + PresetsStore& getPresetsStore(); private: class MiddleWareImpl *impl; }; diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -160,6 +160,10 @@ static const Ports kitPorts = { rToggle(Ppadenabled, "PADsynth enable"), rParamZyn(Psendtoparteffect, "Effect Levels"), rString(Pname, PART_MAX_NAME_LEN, "Kit User Specified Label"), + {"captureMin:", NULL, NULL, [](const char *, RtData &r) + {Part::Kit *p = (Part::Kit*)r.obj; p->Pminkey = p->parent->lastnote;}}, + {"captureMax:", NULL, NULL, [](const char *, RtData &r) + {Part::Kit *p = (Part::Kit*)r.obj; p->Pmaxkey = p->parent->lastnote;}}, {"padpars-data:b", rProp(internal), 0, [](const char *msg, RtData &d) { rObject &o = *(rObject*)d.obj; @@ -186,23 +190,26 @@ const Ports &Part::Kit::ports = kitPorts; const Ports &Part::ports = partPorts; Part::Part(Allocator &alloc, const SYNTH_T &synth_, const AbsTime &time_, - Microtonal *microtonal_, FFTwrapper *fft_) - : - Pdrummode(false), + const int &gzip_compression, const int &interpolation, + Microtonal *microtonal_, FFTwrapper *fft_) + :Pdrummode(false), Ppolymode(true), Plegatomode(false), partoutl(new float[synth_.buffersize]), partoutr(new float[synth_.buffersize]), ctl(synth_), - lastlegatomodevalid(false), - microtonal(microtonal_), fft(fft_), + microtonal(microtonal_), + fft(fft_), memory(alloc), synth(synth_), - time(time_) + time(time_), + gzip_compression(gzip_compression), + interpolation(interpolation) { monomemClear(); for(int n = 0; n < NUM_KIT_ITEMS; ++n) { + kit[n].parent = this; kit[n].Pname = new char [PART_MAX_NAME_LEN]; kit[n].adpars = nullptr; kit[n].subpars = nullptr; @@ -323,16 +330,16 @@ void Part::cleanup(bool final_) { notePool.killAllNotes(); for(int i = 0; i < synth.buffersize; ++i) { - partoutl[i] = final_ ? 0.0f : denormalkillbuf[i]; - partoutr[i] = final_ ? 0.0f : denormalkillbuf[i]; + partoutl[i] = final_ ? 0.0f : synth.denormalkillbuf[i]; + partoutr[i] = final_ ? 0.0f : synth.denormalkillbuf[i]; } ctl.resetall(); for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx) partefx[nefx]->cleanup(); for(int n = 0; n < NUM_PART_EFX + 1; ++n) for(int i = 0; i < synth.buffersize; ++i) { - partfxinputl[n][i] = final_ ? 0.0f : denormalkillbuf[i]; - partfxinputr[n][i] = final_ ? 0.0f : denormalkillbuf[i]; + partfxinputl[n][i] = final_ ? 0.0f : synth.denormalkillbuf[i]; + partfxinputr[n][i] = final_ ? 0.0f : synth.denormalkillbuf[i]; } } @@ -449,7 +456,7 @@ void Part::NoteOn(unsigned char note, {memory.alloc<SUBnote>(kit[0].subpars, pars), 1, i}); if(item.Ppadenabled) notePool.insertNote(note, sendto, - {memory.alloc<PADnote>(kit[0].padpars, pars), 2, i}); + {memory.alloc<PADnote>(kit[0].padpars, pars, interpolation), 2, i}); //Partial Kit Use if(isNonKit() || (isSingleKit() && item.active())) @@ -909,7 +916,7 @@ int Part::saveXML(const char *filename) add2XMLinstrument(&xml); xml.endbranch(); - int result = xml.saveXMLfile(filename); + int result = xml.saveXMLfile(filename, gzip_compression); return result; } diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -39,7 +39,8 @@ class Part * @param microtonal_ Pointer to the microtonal object * @param fft_ Pointer to the FFTwrapper*/ Part(Allocator &alloc, const SYNTH_T &synth, const AbsTime &time, - Microtonal *microtonal_, FFTwrapper *fft_); + const int& gzip_compression, const int& interpolation, + Microtonal *microtonal_, FFTwrapper *fft_); /**Destructor*/ ~Part(); @@ -87,6 +88,7 @@ class Part //the part's kit struct Kit { + Part *parent; bool Penabled, Pmuted; unsigned char Pminkey, Pmaxkey; char *Pname; @@ -202,6 +204,7 @@ class Part Allocator &memory; const SYNTH_T &synth; const AbsTime &time; + const int &gzip_compression, &interpolation; }; #endif diff --git a/src/Misc/PresetExtractor.cpp b/src/Misc/PresetExtractor.cpp @@ -17,7 +17,6 @@ #include "../Params/PADnoteParameters.h" #include "../Params/Presets.h" #include "../Params/PresetsArray.h" -#include "../Params/PresetsStore.h" #include "../Params/SUBnoteParameters.h" #include "../Misc/MiddleWare.h" #include "PresetExtractor.h" @@ -32,8 +31,9 @@ const rtosc::Ports real_preset_ports = { {"scan-for-presets:", 0, 0, [](const char *msg, rtosc::RtData &d) { - presetsstore.scanforpresets(); - auto &pre = presetsstore.presets; + MiddleWare &mw = *(MiddleWare*)d.obj; + mw.getPresetsStore().scanforpresets(); + auto &pre = mw.getPresetsStore().presets; d.reply(d.loc, "i", pre.size()); for(unsigned i=0; i<pre.size();++i) d.reply(d.loc, "isss", i, @@ -84,11 +84,13 @@ const rtosc::Ports real_preset_ports = }}, {"clipboard-type:", 0, 0, [](const char *msg, rtosc::RtData &d) { - d.reply(d.loc, "s", presetsstore.clipboard.type.c_str()); + const MiddleWare &mw = *(MiddleWare*)d.obj; + d.reply(d.loc, "s", mw.getPresetsStore().clipboard.type.c_str()); }}, {"delete:s", 0, 0, [](const char *msg, rtosc::RtData &d) { - presetsstore.deletepreset(rtosc_argument(msg,0).s); + MiddleWare &mw = *(MiddleWare*)d.obj; + mw.getPresetsStore().deletepreset(rtosc_argument(msg,0).s); }}, }; @@ -202,7 +204,7 @@ std::string doCopy(MiddleWare &mw, string url, string name) T *t = (T*)capture<void*>(m, url+"self"); //Extract Via mxml //t->add2XML(&xml); - t->copy(presetsstore, name.empty()? NULL:name.c_str()); + t->copy(mw.getPresetsStore(), name.empty()? NULL:name.c_str()); }); return "";//xml.getXMLdata(); @@ -241,7 +243,7 @@ std::string doArrayCopy(MiddleWare &mw, int field, string url, string name) //Get the pointer T *t = (T*)capture<void*>(m, url+"self"); //Extract Via mxml - t->copy(presetsstore, field, name.empty()?NULL:name.c_str()); + t->copy(mw.getPresetsStore(), field, name.empty()?NULL:name.c_str()); }); return "";//xml.getXMLdata(); @@ -415,7 +417,7 @@ void presetPaste(MiddleWare &mw, std::string url, std::string name) string data = ""; XMLwrapper xml; if(name.empty()) { - data = presetsstore.clipboard.data; + data = mw.getPresetsStore().clipboard.data; if(data.length() < 20) return; if(!xml.putXMLdata(data.c_str())) @@ -440,7 +442,7 @@ void presetPasteArray(MiddleWare &mw, std::string url, int field, std::string na string data = ""; XMLwrapper xml; if(name.empty()) { - data = presetsstore.clipboard.data; + data = mw.getPresetsStore().clipboard.data; if(data.length() < 20) return; if(!xml.putXMLdata(data.c_str())) diff --git a/src/Misc/TmpFileMgr.cpp b/src/Misc/TmpFileMgr.cpp @@ -0,0 +1,114 @@ +#include <cstdlib> +#include <cstring> +#include <string> +#include <cstdio> +#include <fstream> +#include <unistd.h> +#include <dirent.h> + +#include "Util.h" +#include "TmpFileMgr.h" + +std::string TmpFileMgr::get_tmp_nam() const +{ + return tmp_nam_prefix + to_s(getpid()); +} + +void TmpFileMgr::create_tmp_file(unsigned server_port) const +{ + std::string tmp_nam = get_tmp_nam(); + if(0 == access(tmp_nam.c_str(), F_OK)) { + fprintf(stderr, "Error: Cannot overwrite file %s. " + "You should probably remove it.", tmp_nam.c_str()); + exit(EXIT_FAILURE); + } + FILE* tmp_fp = fopen(tmp_nam.c_str(), "w"); + if(!tmp_fp) + fprintf(stderr, "Warning: could not create new file %s.\n", + tmp_nam.c_str()); + else + fprintf(tmp_fp, "%u", server_port); + fclose(tmp_fp); +} + +void TmpFileMgr::clean_up_tmp_nams() const +{ + DIR *dir; + struct dirent *entry; + if ((dir = opendir ("/tmp/")) != nullptr) + { + while ((entry = readdir (dir)) != nullptr) + { + std::string name = std::string("/tmp/") + entry->d_name; + if(!name.compare(0, strlen(tmp_nam_prefix),tmp_nam_prefix)) + { + std::string pid = name.substr(strlen(tmp_nam_prefix)); + std::string proc_file = "/proc/" + std::move(pid) + + "/comm"; + + std::ifstream ifs(proc_file); + bool remove = false; + + if(!ifs.good()) + { + fprintf(stderr, "Note: trying to remove %s - the " + "process does not exist anymore.\n", + name.c_str()); + remove = true; + } + else + { + std::string comm_name; + ifs >> comm_name; + if(comm_name == "zynaddsubfx") + fprintf(stderr, "Note: detected running " + "zynaddsubfx with PID %s.\n", + name.c_str() + strlen(tmp_nam_prefix)); + else { + fprintf(stderr, "Note: trying to remove %s - the " + "PID is owned by\n another " + "process: %s\n", + name.c_str(), comm_name.c_str()); + remove = true; + } + } + + + if(remove) + { + // make sure this file contains only one unsigned + unsigned udp_port; + std::ifstream ifs2(name); + if(!ifs2.good()) + fprintf(stderr, "Warning: could not open %s.\n", + name.c_str()); + else + { + ifs2 >> udp_port; + if(ifs.good()) + fprintf(stderr, "Warning: could not remove " + "%s, \n it has not been " + "written by zynaddsubfx\n", + name.c_str()); + else + { + if(std::remove(name.c_str()) != 0) + fprintf(stderr, "Warning: can not remove " + "%s.\n", name.c_str()); + } + } + } + + /* one might want to connect to zyn here, + but it is not necessary: + lo_address la = lo_address_new(nullptr, udp_port.c_str()); + if(lo_send(la, "/echo", nullptr) <= 0) + fputs("Note: found crashed file %s\n", stderr); + lo_address_free(la);*/ + } + } + closedir (dir); + } else { + fputs("Warning: can not read /tmp.\n", stderr); + } +} diff --git a/src/Misc/TmpFileMgr.h b/src/Misc/TmpFileMgr.h @@ -0,0 +1,18 @@ + +/** + This file provides routines for using zyn's tmp files. +*/ +class TmpFileMgr +{ + static constexpr const char* tmp_nam_prefix = "/tmp/zynaddsubfx_"; + +public: + //! returns file name to where UDP port is saved + std::string get_tmp_nam() const; + + //! creates a tmp file with given UDP port information + void create_tmp_file(unsigned server_port) const; + + //! cleans up as many tmp files as possible + void clean_up_tmp_nams() const; +}; diff --git a/src/Misc/Util.cpp b/src/Misc/Util.cpp @@ -20,6 +20,7 @@ */ +#include "globals.h" #include "Util.h" #include <vector> #include <cassert> @@ -45,10 +46,6 @@ prng_t prng_state = 0x1234; -Config config; -float *denormalkillbuf; - - /* * Transform the velocity according the scaling parameter (velocity sensing) */ diff --git a/src/Misc/Util.h b/src/Misc/Util.h @@ -28,8 +28,6 @@ #include <stdint.h> #include <algorithm> #include <set> -#include "Config.h" -#include "../globals.h" using std::min; using std::max; @@ -58,10 +56,6 @@ std::string os_pid_as_padded_string(); std::string legalizeFilename(std::string filename); -extern float *denormalkillbuf; /**<the buffer to add noise in order to avoid denormalisation*/ - -extern class Config config; - void invSignal(float *sig, size_t len); template<class T> diff --git a/src/Misc/XMLwrapper.cpp b/src/Misc/XMLwrapper.cpp @@ -31,7 +31,7 @@ #include <iostream> #include <sstream> -#include "../globals.h" +#include "globals.h" #include "Util.h" using namespace std; @@ -187,13 +187,12 @@ bool XMLwrapper::hasPadSynth() const /* SAVE XML members */ -int XMLwrapper::saveXMLfile(const string &filename) const +int XMLwrapper::saveXMLfile(const string &filename, int compression) const { char *xmldata = getXMLdata(); if(xmldata == NULL) return -2; - int compression = config.cfg.GzipCompression; int result = dosavefile(filename.c_str(), compression, xmldata); free(xmldata); diff --git a/src/Misc/XMLwrapper.h b/src/Misc/XMLwrapper.h @@ -49,7 +49,7 @@ class XMLwrapper * @param filename the name of the destination file. * @returns 0 if ok or -1 if the file cannot be saved. */ - int saveXMLfile(const std::string &filename) const; + int saveXMLfile(const std::string &filename, int compression) const; /** * Return XML tree as a string. diff --git a/src/Nio/EngineMgr.cpp b/src/Nio/EngineMgr.cpp @@ -25,13 +25,14 @@ using namespace std; -EngineMgr &EngineMgr::getInstance(const SYNTH_T *synth) +EngineMgr &EngineMgr::getInstance(const SYNTH_T *synth, + const oss_devs_t *oss_devs) { - static EngineMgr instance(synth); + static EngineMgr instance(synth, *oss_devs); return instance; } -EngineMgr::EngineMgr(const SYNTH_T *synth) +EngineMgr::EngineMgr(const SYNTH_T *synth, const oss_devs_t& oss_devs) { assert(synth); Engine *defaultEng = new NulEngine(*synth); @@ -39,8 +40,8 @@ EngineMgr::EngineMgr(const SYNTH_T *synth) //conditional compiling mess (but contained) engines.push_back(defaultEng); #if OSS - engines.push_back(new OssEngine(*synth)); - engines.push_back(new OssMultiEngine(*synth)); + engines.push_back(new OssEngine(*synth, oss_devs)); + engines.push_back(new OssMultiEngine(*synth, oss_devs)); #endif #if ALSA engines.push_back(new AlsaEngine(*synth)); diff --git a/src/Nio/EngineMgr.h b/src/Nio/EngineMgr.h @@ -14,7 +14,9 @@ struct SYNTH_T; class EngineMgr { public: - static EngineMgr &getInstance(const SYNTH_T *synth=NULL); + static EngineMgr &getInstance( + const SYNTH_T *synth = nullptr, + const class oss_devs_t* oss_devs = nullptr); ~EngineMgr(); /**Gets requested engine @@ -39,6 +41,6 @@ class EngineMgr AudioOut *defaultOut; MidiIn *defaultIn; private: - EngineMgr(const SYNTH_T *synth); + EngineMgr(const SYNTH_T *synth, const oss_devs_t &oss_devs); }; #endif diff --git a/src/Nio/Nio.cpp b/src/Nio/Nio.cpp @@ -5,6 +5,7 @@ #include "MidiIn.h" #include "AudioOut.h" #include "WavEngine.h" +#include "../Misc/Config.h" #include <cstring> #include <iostream> #include <algorithm> @@ -30,11 +31,12 @@ bool Nio::pidInClientName = false; string Nio::defaultSource = IN_DEFAULT; string Nio::defaultSink = OUT_DEFAULT; -void Nio::init(const SYNTH_T &synth, class Master *master) +void Nio::init(const SYNTH_T &synth, const oss_devs_t& oss_devs, + class Master *master) { in = &InMgr::getInstance(); //Enable input wrapper out = &OutMgr::getInstance(&synth); //Initialize the Output Systems - eng = &EngineMgr::getInstance(&synth); //Initialize The Engines + eng = &EngineMgr::getInstance(&synth, &oss_devs); //Initialize the Engines in->setMaster(master); out->setMaster(master); diff --git a/src/Nio/Nio.h b/src/Nio/Nio.h @@ -6,13 +6,14 @@ class WavFile; class Master; struct SYNTH_T; +class oss_devs_t; /**Interface to Nio Subsystem * * Should be only externally included header */ namespace Nio { - void init(const SYNTH_T &synth, Master *master); + void init(const SYNTH_T &synth, const oss_devs_t &oss_devs, Master *master); bool start(void); void stop(void); diff --git a/src/Nio/OssEngine.cpp b/src/Nio/OssEngine.cpp @@ -22,6 +22,7 @@ #include "OssEngine.h" #include "../Misc/Util.h" +#include "../Misc/Config.h" #include "../globals.h" #include <cstring> @@ -179,8 +180,11 @@ OssMidiParse(struct OssMidiParse &midi_parse, return (0); } -OssEngine::OssEngine(const SYNTH_T &synth) - :AudioOut(synth), audioThread(NULL), midiThread(NULL) +OssEngine::OssEngine(const SYNTH_T &synth, + const oss_devs_t& oss_devs) + :AudioOut(synth), audioThread(NULL), midiThread(NULL), + linux_oss_wave_out_dev(oss_devs.linux_wave_out), + linux_oss_seq_in_dev(oss_devs.linux_seq_in) { name = "OSS"; @@ -212,7 +216,7 @@ bool OssEngine::openAudio() const char *device = getenv("DSP_DEVICE"); if(device == NULL) - device = config.cfg.LinuxOSSWaveOutDev; + device = linux_oss_wave_out_dev; /* NOTE: PIPEs and FIFOs can block when opening them */ audio.handle = open(device, O_WRONLY, O_NONBLOCK); @@ -350,7 +354,7 @@ bool OssEngine::openMidi() const char *device = getenv("MIDI_DEVICE"); if(device == NULL) - device = config.cfg.LinuxOSSSeqInDev; + device = linux_oss_seq_in_dev; /* NOTE: PIPEs and FIFOs can block when opening them */ handle = open(device, O_RDONLY, O_NONBLOCK); diff --git a/src/Nio/OssEngine.h b/src/Nio/OssEngine.h @@ -45,7 +45,7 @@ struct OssMidiParse { class OssEngine:public AudioOut, MidiIn { public: - OssEngine(const SYNTH_T &synth); + OssEngine(const SYNTH_T &synth, const class oss_devs_t& oss_devs); ~OssEngine(); bool Start(); @@ -83,6 +83,8 @@ class OssEngine:public AudioOut, MidiIn bool en; bool is32bit; } audio; + + const char* linux_oss_wave_out_dev; //Midi bool openMidi(); @@ -94,6 +96,8 @@ class OssEngine:public AudioOut, MidiIn bool en; bool run; } midi; + + const char* linux_oss_seq_in_dev; }; #endif diff --git a/src/Nio/OssMultiEngine.cpp b/src/Nio/OssMultiEngine.cpp @@ -43,8 +43,10 @@ extern MiddleWare *middleware; using namespace std; -OssMultiEngine :: OssMultiEngine(const SYNTH_T &synth) - :AudioOut(synth) +OssMultiEngine :: OssMultiEngine(const SYNTH_T &synth, + const oss_devs_t &oss_devs) + :AudioOut(synth), + linux_oss_wave_out_dev(oss_devs.linux_wave_out) { /* setup variables */ name = "OSS-MULTI"; @@ -81,7 +83,7 @@ OssMultiEngine :: openAudio() const char *device = getenv("DSP_DEVICE"); if(device == 0) - device = config.cfg.LinuxOSSWaveOutDev; + device = linux_oss_wave_out_dev; /* NOTE: PIPEs and FIFOs can block when opening them */ handle = open(device, O_WRONLY, O_NONBLOCK); diff --git a/src/Nio/OssMultiEngine.h b/src/Nio/OssMultiEngine.h @@ -29,7 +29,8 @@ class OssMultiEngine : public AudioOut { public: - OssMultiEngine(const SYNTH_T &synth); + OssMultiEngine(const SYNTH_T &synth, + const class oss_devs_t& oss_devs); ~OssMultiEngine(); bool Start(); @@ -62,6 +63,8 @@ class OssMultiEngine : public AudioOut bool en; bool is32bit; + + const char* linux_oss_wave_out_dev; }; #endif diff --git a/src/Nio/OutMgr.h b/src/Nio/OutMgr.h @@ -2,6 +2,7 @@ #define OUTMGR_H #include "../Misc/Stereo.h" +#include "../globals.h" #include <list> #include <string> #include <semaphore.h> @@ -16,7 +17,7 @@ class OutMgr ~OutMgr(); /**Execute a tick*/ - const Stereo<float *> tick(unsigned int frameSize) __attribute__((annotate("realtime"))); + const Stereo<float *> tick(unsigned int frameSize) REALTIME; /**Request a new set of samples * @param n number of requested samples (defaults to 1) diff --git a/src/Output/DSSIaudiooutput.cpp b/src/Output/DSSIaudiooutput.cpp @@ -29,7 +29,6 @@ #include "DSSIaudiooutput.h" #include "../Misc/Master.h" -#include "../Misc/Config.h" #include "../Misc/Bank.h" #include "../Misc/Util.h" #include <rtosc/thread-link.h> @@ -611,12 +610,9 @@ DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate) config.init(); sprng(time(NULL)); - denormalkillbuf = new float [synth.buffersize]; - for(int i = 0; i < synth.buffersize; i++) - denormalkillbuf[i] = (RND - 0.5f) * 1e-16; synth.alias(); - middleware = new MiddleWare(synth); + middleware = new MiddleWare(std::move(synth), &config); initBanks(); loadThread = new std::thread([this]() { while(middleware) { diff --git a/src/Output/DSSIaudiooutput.h b/src/Output/DSSIaudiooutput.h @@ -25,6 +25,7 @@ #include <thread> #include "../globals.h" +#include "../Misc/Config.h" #include "../Misc/MiddleWare.h" #include <dssi.h> @@ -117,8 +118,8 @@ class DSSIaudiooutput */ bool banksInited; - static - long bankNoToMap; + static long bankNoToMap; + Config config; }; #endif diff --git a/src/Params/PresetsStore.cpp b/src/Params/PresetsStore.cpp @@ -30,13 +30,14 @@ #include "PresetsStore.h" #include "../Misc/XMLwrapper.h" #include "../Misc/Util.h" +#include "../Misc/Config.h" using namespace std; //XXX to remove -PresetsStore presetsstore; +//PresetsStore presetsstore; -PresetsStore::PresetsStore() +PresetsStore::PresetsStore(const Config& config) : config(config) { } @@ -154,7 +155,7 @@ void PresetsStore::copypreset(XMLwrapper &xml, char *type, string name) string filename("" + dirname + tmps + name + "." + &type[1] + ".xpz"); - xml.saveXMLfile(filename); + xml.saveXMLfile(filename, config.cfg.GzipCompression); } bool PresetsStore::pastepreset(XMLwrapper &xml, unsigned int npreset) diff --git a/src/Params/PresetsStore.h b/src/Params/PresetsStore.h @@ -29,8 +29,9 @@ class XMLwrapper; class PresetsStore { + const class Config& config; public: - PresetsStore(); + PresetsStore(const class Config &config); ~PresetsStore(); //Clipboard stuff @@ -62,5 +63,5 @@ class PresetsStore void clearpresets(); }; -extern PresetsStore presetsstore; +//extern PresetsStore presetsstore; #endif diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp @@ -1440,8 +1440,8 @@ inline void ADnote::ComputeVoiceNoise(int nvoice) */ int ADnote::noteout(float *outl, float *outr) { - memcpy(outl, denormalkillbuf, synth.bufferbytes); - memcpy(outr, denormalkillbuf, synth.bufferbytes); + memcpy(outl, synth.denormalkillbuf, synth.bufferbytes); + memcpy(outr, synth.denormalkillbuf, synth.bufferbytes); if(NoteEnabled == OFF) return 0; diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -482,7 +482,8 @@ void OscilGen::changebasefunction(void) { if(Pcurrentbasefunc != 0) { getbasefunction(tmpsmps); - fft->smps2freqs(tmpsmps, basefuncFFTfreqs); + if(fft) + fft->smps2freqs(tmpsmps, basefuncFFTfreqs); clearDC(basefuncFFTfreqs); } else //in this case basefuncFFTfreqs are not used @@ -1139,6 +1140,8 @@ void OscilGen::paste(OscilGen &o) RESTORE(fft); RESTORE(basefuncFFTfreqs); RESTORE(res); + if(this->Pcurrentbasefunc) + changebasefunction(); this->prepare(); } diff --git a/src/Synth/PADnote.cpp b/src/Synth/PADnote.cpp @@ -29,8 +29,8 @@ #include "../Misc/Util.h" PADnote::PADnote(const PADnoteParameters *parameters, - SynthParams pars) - :SynthNote(pars), pars(*parameters) + SynthParams pars, const int& interpolation) + :SynthNote(pars), pars(*parameters), interpolation(interpolation) { firsttime = true; setup(pars.frequency, pars.velocity, pars.portamento, pars.note); @@ -170,7 +170,7 @@ SynthNote *PADnote::cloneLegato(void) { SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity, (bool)portamento, legato.param.midinote, true}; - return memory.alloc<PADnote>(&pars, sp); + return memory.alloc<PADnote>(&pars, sp, interpolation); } void PADnote::legatonote(LegatoParams pars) @@ -354,7 +354,7 @@ int PADnote::noteout(float *outl, float *outr) float freqlo = freqrap - floor(freqrap); - if(config.cfg.Interpolation) + if(interpolation) Compute_Cubic(outl, outr, freqhi, freqlo); else Compute_Linear(outl, outr, freqhi, freqlo); diff --git a/src/Synth/PADnote.h b/src/Synth/PADnote.h @@ -30,7 +30,8 @@ class PADnote:public SynthNote { public: - PADnote(const PADnoteParameters *parameters, SynthParams pars); + PADnote(const PADnoteParameters *parameters, SynthParams pars, + const int &interpolation); ~PADnote(); SynthNote *cloneLegato(void); @@ -105,6 +106,7 @@ class PADnote:public SynthNote float globaloldamplitude, globalnewamplitude, velocity, realfreq; + const int& interpolation; }; diff --git a/src/Synth/SUBnote.cpp b/src/Synth/SUBnote.cpp @@ -499,8 +499,8 @@ void SUBnote::computecurrentparameters() */ int SUBnote::noteout(float *outl, float *outr) { - memcpy(outl, denormalkillbuf, synth.bufferbytes); - memcpy(outr, denormalkillbuf, synth.bufferbytes); + memcpy(outl, synth.denormalkillbuf, synth.bufferbytes); + memcpy(outr, synth.denormalkillbuf, synth.bufferbytes); if(NoteEnabled == OFF) return 0; diff --git a/src/Tests/AdNoteTest.h b/src/Tests/AdNoteTest.h @@ -42,22 +42,20 @@ using namespace std; class AdNoteTest:public CxxTest::TestSuite { public: - ADnote *note; AbsTime *time; FFTwrapper *fft; Controller *controller; - Allocator memory; + Alloc memory; unsigned char testnote; - float *outR, *outL; void setUp() { //First the sensible settings and variables that have to be set: synth = new SYNTH_T; synth->buffersize = 256; - synth->alias(); + //synth->alias(); time = new AbsTime(*synth); outL = new float[synth->buffersize]; @@ -67,13 +65,6 @@ class AdNoteTest:public CxxTest::TestSuite for(int i = 0; i < synth->buffersize; ++i) *(outR + i) = 0; - //next the bad global variables that for some reason have not been properly placed in some - //initialization routine, but rather exist as cryptic oneliners in main.cpp: - denormalkillbuf = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - denormalkillbuf[i] = 0; - - //phew, glad to get thouse out of my way. took me a lot of sweat and gdb to get this far... fft = new FFTwrapper(synth->oscilsize); //prepare the default settings @@ -120,7 +111,6 @@ class AdNoteTest:public CxxTest::TestSuite delete fft; delete [] outL; delete [] outR; - delete [] denormalkillbuf; FFT_cleanup(); delete synth; } diff --git a/src/Tests/AllocatorTest.h b/src/Tests/AllocatorTest.h @@ -37,7 +37,7 @@ class AllocatorTest:public CxxTest::TestSuite vector<void*> data; void setUp() { - memory_ = new Allocator(); + memory_ = new AllocatorClass(); } void tearDown() { diff --git a/src/Tests/EchoTest.h b/src/Tests/EchoTest.h @@ -125,5 +125,5 @@ class EchoTest:public CxxTest::TestSuite Stereo<float *> *input; float *outR, *outL; Echo *testFX; - Allocator alloc; + Alloc alloc; }; diff --git a/src/Tests/InstrumentStats.cpp b/src/Tests/InstrumentStats.cpp @@ -26,9 +26,10 @@ enum RunMode { RunMode mode; +int compress = 0; float *outL, *outR; -Allocator alloc; -Microtonal microtonal; +Alloc alloc; +Microtonal microtonal(compress); FFTwrapper fft(1024); Part *p; @@ -47,6 +48,7 @@ double toc() return tic(); } +int interp=1; void setup() { synth = new SYNTH_T; synth->buffersize = 256; @@ -63,12 +65,7 @@ void setup() { for(int i = 0; i < synth->buffersize; ++i) outR[i] = 0.0f; - //next the bad global variables that for some reason have not been properly placed in some - //initialization routine, but rather exist as cryptic oneliners in main.cpp: - denormalkillbuf = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - denormalkillbuf[i] = 0; - p = new Part(alloc, *synth, *time_, &microtonal, &fft); + p = new Part(alloc, *synth, *time_, compress, interp, &microtonal, &fft); } void xml(string s) diff --git a/src/Tests/KitTest.h b/src/Tests/KitTest.h @@ -13,14 +13,14 @@ #include "../Misc/Part.h" #include "../globals.h" SYNTH_T *synth; -extern float *denormalkillbuf; +int dummy=0; using namespace std; class KitTest:public CxxTest::TestSuite { private: - Allocator alloc; + Alloc alloc; FFTwrapper fft; Microtonal microtonal; Part *part; @@ -28,20 +28,18 @@ class KitTest:public CxxTest::TestSuite float *outL, *outR; public: KitTest() - :fft(512) + :fft(512), microtonal(dummy) {} void setUp() { synth = new SYNTH_T; time = new AbsTime(*synth); - denormalkillbuf = new float[synth->buffersize]; outL = new float[synth->buffersize]; outR = new float[synth->buffersize]; - memset(denormalkillbuf, 0, synth->bufferbytes); memset(outL, 0, synth->bufferbytes); memset(outR, 0, synth->bufferbytes); - part = new Part(alloc, *synth, *time, &microtonal, &fft); + part = new Part(alloc, *synth, *time, dummy, dummy, &microtonal, &fft); } //Enumerate cases of: @@ -531,7 +529,6 @@ class KitTest:public CxxTest::TestSuite void tearDown() { delete part; - delete[] denormalkillbuf; delete[] outL; delete[] outR; delete time; diff --git a/src/Tests/MicrotonalTest.h b/src/Tests/MicrotonalTest.h @@ -34,9 +34,11 @@ using namespace std; class MicrotonalTest:public CxxTest::TestSuite { public: + int compression; void setUp() { - synth = new SYNTH_T; - testMicro = new Microtonal(); + compression = 0; + synth = new SYNTH_T; + testMicro = new Microtonal(compression); } void tearDown() { @@ -85,7 +87,7 @@ class MicrotonalTest:public CxxTest::TestSuite xml.endbranch(); char *tmp = xml.getXMLdata(); - Microtonal other; + Microtonal other(compression); other.Penabled = 1; strcpy((char *)other.Pname, "Myname"); //will be nicer with strings diff --git a/src/Tests/MiddlewareTest.h b/src/Tests/MiddlewareTest.h @@ -42,11 +42,12 @@ char *instance_name=(char*)""; class PluginTest:public CxxTest::TestSuite { public: + Config config; void setUp() { synth = new SYNTH_T; synth->buffersize = 256; synth->samplerate = 48000; - synth->alias(); + //synth->alias(); outL = new float[1024]; for(int i = 0; i < synth->buffersize; ++i) @@ -55,15 +56,16 @@ class PluginTest:public CxxTest::TestSuite for(int i = 0; i < synth->buffersize; ++i) outR[i] = 0.0f; - //next the bad global variables that for some reason have not been properly placed in some - //initialization routine, but rather exist as cryptic oneliners in main.cpp: - denormalkillbuf = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - denormalkillbuf[i] = 0; - + delete synth; + synth = NULL; for(int i = 0; i < 16; ++i) { - middleware[i] = new MiddleWare(*synth); + synth = new SYNTH_T; + synth->buffersize = 256; + synth->samplerate = 48000; + //synth->alias(); + middleware[i] = new MiddleWare(std::move(*synth), &config); master[i] = middleware[i]->spawnMaster(); + printf("Octave size = %d\n", master[i]->microtonal.getoctavesize()); } } @@ -73,7 +75,6 @@ class PluginTest:public CxxTest::TestSuite delete[] outL; delete[] outR; - delete[] denormalkillbuf; delete synth; } diff --git a/src/Tests/OscilGenTest.h b/src/Tests/OscilGenTest.h @@ -49,12 +49,6 @@ class OscilGenTest:public CxxTest::TestSuite memset(outL, 0, sizeof(float) * synth->oscilsize); memset(outR, 0, sizeof(float) * synth->oscilsize); - //next the bad global variables that for some reason have not been properly placed in some - //initialization routine, but rather exist as cryptic oneliners in main.cpp: - denormalkillbuf = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - denormalkillbuf[i] = 0; - //prepare the default settings fft = new FFTwrapper(synth->oscilsize); oscil = new OscilGen(*synth, fft, NULL); @@ -88,7 +82,6 @@ class OscilGenTest:public CxxTest::TestSuite delete fft; delete[] outL; delete[] outR; - delete[] denormalkillbuf; FFT_cleanup(); delete synth; } diff --git a/src/Tests/PadNoteTest.h b/src/Tests/PadNoteTest.h @@ -55,16 +55,17 @@ class PadNoteTest:public CxxTest::TestSuite Controller *controller; AbsTime *time; unsigned char testnote; - Allocator memory; + Alloc memory; + int interpolation; float *outR, *outL; void setUp() { + interpolation = 0; synth = new SYNTH_T; //First the sensible settings and variables that have to be set: synth->buffersize = 256; - synth->alias(); time = new AbsTime(*synth); outL = new float[synth->buffersize]; @@ -74,13 +75,6 @@ class PadNoteTest:public CxxTest::TestSuite for(int i = 0; i < synth->buffersize; ++i) *(outR + i) = 0; - //next the bad global variables that for some reason have not been properly placed in some - //initialization routine, but rather exist as cryptic oneliners in main.cpp: - denormalkillbuf = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - denormalkillbuf[i] = 0; - - //phew, glad to get thouse out of my way. took me a lot of sweat and gdb to get this far... fft = new FFTwrapper(synth->oscilsize); //prepare the default settings @@ -119,7 +113,7 @@ class PadNoteTest:public CxxTest::TestSuite float freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f); SynthParams pars_{memory, *controller, *synth, *time, freq, 120, 0, testnote, false}; - note = new PADnote(pars, pars_); + note = new PADnote(pars, pars_, interpolation); } void tearDown() { @@ -128,7 +122,6 @@ class PadNoteTest:public CxxTest::TestSuite delete fft; delete [] outL; delete [] outR; - delete [] denormalkillbuf; delete pars; FFT_cleanup(); delete synth; @@ -138,7 +131,6 @@ class PadNoteTest:public CxxTest::TestSuite fft = NULL; outL = NULL; outR = NULL; - denormalkillbuf = NULL; pars = NULL; synth = NULL; } diff --git a/src/Tests/PluginTest.h b/src/Tests/PluginTest.h @@ -43,6 +43,7 @@ MiddleWare *middleware; class PluginTest:public CxxTest::TestSuite { public: + Config config; void setUp() { synth = new SYNTH_T; synth->buffersize = 256; @@ -56,14 +57,8 @@ class PluginTest:public CxxTest::TestSuite for(int i = 0; i < synth->buffersize; ++i) outR[i] = 0.0f; - //next the bad global variables that for some reason have not been properly placed in some - //initialization routine, but rather exist as cryptic oneliners in main.cpp: - denormalkillbuf = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - denormalkillbuf[i] = 0; - for(int i = 0; i < 16; ++i) - master[i] = new Master(*synth); + master[i] = new Master(*synth, &config); } void tearDown() { diff --git a/src/Tests/RandTest.h b/src/Tests/RandTest.h @@ -21,8 +21,6 @@ */ #include "../Misc/Util.h" -SYNTH_T *synth; - #include <cstdlib> #include <cstdio> #include <cxxtest/TestSuite.h> diff --git a/src/Tests/SubNoteTest.h b/src/Tests/SubNoteTest.h @@ -47,7 +47,7 @@ class SubNoteTest:public CxxTest::TestSuite AbsTime *time; Controller *controller; unsigned char testnote; - Allocator memory; + Alloc memory; float *outR, *outL; @@ -56,7 +56,6 @@ class SubNoteTest:public CxxTest::TestSuite synth = new SYNTH_T; //First the sensible settings and variables that have to be set: synth->buffersize = 256; - synth->alias(); time = new AbsTime(*synth); outL = new float[synth->buffersize]; @@ -66,12 +65,6 @@ class SubNoteTest:public CxxTest::TestSuite for(int i = 0; i < synth->buffersize; ++i) *(outR + i) = 0; - //next the bad global variables that for some reason have not been properly placed in some - //initialization routine, but rather exist as cryptic oneliners in main.cpp: - denormalkillbuf = new float[synth->buffersize]; - for(int i = 0; i < synth->buffersize; ++i) - denormalkillbuf[i] = 0; - //prepare the default settings SUBnoteParameters *defaultPreset = new SUBnoteParameters(); XMLwrapper *wrap = new XMLwrapper(); @@ -102,7 +95,6 @@ class SubNoteTest:public CxxTest::TestSuite delete note; delete [] outL; delete [] outR; - delete [] denormalkillbuf; delete time; delete synth; } diff --git a/src/Tests/UnisonTest.h b/src/Tests/UnisonTest.h @@ -50,7 +50,7 @@ class AdNoteTest:public CxxTest::TestSuite unsigned char testnote; ADnoteParameters *params; AbsTime *time; - Allocator memory; + Alloc memory; float freq; @@ -66,11 +66,6 @@ class AdNoteTest:public CxxTest::TestSuite memset(outL,0,sizeof(outL)); memset(outR,0,sizeof(outR)); - //next the bad global variables that for some reason have not been properly placed in some - //initialization routine, but rather exist as cryptic oneliners in main.cpp: - denormalkillbuf = new float[BUF]; - memset(denormalkillbuf, 0, sizeof(float)*BUF); - fft = new FFTwrapper(BUF); //prepare the default settings params = new ADnoteParameters(*synth, fft); @@ -83,14 +78,12 @@ class AdNoteTest:public CxxTest::TestSuite //lets go with.... 50! as a nice note testnote = 50; freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f); - } void tearDown() { delete note; delete controller; delete fft; - delete [] denormalkillbuf; FFT_cleanup(); delete time; delete synth; diff --git a/src/UI/ADnoteUI.fl b/src/UI/ADnoteUI.fl @@ -119,7 +119,7 @@ class ADvoicelistitem {open : {public Fl_Osc_Group} class Fl_Osc_Output } Fl_Slider voicedetune { - callback {//detunevalueoutput->do_callback();} + callback {detunevalueoutput->update();} tooltip {Fine Detune (cents)} xywh {315 5 185 20} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 code0 {o->init("PDetune",'i');} class Fl_Osc_Slider @@ -253,7 +253,7 @@ o->redraw();} class Fl_Osc_Counter } Fl_Slider {} { - callback {o->oscWrite("detunevalue");} + callback {fmdetunevalueoutput->update();} tooltip {Fine Detune (cents)} xywh {590 245 155 15} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 code0 {o->init("PFMDetune", 'i');} class Fl_Osc_Slider @@ -266,7 +266,7 @@ o->redraw();} } Fl_Choice {} { label {Detune Type} - callback {fmdetunevalueoutput->do_callback();} open + callback {fmdetunevalueoutput->update();} open xywh {540 280 75 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10 code0 {o->add("Default");o->add("L35cents");o->add("L10cents");o->add("E100cents");o->add("E1200cents");} code1 {o->init("PFMDetuneType");} @@ -466,7 +466,7 @@ o->redraw();} class Fl_Osc_Counter } Fl_Slider {} { - callback {detunevalueoutput->do_callback();} + callback {detunevalueoutput->update();} tooltip {Fine Detune (cents)} xywh {58 287 392 13} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 code0 {o->init("PDetune", 'i');} class Fl_Osc_Slider @@ -493,7 +493,7 @@ o->redraw();} } Fl_Choice {} { label {Detune Type} - callback {detunevalueoutput->do_callback();} open + callback {detunevalueoutput->update();} open xywh {455 320 70 15} down_box BORDER_BOX labelsize 10 align 5 textfont 1 textsize 10 code0 {o->add("Default");o->add("L35cents");o->add("L10cents");o->add("E100cents");o->add("E1200cents");} code1 {o->init("PDetuneType");} @@ -866,7 +866,7 @@ class ADnoteUI {open : {public PresetsUI_} class LFOUI } {} Fl_Slider detune { - callback {o->oscWrite("detunevalue");} + callback {detunevalueoutput->update();} tooltip {Fine Detune (cents)} xywh {60 300 385 15} type {Horz Knob} box NO_BOX minimum -8192 maximum 8191 step 1 code0 {o->init("PDetune", 'i');} class Fl_Osc_Slider @@ -879,7 +879,7 @@ class ADnoteUI {open : {public PresetsUI_} } Fl_Choice detunetype { label {Detune Type} - callback {o->oscWrite("detunevalue");} open + callback {detunevalueoutput->update();} open xywh {455 340 75 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->init("PDetuneType",1);} diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt @@ -34,16 +34,22 @@ if(FltkGui) add_executable(zynaddsubfx-ext-gui guimain.cpp) target_link_libraries(zynaddsubfx-ext-gui zynaddsubfx_gui ${FLTK_LIBRARIES} ${FLTK_LIBRARIES} ${OPENGL_LIBRARIES} ${LIBLO_LIBRARIES} rtosc rtosc-cpp) - if(X11_FOUND) + if(X11_FOUND AND HAS_XPM) + add_definitions(-DHAS_X11=1) target_link_libraries(zynaddsubfx-ext-gui ${X11_LIBRARIES} -lXpm) + else() + add_definitions(-DHAS_X11=0) endif() install(TARGETS zynaddsubfx-ext-gui RUNTIME DESTINATION bin) elseif(NtkGui) add_executable(zynaddsubfx-ext-gui guimain.cpp) target_link_libraries(zynaddsubfx-ext-gui zynaddsubfx_gui ${NTK_LDFLAGS} ${OPENGL_LIBRARIES} ${LIBLO_LIBRARIES} rtosc rtosc-cpp) - if(X11_FOUND) + if(X11_FOUND AND HAS_XPM) + add_definitions(-DHAS_X11=1) target_link_libraries(zynaddsubfx-ext-gui ${X11_LIBRARIES} -lXpm) + else() + add_definitions(-DHAS_X11=0) endif() install(TARGETS zynaddsubfx-ext-gui RUNTIME DESTINATION bin) endif() diff --git a/src/UI/EffUI.fl b/src/UI/EffUI.fl @@ -39,7 +39,13 @@ decl {\#include "../Misc/Util.h"} {public local } decl {\#include "../Effects/EffectMgr.h"} {public local -} +} + +decl {\#include "../Effects/Phaser.h" /* for macros only, TODO */} {public local +} + +decl {\#include "../Effects/Alienwah.h" /* for macros only, TODO */ } {public local +} decl {\#include "PresetsUI.h"} {public local } @@ -943,7 +949,7 @@ stagescounter->oscMove("parameter"+to_s(npb+4));} Fl_Counter stagescounter { label {St.} callback {eqgraph->update();} - tooltip {Additional filter stages} xywh {340 60 30 15} type Simple labelfont 1 labelsize 10 minimum 1 maximum 127 step 1 textfont 1 textsize 11 + tooltip {Additional filter stages} xywh {340 60 30 15} type Simple labelfont 1 labelsize 10 minimum 0 maximum 127 step 1 textfont 1 textsize 11 code0 {o->init("parameter14");} class Fl_Osc_Counter } diff --git a/src/UI/EnvelopeFreeEdit.cpp b/src/UI/EnvelopeFreeEdit.cpp @@ -223,3 +223,13 @@ void EnvelopeFreeEdit::update(void) oscWrite("Penvval"); oscWrite("Penvsustain"); } + +void EnvelopeFreeEdit::rebase(std::string new_base) +{ + osc->renameLink(loc+"Penvpoints", new_base+"Penvpoints", this); + osc->renameLink(loc+"Penvdt", new_base+"Penvdt", this); + osc->renameLink(loc+"Penvval", new_base+"Penvval", this); + osc->renameLink(loc+"Penvsustain", new_base+"Penvsustain", this); + loc = new_base; + update(); +} diff --git a/src/UI/EnvelopeFreeEdit.h b/src/UI/EnvelopeFreeEdit.h @@ -13,17 +13,18 @@ #define ENV_ADSR_FILTER 4 #define ENV_ADSR_BW 5 -class EnvelopeFreeEdit : public Fl_Box, Fl_Osc_Widget +class EnvelopeFreeEdit : public Fl_Box, public Fl_Osc_Widget { public: EnvelopeFreeEdit(int x,int y, int w, int h, const char *label=0); void init(void); void setpair(Fl_Box *pair_); - int handle(int event); + int handle(int event) override; - void draw(void); + void draw(void) override; void OSC_raw(const char *msg) override; - void update(void); + void update(void) override; + void rebase(std::string new_base) override; int lastpoint; diff --git a/src/UI/Fl_EQGraph.H b/src/UI/Fl_EQGraph.H @@ -24,6 +24,6 @@ class Fl_EQGraph:public Fl_Box, public Fl_Osc_Widget float getfreqpos(float freq) const; float samplerate; - float num[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]; - float dem[MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1]; + float num[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; + float dem[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; }; diff --git a/src/UI/Fl_EQGraph.cpp b/src/UI/Fl_EQGraph.cpp @@ -32,7 +32,7 @@ void Fl_EQGraph::OSC_raw(const char *msg) samplerate = rtosc_argument(msg, 0).f; } else { memcpy(dem, rtosc_argument(msg, 0).b.data, sizeof(dem)); - memcpy(num, rtosc_argument(msg, 1).b.data, sizeof(dem)); + memcpy(num, rtosc_argument(msg, 1).b.data, sizeof(num)); redraw(); } } @@ -141,16 +141,24 @@ void Fl_EQGraph::draw(void) double Fl_EQGraph::getresponse(int maxy,float freq) const { const float angle = 2*PI*freq/samplerate; - std::complex<float> num_res = 0; - std::complex<float> dem_res = 0; + float mag = 1; + //std::complex<float> num_res = 0; + //std::complex<float> dem_res = 0; - for(int i = 0; i < MAX_EQ_BANDS*MAX_FILTER_STAGES*2+1; ++i) { - num_res += FFTpolar<float>(num[i], i*angle); - dem_res += FFTpolar<float>(dem[i], i*angle); + for(int i = 0; i < MAX_EQ_BANDS*MAX_FILTER_STAGES; ++i) { + if(num[3*i] == 0) + break; + std::complex<float> num_res= 0; + std::complex<float> dem_res= 0; + for(int j=0; j<3; ++j) { + num_res += FFTpolar<float>(num[3*i+j], j*angle); + dem_res += FFTpolar<float>(dem[3*i+j], j*angle); + } + mag *= abs(num_res/dem_res); } - float dbresp=20*log(abs(num_res/dem_res))/log(10); + float dbresp=20*log(mag)/log(10); //rescale return (int) ((dbresp/MAX_DB+1.0)*maxy/2.0); diff --git a/src/UI/Fl_Osc_Dial.cpp b/src/UI/Fl_Osc_Dial.cpp @@ -78,7 +78,10 @@ int Fl_Osc_Dial::handle(int ev) void Fl_Osc_Dial::OSC_value(int v) { - value(v+minimum()+fmodf(value(), 1)); + if(64 != (int)minimum()) + value(v+minimum()+fmodf(value(), 1)); + else + value(v+fmodf(value(), 1)); } void Fl_Osc_Dial::OSC_value(char v) @@ -95,11 +98,10 @@ void Fl_Osc_Dial::cb(void) { assert(osc); -/* if((maximum()-minimum()) == 127 || (maximum()-minimum()) == 255) { - oscWrite(ext, "i", (int)(value()-minimum())); - } - else*/ + if(64 != (int)minimum()) oscWrite(ext, "i", (int)(value()-minimum())); + else + oscWrite(ext, "i", (int)(value())); if(cb_data.first) cb_data.first(this, cb_data.second); diff --git a/src/UI/Fl_Osc_DialF.H b/src/UI/Fl_Osc_DialF.H @@ -4,7 +4,7 @@ #include "Fl_Osc_Widget.H" #include <string> -class Fl_Osc_DialF:public WidgetPDial, Fl_Osc_Widget +class Fl_Osc_DialF:public WidgetPDial, public Fl_Osc_Widget { public: diff --git a/src/UI/Fl_Osc_Output.H b/src/UI/Fl_Osc_Output.H @@ -2,7 +2,7 @@ #include <FL/Fl_Value_Output.H> #include "Fl_Osc_Widget.H" -class Fl_Osc_Output:public Fl_Value_Output, Fl_Osc_Widget +class Fl_Osc_Output:public Fl_Value_Output, public Fl_Osc_Widget { public: Fl_Osc_Output(int x, int y, int w, int h, const char *label = NULL); @@ -19,6 +19,5 @@ class Fl_Osc_Output:public Fl_Value_Output, Fl_Osc_Widget void cb(void); private: float newvalue_; - std::string name; std::pair<Fl_Callback*, void*> cb_data; }; diff --git a/src/UI/Fl_Osc_Output.cpp b/src/UI/Fl_Osc_Output.cpp @@ -19,7 +19,7 @@ Fl_Osc_Output::Fl_Osc_Output(int X, int Y, int W, int H, const char *label) void Fl_Osc_Output::init(const char *path) { - name = path; + ext = path; oscRegister(path); }; @@ -51,7 +51,7 @@ void Fl_Osc_Output::OSC_value(float v) void Fl_Osc_Output::update(void) { - oscWrite(name); + oscWrite(ext); } float Fl_Osc_Output::newvalue(void) const @@ -61,5 +61,5 @@ float Fl_Osc_Output::newvalue(void) const void Fl_Osc_Output::cb(void) { - oscWrite(name); + oscWrite(ext); } diff --git a/src/UI/Fl_OscilSpectrum.h b/src/UI/Fl_OscilSpectrum.h @@ -4,7 +4,7 @@ #include "Fl_Osc_Widget.H" //consider merging with Fl_Oscilloscope -class Fl_OscilSpectrum : public Fl_Box, Fl_Osc_Widget +class Fl_OscilSpectrum : public Fl_Box, public Fl_Osc_Widget { public: Fl_OscilSpectrum(int x,int y, int w, int h, const char *label=0) diff --git a/src/UI/Fl_PADnoteOvertonePosition.h b/src/UI/Fl_PADnoteOvertonePosition.h @@ -6,7 +6,7 @@ #include "Fl_Osc_Widget.H" #include "Fl_Osc_Interface.h" -class PADnoteOvertonePosition: public Fl_Box, Fl_Osc_Widget +class PADnoteOvertonePosition: public Fl_Box, public Fl_Osc_Widget { public: PADnoteOvertonePosition(int x,int y, int w, int h, const char *label=0) diff --git a/src/UI/FormantFilterGraph.H b/src/UI/FormantFilterGraph.H @@ -13,7 +13,7 @@ class FilterParams; -class FormantFilterGraph : public Fl_Box, Fl_Osc_Widget { +class FormantFilterGraph : public Fl_Box, public Fl_Osc_Widget { public: FormantFilterGraph(int x,int y, int w, int h, const char *label=0); void init(int *nvowel_, int *nformant_); diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl @@ -17,7 +17,7 @@ decl {\#include <stdio.h>} {public local decl {\#include <string.h>} {public local } -decl {\#if defined(__linux__) && ! defined(PLUGINVERSION) +decl {\#if ! defined(PLUGINVERSION) && HAS_X11 \#include "zynaddsubfx.xpm" \#endif} {public local } @@ -76,7 +76,7 @@ extern NSM_Client *nsm; \#endif} {public local } -decl {\#if defined(__linux__) && ! defined(PLUGINVERSION) +decl {\#if !defined(PLUGINVERSION) && HAS_X11 \#include <X11/xpm.h> \#endif} {public local } @@ -1502,7 +1502,7 @@ configui=new ConfigUI(osc); make_window(); fl_open_display(); -\#if defined(__linux__) && ! defined(PLUGINVERSION) +\#if !defined(PLUGINVERSION) && HAS_X11 Pixmap p, mask; XCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display), (char**)zynaddsubfx_xpm, &p, &mask, NULL); diff --git a/src/UI/OscilGenUI.fl b/src/UI/OscilGenUI.fl @@ -119,7 +119,7 @@ class Oscilharmonic {: {public Fl_Group} Fl_Slider mag { callback {int x=64; if (Fl::event_button3()) o->value(x); - else x=127-(int)o->value(); + else x=128-(int)o->value(); if (x==64) o->selection_color(0); else o->selection_color(222); @@ -496,12 +496,15 @@ redrawoscil();} if (autoclearbutton->value()){ for (int i=0;i<MAX_AD_HARMONICS;i++){ h[i]->mag->value(64); + h[i]->mag->do_callback(); h[i]->phase->value(64); + h[i]->phase->do_callback(); }; harmonicshiftcounter->value(0); h[0]->mag->value(0); + h[0]->mag->do_callback(); wshbutton->value(0); wshbutton->do_callback(); fltbutton->value(0); @@ -527,9 +530,12 @@ redrawoscil();} for (int i=0;i<MAX_AD_HARMONICS;i++){ h[i]->mag->value(64); + h[i]->mag->do_callback(); h[i]->phase->value(64); + h[i]->phase->do_callback(); }; h[0]->mag->value(0); +h[0]->mag->do_callback(); //for (int i=0;i<MAX_AD_HARMONICS;i++){ // if (oscil->Phmag[i]==64) h[i]->mag->selection_color(0); diff --git a/src/UI/PartUI.fl b/src/UI/PartUI.fl @@ -112,13 +112,17 @@ class PartKitItem {open : {public Fl_Osc_Group} } Fl_Button {} { label m - callback {o->oscWrite("grabMinKey");} + callback {o->oscWrite("captureMin"); +minkcounter->update(); +maxkcounter->update();} tooltip {set the minimum key to the last pressed key} xywh {285 3 15 12} box THIN_UP_BOX labelsize 10 class Fl_Osc_Button } Fl_Button {} { label M - callback {o->oscWrite("grabMaxKey");} + callback {o->oscWrite("captureMax"); +minkcounter->update(); +maxkcounter->update();} tooltip {set the maximum key to the last pressed key} xywh {315 3 15 12} box THIN_UP_BOX labelsize 10 class Fl_Osc_Button } diff --git a/src/UI/SUBnoteUI.fl b/src/UI/SUBnoteUI.fl @@ -52,6 +52,20 @@ class PPSlider {: {public Fl_Slider, public Fl_Osc_Widget} } { code {int X=x(),Y=y(),W=w(),H=h(); +// catch any (un)learn event first +{ + bool middle_mouse = (event == FL_PUSH && Fl::event_state(FL_BUTTON2) && !Fl::event_shift()); + bool ctl_click = (event == FL_PUSH && Fl::event_state(FL_BUTTON1) && Fl::event_ctrl()); + bool shift_middle = (event == FL_PUSH && Fl::event_state(FL_BUTTON2) && Fl::event_shift()); + if(middle_mouse || ctl_click) { + osc->write("/learn", "s", (loc+ext).c_str()); + return 1; + } else if(shift_middle) { + osc->write("/unlearn", "s", (loc+ext).c_str()); + return 1; + } +} + if ((!Fl::event_buttons())|| (event==0)||(Fl::event_shift()==0)) return(Fl_Slider::handle(event)); if (!Fl::event_inside(X,Y,W,H)) { @@ -100,7 +114,7 @@ class SUBnoteharmonic {: {public Fl_Osc_Group} int x=0; if (Fl::event_button1() || Fl::event() == FL_MOUSEWHEEL) x=127-(int)o->value(); else o->value(127-x); - o->osc->writeValue(o->loc + "Phmag" + to_s(n), (char) x); + o->osc->writeValue(o->loc + o->ext, (char) x); if (x==0) o->selection_color(0); else o->selection_color(222);} tooltip {harmonic's magnitude} xywh {0 15 10 135} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 127 @@ -110,7 +124,7 @@ if (x==0) o->selection_color(0); callback {int x=64; if (Fl::event_button1() || Fl::event() == FL_MOUSEWHEEL) x=127-(int)o->value(); else o->value(x); - o->osc->writeValue(o->loc+"Phrelbw"+to_s(n), (char) x);} + o->osc->writeValue(o->loc + o->ext, (char) x)}; tooltip {harmonic's bandwidth} xywh {0 157 10 130} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 64 class PPSlider } @@ -137,17 +151,18 @@ if (Fl::event_button1() || Fl::event() == FL_MOUSEWHEEL) x=127-(int)o->value(); code {n=n_; make_window(); harmonic->show(); - -osc->createLink(base+"Phmag"+to_s(n), mag); -osc->createLink(base+"Phrelbw"+to_s(n), bw); -osc->requestValue(base+"Phmag"+to_s(n)); +mag->ext = "Phmag" + to_s(n); +mag->oscRegister(mag->ext.c_str()); +bw->ext = "Phrelbw" + to_s(n); +bw->oscRegister(bw->ext.c_str()); osc->requestValue(base+"Phrelbw"+to_s(n)); end();} {} } Function {refresh()} {} { - code {osc->requestValue(base+"Phmag"+to_s(n)); -osc->requestValue(base+"Phrelbw"+to_s(n));} {} + code {// request values for the widgets +mag->oscWrite(mag->ext); +bw->oscWrite(bw->ext);} {} } Function {~SUBnoteharmonic()} {} { code {harmonic->hide(); diff --git a/src/globals.cpp b/src/globals.cpp @@ -0,0 +1,43 @@ +/* + ZynAddSubFX - a software synthesizer + + globals.h - it contains program settings and the program capabilities + like number of parts, of effects + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2 or later) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "Misc/Util.h" +#include "globals.h" + +void SYNTH_T::alias(bool randomize) +{ + halfsamplerate_f = (samplerate_f = samplerate) / 2.0f; + buffersize_f = buffersize; + bufferbytes = buffersize * sizeof(float); + oscilsize_f = oscilsize; + + //produce denormal buf + // note: once there will be more buffers, use a cleanup function + // for deleting the buffers and also call it in the dtor + denormalkillbuf.resize(buffersize); + for(int i = 0; i < buffersize; ++i) + if(randomize) + denormalkillbuf[i] = (RND - 0.5f) * 1e-16; + else + denormalkillbuf[i] = 0; +} diff --git a/src/globals.h b/src/globals.h @@ -254,22 +254,51 @@ enum LegatoMsg { #define O_BINARY 0 #endif +template<class T> +class m_unique_ptr +{ + T* ptr = nullptr; +public: + m_unique_ptr() = default; + m_unique_ptr(m_unique_ptr&& other) { + ptr = other.ptr; + other.ptr = nullptr; + } + m_unique_ptr(const m_unique_ptr& other) = delete; + ~m_unique_ptr() { ptr = nullptr; } + void resize(unsigned sz) { + delete[] ptr; + ptr = new T[sz]; } + + operator T*() { return ptr; } + operator const T*() const { return ptr; } + //T& operator[](unsigned idx) { return ptr[idx]; } + //const T& operator[](unsigned idx) const { return ptr[idx]; } +}; + //temporary include for synth->{samplerate/buffersize} members struct SYNTH_T { + SYNTH_T(void) :samplerate(44100), buffersize(256), oscilsize(1024) { - alias(); + alias(false); } + SYNTH_T(const SYNTH_T& ) = delete; + SYNTH_T(SYNTH_T&& ) = default; + + /** the buffer to add noise in order to avoid denormalisation */ + m_unique_ptr<float> denormalkillbuf; + /**Sampling rate*/ unsigned int samplerate; /** * The size of a sound buffer (or the granularity) - * All internal transfer of sound data use buffer of this size - * All parameters are constant during this period of time, exception - * some parameters(like amplitudes) which are linear interpolated. + * All internal transfer of sound data use buffer of this size. + * All parameters are constant during this period of time, except + * some parameters(like amplitudes) which are linearly interpolated. * If you increase this you'll ecounter big latencies, but if you * decrease this the CPU requirements gets high. */ @@ -293,13 +322,7 @@ struct SYNTH_T { { return buffersize_f / samplerate_f; } - inline void alias(void) - { - halfsamplerate_f = (samplerate_f = samplerate) / 2.0f; - buffersize_f = buffersize; - bufferbytes = buffersize * sizeof(float); - oscilsize_f = oscilsize; - } + void alias(bool randomize=true); static float numRandom(void); //defined in Util.cpp for now }; #endif diff --git a/src/main.cpp b/src/main.cpp @@ -76,7 +76,7 @@ NSM_Client *nsm = 0; char *instance_name = 0; -void exitprogram(); +void exitprogram(const Config &config); extern pthread_t main_thread; @@ -91,21 +91,21 @@ void sigterm_exit(int /*sig*/) /* * Program initialisation */ -void initprogram(SYNTH_T synth, int prefered_port) +void initprogram(SYNTH_T synth, Config* config, int prefered_port) { - middleware = new MiddleWare(synth, prefered_port); + middleware = new MiddleWare(std::move(synth), config, prefered_port); master = middleware->spawnMaster(); master->swaplr = swaplr; signal(SIGINT, sigterm_exit); signal(SIGTERM, sigterm_exit); - Nio::init(master->synth, master); + Nio::init(master->synth, config->cfg.oss_devs, master); } /* * Program exit */ -void exitprogram() +void exitprogram(const Config& config) { Nio::stop(); config.save(); @@ -121,7 +121,6 @@ void exitprogram() delete nsm; #endif - delete [] denormalkillbuf; FFT_cleanup(); } @@ -129,6 +128,7 @@ int main(int argc, char *argv[]) { main_thread = pthread_self(); SYNTH_T synth; + Config config; config.init(); int noui = 0; cerr @@ -375,12 +375,14 @@ int main(int argc, char *argv[]) return 0; } - //produce denormal buf - denormalkillbuf = new float [synth.buffersize]; - for(int i = 0; i < synth.buffersize; ++i) - denormalkillbuf[i] = (RND - 0.5f) * 1e-16; + cerr.precision(1); + cerr << std::fixed; + cerr << "\nSample Rate = \t\t" << synth.samplerate << endl; + cerr << "Sound Buffer Size = \t" << synth.buffersize << " samples" << endl; + cerr << "Internal latency = \t" << synth.dt() * 1000.0f << " ms" << endl; + cerr << "ADsynth Oscil.Size = \t" << synth.oscilsize << " samples" << endl; - initprogram(synth, prefered_port); + initprogram(std::move(synth), &config, prefered_port); if(!loadfile.empty()) { int tmp = master->loadXML(loadfile.c_str()); @@ -413,13 +415,6 @@ int main(int argc, char *argv[]) //Run the Nio system bool ioGood = Nio::start(); - - cerr.precision(1); - cerr << std::fixed; - cerr << "\nSample Rate = \t\t" << synth.samplerate << endl; - cerr << "Sound Buffer Size = \t" << synth.buffersize << " samples" << endl; - cerr << "Internal latency = \t" << synth.dt() * 1000.0f << " ms" << endl; - cerr << "ADsynth Oscil.Size = \t" << synth.oscilsize << " samples" << endl; if(!execAfterInit.empty()) { cout << "Executing user supplied command: " << execAfterInit << endl; @@ -519,6 +514,6 @@ done: middleware->tick(); } - exitprogram(); + exitprogram(config); return 0; } diff --git a/zynaddsubfx-alsa.desktop b/zynaddsubfx-alsa.desktop @@ -1,6 +1,7 @@ [Desktop Entry] Name=ZynAddSubFX - Alsa Comment=A powerful realtime software synthesizer +Comment[fr]=Un synthétiseur logiciel temps-réel puissant Exec=zynaddsubfx -I alsa -O alsa Icon=zynaddsubfx Terminal=false diff --git a/zynaddsubfx-jack.desktop b/zynaddsubfx-jack.desktop @@ -1,6 +1,7 @@ [Desktop Entry] Name=ZynAddSubFX - Jack Comment=A powerful realtime software synthesizer +Comment[fr]=Un synthétiseur logiciel temps-réel puissant Exec=zynaddsubfx -I jack -O jack Icon=zynaddsubfx Terminal=false