1 /***************************************************************************
2 initeffects.cpp - description
5 copyright : (C) 2006 by Jean-Baptiste Mardelle
7 copyright : (C) 2008 Marco Gittler
8 email : g.marco@freenet.de
9 ***************************************************************************/
11 /***************************************************************************
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
18 ***************************************************************************/
27 #include <KStandardDirs>
29 #include "initeffects.h"
30 #include "kdenlivesettings.h"
31 #include "effectslist.h"
33 initEffects::initEffects() {
36 initEffects::~initEffects() {
40 Mlt::Repository *initEffects::parseEffectFiles(EffectsList *audioEffectList, EffectsList *videoEffectList, EffectsList* transitionsList) {
41 QStringList::Iterator more;
42 QStringList::Iterator it;
47 // Build effects. Retrieve the list of MLT's available effects first.
48 Mlt::Repository *repository = Mlt::Factory::init();
50 kDebug() << "Repository did not finish init " ;
53 Mlt::Properties *filters = repository->filters();
54 QStringList filtersList;
56 for (int i = 0 ; i < filters->count() ; i++) {
57 filtersList << filters->get_name(i);
60 // Build effects. check producers first.
62 Mlt::Properties *producers = repository->producers();
63 QStringList producersList;
64 for (int i = 0 ; i < producers->count() ; i++) {
65 producersList << producers->get_name(i);
70 Mlt::Properties *transitions = repository->transitions();
71 QStringList transitionsItemList;
72 for (int i = 0 ; i < transitions->count() ; i++) {
73 transitionsItemList << transitions->get_name(i);
76 fillTransitionsList(repository, transitionsList, transitionsItemList);
78 KGlobal::dirs()->addResourceType("ladspa_plugin", 0, "lib/ladspa");
79 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/lib/ladspa");
80 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/local/lib/ladspa");
81 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/opt/lib/ladspa");
82 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/opt/local/lib/ladspa");
84 kDebug() << "// INIT EFFECT SEARCH" << endl;
86 QStringList direc = KGlobal::dirs()->findDirs("data", "kdenlive/effects");
89 for (more = direc.begin() ; more != direc.end() ; ++more) {
90 directory = QDir(*more);
91 fileList = directory.entryList(QDir::Files);
92 for (it = fileList.begin() ; it != fileList.end() ; ++it) {
93 itemName = KUrl(*more + *it).path();
94 parseEffectFile(audioEffectList, videoEffectList, itemName, filtersList, producersList);
95 // kDebug()<<"// FOUND EFFECT FILE: "<<itemName<<endl;
98 foreach(QString filtername, filtersList) {
99 QDomDocument doc = createDescriptionFromMlt(repository, "filters", filtername);
101 videoEffectList->append(doc.documentElement());
107 void initEffects::parseEffectFile(EffectsList *audioEffectList, EffectsList *videoEffectList, QString name, QStringList filtersList, QStringList producersList) {
110 doc.setContent(&file, false);
111 QDomElement documentElement = doc.documentElement();
112 QDomNodeList effects = doc.elementsByTagName("effect");
114 if (effects.count() == 0) {
115 kDebug() << "// EFFECT FILET: " << name << " IS BROKEN" << endl;
119 if (doc.elementsByTagName("effectgroup").item(0).toElement().tagName() == "effectgroup") {
120 groupName = documentElement.attribute("name", QString::null);
125 while (!effects.item(i).isNull()) {
126 documentElement = effects.item(i).toElement();
127 QString tag = documentElement.attribute("tag", QString::null);
128 bool ladspaOk = true;
129 if (tag == "ladspa") {
130 QString library = documentElement.attribute("library", QString::null);
131 if (KStandardDirs::locate("ladspa_plugin", library).isEmpty()) ladspaOk = false;
135 if ((filtersList.contains(tag) || producersList.contains(tag)) && ladspaOk) {
136 bool isAudioEffect = false;
137 QDomNode propsnode = documentElement.elementsByTagName("properties").item(0);
138 if (!propsnode.isNull()) {
139 QDomElement propselement = propsnode.toElement();
140 // id = propselement.attribute("id", QString::null);
141 // effectTag = propselement.attribute("tag", QString::null);
142 if (propselement.attribute("type", QString::null) == "audio") isAudioEffect = true;
143 //else if (propselement.attribute("type", QString::null) == "custom") type = CUSTOMEFFECT;
144 //else type = VIDEOEFFECT;
146 if (isAudioEffect) audioEffectList->append(documentElement);
147 else videoEffectList->append(documentElement);
151 QDomNode n = documentElement.firstChild();
152 QString id, effectName, effectTag, paramType;
157 EffectParamDescFactory effectDescParamFactory;
158 EffectDesc *effect = NULL;
161 QDomNode namenode = documentElement.elementsByTagName("name").item(0);
162 if (!namenode.isNull()) effectName = i18n(namenode.toElement().text());
163 if (!groupName.isEmpty()) effectName.prepend("_" + groupName + "_");
165 QDomNode propsnode = documentElement.elementsByTagName("properties").item(0);
166 if (!propsnode.isNull()) {
167 QDomElement propselement = propsnode.toElement();
168 id = propselement.attribute("id", QString::null);
169 effectTag = propselement.attribute("tag", QString::null);
170 if (propselement.attribute("type", QString::null) == "audio") type = AUDIOEFFECT;
171 else if (propselement.attribute("type", QString::null) == "custom") type = CUSTOMEFFECT;
172 else type = VIDEOEFFECT;
175 QString effectDescription;
176 QDomNode descnode = documentElement.elementsByTagName("description").item(0);
177 if (!descnode.isNull()) effectDescription = descnode.toElement().text() + "<br />";
179 QString effectAuthor;
180 QDomNode authnode = documentElement.elementsByTagName("author").item(0);
181 if (!authnode.isNull()) effectAuthor = authnode.toElement().text() + "<br />";
183 if (effectName.isEmpty() || id.isEmpty() || effectTag.isEmpty()) return;
185 effect = new EffectDesc(effectName, id, effectTag, effectDescription, effectAuthor, type);
187 QDomNodeList paramList = documentElement.elementsByTagName("parameter");
188 if (paramList.count() == 0) {
189 QDomElement fixed = doc.createElement("parameter");
190 fixed.setAttribute("type", "fixed");
191 effect->addParameter(effectDescParamFactory.createParameter(fixed));
193 else for (int i = 0; i < paramList.count(); i++) {
194 QDomElement e = paramList.item(i).toElement();
197 QDomNamedNodeMap attrs = e.attributes();
200 while (!attrs.item(i).isNull()) {
201 QDomNode n = attrs.item(i);
202 value = n.nodeValue();
203 if (value.find("MAX_WIDTH") != -1)
204 value.replace("MAX_WIDTH", QString::number(KdenliveSettings::defaultwidth()));
205 if (value.find("MID_WIDTH") != -1)
206 value.replace("MID_WIDTH", QString::number(KdenliveSettings::defaultwidth() / 2));
207 if (value.find("MAX_HEIGHT") != -1)
208 value.replace("MAX_HEIGHT", QString::number(KdenliveSettings::defaultheight()));
209 if (value.find("MID_HEIGHT") != -1)
210 value.replace("MID_HEIGHT", QString::number(KdenliveSettings::defaultheight() / 2));
211 n.setNodeValue(value);
214 effect->addParameter(effectDescParamFactory.createParameter(e));
217 effectList->append(effect);
224 char* initEffects::ladspaEffectString(int ladspaId, QStringList params) {
225 if (ladspaId == 1433) //Pitch
226 return ladspaPitchEffectString(params);
227 else if (ladspaId == 1216) //Room Reverb
228 return ladspaRoomReverbEffectString(params);
229 else if (ladspaId == 1423) //Reverb
230 return ladspaReverbEffectString(params);
231 else if (ladspaId == 1901) //Reverb
232 return ladspaEqualizerEffectString(params);
234 kDebug() << "++++++++++ ASKING FOR UNKNOWN LADSPA EFFECT: " << ladspaId << endl;
235 return("<jackrack></jackrack>");
240 void initEffects::ladspaEffectFile(const QString & fname, int ladspaId, QStringList params) {
244 filterString = ladspaPitchEffectString(params);
247 filterString = ladspaVinylEffectString(params);
249 case 1216 : //Room Reverb
250 filterString = ladspaRoomReverbEffectString(params);
253 filterString = ladspaReverbEffectString(params);
255 case 1195: //Declipper
256 filterString = ladspaDeclipEffectString(params);
259 filterString = ladspaEqualizerEffectString(params);
261 case 1913: // Limiter
262 filterString = ladspaLimiterEffectString(params);
264 case 1193: // Pitch Shifter
265 filterString = ladspaPitchShifterEffectString(params);
267 case 1417: // Rate Scaler
268 filterString = ladspaRateScalerEffectString(params);
271 filterString = ladspaPhaserEffectString(params);
274 kDebug() << "++++++++++ ASKING FOR UNKNOWN LADSPA EFFECT: " << ladspaId << endl;
280 if (f.open(QIODevice::WriteOnly)) {
281 QTextStream stream(&f);
282 stream << filterString;
284 } else kDebug() << "++++++++++ ERROR CANNOT WRITE TO: " << KdenliveSettings::currenttmpfolder() + fname << endl;
288 QString jackString = "<?xml version=\"1.0\"?><!DOCTYPE jackrack SYSTEM \"http://purge.bash.sh/~rah/jack_rack_1.2.dtd\"><jackrack><channels>2</channels><samplerate>48000</samplerate><plugin><id>";
291 char* initEffects::ladspaDeclipEffectString(QStringList) {
292 return qstrdup(QString(jackString + "1195</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><lockall>true</lockall></plugin></jackrack>").toUtf8());
296 char* initEffects::ladspaVocoderEffectString(QStringList params)
298 return qstrdup( QString(jackString + "1441</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><lockall>true</lockall><controlrow><lock>true</lock><value>0.000000</value><value>0.000000</value></controlrow><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow><controlrow><lock>true</lock><value>%2</value><value>%2</value></controlrow><controlrow><lock>true</lock><value>%2</value><value>%2</value></controlrow><controlrow><lock>true</lock><value>%2</value><value>%2</value></controlrow><controlrow><lock>true</lock><value>%2</value><value>%2</value></controlrow><controlrow><lock>true</lock><value>%3</value><value>%3</value></controlrow><controlrow><lock>true</lock><value>%3</value><value>%3</value></controlrow><controlrow><lock>true</lock><value>%3</value><value>%3</value></controlrow><controlrow><lock>true</lock><value>%3</value><value>%3</value></controlrow><controlrow><lock>true</lock><value>%4</value><value>%4</value></controlrow><controlrow><lock>true</lock><value>%4</value><value>%4</value></controlrow><controlrow><lock>true</lock><value>%4</value><value>%4</value></controlrow><controlrow><lock>true</lock><value>%4</value><value>%4</value></controlrow></plugin></jackrack>").arg(params[0]).arg(params[1]).arg(params[2]).arg(params[3]));
301 char* initEffects::ladspaVinylEffectString(QStringList params) {
302 return qstrdup(QString(jackString + "1905</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><controlrow><value>%1</value></controlrow><controlrow><value>%2</value></controlrow><controlrow><value>%3</value></controlrow><controlrow><value>%4</value></controlrow><controlrow><value>%5</value></controlrow></plugin></jackrack>").arg(params[0]).arg(params[1]).arg(params[2]).arg(params[3]).arg(params[4]).toUtf8());
305 char* initEffects::ladspaPitchEffectString(QStringList params) {
306 return qstrdup(QString(jackString + "1433</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.0</value><value>1.0</value></wet_dry_values><lockall>true</lockall><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow><controlrow><lock>true</lock><value>4.000000</value><value>4.000000</value></controlrow></plugin></jackrack>").arg(params[0]).toUtf8());
309 char* initEffects::ladspaRoomReverbEffectString(QStringList params) {
310 return qstrdup(QString(jackString + "1216</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><lockall>true</lockall><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow><controlrow><lock>true</lock><value>%2</value><value>%2</value></controlrow><controlrow><lock>true</lock><value>%3</value><value>%3</value></controlrow><controlrow><lock>true</lock><value>0.750000</value><value>0.750000</value></controlrow><controlrow><lock>true</lock><value>-70.000000</value><value>-70.000000</value></controlrow><controlrow><lock>true</lock><value>0.000000</value><value>0.000000</value></controlrow><controlrow><lock>true</lock><value>-17.500000</value><value>-17.500000</value></controlrow></plugin></jackrack>").arg(params[0]).arg(params[1]).arg(params[2]).toUtf8());
313 char* initEffects::ladspaReverbEffectString(QStringList params) {
314 return qstrdup(QString(jackString + "1423</id><enabled>true</enabled> <wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked> <wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values> <lockall>true</lockall><controlrow><lock>true</lock><value>%1</value> <value>%1</value></controlrow><controlrow><lock>true</lock><value>%2</value><value>%2</value></controlrow><controlrow><lock>true</lock><value>0.250000</value><value>0.250000</value></controlrow></plugin></jackrack>").arg(params[0]).arg(params[1]).toUtf8());
317 char* initEffects::ladspaEqualizerEffectString(QStringList params) {
318 return qstrdup(QString(jackString + "1901</id><enabled>true</enabled> <wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked> <wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><controlrow><value>%1</value></controlrow><controlrow><value>%2</value></controlrow> <controlrow><value>%3</value></controlrow></plugin></jackrack>").arg(params[0]).arg(params[1]).arg(params[2]).toUtf8());
321 char* initEffects::ladspaLimiterEffectString(QStringList params) {
322 return qstrdup(QString(jackString + "1913</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><controlrow><value>%1</value></controlrow><controlrow><value>%2</value></controlrow><controlrow><value>%3</value></controlrow></plugin></jackrack>").arg(params[0]).arg(params[1]).arg(params[2]).toUtf8());
325 char* initEffects::ladspaPitchShifterEffectString(QStringList params) {
326 return qstrdup(QString(jackString + "1193</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><lockall>true</lockall><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow></plugin></jackrack>").arg(params[0]).toUtf8());
329 char* initEffects::ladspaRateScalerEffectString(QStringList params) {
330 return qstrdup(QString(jackString + "1417</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><lockall>true</lockall><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow></plugin></jackrack>").arg(params[0]).toUtf8());
333 char* initEffects::ladspaPhaserEffectString(QStringList params) {
334 return qstrdup(QString(jackString + "1217</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><lockall>true</lockall><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow><controlrow><lock>true</lock><value>%2</value><value>%2</value></controlrow><controlrow><lock>true</lock><value>%3</value><value>%3</value></controlrow><controlrow><lock>true</lock><value>%4</value><value>%4</value></controlrow></plugin></jackrack>").arg(params[0]).arg(params[1]).arg(params[2]).arg(params[3]).toUtf8());
338 QDomDocument initEffects::createDescriptionFromMlt(Mlt::Repository* repository, const QString& type, const QString& filtername) {
341 Mlt::Properties *metadata = repository->metadata(filter_type, filtername.toAscii().data());
342 //kDebug() << filtername;
343 if (metadata && metadata->is_valid()) {
344 if (metadata->get("title") && metadata->get("identifier")) {
345 QDomElement eff = ret.createElement("effect");
346 eff.setAttribute("tag", metadata->get("identifier"));
348 QDomElement name = ret.createElement("name");
349 name.appendChild(ret.createTextNode(metadata->get("title")));
351 QDomElement desc = ret.createElement("description");
352 desc.appendChild(ret.createTextNode(metadata->get("description")));
354 QDomElement author = ret.createElement("author");
355 author.appendChild(ret.createTextNode(metadata->get("creator")));
357 QDomElement prop = ret.createElement("properties");
358 prop.setAttribute("id", metadata->get("identifier"));
359 prop.setAttribute("tag", metadata->get("identifier"));
360 eff.appendChild(name);
361 eff.appendChild(author);
362 eff.appendChild(desc);
363 eff.appendChild(prop);
365 Mlt::Properties param_props((mlt_properties) metadata->get_data("parameters"));
366 for (int j = 0; param_props.is_valid() && j < param_props.count();j++) {
367 QDomElement params = ret.createElement("parameter");
369 Mlt::Properties paramdesc((mlt_properties) param_props.get_data(param_props.get_name(j)));
371 params.setAttribute("name", paramdesc.get("identifier"));
373 if (paramdesc.get("maximum")) params.setAttribute("max", paramdesc.get("maximum"));
374 if (paramdesc.get("minimum")) params.setAttribute("min", paramdesc.get("minimum"));
375 if (QString(paramdesc.get("type")) == "integer")
376 params.setAttribute("type", "constant");
377 if (QString(paramdesc.get("type")) == "boolean")
378 params.setAttribute("type", "bool");
379 if (!QString(paramdesc.get("format")).isEmpty()) {
380 params.setAttribute("type", "complex");
381 params.setAttribute("format", paramdesc.get("format"));
383 if (paramdesc.get("default")) params.setAttribute("default", paramdesc.get("default"));
384 if (paramdesc.get("value")) {
385 params.setAttribute("value", paramdesc.get("value"));
387 params.setAttribute("value", paramdesc.get("default"));
391 QDomElement pname = ret.createElement("name");
392 pname.appendChild(ret.createTextNode(paramdesc.get("title")));
393 params.appendChild(pname);
395 eff.appendChild(params);
397 ret.appendChild(eff);
401 QTextStream str(&outstr);
403 kDebug() << outstr;*/
407 void initEffects::fillTransitionsList(Mlt::Repository * repository, EffectsList* transitions, QStringList names) {
408 foreach(QString name, names) {
412 Mlt::Properties *metadata = repository->metadata(transition_type, name.toAscii().data());
413 //kDebug() << filtername;
414 if (metadata && metadata->is_valid()) {
415 QDomElement ktrans = ret.createElement("ktransition");
416 ret.appendChild(ktrans);
417 if (metadata->get("title") && metadata->get("identifier")) {
418 ktrans.setAttribute("tag", name);
419 QDomElement tname = ret.createElement("name");
420 tname.appendChild(ret.createTextNode(metadata->get("title")));
421 ktrans.appendChild(tname);
423 transitions->append(ret.documentElement());
424 //kDebug() << ret.toString();
427 if (name == "luma") {
430 QDomElement ktrans = ret.createElement("ktransition");
431 ret.appendChild(ktrans);
432 ktrans.setAttribute("tag", name);
433 QDomElement tname = ret.createElement("name");
434 tname.appendChild(ret.createTextNode("Luma"));
435 ktrans.appendChild(tname);
436 transitions->append(ret.documentElement());
439 QDomElement ktrans1 = ret1.createElement("ktransition");
440 ret1.appendChild(ktrans1);
441 ktrans1.setAttribute("tag", name);
442 QDomElement tname1 = ret.createElement("name");
443 tname1.appendChild(ret1.createTextNode("Lumafile"));
444 ktrans1.appendChild(tname1);
446 QString path(mlt_environment("MLT_DATA"));
447 path.append("/lumas/").append(mlt_environment("MLT_NORMALISATION"));
448 Mlt::Properties entries;
449 mlt_properties_dir_list(entries.get_properties(), path.toAscii().data(), "*.*", 1);
450 kDebug() << path << entries.count();
451 for (int i = 0;i < entries.count();i++) {
452 kDebug() << "luma:" << entries.get(i);
457 transitions->append(ret1.documentElement());
458 } else if (name == "composite") {
460 QDomElement ktrans = ret.createElement("ktransition");
461 ret.appendChild(ktrans);
462 ktrans.setAttribute("tag", name);
463 QDomElement tname = ret.createElement("name");
464 tname.appendChild(ret.createTextNode("Composite"));
465 ktrans.appendChild(tname);
466 transitions->append(ret.documentElement());
469 QDomElement ktrans1 = ret1.createElement("ktransition");
470 ret1.appendChild(ktrans1);
471 ktrans1.setAttribute("tag", name);
472 QDomElement tname1 = ret.createElement("name");
473 tname1.appendChild(ret1.createTextNode("PIP"));
474 ktrans1.appendChild(tname1);
475 transitions->append(ret1.documentElement());
476 } else if (name == "mix") {
478 QDomElement ktrans = ret.createElement("ktransition");
479 ret.appendChild(ktrans);
480 ktrans.setAttribute("tag", name);
481 QDomElement tname = ret.createElement("name");
482 tname.appendChild(ret.createTextNode("Mix"));
483 ktrans.appendChild(tname);
484 transitions->append(ret.documentElement());
485 } else if (name == "affine") {
487 QDomElement ktrans = ret.createElement("ktransition");
488 ret.appendChild(ktrans);
489 ktrans.setAttribute("tag", name);
490 QDomElement tname = ret.createElement("name");
491 tname.appendChild(ret.createTextNode("Affine"));
492 ktrans.appendChild(tname);
493 transitions->append(ret.documentElement());
494 } else if (name == "region") {
496 QDomElement ktrans = ret.createElement("ktransition");
497 ret.appendChild(ktrans);
498 ktrans.setAttribute("tag", name);
499 QDomElement tname = ret.createElement("name");
500 tname.appendChild(ret.createTextNode("Region"));
501 ktrans.appendChild(tname);
502 transitions->append(ret.documentElement());
507 <transition fill="1" in="11" a_track="1" out="73" mlt_service="luma" b_track="2" softness="0" resource="/home/marco/Projekte/kdenlive/install_cmake/share/apps/kdenlive/pgm/PAL/square2.pgm" />