+ GUI: remove unused (and misleading) fields - the widget pointer is always stored...
[calf.git] / src / preset.cpp
blob919747d4ef6f98f5d8051c70cb1ca1ebfe35648f
1 /* Calf DSP Library
2 * Preset management.
4 * Copyright (C) 2001-2007 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include <config.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <sys/stat.h>
29 #include <expat.h>
30 #include <calf/preset.h>
31 #include <calf/giface.h>
32 #include <calf/utils.h>
34 using namespace std;
35 using namespace calf_plugins;
36 using namespace calf_utils;
38 extern calf_plugins::preset_list &calf_plugins::get_builtin_presets()
40 static calf_plugins::preset_list plist;
41 return plist;
44 extern calf_plugins::preset_list &calf_plugins::get_user_presets()
46 static calf_plugins::preset_list plist;
47 return plist;
50 std::string plugin_preset::to_xml()
52 std::stringstream ss;
53 ss << "<preset bank=\"" << bank << "\" program=\"" << program << "\" plugin=\"" << xml_escape(plugin) << "\" name=\"" << xml_escape(name) << "\">\n";
54 for (unsigned int i = 0; i < values.size(); i++) {
55 if (i < param_names.size())
56 ss << " <param name=\"" << xml_escape(param_names[i]) << "\" value=\"" << values[i] << "\" />\n";
57 else
58 ss << " <param value=\"" << values[i] << "\" />\n";
60 for (map<string, string>::iterator i = variables.begin(); i != variables.end(); i++)
62 ss << " <var name=\"" << xml_escape(i->first) << "\">" << xml_escape(i->second) << "</var>\n";
64 ss << "</preset>\n";
65 return ss.str();
68 string plugin_preset::get_safe_name()
70 stringstream ss;
71 for (size_t i = 0; i < name.length(); i++)
73 if (isdigit(name[i]) || isalpha(name[i]))
74 ss << name[i];
76 return ss.str();
79 void plugin_preset::activate(plugin_ctl_iface *plugin)
81 // First, clear everything to default values (in case some parameters or variables are missing)
82 plugin->clear_preset();
84 map<string, int> names;
85 int count = plugin->get_param_count();
86 // this is deliberately done in two separate loops - if you wonder why, just think for a while :)
87 for (int i = 0; i < count; i++)
88 names[plugin->get_param_props(i)->name] = i;
89 for (int i = 0; i < count; i++)
90 names[plugin->get_param_props(i)->short_name] = i;
91 // no support for unnamed parameters... tough luck :)
92 for (unsigned int i = 0; i < min(param_names.size(), values.size()); i++)
94 map<string, int>::iterator pos = names.find(param_names[i]);
95 if (pos == names.end()) {
96 // XXXKF should have a mechanism for notifying a GUI
97 printf("Warning: unknown parameter %s for plugin %s\n", param_names[i].c_str(), this->plugin.c_str());
98 continue;
100 plugin->set_param_value(pos->second, values[i]);
102 for (map<string, string>::iterator i = variables.begin(); i != variables.end(); i++)
104 printf("configure %s: %s\n", i->first.c_str(), i->second.c_str());
105 plugin->configure(i->first.c_str(), i->second.c_str());
109 void plugin_preset::get_from(plugin_ctl_iface *plugin)
111 int count = plugin->get_param_count();
112 for (int i = 0; i < count; i++) {
113 if ((plugin->get_param_props(i)->flags & PF_TYPEMASK) >= PF_STRING)
114 continue;
115 param_names.push_back(plugin->get_param_props(i)->short_name);
116 values.push_back(plugin->get_param_value(i));
118 struct store_obj: public send_configure_iface
120 map<string, string> *data;
121 void send_configure(const char *key, const char *value)
123 (*data)[key] = value;
125 } tmp;
126 variables.clear();
127 tmp.data = &variables;
128 plugin->send_configures(&tmp);
131 string calf_plugins::preset_list::get_preset_filename(bool builtin)
133 if (builtin)
135 return PKGLIBDIR "/presets.xml";
137 else
139 const char *home = getenv("HOME");
140 return string(home)+"/.calfpresets";
144 void preset_list::xml_start_element_handler(void *user_data, const char *name, const char *attrs[])
146 preset_list &self = *(preset_list *)user_data;
147 parser_state &state = self.state;
148 plugin_preset &parser_preset = self.parser_preset;
149 switch(state)
151 case START:
152 if (!strcmp(name, "presets")) {
153 state = LIST;
154 return;
156 break;
157 case LIST:
158 if (!strcmp(name, "preset")) {
160 parser_preset.bank = parser_preset.program = 0;
161 parser_preset.name = "";
162 parser_preset.plugin = "";
163 parser_preset.param_names.clear();
164 parser_preset.values.clear();
165 parser_preset.variables.clear();
166 for(; *attrs; attrs += 2) {
167 if (!strcmp(attrs[0], "name")) self.parser_preset.name = attrs[1];
168 else
169 if (!strcmp(attrs[0], "plugin")) self.parser_preset.plugin = attrs[1];
171 // autonumbering of programs for DSSI
172 if (!self.last_preset_ids.count(self.parser_preset.plugin))
173 self.last_preset_ids[self.parser_preset.plugin] = 0;
174 self.parser_preset.program = ++self.last_preset_ids[self.parser_preset.plugin];
175 self.parser_preset.bank = (self.parser_preset.program >> 7);
176 self.parser_preset.program &= 127;
177 state = PRESET;
178 return;
180 break;
181 case PRESET:
182 if (!strcmp(name, "param")) {
183 std::string name;
184 float value = 0.f;
185 for(; *attrs; attrs += 2) {
186 if (!strcmp(attrs[0], "name")) name = attrs[1];
187 else
188 if (!strcmp(attrs[0], "value")) {
189 istringstream str(attrs[1]);
190 str >> value;
193 self.parser_preset.param_names.push_back(name);
194 self.parser_preset.values.push_back(value);
195 state = VALUE;
196 return;
198 if (!strcmp(name, "var")) {
199 self.current_key = "";
200 for(; *attrs; attrs += 2) {
201 if (!strcmp(attrs[0], "name")) self.current_key = attrs[1];
203 if (self.current_key.empty())
204 throw preset_exception("No name specified for preset variable", "", 0);
205 self.parser_preset.variables[self.current_key].clear();
206 state = VAR;
207 return;
209 break;
210 case VALUE:
211 // no nested elements allowed inside <param>
212 break;
213 case VAR:
214 // no nested elements allowed inside <var>
215 break;
217 // g_warning("Invalid XML element: %s", name);
218 throw preset_exception("Invalid XML element: %s", name, 0);
221 void preset_list::xml_end_element_handler(void *user_data, const char *name)
223 preset_list &self = *(preset_list *)user_data;
224 preset_vector &presets = self.presets;
225 parser_state &state = self.state;
226 switch(state)
228 case START:
229 break;
230 case LIST:
231 if (!strcmp(name, "presets")) {
232 state = START;
233 return;
235 break;
236 case PRESET:
237 if (!strcmp(name, "preset")) {
238 presets.push_back(self.parser_preset);
239 state = LIST;
240 return;
242 break;
243 case VALUE:
244 if (!strcmp(name, "param")) {
245 state = PRESET;
246 return;
248 break;
249 case VAR:
250 if (!strcmp(name, "var")) {
251 state = PRESET;
252 return;
254 break;
256 throw preset_exception("Invalid XML element close: %s", name, 0);
259 void preset_list::xml_character_data_handler(void *user_data, const XML_Char *data, int len)
261 preset_list &self = *(preset_list *)user_data;
262 parser_state &state = self.state;
263 if (state == VAR)
265 self.parser_preset.variables[self.current_key] += string(data, len);
266 return;
270 bool preset_list::load_defaults(bool builtin)
272 try {
273 struct stat st;
274 string name = preset_list::get_preset_filename(builtin);
275 if (!stat(name.c_str(), &st)) {
276 load(name.c_str());
277 if (!presets.empty())
278 return true;
281 catch(preset_exception &ex)
283 return false;
285 return false;
288 void preset_list::parse(const std::string &data)
290 state = START;
291 XML_Parser parser = XML_ParserCreate("UTF-8");
292 XML_SetUserData(parser, this);
293 XML_SetElementHandler(parser, xml_start_element_handler, xml_end_element_handler);
294 XML_SetCharacterDataHandler(parser, xml_character_data_handler);
295 XML_Status status = XML_Parse(parser, data.c_str(), data.length(), 1);
296 if (status == XML_STATUS_ERROR) {
297 string err = string("Parse error: ") + XML_ErrorString(XML_GetErrorCode(parser))+ " in ";
298 XML_ParserFree(parser);
299 throw preset_exception(err, "string", errno);
301 XML_ParserFree(parser);
304 void preset_list::load(const char *filename)
306 state = START;
307 XML_Parser parser = XML_ParserCreate("UTF-8");
308 XML_SetUserData(parser, this);
309 int fd = open(filename, O_RDONLY);
310 if (fd < 0)
311 throw preset_exception("Could not load the presets from ", filename, errno);
312 XML_SetElementHandler(parser, xml_start_element_handler, xml_end_element_handler);
313 XML_SetCharacterDataHandler(parser, xml_character_data_handler);
314 char buf[4096];
317 int len = read(fd, buf, 4096);
318 // XXXKF not an optimal error/EOF handling :)
319 if (len <= 0)
320 break;
321 XML_Status status = XML_Parse(parser, buf, len, 0);
322 if (status == XML_STATUS_ERROR)
323 throw preset_exception(string("Parse error: ") + XML_ErrorString(XML_GetErrorCode(parser))+ " in ", filename, errno);
324 } while(1);
325 XML_Status status = XML_Parse(parser, buf, 0, 1);
326 close(fd);
327 if (status == XML_STATUS_ERROR)
329 string err = string("Parse error: ") + XML_ErrorString(XML_GetErrorCode(parser))+ " in ";
330 XML_ParserFree(parser);
331 throw preset_exception(err, filename, errno);
333 XML_ParserFree(parser);
336 void preset_list::save(const char *filename)
338 string xml = "<presets>\n";
339 for (unsigned int i = 0; i < presets.size(); i++)
341 xml += presets[i].to_xml();
343 xml += "</presets>";
344 int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0640);
345 if (fd < 0 || ((unsigned)write(fd, xml.c_str(), xml.length()) != xml.length()))
346 throw preset_exception("Could not save the presets in ", filename, errno);
347 close(fd);
350 void preset_list::get_for_plugin(preset_vector &vec, const char *plugin)
352 for (unsigned int i = 0; i < presets.size(); i++)
354 if (presets[i].plugin == plugin)
355 vec.push_back(presets[i]);
359 void preset_list::add(const plugin_preset &sp)
361 for (unsigned int i = 0; i < presets.size(); i++)
363 if (presets[i].plugin == sp.plugin && presets[i].name == sp.name)
365 presets[i] = sp;
366 return;
369 presets.push_back(sp);