commit 788045ba80f4ea84a02e08ab28aec8233c1c4dd3
parent 15e4323e623c4bcd3363776a630bdcf59e50977c
Author: Johannes Lorenz <johannes89@ist-einmalig.de>
Date: Tue, 12 Sep 2017 21:05:07 +0200
Merge branch 'master' of ssh://git.code.sf.net/p/zynaddsubfx/code into pad_synth_par
Diffstat:
68 files changed, 2104 insertions(+), 615 deletions(-)
diff --git a/.gitmodules b/.gitmodules
@@ -4,6 +4,7 @@
[submodule "rtosc"]
path = rtosc
url = https://github.com/fundamental/rtosc
+ branch = default_values
[submodule "DPF"]
path = DPF
url = git://github.com/DISTRHO/DPF
diff --git a/.travis.yml b/.travis.yml
@@ -4,14 +4,6 @@ compiler:
- gcc
before_install:
- - sudo apt-get --purge remove gcc
- - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- - sudo apt-add-repository -y ppa:dhart/ppa
- - sudo apt-get -qq update
- - sudo apt-get -qq install g++-4.8
- - sudo apt-get -qq install gcc-4.8
- - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
- - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90
- sudo apt-get install zlib1g-dev libmxml-dev libfftw3-dev dssi-dev libfltk1.3-dev libxpm-dev
- sudo apt-get install --force-yes cxxtest
- wget http://downloads.sourceforge.net/liblo/liblo-0.28.tar.gz
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -3,8 +3,12 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
project(zynaddsubfx)
set(VERSION_MAJOR "3")
set(VERSION_MINOR "0")
-set(VERSION_REVISION "1")
+set(VERSION_REVISION "2")
+#Set data directory, if any
+if(DEFINED ZYN_DATADIR)
+add_definitions(-DZYN_DATADIR="${ZYN_DATADIR}")
+endif()
#Include RTOSC
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/rtosc/CMakeLists.txt")
@@ -34,14 +38,19 @@ 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
+install(FILES zynaddsubfx-jack.desktop zynaddsubfx-alsa.desktop zynaddsubfx-oss.desktop
DESTINATION share/applications)
install(FILES zynaddsubfx.svg
DESTINATION share/pixmaps)
install(DIRECTORY instruments/banks
DESTINATION share/zynaddsubfx)
+if(DEFINED ZYN_EXAMPLESDIR)
+install(DIRECTORY instruments/examples
+ DESTINATION ${ZYN_EXAMPLESDIR})
+else()
install(DIRECTORY instruments/examples
DESTINATION share/zynaddsubfx)
+endif()
install(DIRECTORY instruments/ZynAddSubFX.lv2presets
DESTINATION ${PluginLibDir}/lv2)
diff --git a/HISTORY.txt b/HISTORY.txt
@@ -1,3 +1,14 @@
+3.0.2 (21 July 2017)
+ - Upgrade MIDI learn system to include host automations and macro
+ learned controls
+ - Upgrade analog filter parameters to floating point resolution
+ - Add default values to OSC metadata
+ - Fix exit when closing zyn-fusion subprocess
+ - Fix crash with large number of pad synth samples
+ - Silence 0 volume effects
+ - Silence 0 volume add synth voices
+ - Fix minor bugs
+
3.0.1 (28 November 2016)
- Fix bank screen with Zyn-Fusion
- Fix crash on startup with GL 2.1 to 3.1
diff --git a/doc/automation-proposal/automation1.png b/doc/automation-proposal/automation1.png
Binary files differ.
diff --git a/doc/automation-proposal/current_slot.png b/doc/automation-proposal/current_slot.png
Binary files differ.
diff --git a/doc/automation-proposal/macro.png b/doc/automation-proposal/macro.png
Binary files differ.
diff --git a/doc/automation-proposal/macro_view.png b/doc/automation-proposal/macro_view.png
Binary files differ.
diff --git a/doc/automation-proposal/parameter-automation-documentation.txt b/doc/automation-proposal/parameter-automation-documentation.txt
@@ -0,0 +1,208 @@
+An Introduction to the ZynAddSubFX Macro System
+===============================================
+:author: Mark McCurry, Spencer Jackson
+:toc:
+
+
+Motivation
+----------
+
+One of the major issues expressed by users around the time of the initial
+3.0.0 launch was that they were dissatisfied with automations when using
+ZynAddSubFX within their preferred VST host. This was a combination of:
+
+1. Hosts providing a poor workflow for sending MIDI CC events compared to VST
+ parameters
+2. Confusion with the use of MIDI learn within Zyn
+3. Issues regarding saving/loading parameters exposed through MIDI learn
+4. Parameter resolution for MIDI CCs
+5. Some parameters only produce updates on the next note
+
+This feature attempts to address points 1, 2, & 3. Issue 4 is a large undertaking
+but is expected to become complete for the 3.1.x release. Issue 5 is being fixed
+one set of parameters at a time and should be addressed in the 3.0.x series.
+
+Overview & Terminology
+----------------------
+
+The Macro System boils down to replacing the existing MIDI learn implementation
+with a series of 'slots' for parameter automation and automation
+macros. In its current state it does that and a little more but as it matures it
+should become a powerful system for automation and live tweaking of sounds.
+
+What is an automation?
+~~~~~~~~~~~~~~~~~~~~~~
+image::automation1.png[]
+
+- A single parameter, e.g. the addsynth base frequency in part 1, kit 1
+- A gain and offset to adjust the range of values the automation will reach
+(e.g. -50 cents to +150 cents)
+- A mapping function (currently only linear, log, custom, etc coming soon)
+
+What is a macro?
+~~~~~~~~~~~~~~~~
+
+- A group of automations that get assigned to an automation slot
+
+All automations in the macro are operated together. Thus turning one knob on
+your MIDI controller or a single automation lane in a DAW can change up to
+4 parameters (see <<FAQ>>)
+at a time. Using the automation mappings allows for all the parameters to be adjusted
+in different amounts and/or directions, but they are all moved by actuating the macro.
+
+Macros are assembled by adding automations to a macro slot.
+
+What is a macro slot?
+~~~~~~~~~~~~~~~~~~~~~~
+
+- A set of one or more automations (a single macro)
+- An optional MIDI CC binding or plugin host automation
+
+In Zynaddsubfx 3.0.2 all macro slots are global. This means that loading new
+instruments does not switch the automations in any way. Only loading and saving
+Zyn master files will allow you to quickly switch between macro slot configurations.
+In future versions there
+will be global macro slots and instrument macro slots that can be saved
+and loaded independently.
+
+The global macro slots are exposed to VST/LV2 hosts.
+This keeps the total number of parameters exposed to a host somewhat
+reasonable: 16 slots for automation of up to 64 parameters.
+
+
+At the level of a Zyn master file (.xmz) the automation slots
+can be bound to MIDI CCs; loading the file will reload the midi bindings.
+Zyn MIDI-learn files (.xlz) can store the MIDI CC+Channel linkage to all
+automation slots.
+
+The Macros View
+---------------
+
+image::macro_view.png[]
+
+The Macro view shows:
+
+. List of Slots
+.. Slot state (active, inactive) - currently this button is disabled, all slots are always active
+.. A "clear slot" button (the x) - removes all automations in the slot
+.. Slot name - click name to edit
+. Macro selector buttons
+.. highlighted button is the slot currently selected
+.. use these when macro learning to select which slot to add to
+. Macro sliders - (green bars under names)
+.. indicates current macro value
+.. slide to adjust through the UI
+. Learning Mode selectors
+.. Normal Learn - each learned automation is added to the next available slot
+.. Macro Learn - learned automations are added to the currently selected slot (if not full)
+
+image::current_slot.png[]
+Currently selected slot is selected/indicated with these buttons.
+
+The selected macro shows:
+
+. MIDI binding if any e.g. "Chan 2, CC 14" (or "None" or "Learning Queue N")
+. 4 Automations
+
+image::automation1.png[]
+
+Each automation shows
+
+. Parameter path/name - clicking a section of the path shows a dropdown menu allowing easy switching between parts, voices, engines, etc.
+. Minimum, maximum, center value of parameter
+. Graph of map function
+.. X is the macro value
+.. Y is value of parameter being automated
+. Gain knob - adjust to change slope of map function
+. Offset knob adjust to move map function up or down
+. Remove button (X) - click to remove the automation
+
+
+Workflow examples
+-----------------
+
+Automating a parameter in plugin mode
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+. Learn mode should be set to Normal Learn (this is the default)
+. Use CTRL or click the [Learn] button to start learning an automation
+. Click on one or more controls (knobs/sliders/buttons) to assign them to
+ automation slots
+.. After clicking, each control is allocated to the next free Master
+ automation slot
+.. the automation slot is put into the unbound state (it can be put into
+ "MIDI learn" mode later.
+. The automation can be adjusted in the automation view
+
+Binding parameters to MIDI in standalone mode
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+. Learn mode should be set to Normal Learn (this is the default)
+. Use CTRL or click the [Learn] button to start learning an automation
+. Click on one or more controls (knobs/sliders/buttons) to assign them to
+ automation slots
+.. After clicking, each control is allocated to the next free Master
+ automation slot
+.. Each automation slot is then placed into the "MIDI learn" mode, watching for
+ the next unbound MIDI CC that arrives in standalone mode
+ (MIDI CCs are identified by Channel+CC# in Master automation slots)
+. The user optionally sends CCs to be bound by wiggling the controls on their
+ physical (or virtual) MIDI device
+. The automation can be adjusted in the automation view
+
+Setting up a macro
+~~~~~~~~~~~~~~~~~~
+
+image::macro.png[]
+A macro with 3 automations
+
+. Enter the Macro view
+. Select the Macro Learn button (the Normal Learn button will turn off)
+. Select the macro slot you would like to add new automations to
+. Hold CTRL or double click the [Learn] button to enter learn mode
+. Click the parameter(s) that you wish to add the the macro slot
+. To add parameters to another macro slot switch the currently selected
+ macro slot in the Macro view
+
+Adjusting automation ranges
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+. Go to the macro view
+. Find the right macro slot and automation
+. Adjust gain
+.. High gain will make the automation's parameter traverse the whole range of travel with just a little movement of the macro.
+.. Low gain will make the automation's parameter travel less range through the knob than the knob in the UI
+.. Negative gain makes the macro adjust the parameter down when the macro is turned up
+. Adjust offset
+.. This moves the automation's parameter range of travel up or down
+. If an automation was unintentional the user can use the X button to remove that automation
+
+Learning/changing MIDI CC bindings after loading an instrument/binding
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+. Go to the [Macro] view
+. Find the right macro slot and automation
+. Single click on the MIDI CC widget
+.. The automation switches to the "learning CC" state
+. Wiggle some MIDI controller
+. OR Double click on the MIDI CC widget
+.. this shows a dialog to manually choose the channel and CC id
+. The CC has been remapped
+
+FAQ
+---
+Q: Why only 4 automations to a slot?
+
+A: Limiting it to only 4 allowed for an easier design in the UI. There is no
+limitation in the software and if many users request more capability, we will
+extend it to more.
+
+
+Q: What happens if a single parameter is in multiple automation slots?
+
+A: Currently the engine will set the parameter to the value from the macro that
+was most recently changed. Future versions may allow for macro fusion to combine
+multiple values in different ways.
+
+
+Q: Why didn't you add _feature X_
+
+A: We love well documented feature requests. Please leave your idea in our bugtracker at https://sourceforge.net/p/zynaddsubfx/feature-requests/
diff --git a/src/Effects/Alienwah.cpp b/src/Effects/Alienwah.cpp
@@ -36,17 +36,26 @@ rtosc::Ports Alienwah::ports = {
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
- //Pvolume/Ppanning are common
- rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"),
- rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"),
+ rEffParVol(rDefault(127), rPresetsAt(3, 93)),
+ rEffParPan(),
+ rEffPar(Pfreq, 2, rShort("freq") rPresets(70, 73, 63, 25),
+ "Effect Frequency"),
+ rEffPar(Pfreqrnd, 3, rShort("rand"), rPreset(1, 106) rDefault(0),
+ "Frequency Randomness"),
rEffPar(PLFOtype, 4, rShort("shape"),
- rOptions(sine, triangle), "LFO Shape"),
- rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"),
- rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"),
- rEffPar(Pfeedback, 7, rShort("fb"), "Feedback"),
- rEffPar(Pdelay, 8, rLinear(1,100), rShort("delay"), "Delay"),
- rEffPar(Plrcross, 9, rShort("l/r"), "Left/Right Crossover"),
- rEffPar(Pphase, 10, rShort("phase"), "Phase"),
+ rOptions(sine, triangle), rPresets(sine, sine, triangle, triangle),
+ "LFO Shape"),
+ rEffPar(PStereo, 5, rShort("stereo"), rPresets(62, 101, 100, 66),
+ "Stereo Mode"),
+ rEffPar(Pdepth, 6, rShort("depth"), rPresets(60, 60, 112, 101),
+ "LFO Depth"),
+ rEffPar(Pfeedback, 7, rShort("fb"), rPreset(3, 11), rDefault(105),
+ "Feedback"),
+ rEffPar(Pdelay, 8, rLinear(1,100), rPresets(25, 17, 31, 47),
+ rShort("delay"), "Delay"),
+ rEffPar(Plrcross, 9, rShort("l/r"), rDefault(0), "Left/Right Crossover"),
+ rEffPar(Pphase, 10, rShort("phase"), rDefault(64), rPreset(2, 42),
+ rPreset(3, 86), "Phase"),
};
#undef rBegin
#undef rEnd
diff --git a/src/Effects/Chorus.cpp b/src/Effects/Chorus.cpp
@@ -39,17 +39,32 @@ rtosc::Ports Chorus::ports = {
rEnd},
//Pvolume/Ppanning are common
- rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"),
- rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"),
+ rEffParVol(rDefault(64)),
+ rEffParPan(),
+ rEffPar(Pfreq, 2, rShort("freq"),
+ rPresets(50, 45, 29, 26, 29, 57, 33, 53, 40, 55),
+ "Effect Frequency"),
+ rEffPar(Pfreqrnd, 3, rShort("rand"),
+ rPreset(4, 117) rPreset(6, 34) rPreset(7, 34) rPreset(9, 105)
+ rDefault(0), "Frequency Randomness"),
rEffPar(PLFOtype, 4, rShort("shape"),
- rOptions(sine, tri), "LFO Shape"),
- rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"),
- rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"),
- rEffPar(Pdelay, 7, rShort("delay"), "Delay"),
- rEffPar(Pfeedback,8, rShort("fb"), "Feedback"),
- rEffPar(Plrcross, 9, rShort("l/r"), "Left/Right Crossover"),
- rEffParTF(Pflangemode, 10, rShort("flange"), "Flange Mode"),
- rEffParTF(Poutsub, 11, rShort("sub"), "Output Subtraction"),
+ rOptions(sine, tri),
+ rPresets(sine, sine, tri, sine, sine, sine, tri, tri, tri, sine)
+ "LFO Shape"),
+ rEffPar(PStereo, 5, rShort("stereo"),
+ rPresets(90, 98, 42, 42, 50, 60, 40, 94, 62), "Stereo Mode"),
+ rEffPar(Pdepth, 6, rShort("depth"),
+ rPresets(40, 56, 97, 115, 115, 23, 35, 35, 12), "LFO Depth"),
+ rEffPar(Pdelay, 7, rShort("delay"),
+ rPresets(85, 90, 95, 18, 9, 3, 3, 3, 19), "Delay"),
+ rEffPar(Pfeedback,8, rShort("fb"),
+ rPresets(64, 64, 90, 90, 31, 62, 109, 54, 97), "Feedback"),
+ rEffPar(Plrcross, 9, rShort("l/r"), rPresets(119, 19, 127, 127, 127),
+ rDefault(0), "Left/Right Crossover"),
+ rEffParTF(Pflangemode, 10, rShort("flange"), rDefault(false),
+ "Flange Mode"),
+ rEffParTF(Poutsub, 11, rShort("sub"), rPreset(4, true), rPreset(7, true),
+ rDefault(false), "Output Subtraction"),
};
#undef rBegin
#undef rEnd
diff --git a/src/Effects/Distorsion.cpp b/src/Effects/Distorsion.cpp
@@ -37,21 +37,29 @@ rtosc::Ports Distorsion::ports = {
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
- //Pvolume/Ppanning are common
- rEffPar(Plrcross, 2, rShort("l/r"), "Left/Right Crossover"),
- rEffPar(Pdrive, 3, rShort("drive"), "Input amplification"),
- rEffPar(Plevel, 4, rShort("output"), "Output amplification"),
+ rEffParVol(rDefault(127), rPresetsAt(2, 64, 64)),
+ rEffParPan(),
+ rEffPar(Plrcross, 2, rShort("l/r"), rDefault(35), "Left/Right Crossover"),
+ rEffPar(Pdrive, 3, rShort("drive"), rPresets(56, 29, 75, 85, 63, 88),
+ "Input amplification"),
+ rEffPar(Plevel, 4, rShort("output"), rPresets(70, 75, 80, 62, 75, 75),
+ "Output amplification"),
rEffPar(Ptype, 5, rShort("type"),
rOptions(Arctangent, Asymmetric, Pow, Sine, Quantisize,
- Zigzag, Limiter, Upper Limiter, Lower Limiter,
- Inverse Limiter, Clip, Asym2, Pow2, sigmoid),
+ Zigzag, Limiter, Upper Limiter, Lower Limiter,
+ Inverse Limiter, Clip, Asym2, Pow2, sigmoid),
+ rPresets(Arctangent, Asymmetric, Zigzag,
+ Asymmetric, Pow, Quantisize),
"Distortion Shape"),
- rEffParTF(Pnegate, 6, rShort("neg"), "Negate Signal"),
- rEffPar(Plpf, 7, rShort("lpf"), "Low Pass Cutoff"),
- rEffPar(Phpf, 8, rShort("hpf"), "High Pass Cutoff"),
- rEffParTF(Pstereo, 9, rShort("stereo"), "Stereo"),
- rEffParTF(Pprefiltering, 10, rShort("p.filt"),
- "Filtering before/after non-linearity"),
+ rEffParTF(Pnegate, 6, rShort("neg"), rDefault(false), "Negate Signal"),
+ rEffPar(Plpf, 7, rShort("lpf"),
+ rPreset(0, 96), rPreset(4, 55), rDefault(127), "Low Pass Cutoff"),
+ rEffPar(Phpf, 8, rShort("hpf"),
+ rPreset(2, 105), rPreset(3, 118), rDefault(0), "High Pass Cutoff"),
+ rEffParTF(Pstereo, 9, rShort("stereo"),
+ rPresets(false, false, true, true, false, true), "Stereo"),
+ rEffParTF(Pprefiltering, 10, rShort("p.filt"), rDefault(false),
+ "Filtering before/after non-linearity"),
{"waveform:", 0, 0, [](const char *, rtosc::RtData &d)
{
Distorsion &dd = *(Distorsion*)d.obj;
diff --git a/src/Effects/DynamicFilter.cpp b/src/Effects/DynamicFilter.cpp
@@ -36,16 +36,24 @@ rtosc::Ports DynamicFilter::ports = {
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
- //Pvolume/Ppanning are common
- rEffPar(Pfreq, 2, rShort("freq"), "Effect Frequency"),
- rEffPar(Pfreqrnd, 3, rShort("rand"), "Frequency Randomness"),
- rEffPar(PLFOtype, 4, rShort("shape"),
- rOptions(sin, tri), "LFO Shape"),
- rEffPar(PStereo, 5, rShort("stereo"), "Stereo Mode"),
- rEffPar(Pdepth, 6, rShort("depth"), "LFO Depth"),
- rEffPar(Pampsns, 7, rShort("sense"), "how the filter varies according to the input amplitude"),
- rEffPar(Pampsnsinv, 8, rShort("sns.inv"), "Sense Inversion"),
- rEffPar(Pampsmooth, 9, rShort("smooth"), "how smooth the input amplitude changes the filter"),
+ rEffParVol(rDefault(110), rPreset(2, 110), rPreset(4, 127)),
+ rEffParPan(),
+ rEffPar(Pfreq, 2, rShort("freq"), rPresets(80, 70, 30, 80, 50),
+ "Effect Frequency"),
+ rEffPar(Pfreqrnd, 3, rShort("rand"), rDefault(0),
+ "Frequency Randomness"),
+ rEffPar(PLFOtype, 4, rShort("shape"), rOptions(sin, tri), rDefault(sin),
+ "LFO Shape"),
+ rEffPar(PStereo, 5, rShort("stereo"), rPresets(64, 80, 50, 64, 96),
+ "Stereo Mode"),
+ rEffPar(Pdepth, 6, rShort("depth"), rPresets(0, 70, 80, 0, 64),
+ "LFO Depth"),
+ rEffPar(Pampsns, 7, rShort("sense"),
+ rPreset(0, 90) rPreset(3, 64) rDefault(0),
+ "how the filter varies according to the input amplitude"),
+ rEffPar(Pampsnsinv, 8, rShort("sns.inv"), rDefault(0), "Sense Inversion"),
+ rEffPar(Pampsmooth, 9, rShort("smooth"), rDefault(60),
+ "how smooth the input amplitude changes the filter"),
};
#undef rBegin
#undef rEnd
diff --git a/src/Effects/EQ.cpp b/src/Effects/EQ.cpp
@@ -80,8 +80,8 @@ rtosc::Ports EQ::ports = {
memset(b, 0, sizeof(b));
eq->getFilter(a,b);
- char type[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2+1] = {0};
- rtosc_arg_t val[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2] = {0};
+ char type[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2+1] = {};
+ rtosc_arg_t val[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2] = {};
for(int i=0; i<MAX_EQ_BANDS*MAX_FILTER_STAGES*3; ++i) {
int stride = MAX_EQ_BANDS*MAX_FILTER_STAGES*3;
type[i] = type[i+stride] = 'f';
diff --git a/src/Effects/Echo.cpp b/src/Effects/Echo.cpp
@@ -39,12 +39,23 @@ rtosc::Ports Echo::ports = {
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
- //Pvolume/Ppanning are common
- rEffPar(Pdelay, 2, rShort("delay"), "Length of Echo"),
- rEffPar(Plrdelay, 3, rShort("lr delay"), "Difference In Left/Right Delay"),
- rEffPar(Plrcross, 4, rShort("cross"), "Left/Right Crossover"),
- rEffPar(Pfb, 5, rShort("feedback"), "Echo Feedback"),
- rEffPar(Phidamp, 6, rShort("damp"), "Dampen High Frequencies"),
+ rEffParVol(rDefault(67), rPresetsAt(6, 81, 81, 62)),
+ rEffParPan(rPresetsAt(2, 75, 60, 60, 64, 60, 60, 64)),
+ rEffPar(Pdelay, 2, rShort("delay"),
+ rPresets(35, 21, 60, 44, 102, 44, 46, 26, 28),
+ "Length of Echo"),
+ rEffPar(Plrdelay, 3, rShort("lr delay"),
+ rPresetsAt(4, 50, 17, 118, 100, 64), rDefault(64),
+ "Difference In Left/Right Delay"),
+ rEffPar(Plrcross, 4, rShort("cross"),
+ rPresetsAt(5, 0, 100, 127, 100), rDefault(30),
+ "Left/Right Crossover"),
+ rEffPar(Pfb, 5, rShort("feedback"),
+ rPresets(59, 59, 59, 0, 82, 82, 68, 67, 90),
+ "Echo Feedback"),
+ rEffPar(Phidamp, 6, rShort("damp"),
+ rPresets(0, 0, 10, 0, 48, 24, 18, 36, 55),
+ "Dampen High Frequencies"),
};
#undef rBegin
#undef rEnd
diff --git a/src/Effects/Effect.h b/src/Effects/Effect.h
@@ -19,11 +19,15 @@
#include "../Params/FilterParams.h"
#include "../Misc/Stereo.h"
+// bug: the effect parameters can currently be set, but such values
+// will not be saved into XML files
#ifndef rEffPar
#define rEffPar(name, idx, ...) \
- {STRINGIFY(name) "::i", rProp(parameter) DOC(__VA_ARGS__), NULL, rEffParCb(idx)}
+ {STRINGIFY(name) "::i", rProp(parameter) rDefaultDepends(preset) \
+ DOC(__VA_ARGS__), NULL, rEffParCb(idx)}
#define rEffParTF(name, idx, ...) \
- {STRINGIFY(name) "::T:F", rProp(parameter) DOC(__VA_ARGS__), NULL, rEffParTFCb(idx)}
+ {STRINGIFY(name) "::T:F", rProp(parameter) rDefaultDepends(preset) \
+ DOC(__VA_ARGS__), NULL, rEffParTFCb(idx)}
#define rEffParCb(idx) \
[](const char *msg, rtosc::RtData &d) {\
rObject &obj = *(rObject*)d.obj; \
@@ -40,6 +44,27 @@
d.reply(d.loc, obj.getpar(idx)?"T":"F");}
#endif
+#define rEffParCommon(pname, rshort, rdoc, idx, ...) \
+{STRINGIFY(pname) "::i", rProp(parameter) rLinear(0,127) \
+ rShort(rshort) rDoc(rdoc), \
+ 0, \
+ [](const char *msg, rtosc::RtData &d) \
+ { \
+ rObject& eff = *(rObject*)d.obj; \
+ if(!rtosc_narguments(msg)) \
+ d.reply(d.loc, "i", eff.getpar(idx)); \
+ else { \
+ eff.changepar(0, rtosc_argument(msg, 0).i); \
+ d.broadcast(d.loc, "i", eff.getpar(idx)); \
+ } \
+ }}
+
+#define rEffParVol(...) rEffParCommon(Pvolume, "amt", "amount of effect", 0, \
+ __VA_ARGS__)
+#define rEffParPan(...) rEffParCommon(Ppanning, "pan", "panning", 1, \
+ __VA_ARGS__)
+
+
namespace zyn {
class FilterParams;
diff --git a/src/Effects/EffectMgr.cpp b/src/Effects/EffectMgr.cpp
@@ -38,15 +38,16 @@ namespace zyn {
{STRINGIFY(name)"/", NULL, &name::ports,\
[](const char *msg, rtosc::RtData &data){\
rObject &o = *(rObject*)data.obj; \
- data.obj = o.efx; \
- if(!dynamic_cast<name*>(o.efx)) \
+ data.obj = dynamic_cast<name*>(o.efx); \
+ if(!data.obj) \
return; \
SNIP \
name::ports.dispatch(msg, data); \
}}
static const rtosc::Ports local_ports = {
- rSelf(EffectMgr),
+ rSelf(EffectMgr, rEnabledByCondition(self-enabled)),
rPaste,
+ rEnabledCondition(self-enabled, obj->geteffect()),
rRecurp(filterpars, "Filter Parameter for Dynamic Filter"),
{"Pvolume::i", rProp(parameter) rLinear(0,127) rShort("amt") rDoc("amount of effect"),
0,
@@ -93,7 +94,8 @@ static const rtosc::Ports local_ports = {
d.broadcast(d.loc, "i", eff->geteffectparrt(atoi(mm)));
}
}},
- {"preset::i", rProp(parameter) rProp(alias) rDoc("Effect Preset Selector"), NULL,
+ {"preset::i", rProp(parameter) rProp(alias) rDoc("Effect Preset Selector")
+ rDefault(0), NULL,
[](const char *msg, rtosc::RtData &d)
{
char loc[1024];
@@ -129,18 +131,10 @@ static const rtosc::Ports local_ports = {
eq->getFilter(a,b);
d.reply(d.loc, "bb", sizeof(a), a, sizeof(b), b);
}},
- {"efftype::i", rOptions(Disabled, Reverb, Echo, Chorus,
- Phaser, Alienwah, Distortion, EQ, DynFilter)
- rProp(parameter) rDoc("Get Effect Type"), NULL,
- [](const char *m, rtosc::RtData &d)
- {
- EffectMgr *eff = (EffectMgr*)d.obj;
- if(rtosc_narguments(m)) {
- eff->changeeffectrt(rtosc_argument(m,0).i);
- d.broadcast(d.loc, "i", eff->nefx);
- } else
- d.reply(d.loc, "i", eff->nefx);
- }},
+ {"efftype::i:c:S", rOptions(Disabled, Reverb, Echo, Chorus,
+ Phaser, Alienwah, Distortion, EQ, DynFilter) rDefault(Disabled)
+ rProp(parameter) rDoc("Get Effect Type"), NULL,
+ rCOptionCb(obj->nefx, obj->changeeffectrt(var))},
{"efftype:b", rProp(internal) rDoc("Pointer swap EffectMgr"), NULL,
[](const char *msg, rtosc::RtData &d)
{
@@ -472,7 +466,12 @@ void EffectMgr::add2XML(XMLwrapper& xml)
xml.beginbranch("EFFECT_PARAMETERS");
for(int n = 0; n < 128; ++n) {
- int par = geteffectpar(n);
+ int par = 0;
+ if(efx)
+ par = efx->getpar(n);
+ else if(n<128)
+ par = settings[n];
+
if(par == 0)
continue;
xml.beginbranch("par_no", n);
diff --git a/src/Effects/EffectMgr.h b/src/Effects/EffectMgr.h
@@ -77,6 +77,30 @@ class EffectMgr:public Presets
//Parameters Prior to initialization
char preset;
+
+ /**
+ * When loading an effect from XML the child effect cannot be loaded
+ * directly as it would require access to the realtime memory pool,
+ * which cannot be done outside of the realtime thread.
+ * Therefore, parameters are loaded to this array which can then be used
+ * to construct the full effect (via init()) once the object is in the
+ * realtime context.
+ *
+ * Additionally this structure is used in the case of pasting effects as
+ * pasted effect object are *not* fully initialized when they're put on
+ * the middleware -> backend ringbuffer, but settings has the values
+ * loaded from the XML serialization.
+ * The settings values can be pasted once they're on the realtime thread
+ * and then they can be applied.
+ *
+ * The requirement that the realtime memory pool is used to create the
+ * effect is in place as it is possible to change the effect type in the
+ * realtime thread and thus the new effect would draw from the realtime
+ * memory pool and the old object would be expected to be freed to the
+ * realtime memory pool.
+ *
+ * See also: PresetExtractor.cpp
+ */
char settings[128];
bool dryonly;
diff --git a/src/Effects/Phaser.cpp b/src/Effects/Phaser.cpp
@@ -37,7 +37,8 @@ namespace zyn {
d.reply(d.loc, "i", p.P##pname); \
rEnd
#define rParamPhaser(name, ...) \
- {STRINGIFY(P##name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) DOC(__VA_ARGS__), NULL, ucharParamCb(name)}
+ {STRINGIFY(P##name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) \
+ rDefaultDepends(preset) DOC(__VA_ARGS__), NULL, ucharParamCb(name)}
rtosc::Ports Phaser::ports = {
{"preset::i", rProp(parameter)
@@ -53,23 +54,52 @@ rtosc::Ports Phaser::ports = {
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
- //Pvolume/Ppanning are common
- rEffPar(lfo.Pfreq, 2, rShort("freq"), "LFO frequency"),
- rEffPar(lfo.Prandomness, 3, rShort("rnd."), "LFO randomness"),
+ rEffParVol(rDefault(64), rPreset(3, 39), rPreset(10, 25)),
+ rEffParPan(),
+ rEffPar(lfo.Pfreq, 2, rShort("freq"),
+ rPresets(36, 35, 31, 22, 20, 53, 14, 14, 9, 14, 127, 1),
+ "LFO frequency"),
+ rEffPar(lfo.Prandomness, 3, rShort("rnd."),
+ rPreset(5, 100), rPreset(7, 5), rPresetsAt(9, 10, 10, 10),
+ rDefault(0), "LFO randomness"),
rEffPar(lfo.PLFOtype, 4, rShort("type"),
- rOptions(sine, tri), "lfo shape"),
- rEffPar(lfo.Pstereo, 5, rShort("stereo"), "Left/right channel phase shift"),
- rEffPar(Pdepth, 6, rShort("depth"), "LFP depth"),
- rEffPar(Pfb, 7, rShort("fb"), "Feedback"),
- rEffPar(Pstages, 8, rLinear(1,12), rShort("stages"), ""),
- rParamPhaser(lrcross, rShort("cross"), "Channel routing"),
- rParamPhaser(offset, rShort("off"), "Offset"),
- rEffParTF(Poutsub, 10, rShort("sub"), "Invert output"),
- rParamPhaser(phase, rShort("phase"), ""),
- rParamPhaser(width, rShort("width"), ""),
- rEffParTF(Phyper, 12, rShort("hyp."), "Square the LFO"),
- rEffPar(Pdistortion, 13, rShort("distort"), "Distortion"),
- rEffParTF(Panalog, 14, rShort("analog"), "Use analog phaser"),
+ rPreset(4, tri), rPresetsAt(6, tri, tri), rPreset(11, tri),
+ rDefault(sine),
+ rOptions(sine, tri), "lfo shape"),
+ rEffPar(lfo.Pstereo, 5, rShort("stereo"),
+ rPresetsAt(1, 88, 66, 66, 110, 58), rDefault(64),
+ "Left/right channel phase shift"),
+ rEffPar(Pdepth, 6, rShort("depth"),
+ rPresets(110, 40, 68, 67, 67, 37, 64, 70, 60, 45, 25, 70),
+ "LFP depth"),
+ rEffPar(Pfb, 7, rShort("fb"),
+ rPresets(64, 64, 107, 10, 78, 78, 40, 40, 40, 80, 16, 40),
+ "Feedback"),
+ rEffPar(Pstages, 8, rLinear(1,12), rShort("stages"),
+ rPresets(1, 3, 2, 5, 10, 3, 4, 6, 8, 7, 8, 12),
+ ""),
+ rParamPhaser(lrcross, rShort("cross"),
+ rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0),
+ "Channel routing"),
+ rParamPhaser(offset, rShort("off"),
+ rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0),
+ "Offset"),
+ rEffParTF(Poutsub, 10, rShort("sub"),
+ rPreset(3, true), rPreset(9, true), rDefault(false),
+ "Invert output"),
+ rParamPhaser(phase, rShort("phase"),
+ rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""),
+ rParamPhaser(width, rShort("width"),
+ rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""),
+ rEffParTF(Phyper, 12, rShort("hyp."),
+ rPresetsAt(6, true, true, false, true, false, true),
+ rDefault(false), "Square the LFO"),
+ rEffPar(Pdistortion, 13, rShort("distort"),
+ rPresetsAt(6, 20, 20, 20, 20, 20, 20), rDefault(0),
+ "Distortion"),
+ rEffParTF(Panalog, 14, rShort("analog"),
+ rPresetsAt(6, true, true, true, true, true, true), rDefault(false),
+ "Use analog phaser"),
};
#undef rBegin
#undef rEnd
diff --git a/src/Effects/Reverb.cpp b/src/Effects/Reverb.cpp
@@ -39,18 +39,38 @@ rtosc::Ports Reverb::ports = {
else
d.reply(d.loc, "i", o->Ppreset);
rEnd},
- //Pvolume/Ppanning are common
- rEffPar(Ptime, 2, rShort("time"), "Length of Reverb"),
- rEffPar(Pidelay, 3, rShort("i.time"), "Delay for first impulse"),
- rEffPar(Pidelayfb,4, rShort("i.fb"), "Feedback for first impulse"),
- rEffPar(Plpf, 7, rShort("lpf"), "Low pass filter"),
- rEffPar(Phpf, 8, rShort("hpf"), "High pass filter"),
- rEffPar(Plohidamp,9, rShort("damp"), "Dampening"),
+ rEffParVol(rDefault(90), rPresets(80, 80, 80),
+ rPresetsAt(5, 100, 100, 110, 85, 95)),
+ rEffParPan(rPreset(8, 80)),
+ rEffPar(Ptime, 2, rShort("time"),
+ rPresets(63, 69, 69, 51, 53, 33, 21, 14, 84, 26, 40, 93, 111),
+ "Length of Reverb"),
+ rEffPar(Pidelay, 3, rShort("i.time"),
+ rPresets(24, 35, 24, 10, 20, 0, 26, 0, 20, 60, 88, 15, 30),
+ "Delay for first impulse"),
+ rEffPar(Pidelayfb,4, rShort("i.fb"), rPresetsAt(8, 42, 71, 71), rDefault(0),
+ "Feedback for first impulse"),
+ rEffPar(Plpf, 7, rShort("lpf"),
+ rPreset(1, 85), rPresetsAt(62, 127, 51, 114, 114, 114),
+ rDefault(127), "Low pass filter"),
+ rEffPar(Phpf, 8, rShort("hpf"),
+ rPresets(5), rPresetsAt(2, 75, 21, 75), rPreset(7, 50),
+ rPreset(12, 90), rDefault(0), "High pass filter"),
+ rEffPar(Plohidamp,9, rShort("damp"), rDefault(0),
+ rPresets(83, 71, 78, 78, 71, 106, 77, 71, 78, 64, 88, 77, 74)
+ "Dampening"),
//Todo make this a selector
- rEffPar(Ptype, 10,rShort("type"),
- rOptions(Random, Freeverb, Bandwidth), "Type"),
- rEffPar(Proomsize,11,rShort("size"), "Room Size"),
- rEffPar(Pbandwidth,12,rShort("bw"), "Bandwidth"),
+ rEffPar(Ptype, 10, rShort("type"),
+ rOptions(Random, Freeverb, Bandwidth),
+ rPresets(Freeverb, Random, Freeverb, Freeverb, Freeverb, Random,
+ Freeverb, Random, Freeverb, Freeverb, Freeverb, Random,
+ Freeverb)
+ rDefault(Random), "Type"),
+ rEffPar(Proomsize,11,rShort("size"),
+ rPreset(2, 85), rPresetsAt(5, 30, 45, 25, 105),
+ rPresetsAt(11, 95, 80), rDefault(64),
+ "Room Size"),
+ rEffPar(Pbandwidth,12,rShort("bw"), rDefault(20), "Bandwidth"),
};
#undef rBegin
#undef rEnd
diff --git a/src/Misc/Bank.cpp b/src/Misc/Bank.cpp
@@ -30,6 +30,9 @@
#include "Util.h"
#include "Part.h"
#include "BankDb.h"
+#ifdef WIN32
+#include <windows.h>
+#endif
using namespace std;
@@ -362,6 +365,18 @@ void Bank::rescanforbanks()
for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i)
if(!config->cfg.bankRootDirList[i].empty())
scanrootdir(config->cfg.bankRootDirList[i]);
+#ifdef WIN32
+ {
+ //Search the VST Directory for banks/preset/etc
+ char path[1024];
+ GetModuleFileName(GetModuleHandle("ZynAddSubFX.dll"), path, sizeof(path));
+ if(strstr(path, "ZynAddSubFX.dll")) {
+ strstr(path, "ZynAddSubFX.dll")[0] = 0;
+ strcat(path, "banks");
+ scanrootdir(path);
+ }
+ }
+#endif
//sort the banks
sort(banks.begin(), banks.end());
@@ -477,7 +492,7 @@ std::vector<std::string> Bank::search(std::string s) const
std::vector<std::string> Bank::blist(std::string s)
{
std::vector<std::string> out;
- int result = loadbank(s);
+ loadbank(s);
for(int i=0; i<128; ++i) {
if(ins[i].filename.empty())
out.push_back("Empty Preset");
diff --git a/src/Misc/BankDb.cpp b/src/Misc/BankDb.cpp
@@ -80,17 +80,17 @@ static svec split(string s)
return vec;
}
-static string line(string s)
-{
- string ss;
- for(char c:s) {
- if(c != '\n')
- ss.push_back(c);
- else
- return ss;
- }
- return ss;
-}
+//static string line(string s)
+//{
+// string ss;
+// for(char c:s) {
+// if(c != '\n')
+// ss.push_back(c);
+// else
+// return ss;
+// }
+// return ss;
+//}
bvec BankDb::search(std::string ss) const
{
@@ -231,10 +231,18 @@ BankEntry BankDb::processXiz(std::string filename,
//Grab a timestamp
struct stat st;
- int ret = lstat(fname.c_str(), &st);
int time = 0;
+
+ //gah windows, just implement the darn standard APIs
+#ifndef WIN32
+ int ret = lstat(fname.c_str(), &st);
if(ret != -1)
time = st.st_mtim.tv_sec;
+#else
+ int ret = 0;
+ time = rand();
+#endif
+
//quickly check if the file exists in the cache and if it is up-to-date
if(cache.find(fname) != cache.end() &&
diff --git a/src/Misc/Config.cpp b/src/Misc/Config.cpp
@@ -122,8 +122,8 @@ static const rtosc::Ports ports = {
//rArrayS(cfg.presetsDirList,MAX_BANK_ROOT_DIRS),
rToggle(cfg.CheckPADsynth, "Old Check For PADsynth functionality within a patch"),
rToggle(cfg.IgnoreProgramChange, "Ignore MIDI Program Change Events"),
- rParamI(cfg.UserInterfaceMode, "Beginner/Advanced Mode Select"),
- rParamI(cfg.VirKeybLayout, "Keyboard Layout For Virtual Piano Keyboard"),
+ rParamI(cfg.UserInterfaceMode, "Beginner/Advanced Mode Select"),
+ rParamI(cfg.VirKeybLayout, "Keyboard Layout For Virtual Piano Keyboard"),
//rParamS(cfg.LinuxALSAaudioDev),
//rParamS(cfg.nameTag)
{"cfg.OscilPower::i", rProp(parameter) rDoc("Size Of Oscillator Wavetable"), 0,
@@ -138,19 +138,26 @@ static const rtosc::Ports ports = {
c.cfg.OscilSize = val;
d.broadcast(d.loc, "i", (int)(log(c.cfg.OscilSize*1.0)/log(2.0)));
}},
+ {"clear-favorites:", rDoc("Clear favorite directories"), 0,
+ [](const char *msg, rtosc::RtData &d) {
+ Config &c = *(Config*)d.obj;
+ for(int i=0; i<MAX_BANK_ROOT_DIRS; ++i)
+ c.cfg.favoriteList[i] = "";
+ }},
{"add-favorite:s", rDoc("Add favorite directory"), 0,
[](const char *msg, rtosc::RtData &d)
{
Config &c = *(Config*)d.obj;
+ const char *path = rtosc_argument(msg, 0).s;
for(int i=0; i<MAX_BANK_ROOT_DIRS; ++i) {
- if(c.cfg.favoriteList[i].empty()) {
- c.cfg.favoriteList[i] = rtosc_argument(msg, 0).s;
+ if(c.cfg.favoriteList[i].empty() || c.cfg.favoriteList[i] == path) {
+ c.cfg.favoriteList[i] = path;
return;
}
}
}},
- {"favorites:", rProp(parameter), 0,
+ {"favorites:", /*rProp(parameter)*/ 0, 0,
[](const char *msg, rtosc::RtData &d)
{
Config &c = *(Config*)d.obj;
@@ -174,7 +181,9 @@ const rtosc::Ports &Config::ports = zyn::ports;
#endif
Config::Config()
-{}
+{
+ init();
+}
void Config::init()
{
@@ -225,14 +234,18 @@ void Config::init()
//banks
cfg.bankRootDirList[0] = "~/banks";
cfg.bankRootDirList[1] = "./";
- cfg.bankRootDirList[2] = "/usr/share/zynaddsubfx/banks";
- cfg.bankRootDirList[3] = "/usr/local/share/zynaddsubfx/banks";
#ifdef __APPLE__
- cfg.bankRootDirList[4] = "../Resources/banks";
+ cfg.bankRootDirList[2] = "../Resources/banks";
#else
- cfg.bankRootDirList[4] = "../banks";
+ cfg.bankRootDirList[2] = "../banks";
+#endif
+ cfg.bankRootDirList[3] = "banks";
+#ifdef ZYN_DATADIR
+ cfg.bankRootDirList[4] = ZYN_DATADIR "/banks";
+#else
+ cfg.bankRootDirList[4] = "/usr/share/zynaddsubfx/banks";
+ cfg.bankRootDirList[5] = "/usr/local/share/zynaddsubfx/banks";
#endif
- cfg.bankRootDirList[5] = "banks";
}
if(cfg.presetsDirList[0].empty()) {
@@ -244,8 +257,12 @@ void Config::init()
cfg.presetsDirList[1] = "../presets";
#endif
cfg.presetsDirList[2] = "presets";
+#ifdef ZYN_DATADIR
+ cfg.presetsDirList[3] = ZYN_DATADIR "/presets";
+#else
cfg.presetsDirList[3] = "/usr/share/zynaddsubfx/presets";
cfg.presetsDirList[4] = "/usr/local/share/zynaddsubfx/presets";
+#endif
}
cfg.LinuxALSAaudioDev = "default";
cfg.nameTag = "";
diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp
@@ -16,6 +16,7 @@
#include "Part.h"
+#include "zyn-version.h"
#include "../Misc/Stereo.h"
#include "../Misc/Util.h"
#include "../Params/LFOParams.h"
@@ -32,6 +33,7 @@
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <fstream>
#include <iostream>
#include <algorithm>
#include <cmath>
@@ -51,12 +53,18 @@ static const Ports sysefxPort =
rDoc("gain on part to sysefx routing"), 0,
[](const char *m, RtData&d)
{
- //ok, this is going to be an ugly workaround
- //we know that if we are here the message previously MUST have
- //matched Psysefxvol#/
- //and the number is one or two digits at most
- const char *index_1 = m;
- index_1 -=2;
+ //we know that if we are here the location must
+ //be ...Psysefxvol#N/part#M
+ //and the number "N" is one or two digits at most
+
+ // go backto the '/'
+ const char* m_findslash = m + strlen(m),
+ * loc_findslash = d.loc + strlen(d.loc);
+ for(;*loc_findslash != '/'; --m_findslash, --loc_findslash)
+ assert(*loc_findslash == *m_findslash);
+ assert(m_findslash + 1 == m);
+
+ const char *index_1 = loc_findslash-1;
assert(isdigit(*index_1));
if(isdigit(index_1[-1]))
index_1--;
@@ -80,9 +88,15 @@ static const Ports sysefsendto =
{"to#" STRINGIFY(NUM_SYS_EFX) "::i",
rProp(parameter) rDoc("sysefx to sysefx routing gain"), 0, [](const char *m, RtData&d)
{
- //same ugly workaround as before
- const char *index_1 = m;
- index_1 -=2;
+ //same workaround as before
+ //go backto the '/'
+ const char* m_findslash = m + strlen(m),
+ * loc_findslash = d.loc + strlen(d.loc);
+ for(;*loc_findslash != '/'; --m_findslash, --loc_findslash)
+ assert(*loc_findslash == *m_findslash);
+ assert(m_findslash + 1 == m);
+
+ const char *index_1 = loc_findslash-1;
assert(isdigit(*index_1));
if(isdigit(index_1[-1]))
index_1--;
@@ -117,7 +131,7 @@ static int get_next_int(const char *msg)
}
static const Ports mapping_ports = {
- {"offset::f", rProp(parameter) rShort("off") rLinear(-50, 50) rMap(unit, percent), 0,
+ {"offset::f", rProp(parameter) rDefault(0) rShort("off") rLinear(-50, 50) rMap(unit, percent), 0,
rBegin;
int slot = d.idx[1];
int param = d.idx[0];
@@ -128,7 +142,7 @@ static const Ports mapping_ports = {
} else
d.reply(d.loc, "f", a.getSlotSubOffset(slot, param));
rEnd},
- {"gain::f", rProp(parameter) rShort("gain") rLinear(-200, 200) rMap(unit, percent), 0,
+ {"gain::f", rProp(parameter) rDefault(100) rShort("gain") rLinear(-200, 200) rMap(unit, percent), 0,
rBegin;
int slot = d.idx[1];
int param = d.idx[0];
@@ -142,7 +156,7 @@ static const Ports mapping_ports = {
};
static const Ports auto_param_ports = {
- {"used:", rProp(parameter) rProp(read-only) rDoc("If automation is assigned to anything"), 0,
+ {"used::T:F", rProp(parameter) rProp(read-only) rDoc("If automation is assigned to anything"), 0,
rBegin;
int slot = d.idx[1];
int param = d.idx[0];
@@ -158,13 +172,13 @@ static const Ports auto_param_ports = {
else
d.reply(d.loc, a.slots[slot].automations[param].active ? "T" : "F");
rEnd},
- {"path:", rProp(parameter) rProp(read-only) rDoc("Path of parameter"), 0,
+ {"path::s", rProp(parameter) rProp(read-only) rDoc("Path of parameter"), 0,
rBegin;
int slot = d.idx[1];
int param = d.idx[0];
d.reply(d.loc, "s", a.slots[slot].automations[param].param_path);
rEnd},
- {"clear:", 0, 0,
+ {"clear:", rDoc("Clear automation param"), 0,
rBegin;
int slot = d.idx[1];
int param = d.idx[0];
@@ -172,6 +186,7 @@ static const Ports auto_param_ports = {
rEnd},
{"mapping/", 0, &mapping_ports,
rBegin;
+ (void) a;
SNIP;
mapping_ports.dispatch(msg, d);
rEnd},
@@ -205,7 +220,7 @@ static const Ports slot_ports = {
// rtosc_argument(msg, 1).s,
// rtosc_argument(msg, 2).T);
// rEnd},
- {"value::f", rProp(parameter) rMap(default, 0.5) rLinear(0, 1) rDoc("Access current value in slot 'i' (0..1)"), 0,
+ {"value::f", rProp(no learn) rProp(parameter) rMap(default, 0.5) rLinear(0, 1) rDoc("Access current value in slot 'i' (0..1)"), 0,
rBegin;
int num = d.idx[0];
if(!strcmp("f",rtosc_argument_string(msg))) {
@@ -241,12 +256,12 @@ static const Ports slot_ports = {
else
d.reply(d.loc, a.slots[slot].active ? "T" : "F");
rEnd},
- {"learning:", rProp(parameter) rMap(default, -1) rDoc("If slot is trying to find a midi learn binding"), 0,
+ {"learning::i", rProp(parameter) rMap(default, -1) rDoc("If slot is trying to find a midi learn binding"), 0,
rBegin;
int slot = d.idx[0];
d.reply(d.loc, "i", a.slots[slot].learning);
rEnd},
- {"clear:", 0, 0,
+ {"clear:", rDoc("Clear automation slot"), 0,
rBegin;
int slot = d.idx[0];
a.clearSlot(slot);
@@ -283,7 +298,8 @@ static const Ports automate_ports = {
if(a.active_slot >= 0)
a.createBinding(a.active_slot, rtosc_argument(msg, 0).s, true);
rEnd},
- {"slot#16/", rDoc("Parameters of individual automation slots"), &slot_ports,
+ // TODO: remove rNoWalk
+ {"slot#16/", rNoWalk rDoc("Parameters of individual automation slots"), &slot_ports,
rBegin;
(void)a;
d.push_index(get_next_int(msg));
@@ -291,6 +307,40 @@ static const Ports automate_ports = {
slot_ports.dispatch(msg, d);
d.pop_index();
rEnd},
+ {"clear", rDoc("Clear all automation slots"), 0,
+ rBegin;
+ for(int i=0; i<a.nslots; ++i)
+ a.clearSlot(i);
+ rEnd},
+ {"load-blob:b", rProp(internal) rDoc("Load blob from middleware"), 0,
+ rBegin;
+ auto &b = **(rtosc::AutomationMgr **)rtosc_argument(msg, 0).b.data;
+ //XXX this code should likely be in rtosc
+ for(int i=0; i<a.nslots; ++i) {
+ auto &slota = a.slots[i];
+ auto &slotb = b.slots[i];
+ std::swap(slota.learning, slotb.learning);
+ std::swap(slota.midi_cc, slotb.midi_cc);
+ std::swap(slota.used, slotb.used);
+ std::swap(slota.active, slotb.active);
+ for(int j=0; j<a.per_slot; ++j) {
+ auto &aa = slota.automations[j];
+ auto &ab = slotb.automations[j];
+ std::swap(aa.used, ab.used);
+ std::swap(aa.active, ab.active);
+ std::swap(aa.param_path, ab.param_path);
+ std::swap(aa.param_min, ab.param_min);
+ std::swap(aa.param_max, ab.param_max);
+ std::swap(aa.param_step, ab.param_step);
+ std::swap(aa.param_type, ab.param_type);
+ std::swap(aa.map.offset, ab.map.offset);
+ std::swap(aa.map.gain, ab.map.gain);
+ std::swap(aa.map.upoints, ab.map.upoints);
+ for(int k=0; k<aa.map.npoints; ++k)
+ std::swap(aa.map.control_points[k], ab.map.control_points[k]);
+ }
+ }
+ rEnd},
};
#undef rBegin
@@ -312,14 +362,15 @@ static const Ports master_ports = {
rRecursp(part, 16, "Part"),//NUM_MIDI_PARTS
rRecursp(sysefx, 4, "System Effect"),//NUM_SYS_EFX
rRecursp(insefx, 8, "Insertion Effect"),//NUM_INS_EFX
- rRecur(microtonal, "Micrtonal Mapping Functionality"),
+ rRecur(microtonal, "Microtonal Mapping Functionality"),
rRecur(ctl, "Controller"),
- rArrayI(Pinsparts, NUM_INS_EFX, rOpt(-2, Master), rOpt(-1, Off)
- rOptions(Part1, Part2, Part3, Part4, Part5, Part6,
- Part7, Part8, Part9, Part10, Part11, Part12,
- Part13, Part14, Part15, Part16),
- "Part to insert part onto"),
- {"Pkeyshift::i", rShort("key shift") rProp(parameter) rLinear(0,127) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) {
+ rArrayOption(Pinsparts, NUM_INS_EFX, rOpt(-2, Master), rOpt(-1, Off),
+ rOptions(Part1, Part2, Part3, Part4, Part5, Part6,
+ Part7, Part8, Part9, Part10, Part11, Part12,
+ Part13, Part14, Part15, Part16) rDefault(Off),
+ "Part to insert part onto"),
+ {"Pkeyshift::i", rShort("key shift") rProp(parameter) rLinear(0,127)
+ rDefault(64) rDoc("Global Key Shift"), 0, [](const char *m, RtData&d) {
if(rtosc_narguments(m)==0) {
d.reply(d.loc, "i", ((Master*)d.obj)->Pkeyshift);
} else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') {
@@ -368,14 +419,16 @@ static const Ports master_ports = {
keys[i] = m->activeNotes[i] ? 'T' : 'F';
d.broadcast(d.loc, keys);
rEnd},
- {"Pvolume::i", rShort("volume") rProp(parameter) rLinear(0,127) rDoc("Master Volume"), 0,
+ {"Pvolume::i", rShort("volume") rProp(parameter) rLinear(0,127)
+ rDefault(80) rDoc("Master Volume"), 0,
[](const char *m, rtosc::RtData &d) {
if(rtosc_narguments(m)==0) {
d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume);
} else if(rtosc_narguments(m)==1 && rtosc_type(m,0)=='i') {
((Master*)d.obj)->setPvolume(limit<char>(rtosc_argument(m,0).i,0,127));
d.broadcast(d.loc, "i", ((Master*)d.obj)->Pvolume);}}},
- {"volume::i", rShort("volume") rProp(parameter) rLinear(0,127) rDoc("Master Volume"), 0,
+ {"volume::i", rShort("volume") rProp(parameter) rLinear(0,127)
+ rDefault(80) rDoc("Master Volume"), 0,
[](const char *m, rtosc::RtData &d) {
if(rtosc_narguments(m)==0) {
d.reply(d.loc, "i", ((Master*)d.obj)->Pvolume);
@@ -460,8 +513,8 @@ static const Ports master_ports = {
[](const char *, rtosc::RtData &d) {d.reply("/undo_pause", "");}},
{"undo_resume:",rProp(internal) rDoc("resume undo event recording"),0,
[](const char *, rtosc::RtData &d) {d.reply("/undo_resume", "");}},
- {"config/", rDoc("Top Level Application Configuration Parameters"), &Config::ports,
- [](const char *, rtosc::RtData &d){d.forward();}},
+ {"config/", rNoWalk rDoc("Top Level Application Configuration Parameters"),
+ &Config::ports, [](const char *, rtosc::RtData &d){d.forward();}},
{"presets/", rDoc("Parameter Presets"), &preset_ports, rBOIL_BEGIN
SNIP
preset_ports.dispatch(msg, data);
@@ -566,6 +619,81 @@ vuData::vuData(void)
rmspeakl(0.0f), rmspeakr(0.0f), clipped(0)
{}
+void Master::saveAutomation(XMLwrapper &xml, const rtosc::AutomationMgr &midi)
+{
+ xml.beginbranch("automation");
+ {
+ XmlNode metadata("mgr-info");
+ metadata["nslots"] = to_s(midi.nslots);
+ metadata["nautomations"] = to_s(midi.per_slot);
+ metadata["ncontrol"] = to_s(midi.slots[0].automations[0].map.npoints);
+ xml.add(metadata);
+
+ for(int i=0; i<midi.nslots; ++i) {
+ const auto &slot = midi.slots[i];
+ if(!slot.used)
+ continue;
+ xml.beginbranch("slot", i);
+ XmlNode params("params");
+ params["midi-cc"] = to_s(slot.midi_cc);
+ xml.add(params);
+ for(int j=0; j<midi.per_slot; ++j) {
+ const auto &au = slot.automations[j];
+ if(!au.used)
+ continue;
+ xml.beginbranch("automation", j);
+ XmlNode automation("params");
+ automation["path"] = au.param_path;
+ XmlNode mapping("mapping");
+ mapping["gain"] = to_s(au.map.gain);
+ mapping["offset"] = to_s(au.map.offset);
+ xml.add(automation);
+ xml.add(mapping);
+ xml.endbranch();
+ }
+
+ xml.endbranch();
+ }
+ }
+ xml.endbranch();
+}
+
+void Master::loadAutomation(XMLwrapper &xml, rtosc::AutomationMgr &midi)
+{
+ if(xml.enterbranch("automation")) {
+ for(int i=0; i<midi.nslots; ++i) {
+ auto &slot = midi.slots[i];
+ if(xml.enterbranch("slot", i)) {
+ for(int j=0; j<midi.per_slot; ++j) {
+ if(xml.enterbranch("automation", j)) {
+ float gain = 1.0;
+ float offset = 0.0;
+ std::string path = "";
+ for(auto node:xml.getBranch()) {
+ if(node.name == "params")
+ path = node["path"];
+ else if(node.name == "mapping") {
+ gain = atof(node["gain"].c_str());
+ offset = atof(node["offset"].c_str());
+ }
+ }
+ printf("createBinding(%d, %s, false)\n", i, path.c_str());
+ midi.createBinding(i, path.c_str(), false);
+ midi.setSlotSubGain(i, j, gain);
+ midi.setSlotSubOffset(i, j, offset);
+ xml.exitbranch();
+ }
+ }
+ for(auto node:xml.getBranch())
+ if(node.name == "params")
+ slot.midi_cc = atoi(node["midi-cc"].c_str());
+ xml.exitbranch();
+ }
+ }
+ xml.exitbranch();
+ }
+}
+
Master::Master(const SYNTH_T &synth_, Config* config)
:HDDRecorder(synth_), time(synth_), ctl(synth_, &time),
microtonal(config->cfg.GzipCompression), bank(config),
@@ -651,6 +779,7 @@ void Master::defaults()
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
part[npart]->defaults();
+ part[npart]->partno = npart % NUM_MIDI_CHANNELS;
part[npart]->Prcvchn = npart % NUM_MIDI_CHANNELS;
}
@@ -1289,6 +1418,8 @@ void Master::add2XML(XMLwrapper& xml)
microtonal.add2XML(xml);
xml.endbranch();
+ saveAutomation(xml, automate);
+
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
xml.beginbranch("PART", npart);
part[npart]->add2XML(xml);
@@ -1413,6 +1544,8 @@ void Master::getfromXML(XMLwrapper& xml)
xml.exitbranch();
}
+ loadAutomation(xml, automate);
+
sysefx[0]->changeeffect(0);
if(xml.enterbranch("SYSTEM_EFFECTS")) {
for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) {
@@ -1464,4 +1597,113 @@ void Master::getfromXML(XMLwrapper& xml)
}
}
+static rtosc_version version_in_rtosc_fmt()
+{
+ return rtosc_version
+ {
+ (unsigned char) version.get_major(),
+ (unsigned char) version.get_minor(),
+ (unsigned char) version.get_revision()
+ };
+}
+
+char* Master::getXMLData()
+{
+ XMLwrapper xml;
+
+ xml.beginbranch("MASTER");
+ add2XML(xml);
+ xml.endbranch();
+
+ return xml.getXMLdata();
+}
+
+int Master::saveOSC(const char *filename)
+{
+ std::string savefile = rtosc::save_to_file(ports, this,
+ "ZynAddSubFX",
+ version_in_rtosc_fmt());
+
+ zyn::Config config;
+ zyn::SYNTH_T* synth = new zyn::SYNTH_T;
+ synth->buffersize = 256;
+ synth->samplerate = 48000;
+ synth->alias();
+
+ zyn::Master master2(*synth, &config);
+ int rval = master2.loadOSCFromStr(savefile.c_str());
+
+
+ if(rval < 0)
+ {
+ std::cerr << "invalid savefile!" << std::endl;
+ std::cerr << "complete savefile:" << std::endl;
+ std::cerr << savefile << std::endl;
+ std::cerr << "first entry that could not be parsed:" << std::endl;
+
+ for(int i = -rval + 1; savefile[i]; ++i)
+ if(savefile[i] == '\n')
+ {
+ savefile.resize(i);
+ break;
+ }
+ std::cerr << (savefile.c_str() - rval) << std::endl;
+
+ rval = -1;
+ }
+ else
+ {
+ char* xml = getXMLData(),
+ * xml2 = master2.getXMLData();
+
+ rval = strcmp(xml, xml2) ? -1 : 0;
+
+ if(rval == 0)
+ {
+ if(filename)
+ {
+ std::ofstream ofs(filename);
+ ofs << savefile;
+ }
+ else if(!filename)
+ std::cout << savefile << std::endl;
+ }
+ else
+ {
+ std::cout << savefile << std::endl;
+ std::cerr << "Can not write OSC savefile!! (see tmp1.txt and tmp2.txt)"
+ << std::endl;
+ std::ofstream tmp1("tmp1.txt"), tmp2("tmp2.txt");
+ tmp1 << xml;
+ tmp2 << xml2;
+ }
+
+ free(xml);
+ free(xml2);
+ }
+ return rval;
+}
+
+int Master::loadOSCFromStr(const char *filename)
+{
+ return rtosc::load_from_file(filename,
+ ports, this,
+ "ZynAddSubFX", version_in_rtosc_fmt());
+}
+
+string loadfile(string fname)
+{
+ std::ifstream t(fname.c_str());
+ std::string str((std::istreambuf_iterator<char>(t)),
+ std::istreambuf_iterator<char>());
+ return str;
+}
+
+int Master::loadOSC(const char *filename)
+{
+ int rval = loadOSCFromStr(loadfile(filename).c_str());
+ return rval < 0 ? rval : 0;
+}
+
+
}
diff --git a/src/Misc/Master.h b/src/Misc/Master.h
@@ -59,12 +59,23 @@ class Master
/**This adds the parameters to the XML data*/
void add2XML(XMLwrapper& xml);
+ static void saveAutomation(XMLwrapper &xml, const rtosc::AutomationMgr &midi);
+ static void loadAutomation(XMLwrapper &xml, rtosc::AutomationMgr &midi);
+
void defaults();
/**loads all settings from a XML file
* @return 0 for ok or -1 if there is an error*/
int loadXML(const char *filename);
+ /**Save all settings to an OSC file (as specified by RT OSC)
+ * @param filename File to save to or NULL (useful for testing)
+ * @return 0 for ok or <0 if there is an error*/
+ int saveOSC(const char *filename);
+ /**loads all settings from an OSC file (as specified by RT OSC)
+ * @return 0 for ok or <0 if there is an error*/
+ int loadOSC(const char *filename);
+
/**Regenerate PADsynth and other non-RT parameters
* It is NOT SAFE to call this from a RT context*/
void applyparameters(void) NONREALTIME;
@@ -199,6 +210,11 @@ class Master
//Callback When Master changes
void(*mastercb)(void*,Master*);
void* mastercb_ptr;
+
+ //Return XML data as string. Must be freed.
+ char* getXMLData();
+ //Used by loadOSC and saveOSC
+ int loadOSCFromStr(const char *filename);
};
}
diff --git a/src/Misc/Microtonal.cpp b/src/Misc/Microtonal.cpp
@@ -42,25 +42,37 @@ namespace zyn {
* A good lookup table should be a good finalization of this
*/
const rtosc::Ports Microtonal::ports = {
- rToggle(Pinvertupdown, rShort("inv."), "key mapping inverse"),
- rParamZyn(Pinvertupdowncenter, rShort("center"), "center of the inversion"),
- rToggle(Penabled, rShort("enable"), "Enable for microtonal mode"),
- rParamZyn(PAnote, rShort("1/1 midi note"), "The note for 'A'"),
- rParamF(PAfreq, rShort("ref freq"), "Frequency of the 'A' note"),
- rParamZyn(Pscaleshift, rShort("shift"), "UNDOCUMENTED"),
- rParamZyn(Pfirstkey, rShort("first key"), "First key to retune"),
- rParamZyn(Plastkey, rShort("last key"), "Last key to retune"),
- rParamZyn(Pmiddlenote, rShort("middle"), "Scale degree 0 note"),
+ rToggle(Pinvertupdown, rShort("inv."), rDefault(false),
+ "key mapping inverse"),
+ rParamZyn(Pinvertupdowncenter, rShort("center"), rDefault(60),
+ "center of the inversion"),
+ rToggle(Penabled, rShort("enable"), rDefault(false),
+ "Enable for microtonal mode"),
+ rParamZyn(PAnote, rShort("1/1 midi note"), rDefault(69),
+ "The note for 'A'"),
+ rParamF(PAfreq, rShort("ref freq"), rDefault(440.0f),
+ "Frequency of the 'A' note"),
+ rParamZyn(Pscaleshift, rShort("shift"), rDefault(64),
+ "UNDOCUMENTED"),
+ rParamZyn(Pfirstkey, rShort("first key"), rDefault(0),
+ "First key to retune"),
+ rParamZyn(Plastkey, rShort("last key"), rDefault(127),
+ "Last key to retune"),
+ rParamZyn(Pmiddlenote, rShort("middle"), rDefault(60),
+ "Scale degree 0 note"),
//TODO check to see if this should be exposed
- rParamZyn(Pmapsize, "Size of key map"),
- rToggle(Pmappingenabled, "Mapping Enable"),
+ rParamZyn(Pmapsize, rDefault(12), "Size of key map"),
+ rToggle(Pmappingenabled, rDefault(false), "Mapping Enable"),
- rParams(Pmapping, 128, "Mapping of keys"),
- rParamZyn(Pglobalfinedetune, rShort("fine"), "Fine detune for all notes"),
+ rParams(Pmapping, 128, rDefaultMissing, "Mapping of keys"),
+ rParamZyn(Pglobalfinedetune, rShort("fine"), rDefault(64),
+ "Fine detune for all notes"),
- rString(Pname, MICROTONAL_MAX_NAME_LEN, rShort("name"), "Microtonal Name"),
- rString(Pcomment, MICROTONAL_MAX_NAME_LEN, rShort("comment"), "Microtonal comments"),
+ rString(Pname, MICROTONAL_MAX_NAME_LEN, rShort("name"),
+ rDefault("12tET"), "Microtonal Name"),
+ rString(Pcomment, MICROTONAL_MAX_NAME_LEN, rShort("comment"),
+ rDefault("Equal Temperament 12 notes per octave"), "Microtonal comments"),
{"octavesize:", rDoc("Get octave size"), 0, [](const char*, RtData &d)
{
@@ -858,6 +870,7 @@ void Microtonal::apply(void)
strncat(buf, tmpbuf, sizeof(buf)-1);
}
int err = texttotunings(buf);
+ (void) err;
}
}
diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp
@@ -228,55 +228,6 @@ void preparePadSynth(string path, PADnoteParameters *p, rtosc::RtData &d)
}
/******************************************************************************
- * MIDI Serialization *
- * *
- ******************************************************************************/
-//void saveMidiLearn(XMLwrapper &xml, const rtosc::MidiMappernRT &midi)
-//{
-// xml.beginbranch("midi-learn");
-// for(auto value:midi.inv_map) {
-// XmlNode binding("midi-binding");
-// auto biject = std::get<3>(value.second);
-// binding["osc-path"] = value.first;
-// binding["coarse-CC"] = to_s(std::get<1>(value.second));
-// binding["fine-CC"] = to_s(std::get<2>(value.second));
-// binding["type"] = "i";
-// binding["minimum"] = to_s(biject.min);
-// binding["maximum"] = to_s(biject.max);
-// xml.add(binding);
-// }
-// xml.endbranch();
-//}
-//
-//void loadMidiLearn(XMLwrapper &xml, rtosc::MidiMappernRT &midi)
-//{
-// using rtosc::Port;
-// if(xml.enterbranch("midi-learn")) {
-// auto nodes = xml.getBranch();
-//
-// //TODO clear mapper
-//
-// for(auto node:nodes) {
-// if(node.name != "midi-binding" ||
-// !node.has("osc-path") ||
-// !node.has("coarse-CC"))
-// continue;
-// const string path = node["osc-path"];
-// const int CC = atoi(node["coarse-CC"].c_str());
-// const Port *p = Master::ports.apropos(path.c_str());
-// if(p) {
-// printf("loading midi port...\n");
-// midi.addNewMapper(CC, *p, path);
-// } else {
-// printf("unknown midi bindable <%s>\n", path.c_str());
-// }
-// }
-// xml.exitbranch();
-// } else
-// printf("cannot find 'midi-learn' branch...\n");
-//}
-
-/******************************************************************************
* Non-RealTime Object Store *
* *
* *
@@ -803,7 +754,7 @@ class MwDataObj:public rtosc::RtData
//Chain calls repeat the call into handle()
//Forward calls send the message directly to the realtime
- virtual void reply(const char *path, const char *args, ...)
+ virtual void reply(const char *path, const char *args, ...) override
{
//printf("reply building '%s'\n", path);
va_list va;
@@ -829,7 +780,7 @@ class MwDataObj:public rtosc::RtData
reply(buffer);
}
}
- virtual void reply(const char *msg){
+ virtual void reply(const char *msg) override{
mwi->sendToCurrentRemote(msg);
};
//virtual void broadcast(const char *path, const char *args, ...){(void)path;(void)args;};
@@ -891,9 +842,9 @@ static std::vector<std::string> getFiles(const char *folder, bool finddir)
}
#else
std::string darn_windows = folder + std::string("/") + std::string(fn->d_name);
- printf("attr on <%s> => %x\n", darn_windows.c_str(), GetFileAttributes(darn_windows.c_str()));
- printf("desired mask = %x\n", mask);
- printf("error = %x\n", INVALID_FILE_ATTRIBUTES);
+ //printf("attr on <%s> => %x\n", darn_windows.c_str(), GetFileAttributes(darn_windows.c_str()));
+ //printf("desired mask = %x\n", mask);
+ //printf("error = %x\n", INVALID_FILE_ATTRIBUTES);
bool is_dir = GetFileAttributes(darn_windows.c_str()) & FILE_ATTRIBUTE_DIRECTORY;
#endif
if(finddir == is_dir && strcmp(".", fn->d_name))
@@ -942,13 +893,28 @@ extern const rtosc::Ports bankPorts;
const rtosc::Ports bankPorts = {
{"rescan:", 0, 0,
rBegin;
+ impl.bankpos = 0;
impl.rescanforbanks();
//Send updated banks
int i = 0;
for(auto &elm : impl.banks)
d.reply("/bank/bank_select", "iss", i++, elm.name.c_str(), elm.dir.c_str());
d.reply("/bank/bank_select", "i", impl.bankpos);
-
+ if (i > 0) {
+ impl.loadbank(impl.banks[0].dir);
+
+ //Reload bank slots
+ for(int i=0; i<BANK_SIZE; ++i) {
+ d.reply("/bankview", "iss",
+ i, impl.ins[i].name.c_str(),
+ impl.ins[i].filename.c_str());
+ }
+ } else {
+ //Clear all bank slots
+ for(int i=0; i<BANK_SIZE; ++i) {
+ d.reply("/bankview", "iss", i, "", "");
+ }
+ }
rEnd},
{"bank_list:", 0, 0,
rBegin;
@@ -1096,8 +1062,8 @@ const rtosc::Ports bankPorts = {
rBegin;
auto res = impl.search(rtosc_argument(msg, 0).s);
#define MAX_SEARCH 300
- char res_type[MAX_SEARCH+1] = {0};
- rtosc_arg_t res_dat[MAX_SEARCH] = {0};
+ char res_type[MAX_SEARCH+1] = {};
+ rtosc_arg_t res_dat[MAX_SEARCH] = {};
for(unsigned i=0; i<res.size() && i<MAX_SEARCH; ++i) {
res_type[i] = 's';
res_dat[i].s = res[i].c_str();
@@ -1109,8 +1075,8 @@ const rtosc::Ports bankPorts = {
rBegin;
auto res = impl.blist(rtosc_argument(msg, 0).s);
#define MAX_SEARCH 300
- char res_type[MAX_SEARCH+1] = {0};
- rtosc_arg_t res_dat[MAX_SEARCH] = {0};
+ char res_type[MAX_SEARCH+1] = {};
+ rtosc_arg_t res_dat[MAX_SEARCH] = {};
for(unsigned i=0; i<res.size() && i<MAX_SEARCH; ++i) {
res_type[i] = 's';
res_dat[i].s = res[i].c_str();
@@ -1206,24 +1172,29 @@ static rtosc::Ports middwareSnoopPorts = {
impl.kitEnable(msg);
d.forward();
rEnd},
- //{"save_xlz:s", 0, 0,
- // rBegin;
- // const char *file = rtosc_argument(msg, 0).s;
- // XMLwrapper xml;
- // saveMidiLearn(xml, impl.midi_mapper);
- // xml.saveXMLfile(file, impl.master->gzip_compression);
- // rEnd},
- //{"load_xlz:s", 0, 0,
- // rBegin;
- // const char *file = rtosc_argument(msg, 0).s;
- // XMLwrapper xml;
- // xml.loadXMLfile(file);
- // loadMidiLearn(xml, impl.midi_mapper);
- // rEnd},
- //{"clear_xlz:", 0, 0,
- // rBegin;
- // impl.midi_mapper.clear();
- // rEnd},
+ {"save_xlz:s", 0, 0,
+ rBegin;
+ impl.doReadOnlyOp([&]() {
+ const char *file = rtosc_argument(msg, 0).s;
+ XMLwrapper xml;
+ Master::saveAutomation(xml, impl.master->automate);
+ xml.saveXMLfile(file, impl.master->gzip_compression);
+ });
+ rEnd},
+ {"load_xlz:s", 0, 0,
+ rBegin;
+ const char *file = rtosc_argument(msg, 0).s;
+ XMLwrapper xml;
+ xml.loadXMLfile(file);
+ rtosc::AutomationMgr *mgr = new rtosc::AutomationMgr(16,4,8);
+ mgr->set_ports(Master::ports);
+ Master::loadAutomation(xml, *mgr);
+ d.chain("/automate/load-blob", "b", sizeof(void*), &mgr);
+ rEnd},
+ {"clear_xlz:", 0, 0,
+ rBegin;
+ d.chain("/automate/clear", "");
+ rEnd},
//scale file stuff
{"load_xsz:s", 0, 0,
rBegin;
@@ -1402,7 +1373,7 @@ static rtosc::Ports middwareSnoopPorts = {
// //cc-id, path, min, max
//#define MAX_MIDI 32
// rtosc_arg_t args[MAX_MIDI*4];
- // char argt[MAX_MIDI*4+1] = {0};
+ // char argt[MAX_MIDI*4+1] = {};
// int j=0;
// for(unsigned i=0; i<key.size() && i<MAX_MIDI; ++i) {
// auto val = midi.inv_map[key[i]];
@@ -1486,10 +1457,6 @@ static rtosc::Ports middlewareReplyPorts = {
if(impl.recording_undo)
impl.undo.recordEvent(msg);
rEnd},
- //{"midi-use-CC:i", 0, 0,
- // rBegin;
- // impl.midi_mapper.useFreeID(rtosc_argument(msg, 0).i);
- // rEnd},
{"broadcast:", 0, 0, rBegin; impl.broadcast = true; rEnd},
{"forward:", 0, 0, rBegin; impl.forward = true; rEnd},
};
@@ -1613,7 +1580,7 @@ void MiddleWareImpl::doReadOnlyOp(std::function<void()> read_only_fn)
int tries = 0;
while(tries++ < 10000) {
if(!bToU->hasNext()) {
- usleep(500);
+ os_usleep(500);
continue;
}
const char *msg = bToU->read();
@@ -1726,7 +1693,7 @@ bool MiddleWareImpl::doReadOnlyOpNormal(std::function<void()> read_only_fn, bool
int tries = 0;
while(tries++ < 2000) {
if(!bToU->hasNext()) {
- usleep(500);
+ os_usleep(500);
continue;
}
const char *msg = bToU->read();
diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp
@@ -47,41 +47,55 @@ static const Ports partPorts = {
rRecurs(kit, 16, "Kit"),//NUM_KIT_ITEMS
rRecursp(partefx, 3, "Part Effect"),
rRecur(ctl, "Controller"),
- rToggle(Penabled, rShort("enable"), "Part enable"),
+ rParamZyn(partno, rProp(internal),
+ "How many parts are before this in the Master"),
+#undef rChangeCb
+#define rChangeCb if(obj->Penabled == false) obj->AllNotesOff();
+ rToggle(Penabled, rShort("enable"), rDefaultDepends(partno),
+ rPresets(true), rDefault(false), "Part enable"),
+#undef rChangeCb
+#define rChangeCb
#undef rChangeCb
#define rChangeCb obj->setPvolume(obj->Pvolume);
- rParamZyn(Pvolume, rShort("Vol"), "Part Volume"),
+ rParamZyn(Pvolume, rShort("Vol"), rDefault(96),"Part Volume"),
#undef rChangeCb
#define rChangeCb obj->setPpanning(obj->Ppanning);
- rParamZyn(Ppanning, rShort("pan"), "Set Panning"),
+ rParamZyn(Ppanning, rShort("pan"), rDefault(64), "Set Panning"),
#undef rChangeCb
#define rChangeCb obj->setkeylimit(obj->Pkeylimit);
- rParamI(Pkeylimit, rShort("limit"), rProp(parameter), rMap(min,0), rMap(max, POLYPHONY), "Key limit per part"),
+ rParamI(Pkeylimit, rShort("limit"), rProp(parameter),
+ rMap(min,0), rMap(max, POLYPHONY), rDefault(15), "Key limit per part"),
#undef rChangeCb
#define rChangeCb
- rParamZyn(Pminkey, rShort("min"), "Min Used Key"),
- rParamZyn(Pmaxkey, rShort("max"), "Max Used Key"),
- rParamZyn(Pkeyshift, rShort("shift"), "Part keyshift"),
+ rParamZyn(Pminkey, rShort("min"), rDefault(0), "Min Used Key"),
+ rParamZyn(Pmaxkey, rShort("max"), rDefault(127), "Max Used Key"),
+ rParamZyn(Pkeyshift, rShort("shift"), rDefault(64), "Part keyshift"),
rParamZyn(Prcvchn, rOptions(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, ch13, ch14, ch15, ch16),
- "Active MIDI channel"),
- rParamZyn(Pvelsns, rShort("sense"), "Velocity sensing"),
- rParamZyn(Pveloffs, rShort("offset"), "Velocity offset"),
- rToggle(Pnoteon, "If the channel accepts note on events"),
- rOption(Pkitmode, rOptions(Off, Multi-Kit, Single-Kit), "Kit mode/enable\n"
+ rPresets(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, ch13, ch14, ch15, ch16),
+ "Active MIDI channel"),
+ rParamZyn(Pvelsns, rShort("sense"), rDefault(64), "Velocity sensing"),
+ rParamZyn(Pveloffs, rShort("offset"), rDefault(64),"Velocity offset"),
+ rToggle(Pnoteon, rDefault(true), "If the channel accepts note on events"),
+ rOption(Pkitmode, rOptions(Off, Multi-Kit, Single-Kit), rDefault(Off),
+ "Kit mode/enable\n"
"Off - Only the first kit is ever utilized\n"
"Multi-kit - Every applicable kit is run for a note\n"
"Single-kit - The first applicable kit is run for a given note"),
- rToggle(Pdrummode, "Drum mode enable\n"
+ rToggle(Pdrummode, rDefault(false), "Drum mode enable\n"
"When drum mode is enabled all keys are mapped to 12tET and legato is disabled"),
- rToggle(Ppolymode, "Polyphony mode"),
- rToggle(Plegatomode, "Legato mode"),
- rParamZyn(info.Ptype, "Class of Instrument"),
- rString(info.Pauthor, MAX_INFO_TEXT_SIZE, "Instrument author"),
- rString(info.Pcomments, MAX_INFO_TEXT_SIZE, "Instrument comments"),
- rString(Pname, PART_MAX_NAME_LEN, "User specified label"),
+ rToggle(Ppolymode, rDefault(true), "Polyphony mode"),
+ rToggle(Plegatomode, rDefault(false), "Legato mode"),
+ rParamZyn(info.Ptype, rDefault(0), "Class of Instrument"),
+ rString(info.Pauthor, MAX_INFO_TEXT_SIZE, rDefault(""),
+ "Instrument author"),
+ rString(info.Pcomments, MAX_INFO_TEXT_SIZE, rDefault(""),
+ "Instrument comments"),
+ rString(Pname, PART_MAX_NAME_LEN, rDefault(""), "User specified label"),
rArrayI(Pefxroute, NUM_PART_EFX,
- rOptions(Next Effect,Part Out,Dry Out), "Effect Routing"),
- rArrayT(Pefxbypass, NUM_PART_EFX, "If an effect is bypassed"),
+ rOptions(Next Effect,Part Out,Dry Out), rDefaultId(Next Effect),
+ "Effect Routing"),
+ rArrayT(Pefxbypass, NUM_PART_EFX, rDefault(false),
+ "If an effect is bypassed"),
{"captureMin:", rDoc("Capture minimum valid note"), NULL,
[](const char *, RtData &r)
{Part *p = (Part*)r.obj; p->Pminkey = p->lastnote;}},
@@ -158,20 +172,26 @@ static const Ports partPorts = {
#undef rObject
#define rObject Part::Kit
static const Ports kitPorts = {
+ rSelf(Part::Kit, rEnabledBy(Penabled)),
rRecurp(padpars, "Padnote parameters"),
rRecurp(adpars, "Adnote parameters"),
rRecurp(subpars, "Adnote parameters"),
- rToggle(Penabled, "Kit item enable"),
- rToggle(Pmuted, "Kit item mute"),
- rParamZyn(Pminkey, "Kit item min key"),
- rParamZyn(Pmaxkey, "Kit item max key"),
- rToggle(Padenabled, "ADsynth enable"),
- rToggle(Psubenabled, "SUBsynth enable"),
- rToggle(Ppadenabled, "PADsynth enable"),
+ rToggle(firstkit, rProp(internal), "If this is the part's first kit"),
+ rToggle(Penabled, rDefaultDepends(firstkit),
+ rPreset(true, true), rPreset(false, false),
+ "Kit item enable"),
+ rToggle(Pmuted, rDefault(false), "Kit item mute"),
+ rParamZyn(Pminkey, rDefault(0), "Kit item min key"),
+ rParamZyn(Pmaxkey, rDefault(127) "Kit item max key"),
+ rToggle(Padenabled, rDefaultDepends(firstkit),
+ rPreset(true, true), rPreset(false, false)
+ "ADsynth enable"),
+ rToggle(Psubenabled, rDefault(false), "SUBsynth enable"),
+ rToggle(Ppadenabled, rDefault(false), "PADsynth enable"),
rParamZyn(Psendtoparteffect,
- rOptions(FX1, FX2, FX3, Off),
+ rOptions(FX1, FX2, FX3, Off), rDefault(FX1),
"Effect Levels"),
- rString(Pname, PART_MAX_NAME_LEN, "Kit User Specified Label"),
+ rString(Pname, PART_MAX_NAME_LEN, rDefault(""), "Kit User Specified Label"),
{"captureMin:", rDoc("Capture minimum valid note"), NULL,
[](const char *, RtData &r)
{Part::Kit *p = (Part::Kit*)r.obj; p->Pminkey = p->parent->lastnote;}},
@@ -328,6 +348,7 @@ void Part::defaultsinstrument()
for(int n = 0; n < NUM_KIT_ITEMS; ++n) {
//kit[n].Penabled = false;
+ kit[n].firstkit = false;
kit[n].Pmuted = false;
kit[n].Pminkey = 0;
kit[n].Pmaxkey = 127;
@@ -339,6 +360,7 @@ void Part::defaultsinstrument()
if(n != 0)
setkititemstatus(n, 0);
}
+ kit[0].firstkit = true;
kit[0].Penabled = 1;
kit[0].Padenabled = 1;
kit[0].adpars->defaults();
diff --git a/src/Misc/Part.h b/src/Misc/Part.h
@@ -85,6 +85,7 @@ class Part
struct Kit {
Kit(void);
Part *parent;
+ bool firstkit;
bool Penabled, Pmuted;
unsigned char Pminkey, Pmaxkey;
char *Pname;
@@ -106,13 +107,14 @@ class Part
void setkeylimit(unsigned char Pkeylimit);
void setkititemstatus(unsigned kititem, bool Penabled_);
+ unsigned char partno; /**<if it's the Master's first part*/
bool Penabled; /**<if the part is enabled*/
unsigned char Pvolume; /**<part volume*/
unsigned char Pminkey; /**<the minimum key that the part receives noteon messages*/
unsigned char Pmaxkey; //the maximum key that the part receives noteon messages
void setPvolume(char Pvolume);
unsigned char Pkeyshift; //Part keyshift
- unsigned char Prcvchn; //from what midi channel it receive commnads
+ unsigned char Prcvchn; //from what midi channel it receives commands
unsigned char Ppanning; //part panning
void setPpanning(char Ppanning);
unsigned char Pvelsns; //velocity sensing (amplitude velocity scale)
diff --git a/src/Misc/Schema.cpp b/src/Misc/Schema.cpp
@@ -11,6 +11,30 @@ void walk_ports2(const rtosc::Ports *base,
namespace zyn {
+static const char *escape_string(const char *msg)
+{
+ if(!msg)
+ return NULL;
+ char *out = (char*)malloc(strlen(msg)*2+1);
+ memset(out, 0, strlen(msg)*2+1);
+ char *itr = out;
+ while(*msg) {
+ if(*msg == '"') {
+ *itr++ = '\\';
+ *itr++ = '\"';
+ } else if(*msg == '\\') {
+ *itr++ = '\\';
+ *itr++ = '\\';
+ } else {
+ *itr++ = *msg;
+ }
+
+ msg++;
+
+ }
+ return out;
+}
+
/*
* root :
* - 'parameters' : [parameter...]
@@ -25,6 +49,8 @@ namespace zyn {
* - 'scale' : scale-type
* - 'domain' : range [OPTIONAL]
* - 'options' : [option...] [OPTIONAL]
+ * - 'default' : string
+ * - 'defaults' : defaults
* type : {'int', 'float', 'boolean'}
* action :
* - 'path' : path-id
@@ -35,10 +61,14 @@ namespace zyn {
* option :
* - 'id' : id-number
* - 'value' : string-rep
+ * defaults :
+ * - 'id' : id-number
+ * - 'value' : string-rep
*/
using std::ostream;
using std::string;
+#if 0
static int enum_min(Port::MetaContainer meta)
{
int min = 0;
@@ -96,6 +126,7 @@ static ostream &add_options(ostream &o, Port::MetaContainer meta)
return o;
}
+#endif
/*
* parameter :
@@ -107,7 +138,8 @@ static ostream &add_options(ostream &o, Port::MetaContainer meta)
* - 'domain' : range [OPTIONAL]
*/
static bool first = true;
-void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v)
+void dump_param_cb(const rtosc::Port *p, const char *full_name, const char*,
+ const Ports&,void *v, void*)
{
typedef std::vector<std::pair<int,string>> opts;
std::ostream &o = *(std::ostream*)v;
@@ -174,6 +206,8 @@ void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v)
const char *min = meta["min"];
const char *max = meta["max"];
+ const char *def = meta["default"];
+ def = escape_string(def);
for(auto m:meta) {
if(strlen(m.title) >= 5 && !memcmp(m.title, "map ", 4)) {
@@ -201,6 +235,8 @@ void dump_param_cb(const rtosc::Port *p, const char *full_name, void *v)
o << " \"type\" : \"" << type << "\"";
if(min && max)
o << ",\n \"range\" : [" << min << "," << max << "]";
+ if(def)
+ o << ",\n \"default\" : \"" << def << "\"\n";
if(!options.empty()) {
o << ",\n \"options\" : [\n";
int N = options.size();
diff --git a/src/Misc/Util.cpp b/src/Misc/Util.cpp
@@ -129,10 +129,31 @@ void set_realtime()
#endif
}
-void os_sleep(long length)
+
+
+#ifdef WIN32
+#include <windows.h>
+
+//https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw
+void os_usleep(long usec)
+{
+ HANDLE timer;
+ LARGE_INTEGER ft;
+
+ ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time
+
+ timer = CreateWaitableTimer(NULL, TRUE, NULL);
+ SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
+ WaitForSingleObject(timer, INFINITE);
+ CloseHandle(timer);
+}
+#else
+
+void os_usleep(long length)
{
usleep(length);
}
+#endif
//!< maximum lenght a pid has on any POSIX system
//!< this is an estimation, but more than 12 looks insane
diff --git a/src/Misc/Util.h b/src/Misc/Util.h
@@ -46,7 +46,7 @@ extern float getdetune(unsigned char type,
void set_realtime();
/**Os independent sleep in microsecond*/
-void os_sleep(long length);
+void os_usleep(long length);
//! returns pid padded to maximum pid lenght, posix conform
std::string os_pid_as_padded_string();
@@ -153,11 +153,6 @@ char *rtosc_splat(const char *path, std::set<std::string>);
#define rParamZyn(name, ...) \
{STRINGIFY(name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) DOC(__VA_ARGS__), NULL, rParamICb(name)}
-#define rSelf(type) \
-{"self:", rProp(internal) rMap(class, type) rDoc("port metadata"), 0, \
- [](const char *, rtosc::RtData &d){ \
- d.reply(d.loc, "b", sizeof(d.obj), &d.obj);}}\
-
#define rPresetType \
{"preset-type:", rProp(internal) rDoc("clipboard type of object"), 0, \
[](const char *, rtosc::RtData &d){ \
diff --git a/src/Misc/XMLwrapper.cpp b/src/Misc/XMLwrapper.cpp
@@ -253,7 +253,7 @@ void XMLwrapper::addparreal(const string &name, float val)
union { float in; uint32_t out; } convert;
char buf[11];
convert.in = val;
- sprintf(buf, "0x%0.8X", convert.out);
+ sprintf(buf, "0x%.8X", convert.out);
addparams("par_real", 3, "name", name.c_str(), "value",
stringFrom<float>(val).c_str(), "exact_value", buf);
}
@@ -397,6 +397,12 @@ bool XMLwrapper::putXMLdata(const char *xmldata)
if(root == NULL)
return false;
+ //fetch version information
+ _fileversion.set_major(stringTo<int>(mxmlElementGetAttr(root, "version-major")));
+ _fileversion.set_minor(stringTo<int>(mxmlElementGetAttr(root, "version-minor")));
+ _fileversion.set_revision(
+ stringTo<int>(mxmlElementGetAttr(root, "version-revision")));
+
return true;
}
diff --git a/src/Nio/NulEngine.cpp b/src/Nio/NulEngine.cpp
@@ -13,8 +13,8 @@
#include "NulEngine.h"
#include "../globals.h"
+#include "../Misc/Util.h"
-#include <unistd.h>
#include <iostream>
using namespace std;
@@ -50,7 +50,7 @@ void *NulEngine::AudioThread()
+ (playing_until.tv_sec - now.tv_sec) * 1000000;
if(remaining > 10000) //Don't sleep() less than 10ms.
//This will add latency...
- usleep(remaining - 10000);
+ os_usleep(remaining - 10000);
if(remaining < 0)
cerr << "WARNING - too late" << endl;
}
diff --git a/src/Output/DSSIaudiooutput.cpp b/src/Output/DSSIaudiooutput.cpp
@@ -625,8 +625,6 @@ DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate) : dssi_control{dssi_c
this->sampleRate = sampleRate;
this->banksInited = false;
- config.init();
-
zyn::sprng(time(NULL));
synth.alias();
diff --git a/src/Params/ADnoteParameters.cpp b/src/Params/ADnoteParameters.cpp
@@ -70,19 +70,26 @@ static const Ports voicePorts = {
rRecurp(FMAmpEnvelope, "Modulator Amplitude Envelope"),
rRecurp(VoiceFilter, "Optional Voice Filter"),
- rToggle(Enabled, rShort("enable"), "Voice Enable"),
- rParamI(Unison_size, rShort("size"), rMap(min, 0), rMap(max, 50), "Number of subvoices"),
- rParamZyn(Unison_phase_randomness, rShort("ph.rnd."), "Phase Randomness"),
- rParamZyn(Unison_frequency_spread, rShort("detune"), "Subvoice detune"),
- rParamZyn(Unison_stereo_spread, rShort("spread"),
- "Subvoice L/R Separation"),
- rParamZyn(Unison_vibratto, rShort("vib."), "Subvoice vibratto"),
- rParamZyn(Unison_vibratto_speed, rShort("speed"),
- "Subvoice vibratto speed"),
+// rToggle(Enabled, rShort("enable"), "Voice Enable"),
+ rParamI(Unison_size, rShort("size"), rMap(min, 0), rMap(max, 50),
+ rDefault(1), "Number of subvoices"),
+ rParamZyn(Unison_phase_randomness, rShort("ph.rnd."), rDefault(127),
+ "Phase Randomness"),
+ rParamZyn(Unison_frequency_spread, rShort("detune"), rDefault(60),
+ "Subvoice detune"),
+ rParamZyn(Unison_stereo_spread, rShort("spread"), rDefault(64),
+ "Subvoice L/R Separation"),
+ rParamZyn(Unison_vibratto, rShort("vib."), rDefault(64),
+ "Subvoice vibratto"),
+ rParamZyn(Unison_vibratto_speed, rShort("speed"), rDefault(64),
+ "Subvoice vibratto speed"),
rOption(Unison_invert_phase, rShort("inv."),
- rOptions(none, random, 50%, 33%, 25%), "Subvoice Phases"),
- rOption(Type, rShort("type"), rOptions(Sound,White,Pink,DC), "Type of Sound"),
- rParamZyn(PDelay, rShort("delay"), "Voice Startup Delay"),
+ rOptions(none, random, 50%, 33%, 25%), rDefault(none),
+ "Subvoice Phases"),
+ rOption(Type, rShort("type"), rOptions(Sound,White,Pink,DC),
+ rDefault(Sound), "Type of Sound"),
+ rParamZyn(PDelay, rShort("delay"), rDefault(0),
+ "Voice Startup Delay"),
rToggle(Presonance, rShort("enable"), "Resonance Enable"),
rParamI(Pextoscil, rShort("ext."),
rMap(min, -1), rMap(max, 16), "External Oscillator Selection"),
@@ -109,37 +116,56 @@ static const Ports voicePorts = {
//Amplitude Stuff
rParamZyn(PPanning, rShort("pan."), "Panning"),
- rParamZyn(PVolume, rShort("vol."), "Volume"),
- rToggle(PVolumeminus, rShort("inv."), "Signal Inverter"), //do we really need this??
- rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), "Velocity Sensing"),
- rToggle(PAmpEnvelopeEnabled, rShort("enable"), "Amplitude Envelope Enable"),
- rToggle(PAmpLfoEnabled, rShort("enable"), "Amplitude LFO Enable"),
+ rParamZyn(PVolume, rShort("vol."), rDefault(100),
+ "Volume"),
+ rToggle(PVolumeminus, rShort("inv."), rDefault(false),
+ "Signal Inverter"), //do we really need this??
+ rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(127),
+ "Velocity Sensing"),
+ rToggle(PAmpEnvelopeEnabled, rShort("enable"), rDefault(false),
+ "Amplitude Envelope Enable"),
+ rToggle(PAmpLfoEnabled, rShort("enable"), rDefault(false),
+ "Amplitude LFO Enable"),
//Filter Stuff
- rToggle(PFilterEnabled, rShort("enable"), "Filter Enable"),
- rToggle(PFilterEnvelopeEnabled, rShort("enable"), "Filter Envelope Enable"),
- rToggle(PFilterLfoEnabled, rShort("enable"), "Filter LFO Enable"),
- rParamZyn(PFilterVelocityScale, rShort("v.scale"), "Filter Velocity Magnitude"),
- rParamZyn(PFilterVelocityScaleFunction, rShort("v.sense"), "Filter Velocity Function Shape"),
+ rToggle(PFilterEnabled, rShort("enable"), rDefault(false),
+ "Filter Enable"),
+ rToggle(PFilterEnvelopeEnabled, rShort("enable"), rDefault(false),
+ "Filter Envelope Enable"),
+ rToggle(PFilterLfoEnabled, rShort("enable"), rDefault(false),
+ "Filter LFO Enable"),
+ rParamZyn(PFilterVelocityScale, rShort("v.scale"), rDefault(0),
+ "Filter Velocity Magnitude"),
+ rParamZyn(PFilterVelocityScaleFunction, rShort("v.sense"), rDefault(64),
+ "Filter Velocity Function Shape"),
//Modulator Stuff
rOption(PFMEnabled, rShort("mode"), rOptions(none, morph, ring, phase,
- frequency, pulse), "Modulator mode"),
- rParamI(PFMVoice, rShort("voice"), "Modulator Oscillator Selection"),
- rParamZyn(PFMVolume, rShort("vol."), "Modulator Magnitude"),
- rParamZyn(PFMVolumeDamp, rShort("damp."), "Modulator HF dampening"),
- rParamZyn(PFMVelocityScaleFunction, rShort("sense"), "Modulator Velocity Function"),
+ frequency, pulse), rDefault(none), "Modulator mode"),
+ rParamI(PFMVoice, rShort("voice"), rDefault(-1),
+ "Modulator Oscillator Selection"),
+ rParamZyn(PFMVolume, rShort("vol."), rDefault(90),
+ "Modulator Magnitude"),
+ rParamZyn(PFMVolumeDamp, rShort("damp."), rDefault(64),
+ "Modulator HF dampening"),
+ rParamZyn(PFMVelocityScaleFunction, rShort("sense"), rDefault(64),
+ "Modulator Velocity Function"),
//nominally -8192..8191
rParamI(PFMDetune, rShort("fine"),
- rLinear(0, 16383), "Modulator Fine Detune"),
- rParamI(PFMCoarseDetune, rShort("coarse"), "Modulator Coarse Detune"),
+ rLinear(0, 16383), rDefault(8192), "Modulator Fine Detune"),
+ rParamI(PFMCoarseDetune, rShort("coarse"), rDefault(0),
+ "Modulator Coarse Detune"),
rParamZyn(PFMDetuneType, rShort("type"),
- rOptions(L35cents, L10cents, E100cents, E1200cents),
- "Modulator Detune Magnitude"),
- rToggle(PFMFixedFreq, rShort("fixed"), "Modulator Frequency Fixed"),
- rToggle(PFMFreqEnvelopeEnabled, rShort("enable"), "Modulator Frequency Envelope"),
- rToggle(PFMAmpEnvelopeEnabled, rShort("enable"), "Modulator Amplitude Envelope"),
+ rOptions(L35cents, L10cents, E100cents, E1200cents),
+ rDefault(L35cents),
+ "Modulator Detune Magnitude"),
+ rToggle(PFMFixedFreq, rShort("fixed"), rDefault(false),
+ "Modulator Frequency Fixed"),
+ rToggle(PFMFreqEnvelopeEnabled, rShort("enable"), rDefault(false),
+ "Modulator Frequency Envelope"),
+ rToggle(PFMAmpEnvelopeEnabled, rShort("enable"), rDefault(false),
+ "Modulator Amplitude Envelope"),
//weird stuff for PCoarseDetune
@@ -250,36 +276,48 @@ static const Ports globalPorts = {
rRecurp(FilterEnvelope, "Frequency Envelope"),
rRecurp(GlobalFilter, "Filter"),
- rToggle(PStereo, rShort("stereo"), "Mono/Stereo Enable"),
+ rToggle(PStereo, rShort("stereo"), rDefault(true), "Mono/Stereo Enable"),
//Frequency
//nominally -8192..8191
rParamI(PDetune, rShort("fine"),
- rLinear(0, 16383), "Fine Detune"),
- rParamI(PCoarseDetune, rShort("coarse"), "Coarse Detune"),
+ rLinear(0, 16383), rDefault(8192), "Fine Detune"),
+ rParamI(PCoarseDetune, rShort("coarse"), rDefault(0), "Coarse Detune"),
rParamZyn(PDetuneType, rShort("type"),
- rOptions(L35cents, L10cents, E100cents, E1200cents),
- "Detune Scaling Type"),
- rParamZyn(PBandwidth, rShort("bw."), "Relative Fine Detune Gain"),
+ rOptions(L35cents, L10cents, E100cents, E1200cents),
+ rDefault(L10cents),
+ "Detune Scaling Type"),
+ rParamZyn(PBandwidth, rShort("bw."), rDefault(64),
+ "Relative Fine Detune Gain"),
//Amplitude
- rParamZyn(PPanning, rShort("pan"), "Panning of ADsynth (0 random, 1 left, 127 right)"),
- rParamZyn(PVolume, rShort("vol"), "volume control"),
- rParamZyn(PAmpVelocityScaleFunction, rShort("scale"), "Volume Velocity Control"),
-
- rParamZyn(Fadein_adjustment, "Adjustment for anti-pop strategy."),
- rParamZyn(PPunchStrength, rShort("strength"), "Punch Strength"),
- rParamZyn(PPunchTime, rShort("time"), "Length of Punch"),
- rParamZyn(PPunchStretch, rShort("stretch"), "How Punch changes with note frequency"),
- rParamZyn(PPunchVelocitySensing, rShort("v.sns"), "Punch Velocity control"),
+ rParamZyn(PPanning, rShort("pan"), rDefault(64),
+ "Panning of ADsynth (0 random, 1 left, 127 right)"),
+ rParamZyn(PVolume, rShort("vol"), rDefault(90), "volume control"),
+ rParamZyn(PAmpVelocityScaleFunction, rShort("scale"), rDefault(64),
+ "Volume Velocity Control"),
+
+ rParamZyn(Fadein_adjustment, rDefault(FADEIN_ADJUSTMENT_SCALE),
+ "Adjustment for anti-pop strategy."),
+ rParamZyn(PPunchStrength, rShort("strength"), rDefault(0),
+ "Punch Strength"),
+ rParamZyn(PPunchTime, rShort("time"), rDefault(60),
+ "Length of Punch"),
+ rParamZyn(PPunchStretch, rShort("stretch"), rDefault(64),
+ "How Punch changes with note frequency"),
+ rParamZyn(PPunchVelocitySensing, rShort("v.sns"), rDefault(72),
+ "Punch Velocity control"),
//Filter
- rParamZyn(PFilterVelocityScale, rShort("scale"), "Filter Velocity Magnitude"),
- rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), "Filter Velocity Function Shape"),
+ rParamZyn(PFilterVelocityScale, rShort("scale"), rDefault(64),
+ "Filter Velocity Magnitude"),
+ rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), rDefault(64),
+ "Filter Velocity Function Shape"),
//Resonance
- rToggle(Hrandgrouping, "How randomness is applied to multiple voices using the same oscil"),
+ rToggle(Hrandgrouping, rDefault(false),
+ "How randomness is applied to multiple voices using the same oscil"),
//weird stuff for PCoarseDetune
{"detunevalue:", rMap(unit,cents) rDoc("Get detune in cents"), NULL,
@@ -325,12 +363,15 @@ static const Ports globalPorts = {
#undef rObject
#define rObject ADnoteParameters
-#define rChangeCb obj->last_update_timestamp = obj->time.time();
+#define rChangeCb obj->last_update_timestamp = obj->time->time();
static const Ports adPorts = {//XXX 16 should not be hard coded
rSelf(ADnoteParameters),
rPaste,
rArrayPaste,
rRecurs(VoicePar, NUM_VOICES),
+ {"VoicePar#" STRINGIFY(NUM_VOICES) "/Enabled::T:F",
+ rProp(parameter) rShort("enable") rDoc("Voice Enable"),
+ NULL, rArrayTCbMember(VoicePar, Enabled)},
rRecur(GlobalPar, "Adnote Parameters"),
};
#undef rChangeCb
@@ -359,16 +400,16 @@ ADnoteGlobalParam::ADnoteGlobalParam(const AbsTime *time_) :
time(time_), last_update_timestamp(0)
{
FreqEnvelope = new EnvelopeParams(0, 0, time_);
- FreqEnvelope->ASRinit(64, 50, 64, 60);
+ FreqEnvelope->init(EnvelopeParams::ad_global_freq_env);
FreqLfo = new LFOParams(70, 0, 64, 0, 0, 0, 0, 0, time_);
AmpEnvelope = new EnvelopeParams(64, 1, time_);
- AmpEnvelope->ADSRinit_dB(0, 40, 127, 25);
+ AmpEnvelope->init(EnvelopeParams::ad_global_amp_env);
AmpLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 1, time_);
GlobalFilter = new FilterParams(2, 94, 40, time_);
FilterEnvelope = new EnvelopeParams(0, 1, time_);
- FilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64);
+ FilterEnvelope->init(EnvelopeParams::ad_global_filter_env);
FilterLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 2, time_);
Reson = new Resonance();
}
@@ -515,22 +556,22 @@ void ADnoteVoiceParam::enable(const SYNTH_T &synth, FFTwrapper *fft,
FMSmp = new OscilGen(synth, fft, NULL);
AmpEnvelope = new EnvelopeParams(64, 1, time);
- AmpEnvelope->ADSRinit_dB(0, 100, 127, 100);
+ AmpEnvelope->init(EnvelopeParams::ad_voice_amp_env);
AmpLfo = new LFOParams(90, 32, 64, 0, 0, 30, 0, 1, time);
FreqEnvelope = new EnvelopeParams(0, 0, time);
- FreqEnvelope->ASRinit(30, 40, 64, 60);
+ FreqEnvelope->init(EnvelopeParams::ad_voice_freq_env);
FreqLfo = new LFOParams(50, 40, 0, 0, 0, 0, 0, 0, time);
VoiceFilter = new FilterParams(2, 50, 60, time);
FilterEnvelope = new EnvelopeParams(0, 0, time);
- FilterEnvelope->ADSRinit_filter(90, 70, 40, 70, 10, 40);
+ FilterEnvelope->init(EnvelopeParams::ad_voice_filter_env);
FilterLfo = new LFOParams(50, 20, 64, 0, 0, 0, 0, 2, time);
FMFreqEnvelope = new EnvelopeParams(0, 0, time);
- FMFreqEnvelope->ASRinit(20, 90, 40, 80);
+ FMFreqEnvelope->init(EnvelopeParams::ad_voice_fm_freq_env);
FMAmpEnvelope = new EnvelopeParams(64, 1, time);
- FMAmpEnvelope->ADSRinit(80, 90, 127, 100);
+ FMAmpEnvelope->init(EnvelopeParams::ad_voice_fm_amp_env);
}
/*
@@ -1114,7 +1155,7 @@ void ADnoteVoiceParam::getfromXML(XMLwrapper& xml, unsigned nvoice)
Unison_invert_phase = xml.getpar127("unison_invert_phase",
Unison_invert_phase);
Unison_phase_randomness = xml.getpar127("unison_phase_randomness",
- Unison_phase_randomness);
+ Unison_phase_randomness);
Type = xml.getpar127("type", Type);
PDelay = xml.getpar127("delay", PDelay);
diff --git a/src/Params/ADnoteParameters.h b/src/Params/ADnoteParameters.h
@@ -330,14 +330,14 @@ class ADnoteParameters:public PresetsArray
void defaults(int n); //n is the nvoice
void add2XMLsection(XMLwrapper& xml, int n);
void getfromXMLsection(XMLwrapper& xml, int n);
- private:
+ const AbsTime *time;
+ int64_t last_update_timestamp;
+
+ private:
void EnableVoice(const SYNTH_T &synth, int nvoice, const AbsTime* time);
void KillVoice(int nvoice);
FFTwrapper *fft;
-
- const AbsTime *time;
- int64_t last_update_timestamp;
};
}
diff --git a/src/Params/Controller.cpp b/src/Params/Controller.cpp
@@ -29,33 +29,59 @@ namespace zyn {
#undef rChangeCb
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); }
const rtosc::Ports Controller::ports = {
- rParamZyn(panning.depth, rShort("pan.d"), "Depth of Panning MIDI Control"),
- rParamZyn(filtercutoff.depth, rShort("fc.d"), "Depth of Filter Cutoff MIDI Control"),
- rParamZyn(filterq.depth, rShort("fq.d"), "Depth of Filter Q MIDI Control"),
- rParamZyn(bandwidth.depth, rShort("bw.d"), "Depth of Bandwidth MIDI Control"),
- rToggle(bandwidth.exponential, rShort("bw.exp"), "Bandwidth Exponential Mode"),
- rParamZyn(modwheel.depth, rShort("mdw.d"), "Depth of Modwheel MIDI Control"),
- rToggle(modwheel.exponential, rShort("mdw.exp"), "Modwheel Exponential Mode"),
- rToggle(pitchwheel.is_split, "If PitchWheel Has unified bendrange or not"),
- rParamI(pitchwheel.bendrange, rShort("pch.d"), "Range of MIDI Pitch Wheel"),
- rParamI(pitchwheel.bendrange_down, "Lower Range of MIDI Pitch Wheel"),
- rToggle(expression.receive, rShort("exp.rcv"), "Expression MIDI Receive"),
- rToggle(fmamp.receive, rShort("fma.rcv"), "FM amplitude MIDI Receive"),
- rToggle(volume.receive, rShort("vol.rcv"), "Volume MIDI Receive"),
- rToggle(sustain.receive, rShort("sus.rcv"), "Sustain MIDI Receive"),
- rToggle(portamento.receive, rShort("prt.rcv"), "Portamento MIDI Receive"),
- rToggle(portamento.portamento, "Portamento Enable"),
- rParamZyn(portamento.time, rShort("time"), "Portamento Length"),
- rToggle(portamento.proportional, rShort("propt."), "Whether the portamento time is proportional"
+ rParamZyn(panning.depth, rShort("pan.d"), rDefault(64),
+ "Depth of Panning MIDI Control"),
+ rParamZyn(filtercutoff.depth, rShort("fc.d"), rDefault(64),
+ "Depth of Filter Cutoff MIDI Control"),
+ rParamZyn(filterq.depth, rShort("fq.d"), rDefault(64),
+ "Depth of Filter Q MIDI Control"),
+ rParamZyn(bandwidth.depth, rShort("bw.d"), rDefault(64),
+ "Depth of Bandwidth MIDI Control"),
+ rToggle(bandwidth.exponential, rShort("bw.exp"), rDefault(false),
+ "Bandwidth Exponential Mode"),
+ rParamZyn(modwheel.depth, rShort("mdw.d"), rDefault(80),
+ "Depth of Modwheel MIDI Control"),
+ rToggle(modwheel.exponential, rShort("mdw.exp"), rDefault(false),
+ "Modwheel Exponential Mode"),
+ rToggle(pitchwheel.is_split, rDefault(false),
+ "If PitchWheel Has unified bendrange or not"),
+ rParamI(pitchwheel.bendrange, rShort("pch.d"), rDefault(200),
+ rLinear(-6400, 6400),
+ "Range of MIDI Pitch Wheel"),
+ rParamI(pitchwheel.bendrange_down, rDefault(0),
+ "Lower Range of MIDI Pitch Wheel"),
+ rToggle(expression.receive, rShort("exp.rcv"), rDefault(true),
+ "Expression MIDI Receive"),
+ rToggle(fmamp.receive, rShort("fma.rcv"), rDefault(true),
+ "FM amplitude MIDI Receive"),
+ rToggle(volume.receive, rShort("vol.rcv"), rDefault(true),
+ "Volume MIDI Receive"),
+ rToggle(sustain.receive, rShort("sus.rcv"), rDefault(true),
+ "Sustain MIDI Receive"),
+ rToggle(portamento.receive, rShort("prt.rcv"), rDefault(true),
+ "Portamento MIDI Receive"),
+ rToggle(portamento.portamento, rDefault(false),
+ "Portamento Enable"),
+ rParamZyn(portamento.time, rShort("time"), rDefault(64),
+ "Portamento Length"),
+ rToggle(portamento.proportional, rShort("propt."), rDefault(false),
+ "Whether the portamento time is proportional"
"to the size of the interval between two notes."),
- rParamZyn(portamento.propRate, rShort("scale"), "Portamento proportional scale"),
- rParamZyn(portamento.propDepth, rShort("depth"), "Portamento proportional depth"),
- rParamZyn(portamento.pitchthresh, rShort("thresh"), "Threshold for portamento"),
- rToggle(portamento.pitchthreshtype, rShort("tr.type"), "Type of threshold"),
- rParamZyn(portamento.updowntimestretch, rShort("up/dwn"), "Relative length of glide up vs glide down"),
- rParamZyn(resonancecenter.depth, rShort("rfc.d"), "Resonance Center MIDI Depth"),
- rParamZyn(resonancebandwidth.depth, rShort("rbw.d"), "Resonance Bandwidth MIDI Depth"),
- rToggle(NRPN.receive, "NRPN MIDI Enable"),
+ rParamZyn(portamento.propRate, rShort("scale"), rDefault(80),
+ "Portamento proportional scale"),
+ rParamZyn(portamento.propDepth, rShort("depth"), rDefault(90),
+ "Portamento proportional depth"),
+ rParamZyn(portamento.pitchthresh, rShort("thresh"), rDefault(3),
+ "Threshold for portamento"),
+ rToggle(portamento.pitchthreshtype, rShort("tr.type"), rDefault(true),
+ "Type of threshold"),
+ rParamZyn(portamento.updowntimestretch, rShort("up/dwn"), rDefault(64),
+ "Relative length of glide up vs glide down"),
+ rParamZyn(resonancecenter.depth, rShort("rfc.d"), rDefault(64),
+ "Resonance Center MIDI Depth"),
+ rParamZyn(resonancebandwidth.depth, rShort("rbw.d"), rDefault(64),
+ "Resonance Bandwidth MIDI Depth"),
+ rToggle(NRPN.receive, rDefault(true), "NRPN MIDI Enable"),
rAction(defaults),
};
#undef rChangeCb
diff --git a/src/Params/EnvelopeParams.cpp b/src/Params/EnvelopeParams.cpp
@@ -37,27 +37,54 @@ static const rtosc::Ports localPorts = {
#undef rChangeCb
#define rChangeCb if(!obj->Pfreemode) obj->converttofree(); if (obj->time) { \
obj->last_update_timestamp = obj->time->time(); }
- rToggle(Pfreemode, "Complex Envelope Definitions"),
+ rToggle(Pfreemode, rDefault(false), "Complex Envelope Definitions"),
#undef rChangeCb
#define rChangeCb if(!obj->Pfreemode) obj->converttofree(); \
if(obj->time) { obj->last_update_timestamp = obj->time->time(); }
- rParamZyn(Penvpoints, rProp(internal), "Number of points in complex definition"),
- rParamZyn(Penvsustain, "Location of the sustain point"),
+ rOption(envelope_type, rProp(internal),
+ rOptions(ad_global_amp, ad_global_freq, ad_global_filter,
+ ad_voice_amp, ad_voice_freq, ad_voice_filter,
+ ad_voice_fm_freq, ad_voice_fm_amp,
+ sub_freq_env, sub_bandwidth_env), "function of the envelope"),
+ rParamZyn(Penvpoints, rProp(internal), rDefaultDepends(envelope_type),
+ rPresets(4, 3, 4, 4, 3, 4, 3, 4, 3, 3),
+ "Number of points in complex definition"),
+ rParamZyn(Penvsustain, rDefaultDepends(envelope_type),
+ rPresets(2, 1, 2, 2, 1, 2, 1, 2, 1, 1),
+ "Location of the sustain point"),
rParams(Penvdt, MAX_ENVELOPE_POINTS, "Envelope Delay Times"),
rParams(Penvval, MAX_ENVELOPE_POINTS, "Envelope Values"),
- rParamZyn(Penvstretch, rShort("stretch"),
+ rParamZyn(Penvstretch, rShort("stretch"), rDefaultDepends(envelope_type),
+ rPresets(64, 0, 0, 64, 0, 0, 0, 64, 64, 64),
"Stretch with respect to frequency"),
- rToggle(Pforcedrelease, rShort("frcr"),
+ rToggle(Pforcedrelease, rShort("frcr"), rDefaultDepends(envelope_type),
+ rPresets(true, false, true, true, false,
+ false, false, true, false, false),
"Force Envelope to fully evaluate"),
- rToggle(Plinearenvelope, rShort("lin/log"),
+ rToggle(Plinearenvelope, rShort("lin/log"), rDefault(false),
"Linear or Logarithmic Envelopes"),
- rParamZyn(PA_dt, rShort("a.dt"), "Attack Time"),
- rParamZyn(PA_val, rShort("a.val"), "Attack Value"),
- rParamZyn(PD_dt, rShort("d.dt"), "Decay Time"),
- rParamZyn(PD_val, rShort("d.val"), "Decay Value"),
- rParamZyn(PS_val, rShort("s.val"), "Sustain Value"),
- rParamZyn(PR_dt, rShort("r.dt"), "Release Time"),
- rParamZyn(PR_val, rShort("r.val"), "Release Value"),
+ rParamZyn(PA_dt, rShort("a.dt"), rDefaultDepends(envelope_type),
+ rPresets(0, 50, 40, 0, 40, 70, 90, 80, 50, 70),
+ "Attack Time"),
+ rParamZyn(PA_val, rShort("a.val"), rDefaultDepends(envelope_type),
+ rDefault(64), rPresetsAt(4, 30, 90, 20, 64, 30, 100),
+ "Attack Value"),
+ rParamZyn(PD_dt, rShort("d.dt"), rDefaultDepends(envelope_type),
+ rDefault(10), rPresets(40, 10, 70, 100, 10, 70, 10, 90),
+ "Decay Time"),
+ rParamZyn(PD_val, rShort("d.val"), rDefaultDepends(envelope_type),
+ rDefault(64), rPresetsAt(5, 40),
+ "Decay Value"),
+ rParamZyn(PS_val, rShort("s.val"), rDefaultDepends(envelope_type),
+ rDefault(64),
+ rPresets(127), rPresetsAt(3, 127), rPresetsAt(7, 127),
+ "Sustain Value"),
+ rParamZyn(PR_dt, rShort("r.dt"), rDefaultDepends(envelope_type),
+ rPresets(25, 60, 60, 100, 60, 10, 80, 100, 60, 60),
+ "Release Time"),
+ rParamZyn(PR_val, rShort("r.val"), rDefaultDepends(envelope_type),
+ rDefault(64), rPresetsAt(5, 40, 40),
+ "Release Value"),
{"Envmode:", rDoc("Envelope variant type"), NULL,
rBegin;
@@ -202,6 +229,26 @@ void EnvelopeParams::paste(const EnvelopeParams &ep)
}
#undef COPY
+void EnvelopeParams::init(EnvelopeParams::envelope_type_t etype)
+{
+ switch(etype)
+ {
+ case ad_global_amp_env: ADSRinit_dB(0, 40, 127, 25); break;
+ case ad_global_freq_env: ASRinit(64, 50, 64, 60); break;
+ case ad_global_filter_env: ADSRinit_filter(64, 40, 64, 70, 60, 64);
+ break;
+ case ad_voice_amp_env: ADSRinit_dB(0, 100, 127, 100); break;
+ case ad_voice_freq_env: ASRinit(30, 40, 64, 60); break;
+ case ad_voice_filter_env: ADSRinit_filter(90, 70, 40, 70, 10, 40);
+ break;
+ case ad_voice_fm_freq_env: ASRinit(20, 90, 40, 80); break;
+ case ad_voice_fm_amp_env: ADSRinit(80, 90, 127, 100); break;
+ case sub_freq_env: ASRinit(30, 50, 64, 60); break;
+ case sub_bandwidth_env: ASRinit_bw(100, 70, 64, 60); break;
+ };
+ envelope_type = etype;
+}
+
float EnvelopeParams::getdt(char i) const
{
return EnvelopeParams::dt(Penvdt[(int)i]);
@@ -304,16 +351,6 @@ void EnvelopeParams::converttofree()
{
switch(Envmode) {
case 1:
- Penvpoints = 4;
- Penvsustain = 2;
- Penvval[0] = 0;
- Penvdt[1] = PA_dt;
- Penvval[1] = 127;
- Penvdt[2] = PD_dt;
- Penvval[2] = PS_val;
- Penvdt[3] = PR_dt;
- Penvval[3] = 0;
- break;
case 2:
Penvpoints = 4;
Penvsustain = 2;
@@ -326,6 +363,7 @@ void EnvelopeParams::converttofree()
Penvval[3] = 0;
break;
case 3:
+ case 5:
Penvpoints = 3;
Penvsustain = 1;
Penvval[0] = PA_val;
@@ -345,15 +383,6 @@ void EnvelopeParams::converttofree()
Penvdt[3] = PR_dt;
Penvval[3] = PR_val;
break;
- case 5:
- Penvpoints = 3;
- Penvsustain = 1;
- Penvval[0] = PA_val;
- Penvdt[1] = PA_dt;
- Penvval[1] = 64;
- Penvdt[2] = PR_dt;
- Penvval[2] = PR_val;
- break;
}
}
@@ -413,7 +442,7 @@ public:
// f^{-1} o (env_dB2rap^{-1}) o dB2rap o f
// from the xml file. This results in the following formula:
? roundf(127.0f * (0.5f *
- log10f( 0.01f + 0.99f *
+ log10f( 0.01f + 0.99f *
powf(100, input/127.0f - 1))
+ 1))
: input;
diff --git a/src/Params/EnvelopeParams.h b/src/Params/EnvelopeParams.h
@@ -23,21 +23,28 @@ namespace zyn {
class EnvelopeParams:public Presets
{
public:
+ enum envelope_type_t
+ {
+ ad_global_amp_env, // ADSRinit_dB(0, 40, 127, 25);
+ ad_global_freq_env, // ASRinit(64, 50, 64, 60);
+ ad_global_filter_env, // ADSRinit_filter(64, 40, 64, 70, 60, 64)
+
+ ad_voice_amp_env, // ADSRinit_dB(0, 100, 127, 100);
+ ad_voice_freq_env, // ASRinit(30, 40, 64, 60);
+ ad_voice_filter_env, // ADSRinit_filter(90, 70, 40, 70, 10, 40);
+ ad_voice_fm_freq_env, // ASRinit(20, 90, 40, 80);
+ ad_voice_fm_amp_env, // ADSRinit(80, 90, 127, 100)
+ sub_freq_env, // ASRinit(30, 50, 64, 60);
+ sub_bandwidth_env, // ASRinit_bw(100, 70, 64, 60)
+ };
+
EnvelopeParams(unsigned char Penvstretch_=64,
unsigned char Pforcedrelease_=0,
const AbsTime *time_ = nullptr);
~EnvelopeParams();
void paste(const EnvelopeParams &ep);
- void ADSRinit(char A_dt, char D_dt, char S_val, char R_dt);
- void ADSRinit_dB(char A_dt, char D_dt, char S_val, char R_dt);
- void ASRinit(char A_val, char A_dt, char R_val, char R_dt);
- void ADSRinit_filter(char A_val,
- char A_dt,
- char D_val,
- char D_dt,
- char R_dt,
- char R_val);
- void ASRinit_bw(char A_val, char A_dt, char R_val, char R_dt);
+
+ void init(envelope_type_t etype);
void converttofree();
void add2XML(XMLwrapper& xml);
@@ -48,6 +55,10 @@ class EnvelopeParams:public Presets
static float dt(char val);
static char inv_dt(float val);
+ //! @brief defines where it is used and its default settings
+ //! corresponds to envelope_type_t
+ int envelope_type;
+
/* MIDI Parameters */
unsigned char Pfreemode; //1 for free mode, 0 otherwise
unsigned char Penvpoints;
@@ -78,6 +89,17 @@ class EnvelopeParams:public Presets
static float env_dB2rap(float db);
private:
+ void ADSRinit(char A_dt, char D_dt, char S_val, char R_dt);
+ void ADSRinit_dB(char A_dt, char D_dt, char S_val, char R_dt);
+ void ASRinit(char A_val, char A_dt, char R_val, char R_dt);
+ void ADSRinit_filter(char A_val,
+ char A_dt,
+ char D_val,
+ char D_dt,
+ char R_dt,
+ char R_val);
+ void ASRinit_bw(char A_val, char A_dt, char R_val, char R_dt);
+
void store2defaults();
/* Default parameters */
diff --git a/src/Params/FilterParams.cpp b/src/Params/FilterParams.cpp
@@ -101,8 +101,9 @@ const rtosc::Ports FilterParams::ports = {
unsigned idx = atoi(mm);
if(rtosc_narguments(msg)) {
obj->Psequence[idx].nvowel = rtosc_argument(msg, 0).i;
- } else
d.broadcast(d.loc, "i", obj->Psequence[idx].nvowel);
+ } else
+ d.reply(d.loc, "i", obj->Psequence[idx].nvowel);
}},
{"type-svf::i", rProp(parameter) rShort("type")
rOptions(low, high, band, notch)
@@ -171,7 +172,6 @@ const rtosc::Ports FilterParams::ports = {
0.0, cf.d[1]);
}
} else if(obj->Pcategory == 2) {
- int order = 0;
float gain = dB2rap(obj->getgain());
auto cf = SVFilter::computeResponse(obj->Ptype,
Filter::getrealfreq(obj->getfreq()),
@@ -569,7 +569,7 @@ void FilterParams::getfromXML(XMLwrapper& xml)
basefreq = xml.getparreal("basefreq", 1000);
baseq = xml.getparreal("baseq", 10);
gain = xml.getparreal("gain", 0);
- freqtracking = xml.getparreal("freq_track", 0);
+ freqtracking = xml.getparreal("freq_tracking", 0);
}
//formant filter parameters
diff --git a/src/Params/LFOParams.cpp b/src/Params/LFOParams.cpp
@@ -42,13 +42,15 @@ static const rtosc::Ports _ports = {
exp1, exp2), "Shape of LFO"),
rParamZyn(Prandomness, rShort("a.r."), rSpecial(disable),
"Amplitude Randomness (calculated uniformly at each cycle)"),
- rParamZyn(Pfreqrand, rShort("f.r."), rSpecial(disable),
+ rParamZyn(Pfreqrand, rShort("f.r."), rSpecial(disable), rDefault(0),
"Frequency Randomness (calculated uniformly at each cycle)"),
rParamZyn(Pdelay, rShort("delay"), rSpecial(disable), "Delay before LFO start\n"
"0..4 second delay"),
rToggle(Pcontinous, rShort("c"), "Enable for global operation"),
- rParamZyn(Pstretch, rShort("str"), rCentered, "Note frequency stretch"),
-
+ rParamZyn(Pstretch, rShort("str"), rCentered, rDefault(64),
+ "Note frequency stretch"),
+// these are currently not yet implemented at must be hidden therefore
+#ifdef DEAD_PORTS
//Float valued aliases
{"delay::f", rProp(parameter) rMap(units, ms) rLog(0,4000), 0,
rBegin;
@@ -58,6 +60,7 @@ static const rtosc::Ports _ports = {
{"period::f", rProp(parameter) rMap(units, ms) rPseudoLog(0.10, 1500.0), 0,
rBegin;
rEnd},
+#endif
};
#undef rPseudoLog
#undef rBegin
diff --git a/src/Params/PADnoteParameters.cpp b/src/Params/PADnoteParameters.cpp
@@ -43,33 +43,46 @@ static const rtosc::Ports realtime_ports =
rRecurp(GlobalFilter, "Post Filter"),
//Volume
- rToggle(PStereo, rShort("stereo"), "Stereo/Mono Mode"),
- rParamZyn(PPanning, rShort("panning"), "Left Right Panning"),
- rParamZyn(PVolume, rShort("vol"), "Synth Volume"),
- rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), "Amplitude Velocity Sensing function"),
+ rToggle(PStereo, rShort("stereo"), rDefault(true), "Stereo/Mono Mode"),
+ rParamZyn(PPanning, rShort("panning"), rDefault(64), "Left Right Panning"),
+ rParamZyn(PVolume, rShort("vol"), rDefault(90), "Synth Volume"),
+ rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(64),
+ "Amplitude Velocity Sensing function"),
- rParamZyn(Fadein_adjustment, rShort("a.pop."), "Adjustment for anti-pop strategy."),
+ rParamZyn(Fadein_adjustment, rShort("a.pop."),
+ rDefault(FADEIN_ADJUSTMENT_SCALE), "Adjustment for anti-pop strategy."),
//Punch
- rParamZyn(PPunchStrength, rShort("strength"), "Punch Strength"),
- rParamZyn(PPunchTime, rShort("time"), "Length of punch"),
- rParamZyn(PPunchStretch, rShort("stretch"), "How Punch changes with note frequency"),
- rParamZyn(PPunchVelocitySensing, rShort("sense"), "Punch Velocity control"),
+ rParamZyn(PPunchStrength, rShort("strength"), rDefault(0),
+ "Punch Strength"),
+ rParamZyn(PPunchTime, rShort("time"), rDefault(60),
+ "Length of punch"),
+ rParamZyn(PPunchStretch, rShort("stretch"), rDefault(64),
+ "How Punch changes with note frequency"),
+ rParamZyn(PPunchVelocitySensing, rShort("sense"), rDefault(72),
+ "Punch Velocity control"),
//Filter
- rParamZyn(PFilterVelocityScale, rShort("scale"), "Filter Velocity Magnitude"),
- rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), "Filter Velocity Function Shape"),
+ rParamZyn(PFilterVelocityScale, rShort("scale"), rDefault(64),
+ "Filter Velocity Magnitude"),
+ rParamZyn(PFilterVelocityScaleFunction, rShort("sense"), rDefault(64),
+ "Filter Velocity Function Shape"),
//Freq
- rToggle(Pfixedfreq, rShort("fixed"), "Base frequency fixed frequency enable"),
- rParamZyn(PfixedfreqET, rShort("f.ET"), "Equal temeperate control for fixed frequency operation"),
- rParamZyn(PBendAdjust, "Pitch bend adjustment"),
- rParamZyn(POffsetHz, rShort("offset"), "Voice constant offset"),
- rParamI(PDetune, rShort("fine"), rLinear(0, 16383), "Fine Detune"),
- rParamI(PCoarseDetune, rShort("coarse"), "Coarse Detune"),
+ rToggle(Pfixedfreq, rShort("fixed"), rDefault(false),
+ "Base frequency fixed frequency enable"),
+ rParamZyn(PfixedfreqET, rShort("f.ET"), rDefault(0),
+ "Equal temeperate control for fixed frequency operation"),
+ rParamZyn(PBendAdjust, rDefault(88),
+ "Pitch bend adjustment"),
+ rParamZyn(POffsetHz, rShort("offset"), rDefault(64),
+ "Voice constant offset"),
+ rParamI(PDetune, rShort("fine"), rLinear(0, 16383), rDefault(8192),
+ "Fine Detune"),
+ rParamI(PCoarseDetune, rShort("coarse"), rDefault(0), "Coarse Detune"),
rParamZyn(PDetuneType, rShort("type"),
rOptions(L35cents, L10cents, E100cents, E1200cents),
- "Magnitude of Detune"),
+ rDefault(L10cents), "Magnitude of Detune"),
{"sample#64:ifb", rProp(internal) rDoc("Nothing to see here"), 0,
[](const char *m, rtosc::RtData &d)
@@ -144,58 +157,78 @@ static const rtosc::Ports non_realtime_ports =
rRecurp(resonance, "Resonance"),
//Harmonic Shape
- rOption(Pmode, rMap(min, 0), rMap(max, 2), rShort("distribution"), rOptions(bandwidth,discrete,continious),
+ rOption(Pmode, rMap(min, 0), rMap(max, 2), rShort("distribution"),
+ rOptions(bandwidth,discrete,continious),
+ rDefault(bandwidth),
"Harmonic Distribution Model"),
- rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential), rShort("shape"),
+ rOption(Php.base.type, rOptions(Gaussian, Rectanglar, Double Exponential),
+ rShort("shape"), rDefault(Gaussian),
"Harmonic profile shape"),
- rParamZyn(Php.base.par1, rShort("warp"), "Harmonic shape distribution parameter"),
- rParamZyn(Php.freqmult, rShort("clone"), "Frequency multiplier on distribution"),
- rParamZyn(Php.modulator.par1, rShort("p1"), "Distribution modulator parameter"),
- rParamZyn(Php.modulator.freq, rShort("freq"), "Frequency of modulator parameter"),
- rParamZyn(Php.width, rShort("bandwidth"), "Width of base harmonic"),
- rOption(Php.amp.mode, rShort("mode"), rOptions(Sum, Mult, Div1, Div2),
+ rParamZyn(Php.base.par1, rShort("warp"), rDefault(80),
+ "Harmonic shape distribution parameter"),
+ rParamZyn(Php.freqmult, rShort("clone"), rDefault(0),
+ "Frequency multiplier on distribution"),
+ rParamZyn(Php.modulator.par1, rShort("p1"), rDefault(0),
+ "Distribution modulator parameter"),
+ rParamZyn(Php.modulator.freq, rShort("freq"), rDefault(30),
+ "Frequency of modulator parameter"),
+ rParamZyn(Php.width, rShort("bandwidth"), rDefault(127),
+ "Width of base harmonic"),
+ rOption(Php.amp.mode, rShort("mode"),
+ rOptions(Sum, Mult, Div1, Div2), rDefault(Sum),
"Amplitude harmonic multiplier type"),
//Harmonic Modulation
rOption(Php.amp.type, rShort("mult"), rOptions(Off, Gauss, Sine, Flat),
- "Type of amplitude multipler"),
- rParamZyn(Php.amp.par1, rShort("p1"), "Amplitude multiplier parameter"),
- rParamZyn(Php.amp.par2, rShort("p2"), "Amplitude multiplier parameter"),
- rToggle(Php.autoscale, rShort("auto"), "Autoscaling Harmonics"),
+ rDefault(Off), "Type of amplitude multipler"),
+ rParamZyn(Php.amp.par1, rShort("p1"), rDefault(80),
+ "Amplitude multiplier parameter"),
+ rParamZyn(Php.amp.par2, rShort("p2"), rDefault(60),
+ "Amplitude multiplier parameter"),
+ rToggle(Php.autoscale, rShort("auto"), rDefault(true),
+ "Autoscaling Harmonics"),
rOption(Php.onehalf, rShort("side"),
- rOptions(Full, Upper Half, Lower Half),
+ rOptions(Full, Upper Half, Lower Half), rDefault(Full)
"Harmonic cutoff model"),
//Harmonic Bandwidth
rOption(Pbwscale, rShort("bw scale"),
rOptions(Normal,
- EqualHz, Quater,
+ EqualHz, Quarter,
Half, 75%, 150%,
Double, Inv. Half),
+ rDefault(Normal),
"Bandwidth scaling"),
//Harmonic Position Modulation
rOption(Phrpos.type,
rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine,
Power, Shift),
+ rDefault(Harmonic)
"Harmonic Overtone shifting mode"),
- rParamI(Phrpos.par1, rShort("p1"), rLinear(0,255), "Harmonic position parameter"),
- rParamI(Phrpos.par2, rShort("p2"), rLinear(0,255), "Harmonic position parameter"),
- rParamI(Phrpos.par3, rShort("force h."), rLinear(0,255), "Harmonic position parameter"),
+ rParamI(Phrpos.par1, rShort("p1"), rLinear(0,255), rDefault(0),
+ "Harmonic position parameter"),
+ rParamI(Phrpos.par2, rShort("p2"), rLinear(0,255), rDefault(0),
+ "Harmonic position parameter"),
+ rParamI(Phrpos.par3, rShort("force h."), rLinear(0,255), rDefault(0),
+ "Harmonic position parameter"),
//Quality
rOption(Pquality.samplesize, rShort("quality"),
rOptions(16k (Tiny), 32k, 64k (Small), 128k,
256k (Normal), 512k, 1M (Big)),
+ rDefaultId(128k),
"Size of each wavetable element"),
rOption(Pquality.basenote, rShort("basenote"),
rOptions(C-2, G-2, C-3, G-3, C-4,
G-4, C-5, G-5, G-6,),
+ rDefaultId(C-4),
"Base note for wavetable"),
rOption(Pquality.smpoct, rShort("smp/oct"),
rOptions(0.5, 1, 2, 3, 4, 6, 12),
+ rDefault(2),
"Samples per octave"),
- rParamI(Pquality.oct, rShort("octaves"), rLinear(0,7),
+ 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,
@@ -278,16 +311,16 @@ PADnoteParameters::PADnoteParameters(const SYNTH_T &synth_, FFTwrapper *fft_,
oscilgen->ADvsPAD = true;
FreqEnvelope = new EnvelopeParams(0, 0, time_);
- FreqEnvelope->ASRinit(64, 50, 64, 60);
+ FreqEnvelope->init(EnvelopeParams::ad_global_freq_env);
FreqLfo = new LFOParams(70, 0, 64, 0, 0, 0, 0, 0, time_);
AmpEnvelope = new EnvelopeParams(64, 1, time_);
- AmpEnvelope->ADSRinit_dB(0, 40, 127, 25);
+ AmpEnvelope->init(EnvelopeParams::ad_global_amp_env);
AmpLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 1, time_);
GlobalFilter = new FilterParams(2, 94, 40, time_);
FilterEnvelope = new EnvelopeParams(0, 1, time_);
- FilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64);
+ FilterEnvelope->init(EnvelopeParams::ad_global_filter_env);
FilterLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 2, time_);
for(int i = 0; i < PAD_MAX_SAMPLES; ++i)
diff --git a/src/Params/SUBnoteParameters.cpp b/src/Params/SUBnoteParameters.cpp
@@ -37,52 +37,74 @@ namespace zyn {
static const rtosc::Ports SUBnotePorts = {
rSelf(SUBnoteParameters),
rPaste,
- rToggle(Pstereo, rShort("stereo"), "Stereo Enable"),
- rParamZyn(PVolume, rShort("volume"), "Volume"),
- rParamZyn(PPanning, rShort("panning"), "Left Right Panning"),
- rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), "Amplitude Velocity Sensing function"),
- rParamI(PDetune, rShort("detune"), rLinear(0, 16383), "Detune in detune type units"),
- rParamI(PCoarseDetune, rShort("cdetune"), "Coarse Detune"),
+ rToggle(Pstereo, rShort("stereo"), rDefault(true), "Stereo Enable"),
+ rParamZyn(PVolume, rShort("volume"), rDefault(96), "Volume"),
+ rParamZyn(PPanning, rShort("panning"), rDefault(64), "Left Right Panning"),
+ rParamZyn(PAmpVelocityScaleFunction, rShort("sense"), rDefault(90),
+ "Amplitude Velocity Sensing function"),
+ rParamI(PDetune, rShort("detune"), rLinear(0, 16383), rDefault(8192),
+ "Detune in detune type units"),
+ rParamI(PCoarseDetune, rShort("cdetune"), rDefault(0), "Coarse Detune"),
//Real values needed
rOption(PDetuneType, rShort("det. scl."),
- rOptions(L35 cents, L10 cents, E100 cents, E1200 cents), "Detune Scale"),
- rToggle(PFreqEnvelopeEnabled, rShort("enable"), "Enable for Frequency Envelope"),
- rToggle(PBandWidthEnvelopeEnabled, rShort("enable"), "Enable for Bandwidth Envelope"),
- rToggle(PGlobalFilterEnabled, rShort("enable"), "Enable for Global Filter"),
- rParamZyn(PGlobalFilterVelocityScale, rShort("scale"), "Filter Velocity Magnitude"),
- rParamZyn(PGlobalFilterVelocityScaleFunction, rShort("sense"), "Filter Velocity Function Shape"),
+ rOptions(L35 cents, L10 cents, E100 cents, E1200 cents),
+ rDefaultId(L10 cents), "Detune Scale"),
+ rToggle(PFreqEnvelopeEnabled, rShort("enable"), rDefault(false),
+ "Enable for Frequency Envelope"),
+ rToggle(PBandWidthEnvelopeEnabled, rShort("enable"), rDefault(false),
+ "Enable for Bandwidth Envelope"),
+ rToggle(PGlobalFilterEnabled, rShort("enable"),
+ rDefault(false), "Enable for Global Filter"),
+ rParamZyn(PGlobalFilterVelocityScale, rShort("scale"), rDefault(64),
+ "Filter Velocity Magnitude"),
+ rParamZyn(PGlobalFilterVelocityScaleFunction, rShort("sense"), rDefault(64),
+ "Filter Velocity Function Shape"),
//rRecur(FreqEnvelope, EnvelopeParams),
//rToggle(),//continue
- rToggle(Pfixedfreq, rShort("fixed freq"), "Base frequency fixed frequency enable"),
- rParamZyn(PfixedfreqET, rShort("fixed ET"), "Equal temeperate control for fixed frequency operation"),
- rParamZyn(PBendAdjust, rShort("bend"), "Pitch bend adjustment"),
- rParamZyn(POffsetHz, rShort("+ Hz"), "Voice constant offset"),
+ rToggle(Pfixedfreq, rShort("fixed freq"), rDefault(false),
+ "Base frequency fixed frequency enable"),
+ rParamZyn(PfixedfreqET, rShort("fixed ET"), rDefault(0),
+ "Equal temeperate control for fixed frequency operation"),
+ rParamZyn(PBendAdjust, rShort("bend"), rDefault(88),
+ "Pitch bend adjustment"),
+ rParamZyn(POffsetHz, rShort("+ Hz"), rDefault(64),
+ "Voice constant offset"),
#undef rChangeCb
#define rChangeCb obj->updateFrequencyMultipliers(); if (obj->time) { \
obj->last_update_timestamp = obj->time->time(); }
rParamI(POvertoneSpread.type, rMap(min, 0), rMap(max, 7), rShort("spread type")
rOptions(Harmonic, ShiftU, ShiftL, PowerU, PowerL, Sine, Power, Shift),
+ rDefault(Harmonic)
"Spread of harmonic frequencies"),
rParamI(POvertoneSpread.par1, rMap(min, 0), rMap(max, 255), rShort("p1"),
- "Overtone Parameter"),
+ rDefault(0), "Overtone Parameter"),
rParamI(POvertoneSpread.par2, rMap(min, 0), rMap(max, 255), rShort("p2"),
- "Overtone Parameter"),
+ rDefault(0), "Overtone Parameter"),
rParamI(POvertoneSpread.par3, rMap(min, 0), rMap(max, 255), rShort("forceH"),
- "Force Overtones To Harmonics"),
+ rDefault(0), "Force Overtones To Harmonics"),
#undef rChangeCb
#define rChangeCb if (obj->time) { obj->last_update_timestamp = obj->time->time(); }
- rParamI(Pnumstages, rShort("stages"), rMap(min, 1), rMap(max, 5), "Number of filter stages"),
- rParamZyn(Pbandwidth, rShort("bandwidth"), "Bandwidth of filters"),
- rParamZyn(Phmagtype, rShort("mag. type"), rOptions(linear, -40dB, -60dB, -80dB, -100dB), "Magnitude scale"),
- rArray(Phmag, MAX_SUB_HARMONICS, "Harmonic magnitudes"),
- rArray(Phrelbw, MAX_SUB_HARMONICS, "Relative bandwidth"),
- rParamZyn(Pbwscale, rShort("stretch"), "Bandwidth scaling with frequency"),
+ rParamI(Pnumstages, rShort("stages"), rMap(min, 1), rMap(max, 5),
+ rDefault(2), "Number of filter stages"),
+ rParamZyn(Pbandwidth, rShort("bandwidth"), rDefault(40),
+ "Bandwidth of filters"),
+ rParamZyn(Phmagtype, rShort("mag. type"),
+ rOptions(linear, -40dB, -60dB, -80dB, -100dB),
+ rDefault(linear), "Magnitude scale"),
+ rArray(Phmag, MAX_SUB_HARMONICS, rDefaultMissing,
+ "Harmonic magnitudes"),
+ rArray(Phrelbw, MAX_SUB_HARMONICS, rDefaultMissing,
+ "Relative bandwidth"),
+ rParamZyn(Pbwscale, rShort("stretch"), rDefault(64),
+ "Bandwidth scaling with frequency"),
rRecurp(AmpEnvelope, "Amplitude envelope"),
rRecurp(FreqEnvelope, "Frequency Envelope"),
rRecurp(BandWidthEnvelope, "Bandwidth Envelope"),
rRecurp(GlobalFilterEnvelope, "Post Filter Envelope"),
rRecurp(GlobalFilter, "Post Filter"),
- rOption(Pstart, rShort("initial"), rOptions(zero, random, ones), "How harmonics are initialized"),
+ rOption(Pstart, rShort("initial"), rOptions(zero, random, ones),
+ rDefault(random),
+ "How harmonics are initialized"),
{"clear:", rDoc("Reset all harmonics to equal bandwidth/zero amplitude"), NULL,
rBegin;
@@ -179,15 +201,15 @@ SUBnoteParameters::SUBnoteParameters(const AbsTime *time_)
{
setpresettype("Psubsynth");
AmpEnvelope = new EnvelopeParams(64, 1, time_);
- AmpEnvelope->ADSRinit_dB(0, 40, 127, 25);
+ AmpEnvelope->init(EnvelopeParams::ad_global_amp_env);
FreqEnvelope = new EnvelopeParams(64, 0, time_);
- FreqEnvelope->ASRinit(30, 50, 64, 60);
+ FreqEnvelope->init(EnvelopeParams::sub_freq_env);
BandWidthEnvelope = new EnvelopeParams(64, 0, time_);
- BandWidthEnvelope->ASRinit_bw(100, 70, 64, 60);
+ BandWidthEnvelope->init(EnvelopeParams::sub_bandwidth_env);
GlobalFilter = new FilterParams(2, 80, 40, time_);
GlobalFilterEnvelope = new EnvelopeParams(0, 1, time_);
- GlobalFilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64);
+ GlobalFilterEnvelope->init(EnvelopeParams::ad_global_filter_env);
defaults();
}
diff --git a/src/Plugin/AlienWah/CMakeLists.txt b/src/Plugin/AlienWah/CMakeLists.txt
@@ -24,6 +24,8 @@ add_custom_command(TARGET ZynAlienWah_lv2 POST_BUILD
COMMAND ../../lv2-ttl-generator $<TARGET_FILE:ZynAlienWah_lv2>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lv2)
+add_dependencies(ZynAlienWah_lv2 lv2-ttl-generator)
+
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lv2/manifest.ttl
${CMAKE_CURRENT_BINARY_DIR}/lv2/presets.ttl
diff --git a/src/Plugin/Chorus/CMakeLists.txt b/src/Plugin/Chorus/CMakeLists.txt
@@ -24,6 +24,8 @@ add_custom_command(TARGET ZynChorus_lv2 POST_BUILD
COMMAND ../../lv2-ttl-generator $<TARGET_FILE:ZynChorus_lv2>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lv2)
+add_dependencies(ZynChorus_lv2 lv2-ttl-generator)
+
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lv2/manifest.ttl
${CMAKE_CURRENT_BINARY_DIR}/lv2/presets.ttl
diff --git a/src/Plugin/Distortion/CMakeLists.txt b/src/Plugin/Distortion/CMakeLists.txt
@@ -24,6 +24,8 @@ add_custom_command(TARGET ZynDistortion_lv2 POST_BUILD
COMMAND ../../lv2-ttl-generator $<TARGET_FILE:ZynDistortion_lv2>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lv2)
+add_dependencies(ZynDistortion_lv2 lv2-ttl-generator)
+
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lv2/manifest.ttl
${CMAKE_CURRENT_BINARY_DIR}/lv2/presets.ttl
diff --git a/src/Plugin/DynamicFilter/CMakeLists.txt b/src/Plugin/DynamicFilter/CMakeLists.txt
@@ -24,6 +24,8 @@ add_custom_command(TARGET ZynDynamicFilter_lv2 POST_BUILD
COMMAND ../../lv2-ttl-generator $<TARGET_FILE:ZynDynamicFilter_lv2>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lv2)
+add_dependencies(ZynDynamicFilter_lv2 lv2-ttl-generator)
+
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lv2/manifest.ttl
${CMAKE_CURRENT_BINARY_DIR}/lv2/presets.ttl
diff --git a/src/Plugin/Echo/CMakeLists.txt b/src/Plugin/Echo/CMakeLists.txt
@@ -24,6 +24,8 @@ add_custom_command(TARGET ZynEcho_lv2 POST_BUILD
COMMAND ../../lv2-ttl-generator $<TARGET_FILE:ZynEcho_lv2>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lv2)
+add_dependencies(ZynEcho_lv2 lv2-ttl-generator)
+
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lv2/manifest.ttl
${CMAKE_CURRENT_BINARY_DIR}/lv2/presets.ttl
diff --git a/src/Plugin/Phaser/CMakeLists.txt b/src/Plugin/Phaser/CMakeLists.txt
@@ -24,6 +24,8 @@ add_custom_command(TARGET ZynPhaser_lv2 POST_BUILD
COMMAND ../../lv2-ttl-generator $<TARGET_FILE:ZynPhaser_lv2>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lv2)
+add_dependencies(ZynPhaser_lv2 lv2-ttl-generator)
+
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lv2/manifest.ttl
${CMAKE_CURRENT_BINARY_DIR}/lv2/presets.ttl
diff --git a/src/Plugin/Reverb/CMakeLists.txt b/src/Plugin/Reverb/CMakeLists.txt
@@ -24,6 +24,8 @@ add_custom_command(TARGET ZynReverb_lv2 POST_BUILD
COMMAND ../../lv2-ttl-generator $<TARGET_FILE:ZynReverb_lv2>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lv2)
+add_dependencies(ZynReverb_lv2 lv2-ttl-generator)
+
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lv2/manifest.ttl
${CMAKE_CURRENT_BINARY_DIR}/lv2/presets.ttl
diff --git a/src/Plugin/ZynAddSubFX/CMakeLists.txt b/src/Plugin/ZynAddSubFX/CMakeLists.txt
@@ -48,6 +48,7 @@ add_library(ZynAddSubFX_vst SHARED
elseif(ZestGui)
# UI Enabled using Zest: internal only
+if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
add_library(ZynAddSubFX_lv2 SHARED
${CMAKE_SOURCE_DIR}/src/globals.cpp
${CMAKE_SOURCE_DIR}/src/UI/ConnectionDummy.cpp
@@ -61,6 +62,7 @@ add_library(ZynAddSubFX_lv2_ui SHARED
${CMAKE_SOURCE_DIR}/DPF/dgl/src/Application.cpp
${CMAKE_SOURCE_DIR}/DPF/distrho/DistrhoUIMain.cpp
ZynAddSubFX-UI-Zest.cpp)
+endif()
add_library(ZynAddSubFX_vst SHARED
${CMAKE_SOURCE_DIR}/src/globals.cpp
@@ -91,10 +93,12 @@ add_library(ZynAddSubFX_vst SHARED
endif()
-set_target_properties(ZynAddSubFX_lv2 PROPERTIES COMPILE_DEFINITIONS "DISTRHO_PLUGIN_TARGET_LV2")
-set_target_properties(ZynAddSubFX_lv2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY "lv2")
-set_target_properties(ZynAddSubFX_lv2 PROPERTIES OUTPUT_NAME "ZynAddSubFX")
-set_target_properties(ZynAddSubFX_lv2 PROPERTIES PREFIX "")
+if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+ set_target_properties(ZynAddSubFX_lv2 PROPERTIES COMPILE_DEFINITIONS "DISTRHO_PLUGIN_TARGET_LV2")
+ set_target_properties(ZynAddSubFX_lv2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY "lv2")
+ set_target_properties(ZynAddSubFX_lv2 PROPERTIES OUTPUT_NAME "ZynAddSubFX")
+ set_target_properties(ZynAddSubFX_lv2 PROPERTIES PREFIX "")
+endif()
set_target_properties(ZynAddSubFX_vst PROPERTIES COMPILE_DEFINITIONS "DISTRHO_PLUGIN_TARGET_VST")
set_target_properties(ZynAddSubFX_vst PROPERTIES LIBRARY_OUTPUT_DIRECTORY "vst")
@@ -104,29 +108,40 @@ set_target_properties(ZynAddSubFX_vst PROPERTIES PREFIX "")
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(PLATFORM_LIBRARIES ws2_32
winmm
+ glu32
+ gdi32
+ opengl32
wsock32
"-static" iphlpapi
"-static" winpthread)
elseif(ZestGui)
set(PLATFORM_LIBRARIES X11 GL rt)
-else()
+elseif(NtkGui OR FltkGui)
set(PLATFORM_LIBRARIES X11 rt)
+else()
+ set(PLATFORM_LIBRARIES rt)
endif()
-target_link_libraries(ZynAddSubFX_lv2 zynaddsubfx_core ${OS_LIBRARIES} ${LIBLO_LIBRARIES}
- ${PLATFORM_LIBRARIES})
+if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+ target_link_libraries(ZynAddSubFX_lv2 zynaddsubfx_core ${OS_LIBRARIES} ${LIBLO_LIBRARIES}
+ ${PLATFORM_LIBRARIES})
+endif()
target_link_libraries(ZynAddSubFX_vst zynaddsubfx_core ${OS_LIBRARIES} ${LIBLO_LIBRARIES}
${PLATFORM_LIBRARIES})
-if(ZestGui)
+if(ZestGui AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
target_link_libraries(ZynAddSubFX_lv2_ui X11 GL)
endif()
-install(TARGETS ZynAddSubFX_lv2 LIBRARY DESTINATION ${PluginLibDir}/lv2/ZynAddSubFX.lv2/)
-install(TARGETS ZynAddSubFX_vst LIBRARY DESTINATION ${PluginLibDir}/vst/)
+if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+ install(TARGETS ZynAddSubFX_lv2 LIBRARY DESTINATION ${PluginLibDir}/lv2/ZynAddSubFX.lv2/)
+ install(TARGETS ZynAddSubFX_vst LIBRARY DESTINATION ${PluginLibDir}/vst/)
-add_custom_command(TARGET ZynAddSubFX_lv2 POST_BUILD
- COMMAND ../../lv2-ttl-generator $<TARGET_FILE:ZynAddSubFX_lv2>
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lv2)
+ add_custom_command(TARGET ZynAddSubFX_lv2 POST_BUILD
+ COMMAND ../../lv2-ttl-generator $<TARGET_FILE:ZynAddSubFX_lv2>
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lv2)
+
+ add_dependencies(ZynAddSubFX_lv2 lv2-ttl-generator)
+endif()
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/lv2/manifest.ttl
diff --git a/src/Plugin/ZynAddSubFX/ZynAddSubFX-UI-Zest.cpp b/src/Plugin/ZynAddSubFX/ZynAddSubFX-UI-Zest.cpp
@@ -13,7 +13,14 @@
// DPF includes
#include "DistrhoUI.hpp"
+#ifdef WIN32
+#include <windows.h>
+#else
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
#include <dlfcn.h>
+#endif
typedef void *zest_t;
struct zest_handles {
@@ -41,13 +48,37 @@ public:
: UI(1181, 659)
{
printf("[INFO] Opened the zynaddsubfx UI...\n");
- handle = dlopen("/opt/zyn-fusion/libzest.so", RTLD_LAZY);
+#ifdef WIN32
+ char path[1024];
+ GetModuleFileName(GetModuleHandle("ZynAddSubFX.dll"), path, sizeof(path));
+ if(strstr(path, "ZynAddSubFX.dll"))
+ strstr(path, "ZynAddSubFX.dll")[0] = 0;
+ strcat(path, "libzest.dll");
+ printf("[DEBUG] Loading zest library from <%s>\n", path);
+ handle = LoadLibrary(path);
+ if(!handle)
+ handle = LoadLibrary("./libzest.dll");
+ if(!handle)
+ handle = LoadLibrary("libzest.dll");
+#else
+ handle = dlopen("./libzest.so", RTLD_LAZY);
+ if(!handle)
+ handle = dlopen("/opt/zyn-fusion/libzest.so", RTLD_LAZY);
+ if(!handle)
+ handle = dlopen("libzest.so", RTLD_LAZY);
+#endif
if(!handle) {
printf("[ERROR] Cannot Open libzest.so\n");
+#ifndef WIN32
printf("[ERROR] '%s'\n", dlerror());
+#endif
}
memset(&z, 0, sizeof(z));
+#ifdef WIN32
+#define get_sym(x) z.zest_##x = (decltype(z.zest_##x))GetProcAddress(handle, "zest_"#x)
+#else
#define get_sym(x) z.zest_##x = (decltype(z.zest_##x))dlsym(handle, "zest_"#x)
+#endif
if(handle) {
get_sym(open);
get_sym(setup);
@@ -70,8 +101,11 @@ public:
printf("[INFO:Zyn] zest_close()\n");
if(z.zest)
z.zest_close(z.zest);
+#ifdef WIN32
+#else
if(handle)
- dlclose(handle);
+ dlclose(handle);
+#endif
}
protected:
@@ -156,13 +190,15 @@ protected:
if(!z.zest) {
if(!z.zest_open)
return;
- //printf("[INFO:Zyn] zest_open()\n");
+if(!oscPort)
+ return;
+ printf("[INFO:Zyn] zest_open()\n");
char address[1024];
snprintf(address, sizeof(address), "osc.udp://127.0.0.1:%d",oscPort);
printf("[INFO:Zyn] zest_open(%s)\n", address);
z.zest = z.zest_open(address);
- printf("[INFO:Zyn] zest_setup()\n");
+ printf("[INFO:Zyn] zest_setup(%s)\n", address);
z.zest_setup(z.zest);
}
@@ -195,7 +231,11 @@ protected:
private:
int oscPort;
zest_handles z;
+#ifdef WIN32
+ HMODULE handle;
+#else
void *handle;
+#endif
DISTRHO_DECLARE_NON_COPY_CLASS(ZynAddSubFXUI)
diff --git a/src/Plugin/ZynAddSubFX/ZynAddSubFX.cpp b/src/Plugin/ZynAddSubFX/ZynAddSubFX.cpp
@@ -115,8 +115,6 @@ public:
oscPort(0),
middlewareThread(new MiddleWareThread())
{
- config.init();
-
synth.buffersize = static_cast<int>(getBufferSize());
synth.samplerate = static_cast<uint>(getSampleRate());
@@ -226,7 +224,7 @@ protected:
parameter.ranges.def = 0.0f;
break;
}
- if(kParamSlot1 <= index && index <= kParamSlot16) {
+ if(index <= kParamSlot16) {
parameter.hints = kParameterIsAutomable;
parameter.name = ("Slot " + zyn::to_s(index-kParamSlot1 + 1)).c_str();
parameter.symbol = ("slot" + zyn::to_s(index-kParamSlot1 + 1)).c_str();
@@ -248,7 +246,7 @@ protected:
case kParamOscPort:
return oscPort;
}
- if(kParamSlot1 <= index && index <= kParamSlot16) {
+ if(index <= kParamSlot16) {
return master->automate.getSlot(index - kParamSlot1);
}
return 0.0f;
@@ -262,10 +260,8 @@ protected:
*/
void setParameterValue(uint32_t index, float value) noexcept override
{
- // only an output port for now
- if(kParamSlot1 <= index && index <= kParamSlot16) {
+ if(index <= kParamSlot16)
master->automate.setSlot(index - kParamSlot1, value);
- }
}
/* --------------------------------------------------------------------------------------------------------
diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp
@@ -38,27 +38,30 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
rOptions(linear,dB scale (-40),
dB scale (-60), dB scale (-80),
dB scale (-100)),
+ rDefault(linear),
"Type of magnitude for harmonics"),
rOption(Pcurrentbasefunc, rShort("base"),
rOptions(sine, triangle, pulse, saw, power, gauss,
diode, abssine, pulsesine, stretchsine,
chirp, absstretchsine, chebyshev, sqr,
spike, circle), rOpt(127,use-as-base waveform),
+ rDefault(sine),
"Base Waveform for harmonics"),
- rParamZyn(Pbasefuncpar, rShort("shape"),
+ rParamZyn(Pbasefuncpar, rShort("shape"), rDefault(64),
"Morph between possible base function shapes "
"(e.g. rising sawtooth vs a falling sawtooth)"),
rOption(Pbasefuncmodulation, rShort("mod"),
- rOptions(None, Rev, Sine, Power, Chop),
+ rOptions(None, Rev, Sine, Power, Chop), rDefault(None),
"Modulation applied to Base function spectra"),
- rParamZyn(Pbasefuncmodulationpar1, rShort("p1"),
+ rParamZyn(Pbasefuncmodulationpar1, rShort("p1"), rDefault(64),
"Base function modulation parameter"),
- rParamZyn(Pbasefuncmodulationpar2, rShort("p2"),
+ rParamZyn(Pbasefuncmodulationpar2, rShort("p2"), rDefault(64),
"Base function modulation parameter"),
- rParamZyn(Pbasefuncmodulationpar3, rShort("p3"),
+ rParamZyn(Pbasefuncmodulationpar3, rShort("p3"), rDefault(32),
"Base function modulation parameter"),
- rParamZyn(Pwaveshaping, rShort("amount"), "Degree Of Waveshaping"),
- rOption(Pwaveshapingfunction, rShort("distort"),
+ rParamZyn(Pwaveshaping, rShort("amount"), rDefault(64),
+ "Degree Of Waveshaping"),
+ rOption(Pwaveshapingfunction, rShort("distort"), rDefault(Undistorted),
rOptions(Undistorted,
Arctangent, Asymmetric, Pow, Sine, Quantisize,
Zigzag, Limiter, Upper Limiter, Lower Limiter,
@@ -66,22 +69,29 @@ const rtosc::Ports OscilGen::non_realtime_ports = {
"Shape of distortion to be applied"),
rOption(Pfiltertype, rShort("filter"), rOptions(No Filter,
lp, hp1, hp1b, bp1, bs1, lp2, hp2, bp2, bs2,
- cos, sin, low_shelf, s), "Harmonic Filter"),
- rParamZyn(Pfilterpar1, rShort("p1"), "Filter parameter"),
- rParamZyn(Pfilterpar2, rShort("p2"), "Filter parameter"),
- rToggle(Pfilterbeforews, rShort("pre/post"), "Filter before waveshaping spectra;"
+ cos, sin, low_shelf, s), rDefaultId(No Filter), "Harmonic Filter"),
+ rParamZyn(Pfilterpar1, rShort("p1"), rDefault(64), "Filter parameter"),
+ rParamZyn(Pfilterpar2, rShort("p2"), rDefault(64), "Filter parameter"),
+ rToggle(Pfilterbeforews, rShort("pre/post"), rDefault(false),
+ "Filter before waveshaping spectra;"
"When enabled oscilfilter(freqs); then waveshape(freqs);, "
"otherwise waveshape(freqs); then oscilfilter(freqs);"),
rOption(Psatype, rShort("spec. adj."), rOptions(None, Pow, ThrsD, ThrsU),
- "Spectral Adjustment Type"),
- rParamZyn(Psapar, rShort("p1"), "Spectral Adjustment Parameter"),
- rParamI(Pharmonicshift, rLinear(-64,64), rShort("shift"), "Amount of shift on harmonics"),
- rToggle(Pharmonicshiftfirst, rShort("pre/post"), "If harmonics are shifted before waveshaping/filtering"),
+ rDefault(None), "Spectral Adjustment Type"),
+ rParamZyn(Psapar, rShort("p1"), rDefault(64),
+ "Spectral Adjustment Parameter"),
+ rParamI(Pharmonicshift, rLinear(-64,64), rShort("shift"), rDefault(0),
+ "Amount of shift on harmonics"),
+ rToggle(Pharmonicshiftfirst, rShort("pre/post"), rDefault(false),
+ "If harmonics are shifted before waveshaping/filtering"),
rOption(Pmodulation, rShort("FM"), rOptions(None, Rev, Sine, Power),
- "Frequency Modulation To Combined Spectra"),
- rParamZyn(Pmodulationpar1, rShort("p1"), "modulation parameter"),
- rParamZyn(Pmodulationpar2, rShort("p2"), "modulation parameter"),
- rParamZyn(Pmodulationpar3, rShort("p3"), "modulation parameter"),
+ rDefault(None), "Frequency Modulation To Combined Spectra"),
+ rParamZyn(Pmodulationpar1, rShort("p1"), rDefault(64),
+ "modulation parameter"),
+ rParamZyn(Pmodulationpar2, rShort("p2"), rDefault(64),
+ "modulation parameter"),
+ rParamZyn(Pmodulationpar3, rShort("p3"), rDefault(32),
+ "modulation parameter"),
//TODO update to rArray and test
@@ -190,19 +200,21 @@ const rtosc::Ports OscilGen::realtime_ports{
rPresetType,
rParamZyn(Prand, rLinear(-64, 63), rShort("phase rnd"), "Oscillator Phase Randomness: smaller than 0 is \""
"group\", larger than 0 is for each harmonic"),
- rParamZyn(Pamprandpower, rShort("variance"),
+ rParamZyn(Pamprandpower, rShort("variance"), rDefault(64),
"Variance of harmonic randomness"),
rOption(Pamprandtype, rShort("distribution"), rOptions(None, Pow, Sin),
+ rDefault(None),
"Harmonic random distribution to select from"),
rOption(Padaptiveharmonics, rShort("adapt")
rOptions(OFF, ON, Square, 2xSub, 2xAdd, 3xSub, 3xAdd, 4xSub, 4xAdd),
+ rDefault(OFF),
"Adaptive Harmonics Mode"),
rParamI(Padaptiveharmonicsbasefreq, rShort("c. freq"), rLinear(0,255),
- "Base frequency of adaptive harmonic (30..3000Hz)"),
+ rDefault(128), "Base frequency of adaptive harmonic (30..3000Hz)"),
rParamI(Padaptiveharmonicspower, rShort("amount"), rLinear(0,200),
- "Adaptive Harmonic Strength"),
+ rDefault(100), "Adaptive Harmonic Strength"),
rParamI(Padaptiveharmonicspar, rShort("power"), rLinear(0,100),
- "Adaptive Harmonics Postprocessing Power"),
+ rDefault(50), "Adaptive Harmonics Postprocessing Power"),
{"waveform:", rDoc("Returns waveform points"),
NULL, [](const char *, rtosc::RtData &d) {
OscilGen &o = *((OscilGen*)d.obj);
diff --git a/src/Synth/Resonance.cpp b/src/Synth/Resonance.cpp
@@ -29,12 +29,17 @@ namespace zyn {
const rtosc::Ports Resonance::ports = {
rSelf(Resonance),
rPaste,
- rToggle(Penabled, rShort("enable"), "resonance enable"),
- rToggle(Pprotectthefundamental, rShort("p.fund."), "Disable resonance filter on first harmonic"),
- rParams(Prespoints, N_RES_POINTS, "Resonance data points"),
- rParamZyn(PmaxdB, rShort("max"), "how many dB the signal may be amplified"),
- rParamZyn(Pcenterfreq, rShort("c.freq"), "Center frequency"),
- rParamZyn(Poctavesfreq, rShort("oct"), "The number of octaves..."),
+ rToggle(Penabled, rShort("enable"), rDefault(false),
+ "resonance enable"),
+ rToggle(Pprotectthefundamental, rShort("p.fund."), rDefault(false),
+ "Disable resonance filter on first harmonic"),
+ rParams(Prespoints, N_RES_POINTS, rDefaultMissing,
+ "Resonance data points"),
+ rParamZyn(PmaxdB, rShort("max"), rDefault(20),
+ "how many dB the signal may be amplified"),
+ rParamZyn(Pcenterfreq, rShort("c.freq"), rDefault(64), "Center frequency"),
+ rParamZyn(Poctavesfreq, rShort("oct"), rDefault(64),
+ "The number of octaves..."),
rActioni(randomize, rMap(min,0), rMap(max, 2), "Randomize frequency response"),
rActioni(interpolatepeaks, rMap(min,0), rMap(max, 2), "Generate response from peak values"),
rAction(smooth, "Smooth out frequency response"),
diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt
@@ -29,7 +29,8 @@ CXXTEST_ADD_TEST(MemoryStressTest MemoryStressTest.cpp
#Extra libraries added to make test and full compilation use the same library
#links for quirky compilers
-set(test_lib zynaddsubfx_core ${GUI_LIBRARIES} ${ZLIB_LIBRARY} ${FFTW_LIBRARIES} ${MXML_LIBRARIES} pthread)
+set(test_lib zynaddsubfx_core ${GUI_LIBRARIES} ${ZLIB_LIBRARY} ${FFTW_LIBRARIES}
+ ${MXML_LIBRARIES} pthread "-Wl,--no-as-needed -lpthread")
message(STATUS "Linking tests with: ${test_lib}")
target_link_libraries(ADnoteTest ${test_lib})
@@ -42,7 +43,7 @@ target_link_libraries(XMLwrapperTest ${test_lib})
target_link_libraries(RandTest ${test_lib})
target_link_libraries(PADnoteTest ${test_lib})
target_link_libraries(MqTest ${test_lib})
-target_link_libraries(WatchTest ${test_lib})
+target_link_libraries(WatchTest ${test_lib})
target_link_libraries(PluginTest zynaddsubfx_core zynaddsubfx_nio
zynaddsubfx_gui_bridge
${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES})
@@ -63,5 +64,12 @@ target_link_libraries(EffectTest ${test_lib})
add_executable(ins-test InstrumentStats.cpp)
target_link_libraries(ins-test ${test_lib} rt)
+add_executable(save-osc SaveOSC.cpp)
+target_link_libraries(save-osc
+ zynaddsubfx_core zynaddsubfx_nio
+ zynaddsubfx_gui_bridge
+ ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES})
+
+
#message(STATUS "Plugin Test ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}")
diff --git a/src/Tests/InstrumentStats.cpp b/src/Tests/InstrumentStats.cpp
@@ -22,6 +22,13 @@
#include "../Misc/Microtonal.h"
#include "../DSP/FFTwrapper.h"
#include "../globals.h"
+
+#include "../Effects/EffectMgr.h"
+#include "../Params/LFOParams.h"
+#include "../Params/EnvelopeParams.h"
+#include "../Params/ADnoteParameters.h"
+#include "../Params/PADnoteParameters.h"
+#include "../Params/SUBnoteParameters.h"
using namespace std;
using namespace zyn;
@@ -143,22 +150,250 @@ void memUsage()
printf("%lld", alloc.totalAlloced());
}
+/*
+ * Kit fields used
+ *
+ * Kit type
+ *
+ * Add synth engines used
+ * Add synth voices used
+ * Sub synth engines used
+ * Pad synth engines used
+ *
+ *
+ * Total Envelopes
+ * Optional Envelopes
+ *
+ * Total Free mode Envelopes
+ *
+ * Total LFO
+ * Optional LFO
+ *
+ * Total Filters
+ *
+ * Total 'Analog' Filters
+ * Total SVF Filters
+ * Total Formant Filters
+ *
+ * Total Effects
+ */
+void usage_stats(void)
+{
+ int kit_type = 0;
+ int kits_used = 0;
+ int add_engines = 0;
+ int add_voices = 0;
+ int sub_engines = 0;
+ int pad_engines = 0;
+
+ int env_total = 0;
+ int env_optional = 0;
+ int env_free = 0;
+
+ int lfo_total = 0;
+ int lfo_optional = 0;
+
+ int filter_total = 0;
+ int filter_analog = 0;
+ int filter_svf = 0;
+ int filter_formant = 0;
+
+ int effects_total = 0;
+
+ kit_type = p->Pkitmode;
+ for(int i=0; i<NUM_KIT_ITEMS; ++i) {
+ auto &k = p->kit[i];
+ if(!(k.Penabled || (i==0 && p->Pkitmode == 0l)))
+ continue;
+
+ if(k.Padenabled) {
+ auto &e = *k.adpars;
+ add_engines += 1;
+ for(int j=0; j<NUM_VOICES; ++j) {
+ auto &v = k.adpars->VoicePar[j];
+ if(!v.Enabled)
+ continue;
+ add_voices += 1;
+ if(v.PFilterEnabled) {
+ auto &f = *v.VoiceFilter;
+ filter_total += 1;
+ if(f.Pcategory == 0)
+ filter_analog += 1;
+ else if(f.Pcategory == 1)
+ filter_formant += 1;
+ else
+ filter_svf += 1;
+ }
+ if(v.PFreqLfoEnabled && v.FreqLfo->Pintensity) {
+ lfo_optional += 1;
+ lfo_total += 1;
+ }
+ if(v.PFilterLfoEnabled && v.FilterLfo->Pintensity) {
+ lfo_optional += 1;
+ lfo_total += 1;
+ }
+ if(v.PAmpLfoEnabled && v.AmpLfo->Pintensity) {
+ lfo_optional += 1;
+ lfo_total += 1;
+ }
+ if(v.PFreqEnvelopeEnabled) {
+ env_optional += 1;
+ env_total += 1;
+ env_free += !!v.FreqEnvelope->Pfreemode;
+ }
+ if(v.PFilterEnvelopeEnabled) {
+ env_optional += 1;
+ env_total += 1;
+ env_free += !!v.FilterEnvelope->Pfreemode;
+ }
+ if(v.PAmpEnvelopeEnabled) {
+ env_optional += 1;
+ env_total += 1;
+ env_free += !!v.AmpEnvelope->Pfreemode;
+ }
+ }
+
+
+
+ if(e.GlobalPar.GlobalFilter) {
+ auto &f = *e.GlobalPar.GlobalFilter;
+ filter_total += 1;
+ if(f.Pcategory == 0)
+ filter_analog += 1;
+ else if(f.Pcategory == 1)
+ filter_formant += 1;
+ else
+ filter_svf += 1;
+ }
+ if(e.GlobalPar.FreqLfo->Pintensity)
+ lfo_total += 1;
+ if(e.GlobalPar.FilterLfo->Pintensity)
+ lfo_total += 1;
+ if(e.GlobalPar.AmpLfo->Pintensity)
+ lfo_total += 1;
+ env_total += 3;
+ env_free += !!e.GlobalPar.FreqEnvelope->Pfreemode;
+ env_free += !!e.GlobalPar.FilterEnvelope->Pfreemode;
+ env_free += !!e.GlobalPar.AmpEnvelope->Pfreemode;
+ }
+
+ if(k.Ppadenabled) {
+ pad_engines += 1;
+ auto &e = *k.padpars;
+ if(e.GlobalFilter) {
+ auto &f = *e.GlobalFilter;
+ filter_total += 1;
+ if(f.Pcategory == 0)
+ filter_analog += 1;
+ else if(f.Pcategory == 1)
+ filter_formant += 1;
+ else
+ filter_svf += 1;
+ }
+ if(e.FreqLfo->Pintensity)
+ lfo_total += 1;
+ if(e.FilterLfo->Pintensity)
+ lfo_total += 1;
+ if(e.AmpLfo->Pintensity)
+ lfo_total += 1;
+ env_total += 3;
+ env_free += !!e.FreqEnvelope->Pfreemode;
+ env_free += !!e.FilterEnvelope->Pfreemode;
+ env_free += !!e.AmpEnvelope->Pfreemode;
+ }
+
+ if(k.Psubenabled) {
+ sub_engines += 1;
+ auto &e = *k.subpars;
+
+ if(e.PGlobalFilterEnabled) {
+ auto &f = *e.GlobalFilter;
+ filter_total += 1;
+ if(f.Pcategory == 0)
+ filter_analog += 1;
+ else if(f.Pcategory == 1)
+ filter_formant += 1;
+ else
+ filter_svf += 1;
+ }
+ if(e.PFreqEnvelopeEnabled) {
+ env_total += 1;
+ env_optional += 1;
+ env_free += !!e.FreqEnvelope->Pfreemode;
+ }
+ if(e.PGlobalFilterEnabled) {
+ env_total += 1;
+ env_optional += 1;
+ env_free += !!e.GlobalFilterEnvelope->Pfreemode;
+ }
+ if(e.PBandWidthEnvelopeEnabled) {
+ env_total += 1;
+ env_optional += 1;
+ env_free += !!e.BandWidthEnvelope->Pfreemode;
+ }
+ }
+
+ kits_used += 1;
+ }
+
+ for(int i=0; i<NUM_PART_EFX; ++i) {
+ if(p->partefx[i]->efx)
+ effects_total += 1;
+ }
+
+ printf("Kit type: %d\n", kit_type);
+ printf("Kits used: %d\n", kits_used);
+ printf("Add engines: %d\n", add_engines);
+ printf(" Add voices: %d\n", add_voices);
+ printf("Sub engines: %d\n", sub_engines);
+ printf("Pad engines: %d\n", pad_engines);
+
+ printf("\n");
+
+ printf("Env total: %d\n", env_total);
+ printf("Env optional: %d\n", env_optional);
+ printf("Env free: %d\n", env_free);
+
+ printf("\n");
+
+ printf("LFO total: %d\n", lfo_total);
+ printf("LFO optional: %d\n", lfo_optional);
+
+ printf("\n");
+
+ printf("Filter total: %d\n", filter_total);
+ printf("Filter analog: %d\n", filter_analog);
+ printf("Filter svf: %d\n", filter_svf);
+ printf("Filter formant: %d\n", filter_formant);
+
+ printf("\n");
+
+ printf("Effects Total: %d\n", effects_total);
+}
+
int main(int argc, char **argv)
{
- if(argc != 2) {
+ if(argc < 2) {
fprintf(stderr, "Please supply a xiz file\n");
return 1;
}
-
- mode = MODE_PROFILE;
- setup();
- xml(argv[1]);
- load();
- memUsage();
- printf(", ");
- noteOn();
- speed();
- noteOff();
- memUsage();
- printf("\n");
+ if(argc == 2) {
+ mode = MODE_PROFILE;
+ setup();
+ xml(argv[1]);
+ load();
+ memUsage();
+ printf(", ");
+ noteOn();
+ speed();
+ noteOff();
+ memUsage();
+ printf("\n");
+ } else if(argc == 3) {
+ mode = MODE_TEST;
+ setup();
+ xml(argv[2]);
+ load();
+ usage_stats();
+ }
}
diff --git a/src/Tests/MessageTest.h b/src/Tests/MessageTest.h
@@ -184,14 +184,48 @@ class MessageTest:public CxxTest::TestSuite
mw->transmitMsg("/learn", "s", "/Pvolume");
mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 108);
+ //param is at default until rt-thread is run
+ TS_ASSERT_EQUALS(ms->Pvolume, 80);
+
+
//Perform a learning operation
+ run_realtime();
- run_realtime(); //1. runs learning and identifies a CC to bind
- mw->tick(); //2. produces new binding table
- run_realtime(); //3. applies new binding table
+ //Verify binding affects control
+ TS_ASSERT_EQUALS(ms->Pvolume, 108);
+
+ printf("# Trying to save automations\n");
+ start_realtime();
mw->transmitMsg("/save_xlz", "s", "test-midi-learn.xlz");
+ stop_realtime();
+
+ //Verify that some file exists
+ printf("# Verifying file exists\n");
+ FILE *f = fopen("test-midi-learn.xlz", "r");
+ TS_ASSERT(f);
+
+ if(f)
+ fclose(f);
+
+ printf("# Clearing automation\n");
+ //Clear out state
+ mw->transmitMsg("/clear_xlz", "");
+ //Send dummy message
+ mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 27);
+ run_realtime();
+
+ //Verify automation table is clear
+ TS_ASSERT_EQUALS(ms->Pvolume, 108);
+
+ printf("# Loading automation\n");
mw->transmitMsg("/load_xlz", "s", "test-midi-learn.xlz");
+ //Send message
+ mw->transmitMsg("/virtual_midi_cc", "iii", 0, 23, 28);
+ run_realtime();
+
+ //Verify automation table is restored
+ TS_ASSERT_EQUALS(ms->Pvolume, 28);
}
void testLfoPaste(void)
@@ -246,7 +280,7 @@ class MessageTest:public CxxTest::TestSuite
void testFilterDepricated(void)
{
vector<string> v = {"Pfreq", "Pfreqtrack", "Pgain", "Pq"};
- for(int i=0; i<v.size(); ++i) {
+ for(int i=0; i<(int)v.size(); ++i) {
string path = "/part0/kit0/adpars/GlobalPar/GlobalFilter/"+v[i];
for(int j=0; j<128; ++j) {
mw->transmitMsg(path.c_str(), "i", j); //Set
@@ -284,6 +318,7 @@ class MessageTest:public CxxTest::TestSuite
state = 0;
}
+ (void) id;
//printf("Message #%d %s:%s\n", id++, msg, rtosc_argument_string(msg));
//if(rtosc_narguments(msg))
// printf(" %d\n", rtosc_argument(msg, 0).i);
diff --git a/src/Tests/PluginTest.h b/src/Tests/PluginTest.h
@@ -56,7 +56,7 @@ void print_string_differences(string orig, string next)
//Insertion is 2 cost and moves +2 State (+2 if symbols are different)
//Deletion is 1 cost and moves +0 State (+2 if symbols are different)
char *transition = new char[N*M];
- int *cost = new int[N*M];
+ float *cost = new float[N*M];
const int match = 1;
const int insert = 2;
@@ -69,8 +69,8 @@ void print_string_differences(string orig, string next)
}
//Just assume the -1 line is the same
- cost[0*M + 0] = (a[0] == b[0])*3;
- cost[0*M + 1] = (a[1] == b[0])*2 + 2;
+ cost[0*M + 0] = (a[0] != b[0])*3;
+ cost[0*M + 1] = (a[1] != b[0])*2 + 2;
for(int i=1; i<N; ++i) {
for(int j=0; j<M; ++j) {
int cost_match = 0xffffff;
@@ -80,7 +80,7 @@ void print_string_differences(string orig, string next)
if(j > 1)
cost_ins = cost[(i-1)*M + (j-2)] + 1 + 2*(a[i] != b[j]);
if(j > 0)
- cost_match = cost[(i-1)*M + (j-1)] + 2*(a[i] != b[j]);
+ cost_match = cost[(i-1)*M + (j-1)] + 3*(a[i] != b[j]);
if(cost_match >= 0xffff && cost_ins >= 0xffff && cost_del >= 0xffff) {
;
@@ -97,28 +97,68 @@ void print_string_differences(string orig, string next)
}
}
+ //int off = 0;
+ //int len = N;
+ //for(int i=off; i<off+len; ++i) {
+ // for(int j=off; j<off+len; ++j) {
+ // printf("%4d ", (int)(cost[i*M+j] > 4000 ? -1 : cost[i*M+j]));
+ // }
+ // printf("\n");
+ //}
+ //for(int i=off; i<off+len; ++i) {
+ // for(int j=off; j<off+len; ++j) {
+ // printf("%d ", transition[i*M+j]);
+ // }
+ // printf("\n");
+ //}
+
+ //for(int i=off; i<off+len; ++i)
+ // printf("%d: %s\n", i, a[i].c_str());
+ //for(int i=off; i<off+len; ++i)
+ // printf("%d: %s\n", i, b[i].c_str());
+ //exit(1);
+
int total_cost = cost[(N-1)*M + (M-1)];
if(total_cost < 500) {
- printf("total cost = %d\n", cost[(N-1)*M + (M-1)]);
+ printf("total cost = %f\n", cost[(N-1)*M + (M-1)]);
- //int b_pos = b.size()-1;
+ int b_pos = b.size()-1;
int a_pos = a.size()-1;
- for(int i=(M-1); i >= 0; --i) {
- if(a[a_pos] != b[i]) {
- printf("- %s\n", a[a_pos].c_str());
- printf("+ %s\n", b[i].c_str());
- }
- if(transition[i*M+a_pos] == match) {
+ while(a_pos > 0 && b_pos > 0) {
+ //printf("state = (%d, %d) => %f\n", a_pos, b_pos, cost[a_pos*M+b_pos]);
+ if(transition[a_pos*M+b_pos] == match) {
+ if(a[a_pos] != b[b_pos]) {
+ printf("REF - %s\n", a[a_pos].c_str());
+ printf("NEW + %s\n", b[b_pos].c_str());
+ }
//printf("R");
a_pos -= 1;
- } else if(transition[i*M+a_pos] == del) {
+ b_pos -= 1;
+ } else if(transition[a_pos*M+b_pos] == del) {
//printf("D");
- } else if(transition[i*M+a_pos] == insert) {
+ //if(a[a_pos] != b[b_pos]) {
+ //printf("- %s\n", a[a_pos].c_str());
+ printf("NEW - %s\n", b[b_pos].c_str());
+ //}
+ b_pos -= 1;
+ } else if(transition[a_pos*M+b_pos] == insert) {
+ //if(a[a_pos] != b[b_pos]) {
+ printf("REF - %s\n", a[a_pos].c_str());
+ printf("NEW + %s\n", b[b_pos].c_str());
+ printf("NEW + %s\n", b[b_pos-1].c_str());
+ //}
//printf("I");
- a_pos -= 2;
+ a_pos -= 1;
+ b_pos -= 2;
+ } else {
+ printf("ERROR STATE @(%d, %d)\n", a_pos, b_pos);
+ exit(1);
}
+
}
//printf("%d vs %d\n", N, M);
+ } else {
+ printf("[WARNING] XML File appears to be radically different\n");
}
}
diff --git a/src/Tests/SaveOSC.cpp b/src/Tests/SaveOSC.cpp
@@ -0,0 +1,103 @@
+#include <cassert>
+#include <thread>
+#include <iostream>
+#include <unistd.h>
+
+#include <cxxtest/TestSuite.h>
+
+#include "../Misc/Master.h"
+#include "../Misc/MiddleWare.h"
+#include "../UI/NSM.H"
+
+// for linking purposes only:
+NSM_Client *nsm = 0;
+zyn::MiddleWare *middleware = 0;
+
+char *instance_name=(char*)"";
+
+// Middleware is not required, since all ports requiring MiddleWare use the
+// rNoWalk macro. If you still want to enable it, uncomment this:
+// #define RUN_MIDDLEWARE
+
+class SaveOSCTest
+{
+ void setUp() {
+ synth = new zyn::SYNTH_T;
+ synth->buffersize = 256;
+ synth->samplerate = 48000;
+ synth->alias();
+
+ mw = new zyn::MiddleWare(std::move(*synth), &config);
+ master = mw->spawnMaster();
+ realtime = nullptr;
+ }
+
+ void tearDown() {
+ delete mw;
+ delete synth;
+ }
+
+ public:
+ SaveOSCTest() { setUp(); }
+ ~SaveOSCTest() { tearDown(); }
+
+ int run(int argc, char** argv)
+ {
+ assert(argc == 2);
+ const char *filename = argv[1];
+
+ int tmp = master->loadXML(filename);
+ if(tmp < 0) {
+ std::cerr << "ERROR: Could not load master file " << filename
+ << "." << std::endl;
+ exit(1);
+ }
+
+ assert(master);
+ return (master->saveOSC(NULL) == 0) ? 0 : 1;
+ }
+
+
+ void start_realtime(void)
+ {
+ do_exit = false;
+#ifdef RUN_MIDDLEWARE
+ realtime = new std::thread([this](){
+ while(!do_exit)
+ {
+ /*while(bToU->hasNext()) {
+ const char *rtmsg = bToU->read();
+ bToUhandle(rtmsg);
+ }*/
+ mw->tick();
+ usleep(500);
+ }});
+#endif
+ }
+ void stop_realtime(void)
+ {
+ do_exit = true;
+#ifdef RUN_MIDDLEWARE
+ realtime->join();
+ delete realtime;
+ realtime = NULL;
+#endif
+ }
+
+ private:
+ zyn::Config config;
+ zyn::SYNTH_T* synth;
+ zyn::MiddleWare* mw;
+ zyn::Master* master;
+ std::thread* realtime;
+ bool do_exit;
+};
+
+int main(int argc, char** argv)
+{
+ SaveOSCTest test;
+ test.start_realtime();
+ int res = test.run(argc, argv);
+ test.stop_realtime();
+ return res;
+}
diff --git a/src/Tests/guitar-adnote.xmz b/src/Tests/guitar-adnote.xmz
@@ -2,7 +2,7 @@
<?xml version="1.0f" encoding="UTF-8"?>
<!DOCTYPE ZynAddSubFX-data>
<ZynAddSubFX-data version-major="3" version-minor="0"
-version-revision="1" ZynAddSubFX-author="Nasca Octavian Paul">
+version-revision="2" ZynAddSubFX-author="Nasca Octavian Paul">
<INFORMATION>
<par_bool name="PADsynth_used" value="yes" />
</INFORMATION>
@@ -28,6 +28,9 @@ version-revision="1" ZynAddSubFX-author="Nasca Octavian Paul">
<par name="a_note" value="69" />
<par_real name="a_freq" value="440" exact_value="0x43DC0000" />
</MICROTONAL>
+<automation>
+<mgr-info nslots="16" nautomations="4" ncontrol="8" />
+</automation>
<PART id="0">
<par_bool name="enabled" value="yes" />
<par name="volume" value="96" />
diff --git a/src/UI/BankUI.fl b/src/UI/BankUI.fl
@@ -23,6 +23,9 @@ decl {\#include <FL/Fl_Button.H>} {public local
decl {\#include <FL/Fl_File_Chooser.H>} {public local
}
+decl {\#include <FL/Fl_Input.H>} {public local
+}
+
decl {\#include "Fl_Osc_Interface.h"} {public local
}
@@ -95,6 +98,15 @@ refreshmainwindow();}
banklist->value(0);}
tooltip {Refresh the bank list (rescan)} xywh {230 8 105 20} box THIN_UP_BOX color 50 labelsize 11
}
+ Fl_Input {} {
+ label {Search by name: }
+ code0 {o->when(FL_WHEN_CHANGED);}
+ callback {
+ std::string str = o->value();
+ update_search(str)}
+ tooltip {Enter text to search for}
+ xywh {460 8 105 20} box THIN_UP_BOX color 50 labelsize 11
+ }
}
}
Function {BankUI(int *npart_, Fl_Osc_Interface *osc_)} {open
@@ -139,6 +151,15 @@ bankview->refresh();} {}
if (banklist->size() == 0)
banklist->add(" ");} {}
}
+ Function {update_search(std::string search_string)} {open
+ } {
+ code {if (search_string.empty()) {
+ refreshmainwindow();
+} else {
+ osc->write("/bank/search", "s", search_string.c_str());
+}
+ } {}
+ }
decl {Fl_Osc_Interface *osc;} {private local
}
decl {Fl_Valuator *cbwig;} {public local
diff --git a/src/UI/BankView.cpp b/src/UI/BankView.cpp
@@ -225,15 +225,17 @@ void BankViewControls::mode(int m)
BankView::BankView(int x,int y, int w, int h, const char *label)
- :Fl_Group(x,y,w,h,label), bvc(NULL), slots{0}, osc(0),
- loc(""), nselected(-1), npart(0), cbwig_(0)
+ :Fl_Group(x,y,w,h,label), Fl_Osc_Widget(),
+ bvc(NULL), slots{0}, nselected(-1), npart(0), cbwig_(0)
{}
BankView::~BankView(void)
{
- if(osc)
- osc->removeLink("/bankview", this);
+ if(osc) {
+ osc->removeLink("/bankview", this);
+ osc->removeLink("/bank/search_results", this);
+ }
}
void BankView::init(Fl_Osc_Interface *osc_, BankViewControls *bvc_, int *npart_)
@@ -245,6 +247,7 @@ void BankView::init(Fl_Osc_Interface *osc_, BankViewControls *bvc_, int *npart_)
npart = npart_;
osc->createLink("/bankview", this);
+ osc->createLink("/bank/search_results", this);
//Element Size
const float width = w()/5.0;
@@ -346,14 +349,30 @@ void BankView::react(int event, int nslot)
void BankView::OSC_raw(const char *msg)
{
- if(!strcmp(rtosc_argument_string(msg), "iss")) {
+ if(!strcmp(msg, "/bank/search_results")) {
+ const char *ptr = rtosc_argument_string(msg);
+ int slot = 0;
+
+ while (ptr[0] == 's' && ptr[1] == 's') {
+ const char *bank = rtosc_argument(msg, 2*slot).s;
+ const char *fname = rtosc_argument(msg, 2*slot + 1).s;
+
+ /* store search results directly into slot */
+ slots[slot]->update(bank, fname);
+ if (++slot == 160)
+ break;
+ ptr += 2;
+ }
+ while (slot < 160)
+ slots[slot++]->update("", "");
+ } else if(!strcmp(rtosc_argument_string(msg), "iss")) {
int nslot = rtosc_argument(msg,0).i;
const char *name = rtosc_argument(msg,1).s;
const char *fname = rtosc_argument(msg,2).s;
if(0 <= nslot && nslot < 160)
slots[nslot]->update(name, fname);
- } if(!strcmp(rtosc_argument_string(msg), "ss")) {
+ } else if(!strcmp(rtosc_argument_string(msg), "ss")) {
while(*msg && !isdigit(*msg)) msg++;
int nslot = atoi(msg);
const char *name = rtosc_argument(msg,0).s;
diff --git a/src/UI/BankView.h b/src/UI/BankView.h
@@ -96,9 +96,6 @@ class BankView: public Fl_Group, public Fl_Osc_Widget
BankViewControls *bvc;
BankSlot *slots[160];
- Fl_Osc_Interface *osc;
- std::string loc;
-
//XXX TODO locked banks...
int nselected;
int *npart;
diff --git a/src/UI/Fl_Osc_Tree.H b/src/UI/Fl_Osc_Tree.H
@@ -107,7 +107,7 @@ class Fl_Osc_Tree: public Fl_Tree
const char *name = port.name;
if(!index(name, '/'))//only accept objects that will have subports
continue;
- if(rtosc_match(name, s.c_str())) {
+ if(rtosc_match(name, s.c_str(), NULL)) {
return subtree_lookup(port.ports,
s.substr(index(s.c_str(), '/')-s.c_str()+1));
}
diff --git a/src/main.cpp b/src/main.cpp
@@ -3,7 +3,7 @@
main.cpp - Main file of the synthesizer
Copyright (C) 2002-2005 Nasca Octavian Paul
- Copyright (C) 2012-2016 Mark McCurry
+ Copyright (C) 2012-2017 Mark McCurry
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -21,7 +21,9 @@
#include <algorithm>
#include <signal.h>
+#ifndef WIN32
#include <err.h>
+#endif
#include <unistd.h>
#include <pthread.h>
@@ -48,8 +50,10 @@
GUI::ui_handle_t gui;
#ifdef ZEST_GUI
+#ifndef WIN32
#include <sys/wait.h>
#endif
+#endif
//Glue Layer
#include "Misc/MiddleWare.h"
@@ -135,7 +139,9 @@ void exitprogram(const Config& config)
#ifdef WIN32
#include <windows.h>
#include <mmsystem.h>
+namespace zyn{
extern InMgr *in;
+}
HMIDIIN winmidiinhandle = 0;
void CALLBACK WinMidiInProc(HMIDIIN hMidiIn,UINT wMsg,DWORD dwInstance,
@@ -215,7 +221,6 @@ int main(int argc, char *argv[])
{
SYNTH_T synth;
Config config;
- config.init();
int noui = 0;
cerr
<< "\nZynAddSubFX - Copyright (c) 2002-2013 Nasca Octavian Paul and others"
@@ -313,7 +318,7 @@ int main(int argc, char *argv[])
opterr = 0;
int option_index = 0, opt, exitwithhelp = 0, exitwithversion = 0;
int prefered_port = -1;
- int auto_save_interval = 60;
+ int auto_save_interval = 0;
int wmidi = -1;
string loadfile, loadinstrument, execAfterInit, loadmidilearn;
@@ -324,7 +329,7 @@ int wmidi = -1;
/**\todo check this process for a small memory leak*/
opt = getopt_long(argc,
argv,
- "l:L:M:r:b:o:I:O:N:e:P:A:D:hvapSDUYZ",
+ "l:L:M:r:b:o:I:O:N:e:P:A:d:D:hvapSDUYZ",
opts,
&option_index);
char *optarguments = optarg;
@@ -644,10 +649,13 @@ int wmidi = -1;
}
#ifdef ZEST_GUI
+#ifndef WIN32
pid_t gui_pid = 0;
+#endif
if(!noui) {
printf("[INFO] Launching Zyn-Fusion...\n");
const char *addr = middleware->getServerAddress();
+#ifndef WIN32
gui_pid = fork();
if(gui_pid == 0) {
execlp("zyn-fusion", "zyn-fusion", addr, "--builtin", "--no-hotload", 0);
@@ -655,6 +663,28 @@ int wmidi = -1;
err(1,"Failed to launch Zyn-Fusion");
}
+#else
+ STARTUPINFO si;
+PROCESS_INFORMATION pi;
+memset(&si, 0, sizeof(si));
+memset(&pi, 0, sizeof(pi));
+char *why_windows = strrchr(addr, ':');
+char *seriously_why = why_windows + 1;
+char start_line[256] = {0};
+if(why_windows)
+ snprintf(start_line, sizeof(start_line), "zyn-fusion.exe osc.udp://127.0.0.1:%s", seriously_why);
+else {
+ printf("COULD NOT PARSE <%s>\n", addr);
+ exit(1);
+}
+printf("[INFO] starting subprocess via <%s>\n", start_line);
+if(!CreateProcess(NULL, start_line,
+NULL, NULL, 0, 0, NULL, NULL, &si, &pi)) {
+ printf("Failed to launch Zyn-Fusion...\n");
+ exit(1);
+}
+
+#endif
}
#endif
@@ -698,6 +728,7 @@ done:
#endif
#ifdef ZEST_GUI
+#ifndef WIN32
if(!noui) {
int status = 0;
int ret = waitpid(gui_pid, &status, WNOHANG);
@@ -705,6 +736,7 @@ done:
Pexitprogram = 1;
}
#endif
+#endif
}
exitprogram(config);
diff --git a/zynaddsubfx-oss.desktop b/zynaddsubfx-oss.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Name=ZynAddSubFX - OSS
+Comment=A powerful realtime software synthesizer
+Comment[fr]=Un synthétiseur logiciel temps-réel puissant
+Keywords=audio;sound;alsa;midi;synth;synthesizer;
+Exec=zynaddsubfx -I OSS -O OSS
+Icon=zynaddsubfx
+Terminal=false
+Type=Application
+Categories=AudioVideo;Audio;