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., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 #include <calf/giface.h>
23 #include <calf/preset.h>
31 using namespace calf_plugins
;
32 using namespace calf_utils
;
34 extern calf_plugins::preset_list
&calf_plugins::get_builtin_presets()
36 static calf_plugins::preset_list plist
;
40 extern calf_plugins::preset_list
&calf_plugins::get_user_presets()
42 static calf_plugins::preset_list plist
;
46 std::string
plugin_preset::to_xml()
49 ss
<< "<preset bank=\"" << bank
<< "\" program=\"" << program
<< "\" plugin=\"" << xml_escape(plugin
) << "\" name=\"" << xml_escape(name
) << "\">\n";
50 for (unsigned int i
= 0; i
< values
.size(); i
++) {
51 if (i
< param_names
.size())
52 ss
<< " <param name=\"" << xml_escape(param_names
[i
]) << "\" value=\"" << values
[i
] << "\" />\n";
54 ss
<< " <param value=\"" << values
[i
] << "\" />\n";
56 for (map
<string
, string
>::iterator i
= variables
.begin(); i
!= variables
.end(); ++i
)
58 ss
<< " <var name=\"" << xml_escape(i
->first
) << "\">" << xml_escape(i
->second
) << "</var>\n";
64 string
plugin_preset::get_safe_name()
67 for (size_t i
= 0; i
< name
.length(); i
++)
69 if (isdigit(name
[i
]) || isalpha(name
[i
]))
75 void plugin_preset::activate(plugin_ctl_iface
*plugin
)
77 // First, clear everything to default values (in case some parameters or variables are missing)
78 plugin
->clear_preset();
79 const plugin_metadata_iface
*metadata
= plugin
->get_metadata_iface();
81 map
<string
, int> names
;
82 int count
= metadata
->get_param_count();
83 // this is deliberately done in two separate loops - if you wonder why, just think for a while :)
84 for (int i
= 0; i
< count
; i
++)
85 names
[metadata
->get_param_props(i
)->name
] = i
;
86 for (int i
= 0; i
< count
; i
++)
87 names
[metadata
->get_param_props(i
)->short_name
] = i
;
88 // no support for unnamed parameters... tough luck :)
89 for (unsigned int i
= 0; i
< min(param_names
.size(), values
.size()); i
++)
91 map
<string
, int>::iterator pos
= names
.find(param_names
[i
]);
92 if (pos
== names
.end()) {
93 // XXXKF should have a mechanism for notifying a GUI
94 printf("Warning: unknown parameter %s for plugin %s\n", param_names
[i
].c_str(), this->plugin
.c_str());
97 plugin
->set_param_value(pos
->second
, values
[i
]);
99 vector
<string
> vnames
;
100 metadata
->get_configure_vars(vnames
);
101 for (unsigned n
= 0; n
< vnames
.size(); ++n
)
103 const char *key
= vnames
[n
].c_str();
104 map
<string
, string
>::const_iterator i
= variables
.find(key
);
105 if (i
== variables
.end())
106 plugin
->configure(key
, NULL
);
108 plugin
->configure(key
, i
->second
.c_str());
112 void plugin_preset::get_from(plugin_ctl_iface
*plugin
)
114 const plugin_metadata_iface
*metadata
= plugin
->get_metadata_iface();
115 int count
= metadata
->get_param_count();
116 for (int i
= 0; i
< count
; i
++) {
117 param_names
.push_back(metadata
->get_param_props(i
)->short_name
);
118 values
.push_back(plugin
->get_param_value(i
));
120 struct store_obj
: public send_configure_iface
122 map
<string
, string
> *data
;
123 void send_configure(const char *key
, const char *value
)
125 (*data
)[key
] = value
;
129 tmp
.data
= &variables
;
130 plugin
->send_configures(&tmp
);
133 string
calf_plugins::preset_list::get_preset_filename(bool builtin
, const std::string
*pkglibdir_path
)
138 return (*pkglibdir_path
) + "/presets.xml";
139 return PKGLIBDIR
"/presets.xml";
143 const char *home
= getenv("HOME");
144 return string(home
)+"/.calfpresets";
148 void preset_list::plugin_snapshot::reset()
151 instance_name
.clear();
152 preset_offset
= input_index
= output_index
= midi_index
= 0;
153 automation_entries
.clear();
156 void preset_list::xml_start_element_handler(void *user_data
, const char *name
, const char *attrs
[])
158 preset_list
&self
= *(preset_list
*)user_data
;
159 bool rack_mode
= self
.rack_mode
;
160 parser_state
&state
= self
.state
;
161 plugin_preset
&parser_preset
= self
.parser_preset
;
165 if (!rack_mode
&& !strcmp(name
, "presets")) {
169 if (rack_mode
&& !strcmp(name
, "rack")) {
175 if (!strcmp(name
, "plugin")) {
176 self
.parser_plugin
.reset();
177 self
.parser_plugin
.preset_offset
= self
.presets
.size();
178 for(; *attrs
; attrs
+= 2) {
179 if (!strcmp(attrs
[0], "type")) self
.parser_plugin
.type
= attrs
[1];
181 if (!strcmp(attrs
[0], "instance-name")) self
.parser_plugin
.instance_name
= attrs
[1];
183 if (!strcmp(attrs
[0], "input-index")) self
.parser_plugin
.input_index
= atoi(attrs
[1]);
185 if (!strcmp(attrs
[0], "output-index")) self
.parser_plugin
.output_index
= atoi(attrs
[1]);
187 if (!strcmp(attrs
[0], "midi-index")) self
.parser_plugin
.midi_index
= atoi(attrs
[1]);
194 if (!strcmp(name
, "automation"))
197 for(; *attrs
; attrs
+= 2) {
198 if (!strcmp(*attrs
, "key")) key
= attrs
[1];
200 if (!strcmp(*attrs
, "value")) value
= attrs
[1];
202 if (!key
.empty() && !value
.empty())
203 self
.parser_plugin
.automation_entries
.push_back(make_pair(key
, value
));
204 state
= AUTOMATION_ENTRY
;
209 if (!strcmp(name
, "preset")) {
211 parser_preset
.bank
= parser_preset
.program
= 0;
212 parser_preset
.name
= "";
213 parser_preset
.plugin
= "";
214 parser_preset
.param_names
.clear();
215 parser_preset
.values
.clear();
216 parser_preset
.variables
.clear();
217 for(; *attrs
; attrs
+= 2) {
218 if (!strcmp(attrs
[0], "name")) self
.parser_preset
.name
= attrs
[1];
220 if (!strcmp(attrs
[0], "plugin")) self
.parser_preset
.plugin
= attrs
[1];
222 // autonumbering of programs for DSSI
223 if (!self
.last_preset_ids
.count(self
.parser_preset
.plugin
))
224 self
.last_preset_ids
[self
.parser_preset
.plugin
] = 0;
225 self
.parser_preset
.program
= ++self
.last_preset_ids
[self
.parser_preset
.plugin
];
226 self
.parser_preset
.bank
= (self
.parser_preset
.program
>> 7);
227 self
.parser_preset
.program
&= 127;
233 if (!strcmp(name
, "param")) {
236 for(; *attrs
; attrs
+= 2) {
237 if (!strcmp(attrs
[0], "name")) name
= attrs
[1];
239 if (!strcmp(attrs
[0], "value")) {
240 istringstream
str(attrs
[1]);
244 self
.parser_preset
.param_names
.push_back(name
);
245 self
.parser_preset
.values
.push_back(value
);
249 if (!strcmp(name
, "var")) {
250 self
.current_key
= "";
251 for(; *attrs
; attrs
+= 2) {
252 if (!strcmp(attrs
[0], "name")) self
.current_key
= attrs
[1];
254 if (self
.current_key
.empty())
255 throw preset_exception("No name specified for preset variable", "", 0);
256 self
.parser_preset
.variables
[self
.current_key
].clear();
262 // no nested elements allowed inside <param>
265 // no nested elements allowed inside <var>
267 case AUTOMATION_ENTRY
:
268 // no nested elements allowed inside <automation>
271 // g_warning("Invalid XML element: %s", name);
272 throw preset_exception("Invalid XML element: %s", name
, 0);
275 void preset_list::xml_end_element_handler(void *user_data
, const char *name
)
277 preset_list
&self
= *(preset_list
*)user_data
;
278 bool rack_mode
= self
.rack_mode
;
279 preset_vector
&presets
= self
.presets
;
280 parser_state
&state
= self
.state
;
285 case AUTOMATION_ENTRY
:
286 if (!strcmp(name
, "automation"))
293 if (!strcmp(name
, "presets")) {
299 if (!strcmp(name
, "plugin")) {
300 self
.plugins
.push_back(self
.parser_plugin
);
306 if (!strcmp(name
, "rack")) {
312 if (!strcmp(name
, "preset")) {
313 presets
.push_back(self
.parser_preset
);
314 state
= rack_mode
? PLUGIN
: LIST
;
319 if (!strcmp(name
, "param")) {
325 if (!strcmp(name
, "var")) {
331 throw preset_exception("Invalid XML element close: %s", name
, 0);
334 void preset_list::xml_character_data_handler(void *user_data
, const XML_Char
*data
, int len
)
336 preset_list
&self
= *(preset_list
*)user_data
;
337 parser_state
&state
= self
.state
;
340 self
.parser_preset
.variables
[self
.current_key
] += string(data
, len
);
345 bool preset_list::load_defaults(bool builtin
, const std::string
*pkglibdir_path
)
349 string name
= preset_list::get_preset_filename(builtin
, pkglibdir_path
);
350 if (!stat(name
.c_str(), &st
)) {
351 load(name
.c_str(), false);
352 if (!presets
.empty())
356 catch(preset_exception
&ex
)
363 void preset_list::parse(const std::string
&data
, bool in_rack_mode
)
365 rack_mode
= in_rack_mode
;
367 XML_Parser parser
= XML_ParserCreate("UTF-8");
368 XML_SetUserData(parser
, this);
369 XML_SetElementHandler(parser
, xml_start_element_handler
, xml_end_element_handler
);
370 XML_SetCharacterDataHandler(parser
, xml_character_data_handler
);
371 XML_Status status
= XML_Parse(parser
, data
.c_str(), data
.length(), 1);
372 if (status
== XML_STATUS_ERROR
) {
373 string err
= string("Parse error: ") + XML_ErrorString(XML_GetErrorCode(parser
))+ " in ";
374 XML_ParserFree(parser
);
375 throw preset_exception(err
, "string", errno
);
377 XML_ParserFree(parser
);
380 void preset_list::load(const char *filename
, bool in_rack_mode
)
382 rack_mode
= in_rack_mode
;
384 XML_Parser parser
= XML_ParserCreate("UTF-8");
385 XML_SetUserData(parser
, this);
386 int fd
= open(filename
, O_RDONLY
);
388 throw preset_exception("Could not load the presets from ", filename
, errno
);
389 XML_SetElementHandler(parser
, xml_start_element_handler
, xml_end_element_handler
);
390 XML_SetCharacterDataHandler(parser
, xml_character_data_handler
);
394 int len
= read(fd
, buf
, 4096);
395 // XXXKF not an optimal error/EOF handling :)
398 XML_Status status
= XML_Parse(parser
, buf
, len
, 0);
399 if (status
== XML_STATUS_ERROR
)
400 throw preset_exception(string("Parse error: ") + XML_ErrorString(XML_GetErrorCode(parser
))+ " in ", filename
, errno
);
402 XML_Status status
= XML_Parse(parser
, buf
, 0, 1);
404 if (status
== XML_STATUS_ERROR
)
406 string err
= string("Parse error: ") + XML_ErrorString(XML_GetErrorCode(parser
))+ " in ";
407 XML_ParserFree(parser
);
408 throw preset_exception(err
, filename
, errno
);
410 XML_ParserFree(parser
);
413 void preset_list::save(const char *filename
)
415 string xml
= "<presets>\n";
416 for (unsigned int i
= 0; i
< presets
.size(); i
++)
418 xml
+= presets
[i
].to_xml();
421 int fd
= open(filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0640);
422 if (fd
< 0 || ((unsigned)write(fd
, xml
.c_str(), xml
.length()) != xml
.length()))
423 throw preset_exception("Could not save the presets in ", filename
, errno
);
427 void preset_list::get_for_plugin(preset_vector
&vec
, const char *plugin
)
429 for (unsigned int i
= 0; i
< presets
.size(); i
++)
431 if (presets
[i
].plugin
== plugin
)
432 vec
.push_back(presets
[i
]);
436 void preset_list::add(const plugin_preset
&sp
)
438 for (unsigned int i
= 0; i
< presets
.size(); i
++)
440 if (presets
[i
].plugin
== sp
.plugin
&& presets
[i
].name
== sp
.name
)
446 presets
.push_back(sp
);