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 ***************************************************************************/
20 #include "initeffects.h"
21 #include "kdenlivesettings.h"
22 #include "effectslist.h"
23 #include "effectstackedit.h"
24 #include "mainwindow.h"
28 #include <KStandardDirs>
35 initEffectsThumbnailer::initEffectsThumbnailer() :
41 void initEffectsThumbnailer::prepareThumbnailsCall(const QStringList& list)
48 void initEffectsThumbnailer::run()
50 foreach(const QString &entry, m_list) {
52 if (!entry.isEmpty() && (entry.endsWith(".png") || entry.endsWith(".pgm"))) {
53 if (!EffectStackEdit::iconCache.contains(entry)) {
56 EffectStackEdit::iconCache[entry] = pix.scaled(30, 30);
63 initEffectsThumbnailer initEffects::thumbnailer;
66 void initEffects::refreshLumas()
68 // Check for Kdenlive installed luma files, add empty string at start for no luma
69 QStringList imagenamelist = QStringList() << i18n("None");
70 QStringList imagefiles = QStringList() << QString();
72 filters << "*.pgm" << "*.png";
74 QStringList customLumas = KGlobal::dirs()->findDirs("appdata", "lumas");
75 foreach(const QString &folder, customLumas) {
76 QStringList filesnames = QDir(folder).entryList(filters, QDir::Files);
77 foreach(const QString &fname, filesnames) {
78 imagenamelist.append(fname);
79 imagefiles.append(KUrl(folder).path(KUrl::AddTrailingSlash) + fname);
83 // Check for MLT lumas
84 KUrl folder(mlt_environment("MLT_DATA"));
85 folder.addPath("lumas");
86 folder.addPath(mlt_environment("MLT_NORMALISATION"));
87 QDir lumafolder(folder.path());
88 QStringList filesnames = lumafolder.entryList(filters, QDir::Files);
89 foreach(const QString &fname, filesnames) {
90 imagenamelist.append(fname);
93 imagefiles.append(path.toLocalFile());
95 QDomElement lumaTransition = MainWindow::transitions.getEffectByTag("luma", "luma");
96 QDomNodeList params = lumaTransition.elementsByTagName("parameter");
97 for (int i = 0; i < params.count(); i++) {
98 QDomElement e = params.item(i).toElement();
99 if (e.attribute("tag") == "resource") {
100 e.setAttribute("paramlistdisplay", imagenamelist.join(","));
101 e.setAttribute("paramlist", imagefiles.join(","));
106 QDomElement compositeTransition = MainWindow::transitions.getEffectByTag("composite", "composite");
107 params = compositeTransition.elementsByTagName("parameter");
108 for (int i = 0; i < params.count(); i++) {
109 QDomElement e = params.item(i).toElement();
110 if (e.attribute("tag") == "luma") {
111 e.setAttribute("paramlistdisplay", imagenamelist.join(","));
112 e.setAttribute("paramlist", imagefiles.join(","));
121 Mlt::Repository *initEffects::parseEffectFiles()
123 QStringList::Iterator more;
124 QStringList::Iterator it;
125 QStringList fileList;
129 // Build effects. Retrieve the list of MLT's available effects first.
130 Mlt::Repository *repository = Mlt::Factory::init();
132 kDebug() << "Repository did not finish init " ;
135 Mlt::Properties *filters = repository->filters();
136 QStringList filtersList;
138 // Check for blacklisted effects
139 QString blacklist = KStandardDirs::locate("appdata", "blacklisted_effects.txt");
141 QFile file(blacklist);
142 QStringList blackListed;
144 if (file.open(QIODevice::ReadOnly)) {
145 QTextStream in(&file);
146 while (!in.atEnd()) {
147 QString black = in.readLine().simplified();
148 if (!black.isEmpty() && !black.startsWith('#')) blackListed.append(black);
153 // Check for blacklisted transitions
154 blacklist = KStandardDirs::locate("appdata", "blacklisted_transitions.txt");
156 QFile file2(blacklist);
157 QStringList blackListedtransitions;
159 if (file2.open(QIODevice::ReadOnly)) {
160 QTextStream in(&file2);
161 while (!in.atEnd()) {
162 QString black = in.readLine().simplified();
163 if (!black.isEmpty() && !black.startsWith('#')) blackListedtransitions.append(black);
168 for (int i = 0 ; i < filters->count() ; i++) {
169 filtersList << filters->get_name(i);
172 // Build effects. check producers first.
174 Mlt::Properties *producers = repository->producers();
175 QStringList producersList;
176 for (int i = 0 ; i < producers->count() ; i++) {
177 producersList << producers->get_name(i);
179 KdenliveSettings::setProducerslist(producersList);
183 Mlt::Properties *transitions = repository->transitions();
184 QStringList transitionsItemList;
185 for (int i = 0 ; i < transitions->count() ; i++) {
186 transitionsItemList << transitions->get_name(i);
190 foreach(const QString &trans, blackListedtransitions) {
191 if (transitionsItemList.contains(trans)) transitionsItemList.removeAll(trans);
193 fillTransitionsList(repository, &MainWindow::transitions, transitionsItemList);
195 KGlobal::dirs()->addResourceType("ladspa_plugin", 0, "lib/ladspa");
196 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/lib/ladspa");
197 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/local/lib/ladspa");
198 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/opt/lib/ladspa");
199 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/opt/local/lib/ladspa");
200 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/lib64/ladspa");
201 KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/local/lib64/ladspa");
203 kDebug() << "// INIT EFFECT SEARCH" << endl;
205 QStringList direc = KGlobal::dirs()->findDirs("appdata", "effects");
208 for (more = direc.begin() ; more != direc.end() ; ++more) {
209 directory = QDir(*more);
212 fileList = directory.entryList(filter, QDir::Files);
213 for (it = fileList.begin() ; it != fileList.end() ; ++it) {
214 itemName = KUrl(*more + *it).path();
215 parseEffectFile(&MainWindow::customEffects, &MainWindow::audioEffects, &MainWindow::videoEffects, itemName, filtersList, producersList);
216 // kDebug()<<"// FOUND EFFECT FILE: "<<itemName<<endl;
220 foreach(const QString &effect, blackListed) {
221 if (filtersList.contains(effect)) filtersList.removeAll(effect);
224 foreach(const QString &filtername, filtersList) {
225 QDomDocument doc = createDescriptionFromMlt(repository, "filters", filtername);
227 MainWindow::videoEffects.append(doc.documentElement());
233 void initEffects::parseCustomEffectsFile()
235 MainWindow::customEffects.clear();
236 QString path = KStandardDirs::locateLocal("appdata", "effects/", true);
237 QDir directory = QDir(path);
240 const QStringList fileList = directory.entryList(filter, QDir::Files);
242 foreach(const QString &filename, fileList) {
243 itemName = KUrl(path + filename).path();
245 QFile file(itemName);
246 doc.setContent(&file, false);
248 QDomNodeList effects = doc.elementsByTagName("effect");
249 if (effects.count() != 1) {
250 kDebug() << "More than one effect in file " << itemName << ", NOT SUPPORTED YET";
252 QDomElement e = effects.item(0).toElement();
253 MainWindow::customEffects.append(e);
259 void initEffects::parseEffectFile(EffectsList *customEffectList, EffectsList *audioEffectList, EffectsList *videoEffectList, QString name, QStringList filtersList, QStringList producersList)
263 doc.setContent(&file, false);
265 QDomElement documentElement = doc.documentElement();
266 QDomNodeList effects = doc.elementsByTagName("effect");
268 if (effects.count() == 0) {
269 kDebug() << "// EFFECT FILET: " << name << " IS BROKEN" << endl;
273 if (doc.elementsByTagName("effectgroup").item(0).toElement().tagName() == "effectgroup") {
274 groupName = documentElement.attribute("name", QString());
279 while (!effects.item(i).isNull()) {
280 documentElement = effects.item(i).toElement();
281 QString tag = documentElement.attribute("tag", QString());
282 bool ladspaOk = true;
283 if (tag == "ladspa") {
284 QString library = documentElement.attribute("library", QString());
285 if (KStandardDirs::locate("ladspa_plugin", library).isEmpty()) ladspaOk = false;
289 if ((filtersList.contains(tag) || producersList.contains(tag)) && ladspaOk) {
290 QString type = documentElement.attribute("type", QString());
291 if (type == "audio") audioEffectList->append(documentElement);
292 else if (type == "custom") customEffectList->append(documentElement);
293 else videoEffectList->append(documentElement);
297 QDomNode n = documentElement.firstChild();
298 QString id, effectName, effectTag, paramType;
303 EffectParamDescFactory effectDescParamFactory;
304 EffectDesc *effect = NULL;
307 QDomNode namenode = documentElement.elementsByTagName("name").item(0);
308 if (!namenode.isNull()) effectName = i18n(namenode.toElement().text());
309 if (!groupName.isEmpty()) effectName.prepend("_" + groupName + "_");
311 QDomNode propsnode = documentElement.elementsByTagName("properties").item(0);
312 if (!propsnode.isNull()) {
313 QDomElement propselement = propsnode.toElement();
314 id = propselement.attribute("id", QString());
315 effectTag = propselement.attribute("tag", QString());
316 if (propselement.attribute("type", QString()) == "audio") type = AUDIOEFFECT;
317 else if (propselement.attribute("type", QString()) == "custom") type = CUSTOMEFFECT;
318 else type = VIDEOEFFECT;
321 QString effectDescription;
322 QDomNode descnode = documentElement.elementsByTagName("description").item(0);
323 if (!descnode.isNull()) effectDescription = descnode.toElement().text() + "<br />";
325 QString effectAuthor;
326 QDomNode authnode = documentElement.elementsByTagName("author").item(0);
327 if (!authnode.isNull()) effectAuthor = authnode.toElement().text() + "<br />";
329 if (effectName.isEmpty() || id.isEmpty() || effectTag.isEmpty()) return;
331 effect = new EffectDesc(effectName, id, effectTag, effectDescription, effectAuthor, type);
333 QDomNodeList paramList = documentElement.elementsByTagName("parameter");
334 if (paramList.count() == 0) {
335 QDomElement fixed = doc.createElement("parameter");
336 fixed.setAttribute("type", "fixed");
337 effect->addParameter(effectDescParamFactory.createParameter(fixed));
339 else for (int i = 0; i < paramList.count(); i++) {
340 QDomElement e = paramList.item(i).toElement();
343 QDomNamedNodeMap attrs = e.attributes();
346 while (!attrs.item(i).isNull()) {
347 QDomNode n = attrs.item(i);
348 value = n.nodeValue();
349 if (value.find("MAX_WIDTH") != -1)
350 value.replace("MAX_WIDTH", QString::number(KdenliveSettings::defaultwidth()));
351 if (value.find("MID_WIDTH") != -1)
352 value.replace("MID_WIDTH", QString::number(KdenliveSettings::defaultwidth() / 2));
353 if (value.find("MAX_HEIGHT") != -1)
354 value.replace("MAX_HEIGHT", QString::number(KdenliveSettings::defaultheight()));
355 if (value.find("MID_HEIGHT") != -1)
356 value.replace("MID_HEIGHT", QString::number(KdenliveSettings::defaultheight() / 2));
357 n.setNodeValue(value);
360 effect->addParameter(effectDescParamFactory.createParameter(e));
363 effectList->append(effect);
370 const char* initEffects::ladspaEffectString(int ladspaId, QStringList params)
372 if (ladspaId == 1433) //Pitch
373 return ladspaPitchEffectString(params);
374 else if (ladspaId == 1216) //Room Reverb
375 return ladspaRoomReverbEffectString(params);
376 else if (ladspaId == 1423) //Reverb
377 return ladspaReverbEffectString(params);
378 else if (ladspaId == 1901) //Reverb
379 return ladspaEqualizerEffectString(params);
381 kDebug() << "++++++++++ ASKING FOR UNKNOWN LADSPA EFFECT: " << ladspaId << endl;
382 return "<jackrack></jackrack>";
387 void initEffects::ladspaEffectFile(const QString & fname, int ladspaId, QStringList params)
389 const char *filterString;
392 filterString = ladspaPitchEffectString(params);
395 filterString = ladspaVinylEffectString(params);
397 case 1216 : //Room Reverb
398 filterString = ladspaRoomReverbEffectString(params);
401 filterString = ladspaReverbEffectString(params);
403 case 1195: //Declipper
404 filterString = ladspaDeclipEffectString(params);
407 filterString = ladspaEqualizerEffectString(params);
409 case 1913: // Limiter
410 filterString = ladspaLimiterEffectString(params);
412 case 1193: // Pitch Shifter
413 filterString = ladspaPitchShifterEffectString(params);
415 case 1417: // Rate Scaler
416 filterString = ladspaRateScalerEffectString(params);
419 filterString = ladspaPhaserEffectString(params);
422 kDebug() << "++++++++++ ASKING FOR UNKNOWN LADSPA EFFECT: " << ladspaId << endl;
428 if (f.open(QIODevice::WriteOnly)) {
429 QTextStream stream(&f);
430 stream << filterString;
432 } else kDebug() << "++++++++++ ERROR CANNOT WRITE TO: " << KdenliveSettings::currenttmpfolder() + fname << endl;
433 delete [] filterString;
436 const 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>";
439 const char* initEffects::ladspaDeclipEffectString(QStringList)
441 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());
445 const char* initEffects::ladspaVocoderEffectString(QStringList params)
447 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]));
450 const char* initEffects::ladspaVinylEffectString(QStringList params)
452 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());
455 const char* initEffects::ladspaPitchEffectString(QStringList params)
457 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());
460 const char* initEffects::ladspaRoomReverbEffectString(QStringList params)
462 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());
465 const char* initEffects::ladspaReverbEffectString(QStringList params)
467 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());
470 const char* initEffects::ladspaEqualizerEffectString(QStringList params)
472 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());
475 const char* initEffects::ladspaLimiterEffectString(QStringList params)
477 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());
480 const char* initEffects::ladspaPitchShifterEffectString(QStringList params)
482 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());
485 const char* initEffects::ladspaRateScalerEffectString(QStringList params)
487 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());
490 const char* initEffects::ladspaPhaserEffectString(QStringList params)
492 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());
496 QDomDocument initEffects::createDescriptionFromMlt(Mlt::Repository* repository, const QString& /*type*/, const QString& filtername)
500 Mlt::Properties *metadata = repository->metadata(filter_type, filtername.toAscii().data());
501 //kDebug() << filtername;
502 if (metadata && metadata->is_valid()) {
503 if (metadata->get("title") && metadata->get("identifier")) {
504 QDomElement eff = ret.createElement("effect");
505 eff.setAttribute("tag", metadata->get("identifier"));
506 eff.setAttribute("id", metadata->get("identifier"));
508 QDomElement name = ret.createElement("name");
509 name.appendChild(ret.createTextNode(metadata->get("title")));
511 QDomElement desc = ret.createElement("description");
512 desc.appendChild(ret.createTextNode(metadata->get("description")));
514 QDomElement author = ret.createElement("author");
515 author.appendChild(ret.createTextNode(metadata->get("creator")));
517 eff.appendChild(name);
518 eff.appendChild(author);
519 eff.appendChild(desc);
521 Mlt::Properties param_props((mlt_properties) metadata->get_data("parameters"));
522 for (int j = 0; param_props.is_valid() && j < param_props.count(); j++) {
523 QDomElement params = ret.createElement("parameter");
525 Mlt::Properties paramdesc((mlt_properties) param_props.get_data(param_props.get_name(j)));
527 params.setAttribute("name", paramdesc.get("identifier"));
529 if (paramdesc.get("maximum")) params.setAttribute("max", paramdesc.get("maximum"));
530 if (paramdesc.get("minimum")) params.setAttribute("min", paramdesc.get("minimum"));
531 if (QString(paramdesc.get("type")) == "integer")
532 params.setAttribute("type", "constant");
533 if (QString(paramdesc.get("type")) == "float") {
534 params.setAttribute("type", "constant");
535 params.setAttribute("factor", "1000");
536 if (paramdesc.get("maximum")) params.setAttribute("max", QString(paramdesc.get("maximum")).toFloat()*1000.0);
537 if (paramdesc.get("minimum")) params.setAttribute("min", QString(paramdesc.get("minimum")).toFloat()*1000.0);
539 if (QString(paramdesc.get("type")) == "boolean")
540 params.setAttribute("type", "bool");
541 if (!QString(paramdesc.get("format")).isEmpty() && QString(paramdesc.get("type")) != "geometry") {
542 params.setAttribute("type", "geometry");
543 params.setAttribute("format", paramdesc.get("format"));
545 if (!QString(paramdesc.get("format")).isEmpty() && QString(paramdesc.get("type")) == "geometry") {
546 params.setAttribute("type", "geometry");
547 //params.setAttribute("format", paramdesc.get("format"));
549 if (paramdesc.get("default")) params.setAttribute("default", paramdesc.get("default"));
550 if (paramdesc.get("value")) {
551 params.setAttribute("value", paramdesc.get("value"));
553 params.setAttribute("value", paramdesc.get("default"));
557 QDomElement pname = ret.createElement("name");
558 pname.appendChild(ret.createTextNode(paramdesc.get("title")));
559 params.appendChild(pname);
561 eff.appendChild(params);
563 ret.appendChild(eff);
569 QTextStream str(&outstr);
571 kDebug() << outstr;*/
575 void initEffects::fillTransitionsList(Mlt::Repository * repository, EffectsList* transitions, QStringList names)
577 // remove transitions that are not implemented
578 int pos = names.indexOf("mix");
579 if (pos != -1) names.takeAt(pos);
580 pos = names.indexOf("region");
581 if (pos != -1) names.takeAt(pos);
582 foreach(const QString &name, names) {
584 QDomElement ktrans = ret.createElement("ktransition");
585 ret.appendChild(ktrans);
587 ktrans.setAttribute("tag", name);
588 QDomElement tname = ret.createElement("name");
590 QDomElement desc = ret.createElement("description");
592 QList<QDomElement> paramList;
593 Mlt::Properties *metadata = repository->metadata(transition_type, name.toAscii().data());
594 //kDebug() << filtername;
595 if (metadata && metadata->is_valid()) {
597 desc.appendChild(ret.createTextNode(metadata->get("description")));
599 Mlt::Properties param_props((mlt_properties) metadata->get_data("parameters"));
600 for (int j = 0; param_props.is_valid() && j < param_props.count(); j++) {
601 QDomElement params = ret.createElement("parameter");
603 Mlt::Properties paramdesc((mlt_properties) param_props.get_data(param_props.get_name(j)));
605 params.setAttribute("name", paramdesc.get("identifier"));
607 if (paramdesc.get("maximum")) params.setAttribute("max", paramdesc.get("maximum"));
608 if (paramdesc.get("minimum")) params.setAttribute("min", paramdesc.get("minimum"));
609 if (QString(paramdesc.get("type")) == "integer") {
610 params.setAttribute("type", "constant");
611 params.setAttribute("factor", "100");
613 if (QString(paramdesc.get("type")) == "boolean")
614 params.setAttribute("type", "bool");
615 if (!QString(paramdesc.get("format")).isEmpty()) {
616 params.setAttribute("type", "complex");
617 params.setAttribute("format", paramdesc.get("format"));
620 if (paramdesc.get("default")) params.setAttribute("default", paramdesc.get("default"));
621 if (paramdesc.get("value")) {
622 params.setAttribute("value", paramdesc.get("value"));
624 params.setAttribute("value", paramdesc.get("default"));
628 QDomElement pname = ret.createElement("name");
629 pname.appendChild(ret.createTextNode(paramdesc.get("title")));
630 params.appendChild(pname);
632 ktrans.appendChild(params);
635 ret.appendChild(ktrans);
636 if (metadata->get("title") && metadata->get("identifier")) {
637 ktrans.setAttribute("tag", name);
638 QDomElement tname = ret.createElement("name");
639 tname.appendChild(ret.createTextNode(metadata->get("title")));
640 ktrans.appendChild(tname);
645 //kDebug() << ret.toString();
647 // Check for Kdenlive installed luma files, add empty string at start for no luma
648 QStringList imagenamelist = QStringList() << i18n("None");
649 QStringList imagefiles = QStringList() << QString();
651 filters << "*.pgm" << "*.png";
653 QStringList customLumas = KGlobal::dirs()->findDirs("appdata", "lumas");
654 foreach(const QString &folder, customLumas) {
655 QStringList filesnames = QDir(folder).entryList(filters, QDir::Files);
656 foreach(const QString &fname, filesnames) {
657 imagenamelist.append(fname);
658 imagefiles.append(folder + '/' + fname);
662 // Check for MLT lumas
663 KUrl folder(mlt_environment("MLT_DATA"));
664 folder.addPath("lumas");
665 folder.addPath(mlt_environment("MLT_NORMALISATION"));
666 QDir lumafolder(folder.path());
667 QStringList filesnames = lumafolder.entryList(filters, QDir::Files);
668 foreach(const QString &fname, filesnames) {
669 imagenamelist.append(fname);
672 imagefiles.append(path.toLocalFile());
675 if (name == "luma") {
676 ktrans.setAttribute("id", name);
677 tname.appendChild(ret.createTextNode("Wipe"));
678 desc.appendChild(ret.createTextNode("Applies a stationary transition between the current and next frames"));
680 paramList.append(quickParameterFill(ret, "Softness", "softness", "double", "0", "0", "100", "", "", "100"));
681 paramList.append(quickParameterFill(ret, "Invert", "invert", "bool", "0", "0", "1"));
682 paramList.append(quickParameterFill(ret, "Image File", "resource", "list", "", "", "", imagefiles.join(","), imagenamelist.join(",")));
683 paramList.append(quickParameterFill(ret, "Reverse Transition", "reverse", "bool", "0", "0", "1"));
684 //thumbnailer.prepareThumbnailsCall(imagelist);
686 } else if (name == "composite") {
687 desc.appendChild(ret.createTextNode("A key-framable alpha-channel compositor for two frames."));
688 paramList.append(quickParameterFill(ret, "Geometry", "geometry", "geometry", "0%,0%:100%x100%:100", "-500;-500;-500;-500;0", "500;500;500;500;100"));
689 paramList.append(quickParameterFill(ret, "Alpha Channel Operation", "operator", "list", "over", "", "", "over,and,or,xor", "over,and,or,xor"));
690 paramList.append(quickParameterFill(ret, "Align", "aligned", "bool", "1", "0", "1"));
691 paramList.append(quickParameterFill(ret, "Fill", "fill", "bool", "0", "0", "1"));
692 paramList.append(quickParameterFill(ret, "Distort", "distort", "bool", "0", "0", "1"));
693 paramList.append(quickParameterFill(ret, "Wipe File", "luma", "list", "", "", "", imagefiles.join(","), imagenamelist.join(",")));
694 paramList.append(quickParameterFill(ret, "Wipe Softness", "softness", "double", "0", "0", "100", "", "", "100"));
695 paramList.append(quickParameterFill(ret, "Wipe Invert", "luma_invert", "bool", "0", "0", "1"));
696 paramList.append(quickParameterFill(ret, "Force Progressive Rendering", "progressive", "bool", "1", "0", "1"));
697 paramList.append(quickParameterFill(ret, "Force Deinterlace Overlay", "deinterlace", "bool", "0", "0", "1"));
698 tname.appendChild(ret.createTextNode("Composite"));
699 ktrans.setAttribute("id", "composite");
701 QDomElement ktrans1 = ret1.createElement("ktransition");
702 ret1.appendChild(ktrans1);
703 ktrans1.setAttribute("tag", name);
704 QDomElement tname1 = ret.createElement("name");
705 tname1.appendChild(ret1.createTextNode("PIP"));*/
707 } else if (name == "mix") {
708 tname.appendChild(ret.createTextNode("Mix"));
709 } else if (name == "affine") {
710 tname.appendChild(ret.createTextNode("Affine"));
711 paramList.append(quickParameterFill(ret, "Rotate Y", "rotate_y", "double", "0", "0", "360"));
712 paramList.append(quickParameterFill(ret, "Rotate X", "rotate_x", "double", "0", "0", "360"));
713 paramList.append(quickParameterFill(ret, "Rotate Z", "rotate_z", "double", "0", "0", "360"));
714 paramList.append(quickParameterFill(ret, "Fix Rotate Y", "fix_rotate_y", "double", "0", "0", "360"));
715 paramList.append(quickParameterFill(ret, "Fix Rotate X", "fix_rotate_x", "double", "0", "0", "360"));
716 paramList.append(quickParameterFill(ret, "Fix Rotate Z", "fix_rotate_z", "double", "0", "0", "360"));
717 paramList.append(quickParameterFill(ret, "Shear Y", "shear_y", "double", "0", "0", "360"));
718 paramList.append(quickParameterFill(ret, "Shear X", "shear_x", "double", "0", "0", "360"));
719 paramList.append(quickParameterFill(ret, "Shear Z", "shear_z", "double", "0", "0", "360"));
720 paramList.append(quickParameterFill(ret, "Fix Shear Y", "fix_shear_y", "double", "0", "0", "360"));
721 paramList.append(quickParameterFill(ret, "Fix Shear X", "fix_shear_x", "double", "0", "0", "360"));
722 paramList.append(quickParameterFill(ret, "Fix Shear Z", "fix_shear_z", "double", "0", "0", "360"));
723 paramList.append(quickParameterFill(ret, "Mirror", "mirror_off", "bool", "0", "0", "1"));
724 paramList.append(quickParameterFill(ret, "Repeat", "repeat_off", "bool", "0", "0", "1"));
725 paramList.append(quickParameterFill(ret, "Geometry", "geometry", "geometry", "0;0;100;100;100", "0;0;100;100;100", "0;0;100;100;100"));
726 tname.appendChild(ret.createTextNode("Composite"));
727 } else if (name == "region") {
728 tname.appendChild(ret.createTextNode("Region"));
734 ktrans.appendChild(tname);
735 ktrans.appendChild(desc);
737 foreach(const QDomElement &e, paramList) {
738 ktrans.appendChild(e);
742 transitions->append(ret.documentElement());
743 //kDebug() << "//// //// TRANSITON XML";
744 //kDebug() << ret.toString();
747 <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" />
751 QString slidetrans = "<ktransition tag=\"composite\" id=\"slide\"><name>Slide</name><description>Slide image from one side to another</description><parameter tag=\"geometry\" type=\"wipe\" default=\"-100%,0%:100%x100%;-1=0%,0%:100%x100%\" name=\"geometry\"><name>Direction</name> </parameter><parameter tag=\"aligned\" default=\"0\" type=\"bool\" name=\"aligned\" ><name>Align</name></parameter><parameter tag=\"progressive\" default=\"1\" type=\"bool\" name=\"progressive\" ><name>Force Progressive Rendering</name></parameter><parameter tag=\"deinterlace\" default=\"0\" type=\"bool\" name=\"deinterlace\" ><name>Force Deinterlace Overlay</name></parameter><parameter tag=\"invert\" default=\"0\" type=\"bool\" name=\"invert\" ><name>Invert</name></parameter></ktransition>";
753 ret.setContent(slidetrans);
754 transitions->append(ret.documentElement());
756 QString dissolve = "<ktransition tag=\"luma\" id=\"dissolve\"><name>Dissolve</name><description>Fade out one video while fading in the other video</description><parameter tag=\"reverse\" default=\"0\" type=\"bool\" name=\"reverse\" ><name>Reverse</name></parameter></ktransition>";
757 QDomDocument dissolveDoc;
758 dissolveDoc.setContent(dissolve);
759 transitions->append(dissolveDoc.documentElement());
761 /*QString alphatrans = "<ktransition tag=\"composite\" id=\"alphatransparency\" ><name>Alpha transparency</name><description>Make alpha channel transparent</description><parameter tag=\"geometry\" type=\"fixed\" default=\"0%,0%:100%x100%\" name=\"geometry\"><name>Direction</name></parameter><parameter tag=\"fill\" default=\"0\" type=\"bool\" name=\"fill\" ><name>Rescale</name></parameter><parameter tag=\"aligned\" default=\"0\" type=\"bool\" name=\"aligned\" ><name>Align</name></parameter></ktransition>";
763 ret2.setContent(alphatrans);
764 transitions->append(ret2.documentElement());*/
767 QDomElement initEffects::quickParameterFill(QDomDocument & doc, QString name, QString tag, QString type, QString def, QString min, QString max, QString list, QString listdisplaynames, QString factor, QString namedesc, QString format)
769 QDomElement parameter = doc.createElement("parameter");
770 parameter.setAttribute("tag", tag);
771 parameter.setAttribute("default", def);
772 parameter.setAttribute("type", type);
773 parameter.setAttribute("name", tag);
774 parameter.setAttribute("max", max);
775 parameter.setAttribute("min", min);
777 parameter.setAttribute("paramlist", list);
778 if (!listdisplaynames.isEmpty())
779 parameter.setAttribute("paramlistdisplay", listdisplaynames);
780 if (!factor.isEmpty())
781 parameter.setAttribute("factor", factor);
782 if (!namedesc.isEmpty())
783 parameter.setAttribute("namedesc", namedesc);
784 if (!format.isEmpty())
785 parameter.setAttribute("format", format);
786 QDomElement pname = doc.createElement("name");
787 pname.appendChild(doc.createTextNode(name));
788 parameter.appendChild(pname);