commit 608620d75b967b27553f770e7c7b2ca372eb7e9c
parent c165dab6ba8a661183c72aacc1d77c690332c191
Author: Johannes Lorenz <[email protected]>
Date: Mon, 4 Jun 2018 21:30:46 +0200
Merge branch 'master' of github.com:zynaddsubfx/zynaddsubfx
Diffstat:
15 files changed, 145 insertions(+), 113 deletions(-)
diff --git a/.gitmodules b/.gitmodules
@@ -7,4 +7,4 @@
branch = default_values
[submodule "DPF"]
path = DPF
- url = git://github.com/DISTRHO/DPF
+ url = https://github.com/DISTRHO/DPF
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -38,7 +38,7 @@ add_subdirectory(doc) # Doxygen only
install(FILES AUTHORS.txt COPYING HISTORY.txt README.adoc
DESTINATION share/doc/zynaddsubfx
)
-install(FILES zynaddsubfx-jack.desktop zynaddsubfx-alsa.desktop zynaddsubfx-oss.desktop
+install(FILES zynaddsubfx-jack-multi.desktop zynaddsubfx-jack.desktop zynaddsubfx-alsa.desktop zynaddsubfx-oss.desktop
DESTINATION share/applications)
install(FILES zynaddsubfx.svg
DESTINATION share/pixmaps)
diff --git a/TODO-default-values.txt b/TODO-default-values.txt
@@ -1,16 +0,0 @@
-TODOs for default values:
-* use # for bundles, not a
-* 1 ... 7 => 1 2 ... 7
-* also after scanning?
-
-* rEnabled vs rExists:
- * clarify/rename
- * make a clean function?
-
-test:
-* zyn fx (all presets)
-* rtosc arg val maths
-
-finally:
-* remove rDefaultMissing if possible
-* fix all TODOs from default_values
diff --git a/src/DSP/SVFilter.cpp b/src/DSP/SVFilter.cpp
@@ -26,6 +26,12 @@
namespace zyn {
+enum FilterInterpolationType {
+ INTERPOLATE_EXTREME = 0x01,
+ INTERPOLATE_NON_ZERO,
+ INTERPOLATE_NONE
+};
+
SVFilter::SVFilter(unsigned char Ftype, float Ffreq, float Fq,
unsigned char Fstages, unsigned int srate, int bufsize)
:Filter(srate, bufsize),
@@ -34,7 +40,7 @@ SVFilter::SVFilter(unsigned char Ftype, float Ffreq, float Fq,
freq(Ffreq),
q(Fq),
gain(1.0f),
- needsinterpolation(false),
+ needsinterpolation(INTERPOLATE_NONE),
firsttime(true)
{
if(stages >= MAX_FILTER_STAGES)
@@ -100,6 +106,8 @@ SVFilter::response SVFilter::computeResponse(int type,
}
}
+
+
void SVFilter::computefiltercoefs(void)
{
par.f = freq / samplerate_f * 4.0f;
@@ -127,8 +135,14 @@ void SVFilter::setfreq(float frequency)
//if the frequency is changed fast, it needs interpolation
if((rap > 3.0f) || nyquistthresh) { //(now, filter and coefficients backup)
if(!firsttime)
- needsinterpolation = true;
+ needsinterpolation = INTERPOLATE_EXTREME;
+ ipar = par;
+ } else if(rap != 1.0) {
+ if (!firsttime)
+ needsinterpolation = INTERPOLATE_NON_ZERO;
ipar = par;
+ } else {
+ needsinterpolation = INTERPOLATE_NONE;
}
freq = frequency;
computefiltercoefs();
@@ -168,8 +182,7 @@ void SVFilter::setstages(int stages_)
computefiltercoefs();
}
-void SVFilter::singlefilterout(float *smp, fstage &x, parameters &par)
-{
+float *SVFilter::getfilteroutfortype(SVFilter::fstage &x) {
float *out = NULL;
switch(type) {
case 0:
@@ -188,11 +201,20 @@ void SVFilter::singlefilterout(float *smp, fstage &x, parameters &par)
out = &x.low;
warnx("Impossible SVFilter type encountered [%d]", type);
}
+ return out;
+}
+void SVFilter::singlefilterout_with_par_interpolation(float *smp, fstage &x, parameters &par1, parameters &par2)
+{
+ float *out = getfilteroutfortype(x);
for(int i = 0; i < buffersize; ++i) {
- x.low = x.low + par.f * x.band;
- x.high = par.q_sqrt * smp[i] - x.low - par.q * x.band;
- x.band = par.f * x.high + x.band;
+ float p = i / buffersize_f;
+ float f = par1.f + (par2.f - par1.f) * p;
+ float q = par1.q + (par2.q - par1.q) * p;
+ float q_sqrt = sqrtf(q);
+ x.low = x.low + f * x.band;
+ x.high = q_sqrt * smp[i] - x.low - q * x.band;
+ x.band = f * x.high + x.band;
x.notch = x.high + x.low;
smp[i] = *out;
}
@@ -209,23 +231,38 @@ void SVFilter::singlefilterout(float *smp, fstage &x, parameters &par)
// xl = pf*pfxh*z(-1)/(1-z(-1))^2
-void SVFilter::filterout(float *smp)
+
+void SVFilter::singlefilterout(float *smp, SVFilter::fstage &x, SVFilter::parameters &par)
{
- for(int i = 0; i < stages + 1; ++i)
- singlefilterout(smp, st[i], par);
+ float *out = getfilteroutfortype(x);
+ for(int i = 0; i < buffersize; ++i) {
+ x.low = x.low + par.f * x.band;
+ x.high = par.q_sqrt * smp[i] - x.low - par.q * x.band;
+ x.band = par.f * x.high + x.band;
+ x.notch = x.high + x.low;
+ smp[i] = *out;
+ }
+}
- if(needsinterpolation) {
+void SVFilter::filterout(float *smp)
+{
+ if (needsinterpolation == INTERPOLATE_EXTREME) {
float ismp[buffersize];
+ for(int i = 0; i < stages + 1; ++i)
+ singlefilterout(smp, st[i], par);
memcpy(ismp, smp, bufferbytes);
-
for(int i = 0; i < stages + 1; ++i)
singlefilterout(ismp, st[i], ipar);
-
for(int i = 0; i < buffersize; ++i) {
float x = i / buffersize_f;
smp[i] = ismp[i] * (1.0f - x) + smp[i] * x;
}
- needsinterpolation = false;
+ } else if (needsinterpolation == INTERPOLATE_NON_ZERO) {
+ for(int i = 0; i < stages + 1; ++i)
+ singlefilterout_with_par_interpolation(smp, st[i], ipar, par);
+ } else {
+ for(int i = 0; i < stages + 1; ++i)
+ singlefilterout(smp, st[i], par);
}
for(int i = 0; i < buffersize; ++i)
diff --git a/src/DSP/SVFilter.h b/src/DSP/SVFilter.h
@@ -56,7 +56,9 @@ class SVFilter:public Filter
float f, q, q_sqrt;
} par, ipar;
+ float *getfilteroutfortype(SVFilter::fstage &x);
void singlefilterout(float *smp, fstage &x, parameters &par);
+ void singlefilterout_with_par_interpolation(float *smp, fstage &x, parameters &par1, parameters &par2);
void computefiltercoefs(void);
int type; // The type of the filter (LPF1,HPF1,LPF2,HPF2...)
int stages; // how many times the filter is applied (0->1,1->2,etc.)
@@ -66,7 +68,8 @@ class SVFilter:public Filter
bool abovenq, //if the frequency is above the nyquist
oldabovenq;
- bool needsinterpolation, firsttime;
+ int needsinterpolation;
+ bool firsttime;
};
}
diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp
@@ -94,64 +94,6 @@ static void liblo_error_cb(int i, const char *m, const char *loc)
fprintf(stderr, "liblo :-( %d-%s@%s\n",i,m,loc);
}
-void path_search(const char *m, const char *url)
-{
- using rtosc::Ports;
- using rtosc::Port;
-
- //assumed upper bound of 32 ports (may need to be resized)
- char types[256+1];
- rtosc_arg_t args[256];
- size_t pos = 0;
- const Ports *ports = NULL;
- const char *str = rtosc_argument(m,0).s;
- const char *needle = rtosc_argument(m,1).s;
-
- //zero out data
- memset(types, 0, sizeof(types));
- memset(args, 0, sizeof(args));
-
- if(!*str) {
- ports = &Master::ports;
- } else {
- const Port *port = Master::ports.apropos(rtosc_argument(m,0).s);
- if(port)
- ports = port->ports;
- }
-
- if(ports) {
- //RTness not confirmed here
- for(const Port &p:*ports) {
- if(strstr(p.name, needle) != p.name || !p.name)
- continue;
- types[pos] = 's';
- args[pos++].s = p.name;
- types[pos] = 'b';
- if(p.metadata && *p.metadata) {
- args[pos].b.data = (unsigned char*) p.metadata;
- auto tmp = rtosc::Port::MetaContainer(p.metadata);
- args[pos++].b.len = tmp.length();
- } else {
- args[pos].b.data = (unsigned char*) NULL;
- args[pos++].b.len = 0;
- }
- }
- }
-
-
- //Reply to requester [wow, these messages are getting huge...]
- char buffer[1024*20];
- size_t length = rtosc_amessage(buffer, sizeof(buffer), "/paths", types, args);
- if(length) {
- lo_message msg = lo_message_deserialise((void*)buffer, length, NULL);
- lo_address addr = lo_address_new_from_url(url);
- if(addr)
- lo_send_message(addr, buffer, msg);
- lo_address_free(addr);
- lo_message_free(msg);
- }
-}
-
static int handler_function(const char *path, const char *types, lo_arg **argv,
int argc, lo_message msg, void *user_data)
{
@@ -173,8 +115,26 @@ static int handler_function(const char *path, const char *types, lo_arg **argv,
memset(buffer, 0, sizeof(buffer));
size_t size = 2048;
lo_message_serialise(msg, path, buffer, &size);
- if(!strcmp(buffer, "/path-search") && !strcmp("ss", rtosc_argument_string(buffer))) {
- path_search(buffer, mw->activeUrl().c_str());
+
+ if(!strcmp(buffer, "/path-search") &&
+ !strcmp("ss", rtosc_argument_string(buffer))) {
+ auto reply_cb = [](const char* url, const char* types, const rtosc_arg_t* args)
+ {
+ char buffer[1024*20];
+ size_t length = rtosc_amessage(buffer, sizeof(buffer),
+ "/paths", types, args);
+ if(length) {
+ lo_message msg = lo_message_deserialise((void*)buffer,
+ length, NULL);
+ lo_address addr = lo_address_new_from_url(url);
+ if(addr)
+ lo_send_message(addr, buffer, msg);
+ lo_address_free(addr);
+ lo_message_free(msg);
+ }
+ };
+ rtosc::path_search(Master::ports, buffer, mw->activeUrl().c_str(),
+ reply_cb);
} else if(buffer[0]=='/' && strrchr(buffer, '/')[1]) {
mw->transmitMsg(rtosc::Ports::collapsePath(buffer));
}
diff --git a/src/Params/ADnoteParameters.cpp b/src/Params/ADnoteParameters.cpp
@@ -153,7 +153,7 @@ static const Ports voicePorts = {
//Modulator Stuff
- rOption(PFMEnabled, rShort("mode"), rOptions(none, morph, ring, phase,
+ rOption(PFMEnabled, rShort("mode"), rOptions(none, mix, ring, phase,
frequency, pulse), rDefault(none), "Modulator mode"),
rParamI(PFMVoice, rShort("voice"), rDefault(-1),
"Modulator Oscillator Selection"),
diff --git a/src/Params/ADnoteParameters.h b/src/Params/ADnoteParameters.h
@@ -20,7 +20,7 @@
namespace zyn {
enum FMTYPE {
- NONE, MORPH, RING_MOD, PHASE_MOD, FREQ_MOD, PW_MOD
+ NONE, MIX, RING_MOD, PHASE_MOD, FREQ_MOD, PW_MOD
};
/*****************************************************************/
@@ -258,7 +258,7 @@ struct ADnoteVoiceParam {
* MODULLATOR PARAMETERS *
****************************/
- /* Modullator Parameters (0=off,1=Morph,2=RM,3=PM,4=FM.. */
+ /* Modullator Parameters (0=off,1=Mix,2=RM,3=PM,4=FM.. */
unsigned char PFMEnabled;
/* Voice that I use as modullator instead of FMSmp.
diff --git a/src/Params/PADnoteParameters.cpp b/src/Params/PADnoteParameters.cpp
@@ -231,7 +231,8 @@ static const rtosc::Ports non_realtime_ports =
rParamI(Pquality.oct, rShort("octaves"), rLinear(0,7), rDefault(3),
"Number of octaves to sample (above the first sample"),
- {"Pbandwidth::i", rShort("bandwidth") rProp(parameter) rLinear(0,1000) rDoc("Bandwith Of Harmonics"), NULL,
+ {"Pbandwidth::i", rShort("bandwidth") rProp(parameter) rLinear(0,1000)
+ rDefault(500) rDoc("Bandwith Of Harmonics"), NULL,
[](const char *msg, rtosc::RtData &d) {
PADnoteParameters *p = ((PADnoteParameters*)d.obj);
if(rtosc_narguments(msg)) {
diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp
@@ -422,7 +422,7 @@ void ADnote::setupVoiceMod(int nvoice, bool first_run)
else
switch(param.PFMEnabled) {
case 1:
- voice.FMEnabled = MORPH;
+ voice.FMEnabled = MIX;
break;
case 2:
voice.FMEnabled = RING_MOD;
@@ -453,7 +453,7 @@ void ADnote::setupVoiceMod(int nvoice, bool first_run)
float tmp = 1.0f;
if((pars.VoicePar[vc].FMSmp->Padaptiveharmonics != 0)
- || (voice.FMEnabled == MORPH)
+ || (voice.FMEnabled == MIX)
|| (voice.FMEnabled == RING_MOD))
tmp = getFMvoicebasefreq(nvoice);
@@ -730,7 +730,7 @@ void ADnote::legatonote(LegatoParams lpars)
&& (NoteVoicePar[nvoice].FMVoice < 0)) {
pars.VoicePar[nvoice].FMSmp->newrandseed(prng());
- //Perform Anti-aliasing only on MORPH or RING MODULATION
+ //Perform Anti-aliasing only on MIX or RING MODULATION
int vc = nvoice;
if(pars.VoicePar[nvoice].PextFMoscil != -1)
@@ -920,7 +920,7 @@ void ADnote::initparameters(WatchManager *wm, const char *prefix)
param.FMSmp->newrandseed(prng());
vce.FMSmp = memory.valloc<float>(synth.oscilsize + OSCIL_SMP_EXTRA_SAMPLES);
- //Perform Anti-aliasing only on MORPH or RING MODULATION
+ //Perform Anti-aliasing only on MIX or RING MODULATION
int vc = nvoice;
if(param.PextFMoscil != -1)
@@ -928,7 +928,7 @@ void ADnote::initparameters(WatchManager *wm, const char *prefix)
float tmp = 1.0f;
if((pars.VoicePar[vc].FMSmp->Padaptiveharmonics != 0)
- || (vce.FMEnabled == MORPH)
+ || (vce.FMEnabled == MIX)
|| (vce.FMEnabled == RING_MOD))
tmp = getFMvoicebasefreq(nvoice);
@@ -1301,9 +1301,9 @@ inline void ADnote::ComputeVoiceOscillator_CubicInterpolation(int nvoice){
};
*/
/*
- * Computes the Oscillator (Morphing)
+ * Computes the Oscillator (Mixing)
*/
-inline void ADnote::ComputeVoiceOscillatorMorph(int nvoice)
+inline void ADnote::ComputeVoiceOscillatorMix(int nvoice)
{
ComputeVoiceOscillator_LinearInterpolation(nvoice);
if(FMnewamplitude[nvoice] > 1.0f)
@@ -1617,8 +1617,8 @@ int ADnote::noteout(float *outl, float *outr)
switch (NoteVoicePar[nvoice].noisetype) {
case 0: //voice mode=sound
switch(NoteVoicePar[nvoice].FMEnabled) {
- case MORPH:
- ComputeVoiceOscillatorMorph(nvoice);
+ case MIX:
+ ComputeVoiceOscillatorMix(nvoice);
break;
case RING_MOD:
ComputeVoiceOscillatorRingModulation(nvoice);
diff --git a/src/Synth/ADnote.h b/src/Synth/ADnote.h
@@ -86,9 +86,9 @@ class ADnote:public SynthNote
* Affects tmpwave_unison and updates oscposhi/oscposlo
* @todo remove this declaration if it is commented out*/
inline void ComputeVoiceOscillator_CubicInterpolation(int nvoice);
- /**Computes the Oscillator samples with morphing.
+ /**Computes the Oscillator samples with mixing.
* updates tmpwave_unison*/
- inline void ComputeVoiceOscillatorMorph(int nvoice);
+ inline void ComputeVoiceOscillatorMix(int nvoice);
/**Computes the Ring Modulated Oscillator.*/
inline void ComputeVoiceOscillatorRingModulation(int nvoice);
/**Computes the Frequency Modulated Oscillator.
@@ -255,8 +255,8 @@ class ADnote:public SynthNote
/* INTERNAL VALUES OF THE NOTE AND OF THE VOICES */
/********************************************************/
- //pinking filter (Paul Kellet)
- float pinking[NUM_VOICES][14];
+ //pinking filter (Paul Kellet)
+ float pinking[NUM_VOICES][14];
//the size of unison for a single voice
int unison_size[NUM_VOICES];
diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt
@@ -1,3 +1,8 @@
+function(cp_script script_name)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${script_name}
+ ${CMAKE_CURRENT_BINARY_DIR}/${script_name} COPYONLY)
+endfunction()
+
#for tests looking for files stored in the source dir
add_definitions(-DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
@@ -64,13 +69,18 @@ target_link_libraries(EffectTest ${test_lib})
add_executable(ins-test InstrumentStats.cpp)
target_link_libraries(ins-test ${test_lib} rt)
+if(LIBLO_FOUND)
+ cp_script(check-ports.rb)
+ add_test(PortChecker check-ports.rb)
+endif()
+
add_executable(save-osc SaveOSC.cpp)
target_link_libraries(save-osc
zynaddsubfx_core zynaddsubfx_nio
zynaddsubfx_gui_bridge
${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES})
-#this will be replace with a for loop when the code will get more stable:
-add_test(SaveOsc save-osc ../../../instruments/examples/Arpeggio\ 1.xmz)
+#this will be replaced with a for loop when the code will get more stable:
+add_test(SaveOsc save-osc ${CMAKE_CURRENT_SOURCE_DIR}/../../instruments/examples/Arpeggio\ 1.xmz)
#message(STATUS "Plugin Test ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}")
diff --git a/src/Tests/check-ports.rb b/src/Tests/check-ports.rb
@@ -0,0 +1,16 @@
+#!/usr/bin/ruby
+
+require 'open3'
+
+# start zyn, grep the lo server port, and connect the port checker to it
+Open3.popen3(Dir.pwd + "/../zynaddsubfx -O null --no-gui") do |stdin, stdout, stderr, wait_thr|
+ pid = wait_thr[:pid]
+ while line=stderr.gets do
+ # print "line: " + line;
+ if /^lo server running on (\d+)$/.match(line) then
+ rval = system(Dir.pwd + "/../../rtosc/port-checker 'osc.udp://localhost:" + $1 + "/'")
+ Process.kill("KILL", pid)
+ exit rval
+ end
+ end
+end
diff --git a/src/main.cpp b/src/main.cpp
@@ -28,6 +28,9 @@
#include <getopt.h>
+#include <sys/types.h>
+#include <signal.h>
+
#include <rtosc/rtosc.h>
#include <rtosc/ports.h>
#include "Params/PADnoteParameters.h"
@@ -735,7 +738,14 @@ done:
#endif
#endif
}
-
+#ifdef ZEST_GUI
+#ifndef WIN32
+ int ret = kill(gui_pid, SIGHUP);
+ if (ret == -1) {
+ err(1, "Failed to terminate Zyn-Fusion...\n");
+ }
+#endif
+#endif
exitprogram(config);
return 0;
}
diff --git a/zynaddsubfx-jack-multi.desktop b/zynaddsubfx-jack-multi.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Name=ZynAddSubFX - Jack (multi channel)
+Comment=A powerful realtime software synthesizer
+Comment[fr]=Un synthétiseur logiciel temps-réel puissant
+Comment[pl]=Funkcjonalny syntezator wirtualny czasu rzeczywistego
+Keywords=audio;sound;jack;midi;synth;synthesizer;
+Exec=zynaddsubfx -I jack -O jack-multi
+Icon=zynaddsubfx
+Terminal=false
+Type=Application
+Categories=AudioVideo;Audio;