[SCM] calf/master: + Slightly better preset handling (will load/add/save on each preset add, to avoid problems with multiple windows); still doesn't update other windows automatically + Presets use short names of parameters + Preset parser reports errors in XML (in a slightly crappy way, but...) + Added installation of default presets + Initial preset file (contains some monosynth presets) + Monosynth: added Env->Amp parameter (more useful than I initially thought) + Monosynth: replaced 180 degree phase shift in 2x12dB LP mode with allpass filter-based phase shifter, so that one osc isn't killed when going to mono + Vintage Delay: added denormal killer for delay line
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:36:48 UTC 2013
The following commit has been merged in the master branch:
commit 93312ffdda7ba3b0712db58af957e0400a30a821
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date: Sat Dec 22 22:53:32 2007 +0000
+ Slightly better preset handling (will load/add/save on each preset add, to avoid problems with multiple windows); still doesn't update other windows automatically
+ Presets use short names of parameters
+ Preset parser reports errors in XML (in a slightly crappy way, but...)
+ Added installation of default presets
+ Initial preset file (contains some monosynth presets)
+ Monosynth: added Env->Amp parameter (more useful than I initially thought)
+ Monosynth: replaced 180 degree phase shift in 2x12dB LP mode with allpass filter-based phase shifter, so that one osc isn't killed when going to mono
+ Vintage Delay: added denormal killer for delay line
git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@37 78b06b96-2940-0410-b7fc-879d825d01d8
diff --git a/Makefile.am b/Makefile.am
index 7114d1d..8f93369 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,7 +4,7 @@ SUBDIRS = $(SRCDIRS)
distdir = $(PACKAGE)-$(VERSION)
-EXTRA_DIST = TODO autogen.sh calf.glade
+EXTRA_DIST = TODO autogen.sh calf.glade presets.xml
clean-local:
rm -f *~ *.old
diff --git a/configure.in b/configure.in
index 66d6ae6..87c8967 100644
--- a/configure.in
+++ b/configure.in
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
-AC_INIT([calf],[0.0.7],[wdev at foltman.com])
+AC_INIT([calf],[0.0.8],[wdev at foltman.com])
AC_CONFIG_SRCDIR([config.h.in])
AC_CONFIG_HEADER([config.h])
diff --git a/src/Makefile.am b/src/Makefile.am
index 1df5e0d..4d535af 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -57,8 +57,9 @@ clean-local:
$(RM) -f calfjackhost *~
install-data-hook:
-if USE_JACK
install -d -m 755 $(DESTDIR)$(pkglibdir)
+ install -c -m 644 $(top_srcdir)/presets.xml $(DESTDIR)$(pkglibdir)
+if USE_JACK
install -c -m 644 $(top_srcdir)/calf.glade $(DESTDIR)$(pkglibdir)
endif
if USE_LADSPA
@@ -76,8 +77,9 @@ endif
uninstall-hook:
if USE_JACK
rm -f $(DESTDIR)$(pkglibdir)/calf.glade
- rmdir $(DESTDIR)$(pkglibdir)
endif
+ rm -f $(DESTDIR)$(pkglibdir)/presets.xml
+ rmdir $(DESTDIR)$(pkglibdir)
if USE_LADSPA
$(RM) -f $(DESTDIR)$(with_ladspa_dir)/calf.so
$(RM) -f $(DESTDIR)$(with_ladspa_rdf_dir)/calf.rdf
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index e87e0eb..878075b 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -110,6 +110,7 @@ public:
virtual int get_output_count()=0;
virtual port *get_inputs()=0;
virtual port *get_outputs()=0;
+ virtual port *get_midi_port() { return get_midi() ? &midi_port : NULL; }
virtual float *get_params()=0;
virtual void init_module()=0;
virtual void cache_ports()=0;
diff --git a/src/calf/modules.h b/src/calf/modules.h
index 6a20e3e..409f50c 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -361,6 +361,7 @@ public:
for(uint32_t i = offset; i < end; i++)
{
float in_left = buffers[v][(bufptr - deltime_l) & ADDR_MASK], in_right = buffers[1 - v][(bufptr - deltime_r) & ADDR_MASK], out_left, out_right, del_left, del_right;
+ dsp::sanitize(in_left), dsp::sanitize(in_right);
out_left = ins[0][i] + in_left * amt_left;
out_right = ins[1][i] + in_right * amt_right;
diff --git a/src/calf/modules_synths.h b/src/calf/modules_synths.h
index bf094d4..258b3cb 100644
--- a/src/calf/modules_synths.h
+++ b/src/calf/modules_synths.h
@@ -37,7 +37,7 @@ class monosynth_audio_module: public null_audio_module
public:
enum { wave_saw, wave_sqr, wave_pulse, wave_sine, wave_triangle, wave_count };
enum { flt_lp12, flt_lp24, flt_2lp12, flt_hp12, flt_lpbr, flt_hpbr, flt_bp6, flt_2bp6 };
- enum { par_wave1, par_wave2, par_detune, par_osc2xpose, par_oscmode, par_oscmix, par_filtertype, par_cutoff, par_resonance, par_cutoffsep, par_envmod, par_envtores, par_attack, par_decay, par_sustain, par_release, par_keyfollow, par_legato, par_portamento, par_vel2amp, par_vel2filter, param_count };
+ enum { par_wave1, par_wave2, par_detune, par_osc2xpose, par_oscmode, par_oscmix, par_filtertype, par_cutoff, par_resonance, par_cutoffsep, par_envmod, par_envtores, par_envtoamp, par_attack, par_decay, par_sustain, par_release, par_keyfollow, par_legato, par_portamento, par_vel2filter, par_vel2amp, param_count };
enum { in_count = 0, out_count = 2, support_midi = true, rt_capable = true };
enum { step_size = 64 };
static const char *port_names[];
@@ -52,10 +52,11 @@ public:
float buffer[step_size], buffer2[step_size];
uint32_t output_pos;
+ onepole<float> phaseshifter;
biquad<float> filter;
biquad<float> filter2;
int wave1, wave2, filter_type;
- float freq, start_freq, target_freq, cutoff, decay_factor, fgain, separation;
+ float freq, start_freq, target_freq, cutoff, decay_factor, fgain, fgain_delta, separation;
float detune, xpose, xfade, pitchbend, ampctl, fltctl, queue_vel;
float odcr, porta_time;
int queue_note_on;
@@ -67,6 +68,9 @@ public:
srate = sr;
crate = sr / step_size;
odcr = (float)(1.0 / crate);
+ phaseshifter.set_ap(1000.f, sr);
+ fgain = 0.f;
+ fgain_delta = 0.f;
}
void delayed_note_on()
{
@@ -120,6 +124,7 @@ public:
if (!(legato & 1) || envelope.released()) {
envelope.note_on();
}
+ envelope.advance();
queue_note_on = -1;
}
void note_on(int note, int vel)
@@ -220,6 +225,7 @@ public:
wave = filter.process_d1(wave);
wave = filter2.process_d1(wave);
buffer[i] = softclip(wave);
+ fgain += fgain_delta;
}
}
void calculate_buffer_single()
@@ -231,6 +237,7 @@ public:
float wave = fgain * (osc1val + (osc2val - osc1val) * xfade);
wave = filter.process_d1(wave);
buffer[i] = softclip(wave);
+ fgain += fgain_delta;
}
}
void calculate_buffer_stereo()
@@ -240,9 +247,10 @@ public:
float osc1val = osc1.get();
float osc2val = osc2.get();
float wave1 = osc1val + (osc2val - osc1val) * xfade;
- float wave2 = osc1val + ((-osc2val) - osc1val) * xfade;
+ float wave2 = phaseshifter.process_ap(wave1);
buffer[i] = softclip(fgain * filter.process_d1(wave1));
buffer2[i] = softclip(fgain * filter2.process_d1(wave2));
+ fgain += fgain_delta;
}
}
bool is_stereo_filter() const
@@ -282,48 +290,52 @@ public:
cutoff = dsp::clip(cutoff , 10.f, 18000.f);
float resonance = *params[par_resonance];
float e2r = *params[par_envtores];
+ float e2a = *params[par_envtoamp];
resonance = resonance * (1 - e2r) + (0.7 + (resonance - 0.7) * env * env) * e2r;
float cutoff2 = dsp::clip(cutoff * separation, 10.f, 18000.f);
+ float newfgain = 0.f;
switch(filter_type)
{
case flt_lp12:
filter.set_lp_rbj(cutoff, resonance, srate);
- fgain = min(0.7f, 0.7f / resonance) * ampctl;
+ newfgain = min(0.7f, 0.7f / resonance) * ampctl;
break;
case flt_hp12:
filter.set_hp_rbj(cutoff, resonance, srate);
- fgain = min(0.7f, 0.7f / resonance) * ampctl;
+ newfgain = min(0.7f, 0.7f / resonance) * ampctl;
break;
case flt_lp24:
filter.set_lp_rbj(cutoff, resonance, srate);
filter2.set_lp_rbj(cutoff2, resonance, srate);
- fgain = min(0.5f, 0.5f / resonance) * ampctl;
+ newfgain = min(0.5f, 0.5f / resonance) * ampctl;
break;
case flt_lpbr:
filter.set_lp_rbj(cutoff, resonance, srate);
filter2.set_br_rbj(cutoff2, resonance, srate);
- fgain = min(0.5f, 0.5f / resonance) * ampctl;
+ newfgain = min(0.5f, 0.5f / resonance) * ampctl;
break;
case flt_hpbr:
filter.set_hp_rbj(cutoff, resonance, srate);
filter2.set_br_rbj(cutoff2, resonance, srate);
- fgain = min(0.5f, 0.5f / resonance) * ampctl;
+ newfgain = min(0.5f, 0.5f / resonance) * ampctl;
break;
case flt_2lp12:
filter.set_lp_rbj(cutoff, resonance, srate);
filter2.set_lp_rbj(cutoff2, resonance, srate);
- fgain = min(0.7f, 0.7f / resonance) * ampctl;
+ newfgain = min(0.7f, 0.7f / resonance) * ampctl;
break;
case flt_bp6:
filter.set_bp_rbj(cutoff, resonance, srate);
- fgain = ampctl;
+ newfgain = ampctl;
break;
case flt_2bp6:
filter.set_bp_rbj(cutoff, resonance, srate);
filter2.set_bp_rbj(cutoff2, resonance, srate);
- fgain = ampctl;
+ newfgain = ampctl;
break;
}
+ newfgain *= 1.0 - (1.0 - env) * e2a;
+ fgain_delta = (newfgain - fgain) * (1.0 / step_size);
switch(filter_type)
{
case flt_lp24:
diff --git a/src/calf/preset.h b/src/calf/preset.h
index c2aa766..95b9aa7 100644
--- a/src/calf/preset.h
+++ b/src/calf/preset.h
@@ -37,27 +37,14 @@ struct plugin_preset
std::vector<std::string> param_names;
std::vector<float> values;
std::string blob;
- std::string to_xml()
- {
- std::stringstream ss;
- ss << "<preset bank=\"" << bank << "\" program=\"" << program << "\" plugin=\"" << plugin << "\" name=\"" << xml_escape(name) << "\">\n";
- for (unsigned int i = 0; i < values.size(); i++) {
- if (i < param_names.size())
- ss << " <param name=\"" << param_names[i] << "\" value=\"" << values[i] << "\" />\n";
- else
- ss << " <param value=\"" << values[i] << "\" />\n";
- }
- // XXXKF I'm not writing blob here, because I don't use blobs yet anyway
- ss << "</preset>\n";
- return ss.str();
- }
+ std::string to_xml();
};
struct preset_exception
{
std::string message, param, fulltext;
int error;
- preset_exception(const char *_message, const char *_param, int _error)
+ preset_exception(const std::string &_message, const std::string &_param, int _error)
: message(_message), param(_param), error(_error)
{
}
@@ -73,13 +60,32 @@ struct preset_exception
}
};
-extern std::string get_preset_filename();
-extern void load_presets(const char *filename);
-extern void save_presets(const char *filename);
-extern void add_preset(const plugin_preset &sp);
+typedef std::vector<plugin_preset> preset_vector;
+
+struct preset_list
+{
+ enum parser_state
+ {
+ START,
+ LIST,
+ PRESET,
+ VALUE,
+ } state;
+
+ preset_vector presets;
+ plugin_preset parser_preset;
+
+ static std::string get_preset_filename();
+ void load(const char *filename);
+ void save(const char *filename);
+ void add(const plugin_preset &sp);
+
+protected:
+ static void xml_start_element_handler(void *user_data, const char *name, const char *attrs[]);
+ static void xml_end_element_handler(void *user_data, const char *name);
+};
-// this global variable is a temporary measure
-extern std::vector<plugin_preset> presets;
+extern preset_list global_presets;
};
diff --git a/src/gui.cpp b/src/gui.cpp
index 76a342a..472fa88 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -332,15 +332,16 @@ plugin_gui_window::plugin_gui_window()
string plugin_gui_window::make_gui_preset_list(GtkActionGroup *grp)
{
string preset_xml = preset_pre_xml;
- for (unsigned int i = 0; i < presets.size(); i++)
+ preset_vector &pvec = global_presets.presets;
+ for (unsigned int i = 0; i < pvec.size(); i++)
{
- if (presets[i].plugin != gui->effect_name)
+ if (global_presets.presets[i].plugin != gui->effect_name)
continue;
stringstream ss;
ss << "preset" << i;
- preset_xml += " <menuitem name=\""+presets[i].name+"\" action=\""+ss.str()+"\"/>\n";
+ preset_xml += " <menuitem name=\""+pvec[i].name+"\" action=\""+ss.str()+"\"/>\n";
- GtkActionEntry ae = { ss.str().c_str(), NULL, presets[i].name.c_str(), NULL, NULL, (GCallback)activate_preset };
+ GtkActionEntry ae = { ss.str().c_str(), NULL, pvec[i].name.c_str(), NULL, NULL, (GCallback)activate_preset };
gtk_action_group_add_actions_full(preset_actions, &ae, 1, (gpointer)new activate_preset_params(gui, i), action_destroy_notify);
}
preset_xml += preset_post_xml;
diff --git a/src/jackhost.cpp b/src/jackhost.cpp
index 3128499..3b6ccdc 100644
--- a/src/jackhost.cpp
+++ b/src/jackhost.cpp
@@ -78,6 +78,7 @@ static struct option long_options[] = {
{"plugin", 0, 0, 'p'},
{"input", 1, 0, 'i'},
{"output", 1, 0, 'o'},
+ {"connect-midi", 1, 0, 'M'},
{0,0,0,0},
};
@@ -85,7 +86,7 @@ void print_help(char *argv[])
{
printf("JACK host for Calf effects\n"
"Syntax: %s [--client <name>] [--input <name>] [--output <name>] [--midi <name>]\n"
- " [--help] [--version] pluginname ...\n",
+ " [--connect-midi <name>] [--help] [--version] pluginname ...\n",
argv[0]);
}
@@ -111,11 +112,12 @@ int main(int argc, char *argv[])
vector<jack_host_base *> plugins;
vector<plugin_gui_window *> guis;
set<int> chains;
+ string autoconnect_midi;
gtk_init(&argc, &argv);
glade_init();
while(1) {
int option_index;
- int c = getopt_long(argc, argv, "c:i:o:m:ephv", long_options, &option_index);
+ int c = getopt_long(argc, argv, "c:i:o:m:M:ephv", long_options, &option_index);
if (c == -1)
break;
switch(c) {
@@ -142,6 +144,9 @@ int main(int argc, char *argv[])
case 'm':
client.midi_name = string(optarg) + "_%d";
break;
+ case 'M':
+ autoconnect_midi = string(optarg);
+ break;
}
}
while(optind < argc) {
@@ -157,11 +162,17 @@ int main(int argc, char *argv[])
}
try {
struct stat st;
- if (!stat(get_preset_filename().c_str(), &st))
- load_presets(get_preset_filename().c_str());
- else if (!stat(PKGLIBDIR "/presets.xml", &st))
- load_presets(PKGLIBDIR "/presets.xml");
-
+ if (!stat(preset_list::get_preset_filename().c_str(), &st))
+ global_presets.load(preset_list::get_preset_filename().c_str());
+ if (global_presets.presets.empty() && !stat(PKGLIBDIR "/presets.xml", &st))
+ global_presets.load(PKGLIBDIR "/presets.xml");
+ }
+ catch(synth::preset_exception &e)
+ {
+ fprintf(stderr, "Error while loading presets: %s\n", e.what());
+ exit(1);
+ }
+ try {
client.open(client_name);
string cnp = string(client_name) + ":";
for (unsigned int i = 0; i < names.size(); i++) {
@@ -219,6 +230,13 @@ int main(int argc, char *argv[])
client.connect(cnp + plugins[last]->get_outputs()[1].name, "system:playback_2");
}
}
+ if (autoconnect_midi != "") {
+ for (unsigned int i = 0; i < plugins.size(); i++)
+ {
+ if (plugins[i]->get_midi())
+ client.connect(autoconnect_midi, cnp + plugins[i]->get_midi_port()->name);
+ }
+ }
gtk_main();
client.deactivate();
for (unsigned int i = 0; i < names.size(); i++) {
@@ -228,7 +246,8 @@ int main(int argc, char *argv[])
}
client.close();
- save_presets(get_preset_filename().c_str());
+ // this is now done on preset add
+ // save_presets(get_preset_filename().c_str());
}
catch(std::exception &e)
{
diff --git a/src/modules.cpp b/src/modules.cpp
index 447feed..2a91c4d 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -193,16 +193,17 @@ const char *monosynth_filter_choices[] = {
parameter_properties monosynth_audio_module::param_props[] = {
{ wave_saw, 0, wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO, monosynth_waveform_names, "o1_wave", "Osc1 Wave" },
{ wave_sqr, 0, wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO, monosynth_waveform_names, "o2_wave", "Osc2 Wave" },
- { 10, 0, 100, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "osc_detune", "O1<>2 Detune" },
- { 12, -24, 24, 1.01, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "osc_xpose", "Osc transpose" },
+ { 10, 0, 100, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "o12_detune", "O1<>2 Detune" },
+ { 12, -24, 24, 1.01, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "o2_xpose", "Osc 2 transpose" },
{ 0, 0, 5, 1.01, PF_ENUM | PF_CTL_COMBO, monosynth_mode_names, "phase_mode", "Phase mode" },
{ 0.5, 0, 1, 1.01, PF_FLOAT | PF_SCALE_PERC, NULL, "o12_mix", "O1<>2 Mix" },
{ 1, 0, 7, 1.01, PF_ENUM | PF_CTL_COMBO, monosynth_filter_choices, "filter", "Filter" },
{ 33, 10,16000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "cutoff", "Cutoff" },
{ 2, 0.7, 8, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB, NULL, "res", "Resonance" },
{ 0, -2400, 2400, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "filter_sep", "Separation" },
- { 8000, -10800,10800, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "e2cutoff", "Env->Cutoff" },
- { 1, 0, 1, 1.01, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "e2res", "Env->Res" },
+ { 8000, -10800,10800, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "env2cutoff", "Env->Cutoff" },
+ { 1, 0, 1, 1.01, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "env2res", "Env->Res" },
+ { 1, 0, 1, 1.01, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "env2amp", "Env->Amp" },
{ 1, 1,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_a", "Attack" },
{ 350, 10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_d", "Decay" },
@@ -213,8 +214,8 @@ parameter_properties monosynth_audio_module::param_props[] = {
{ 0, 0, 3, 1.01, PF_ENUM | PF_CTL_COMBO, monosynth_legato_names, "legato", "Legato Mode" },
{ 1, 1, 2000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "portamento", "Portamento" },
+ { 0.5, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2filter", "Vel->Filter" },
{ 0, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2amp", "Vel->Amp" },
- { 0.5, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2flt", "Vel->Filter" },
};
static synth::ladspa_info monosynth_info = { 0x8480, "Monosynth", "Calf Monosynth", "Krzysztof Foltman", copyright, "SynthesizerPlugin" };
diff --git a/src/preset.cpp b/src/preset.cpp
index c1bbdce..41eb23d 100644
--- a/src/preset.cpp
+++ b/src/preset.cpp
@@ -29,32 +29,39 @@
using namespace synth;
using namespace std;
-vector<plugin_preset> synth::presets;
+synth::preset_list synth::global_presets;
-string synth::get_preset_filename()
+std::string plugin_preset::to_xml()
{
- const char *home = getenv("HOME");
- return string(home)+"/.calfpresets";
+ std::stringstream ss;
+ ss << "<preset bank=\"" << bank << "\" program=\"" << program << "\" plugin=\"" << xml_escape(plugin) << "\" name=\"" << xml_escape(name) << "\">\n";
+ for (unsigned int i = 0; i < values.size(); i++) {
+ if (i < param_names.size())
+ ss << " <param name=\"" << xml_escape(param_names[i]) << "\" value=\"" << values[i] << "\" />\n";
+ else
+ ss << " <param value=\"" << values[i] << "\" />\n";
+ }
+ // XXXKF I'm not writing blob here, because I don't use blobs yet anyway
+ ss << "</preset>\n";
+ return ss.str();
}
-enum PresetParserState
+string synth::preset_list::get_preset_filename()
{
- START,
- LIST,
- PRESET,
- VALUE,
-};
-
-static PresetParserState xml_parser_state;
-static plugin_preset parser_preset;
+ const char *home = getenv("HOME");
+ return string(home)+"/.calfpresets";
+}
-static void xml_start_element_handler(void *user_data, const char *name, const char *attrs[])
+void preset_list::xml_start_element_handler(void *user_data, const char *name, const char *attrs[])
{
- switch(xml_parser_state)
+ preset_list &self = *(preset_list *)user_data;
+ parser_state &state = self.state;
+ plugin_preset &parser_preset = self.parser_preset;
+ switch(state)
{
case START:
if (!strcmp(name, "presets")) {
- xml_parser_state = LIST;
+ state = LIST;
return;
}
break;
@@ -67,15 +74,15 @@ static void xml_start_element_handler(void *user_data, const char *name, const c
parser_preset.param_names.clear();
parser_preset.values.clear();
for(; *attrs; attrs += 2) {
- if (!strcmp(attrs[0], "bank")) parser_preset.bank = atoi(attrs[1]);
+ if (!strcmp(attrs[0], "bank")) self.parser_preset.bank = atoi(attrs[1]);
else
- if (!strcmp(attrs[0], "program")) parser_preset.program = atoi(attrs[1]);
+ if (!strcmp(attrs[0], "program")) self.parser_preset.program = atoi(attrs[1]);
else
- if (!strcmp(attrs[0], "name")) parser_preset.name = attrs[1];
+ if (!strcmp(attrs[0], "name")) self.parser_preset.name = attrs[1];
else
- if (!strcmp(attrs[0], "plugin")) parser_preset.plugin = attrs[1];
+ if (!strcmp(attrs[0], "plugin")) self.parser_preset.plugin = attrs[1];
}
- xml_parser_state = PRESET;
+ state = PRESET;
return;
}
break;
@@ -91,9 +98,9 @@ static void xml_start_element_handler(void *user_data, const char *name, const c
str >> value;
}
}
- parser_preset.param_names.push_back(name);
- parser_preset.values.push_back(value);
- xml_parser_state = VALUE;
+ self.parser_preset.param_names.push_back(name);
+ self.parser_preset.values.push_back(value);
+ state = VALUE;
return;
}
break;
@@ -104,28 +111,31 @@ static void xml_start_element_handler(void *user_data, const char *name, const c
throw preset_exception("Invalid XML element: %s", name, 0);
}
-static void xml_end_element_handler(void *user_data, const char *name)
+void preset_list::xml_end_element_handler(void *user_data, const char *name)
{
- switch(xml_parser_state)
+ preset_list &self = *(preset_list *)user_data;
+ preset_vector &presets = self.presets;
+ parser_state &state = self.state;
+ switch(state)
{
case START:
break;
case LIST:
if (!strcmp(name, "presets")) {
- xml_parser_state = START;
+ state = START;
return;
}
break;
case PRESET:
if (!strcmp(name, "preset")) {
- presets.push_back(parser_preset);
- xml_parser_state = LIST;
+ presets.push_back(self.parser_preset);
+ state = LIST;
return;
}
break;
case VALUE:
if (!strcmp(name, "param")) {
- xml_parser_state = PRESET;
+ state = PRESET;
return;
}
break;
@@ -133,10 +143,11 @@ static void xml_end_element_handler(void *user_data, const char *name)
throw preset_exception("Invalid XML element close: %s", name, 0);
}
-void synth::load_presets(const char *filename)
+void preset_list::load(const char *filename)
{
- xml_parser_state = START;
+ state = START;
XML_Parser parser = XML_ParserCreate("UTF-8");
+ XML_SetUserData(parser, this);
int fd = open(filename, O_RDONLY);
if (fd < 0)
throw preset_exception("Could not load the presets from ", filename, errno);
@@ -148,13 +159,17 @@ void synth::load_presets(const char *filename)
// XXXKF not an optimal error/EOF handling :)
if (len <= 0)
break;
- XML_Parse(parser, buf, len, 0);
+ XML_Status status = XML_Parse(parser, buf, len, 0);
+ if (status == XML_STATUS_ERROR)
+ throw preset_exception(string("Parse error: ") + XML_ErrorString(XML_GetErrorCode(parser))+ " in ", filename, errno);
} while(1);
- XML_Parse(parser, buf, 0, 1);
+ XML_Status status = XML_Parse(parser, buf, 0, 1);
+ if (status == XML_STATUS_ERROR)
+ throw preset_exception(string("Parse error: ") + XML_ErrorString(XML_GetErrorCode(parser))+ " in ", filename, errno);
close(fd);
}
-void synth::save_presets(const char *filename)
+void preset_list::save(const char *filename)
{
string xml = "<presets>\n";
for (unsigned int i = 0; i < presets.size(); i++)
@@ -168,7 +183,7 @@ void synth::save_presets(const char *filename)
close(fd);
}
-void synth::add_preset(const plugin_preset &sp)
+void preset_list::add(const plugin_preset &sp)
{
presets.push_back(sp);
}
diff --git a/src/preset_gui.cpp b/src/preset_gui.cpp
index 4447bbf..0005326 100644
--- a/src/preset_gui.cpp
+++ b/src/preset_gui.cpp
@@ -46,10 +46,20 @@ void store_preset_ok(GtkAction *action, plugin_gui *gui)
sp.plugin = gui->effect_name;
int count = gui->plugin->get_param_count();
for (int i = 0; i < count; i++) {
- sp.param_names.push_back(gui->plugin->get_param_props(i)->name);
+ sp.param_names.push_back(gui->plugin->get_param_props(i)->short_name);
sp.values.push_back(gui->plugin->get_param_value(i));
}
- add_preset(sp);
+ preset_list tmp;
+ try {
+ tmp.load(tmp.get_preset_filename().c_str());
+ }
+ catch(...)
+ {
+ tmp = global_presets;
+ }
+ tmp.add(sp);
+ global_presets = tmp;
+ global_presets.save(tmp.get_preset_filename().c_str());
gtk_widget_destroy(store_preset_dlg);
gui->window->fill_gui_presets();
}
@@ -77,19 +87,25 @@ void synth::store_preset(GtkWindow *toplevel, plugin_gui *gui)
void synth::activate_preset(GtkAction *action, activate_preset_params *params)
{
plugin_gui *gui = params->gui;
- plugin_preset &p = presets[params->preset];
+ plugin_preset &p = global_presets.presets[params->preset];
if (p.plugin != gui->effect_name)
return;
map<string, int> names;
int count = gui->plugin->get_param_count();
- for (int i = 0; i < count; i++)
+ // this is deliberately done in two separate loops - if you wonder why, just think for a while :)
+ for (int i = 0; i < count; i++)
names[gui->plugin->get_param_props(i)->name] = i;
+ for (int i = 0; i < count; i++)
+ names[gui->plugin->get_param_props(i)->short_name] = i;
// no support for unnamed parameters... tough luck :)
for (unsigned int i = 0; i < min(p.param_names.size(), p.values.size()); i++)
{
map<string, int>::iterator pos = names.find(p.param_names[i]);
- if (pos == names.end())
+ if (pos == names.end()) {
+ // XXXKF should have a mechanism for notifying a GUI
+ printf("Warning: unknown parameter %s for plugin %s\n", p.param_names[i].c_str(), gui->effect_name);
continue;
+ }
gui->plugin->set_param_value(pos->second, p.values[i]);
}
gui->refresh();
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list