]> git.sesse.net Git - kdenlive/blob - src/initeffects.cpp
Add XML files for frei0r contrast0r and brightness effects so that we have correct...
[kdenlive] / src / initeffects.cpp
1 /***************************************************************************
2                           initeffects.cpp  -  description
3                              -------------------
4     begin                :  Jul 2006
5     copyright            : (C) 2006 by Jean-Baptiste Mardelle
6     email                : jb@ader.ch
7     copyright            : (C) 2008 Marco Gittler
8     email                : g.marco@freenet.de
9  ***************************************************************************/
10
11 /***************************************************************************
12  *                                                                         *
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.                                   *
17  *                                                                         *
18  ***************************************************************************/
19
20 #include "initeffects.h"
21 #include "kdenlivesettings.h"
22 #include "effectslist.h"
23 #include "effectstackedit.h"
24 #include "mainwindow.h"
25
26 #include <KDebug>
27 #include <kglobal.h>
28 #include <KStandardDirs>
29
30 #include <QFile>
31 #include <qregexp.h>
32 #include <QDir>
33 #include <QIcon>
34
35 initEffectsThumbnailer::initEffectsThumbnailer() :
36         QThread()
37 {
38
39 }
40
41 void initEffectsThumbnailer::prepareThumbnailsCall(const QStringList& list)
42 {
43     m_list = list;
44     start();
45     kDebug() << "done";
46 }
47
48 void initEffectsThumbnailer::run()
49 {
50     foreach(const QString &entry, m_list) {
51         kDebug() << entry;
52         if (!entry.isEmpty() && (entry.endsWith(".png") || entry.endsWith(".pgm"))) {
53             if (!EffectStackEdit::iconCache.contains(entry)) {
54                 QImage pix(entry);
55                 //if (!pix.isNull())
56                 EffectStackEdit::iconCache[entry] = pix.scaled(30, 30);
57                 kDebug() << "stored";
58             }
59         }
60     }
61 }
62
63 initEffectsThumbnailer initEffects::thumbnailer;
64
65 // static
66 void initEffects::refreshLumas()
67 {
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();
71     QStringList filters;
72     filters << "*.pgm" << "*.png";
73
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);
80         }
81     }
82
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);
91         KUrl path(folder);
92         path.addPath(fname);
93         imagefiles.append(path.toLocalFile());
94     }
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(","));
102             break;
103         }
104     }
105
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(","));
113             break;
114         }
115     }
116
117
118 }
119
120 //static
121 Mlt::Repository *initEffects::parseEffectFiles()
122 {
123     QStringList::Iterator more;
124     QStringList::Iterator it;
125     QStringList fileList;
126     QString itemName;
127
128
129     // Build effects. Retrieve the list of MLT's available effects first.
130     Mlt::Repository *repository = Mlt::Factory::init();
131     if (!repository) {
132         kDebug() << "Repository did not finish init " ;
133         return NULL;
134     }
135     Mlt::Properties *filters = repository->filters();
136     QStringList filtersList;
137
138     // Check for blacklisted effects
139     QString blacklist = KStandardDirs::locate("appdata", "blacklisted_effects.txt");
140
141     QFile file(blacklist);
142     QStringList blackListed;
143
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);
149         }
150         file.close();
151     }
152
153     // Check for blacklisted transitions
154     blacklist = KStandardDirs::locate("appdata", "blacklisted_transitions.txt");
155
156     QFile file2(blacklist);
157     QStringList blackListedtransitions;
158
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);
164         }
165         file2.close();
166     }
167
168     for (int i = 0 ; i < filters->count() ; i++) {
169         filtersList << filters->get_name(i);
170     }
171
172     // Build effects. check producers first.
173
174     Mlt::Properties *producers = repository->producers();
175     QStringList producersList;
176     for (int i = 0 ; i < producers->count() ; i++) {
177         producersList << producers->get_name(i);
178     }
179     KdenliveSettings::setProducerslist(producersList);
180     delete filters;
181     delete producers;
182
183     Mlt::Properties *transitions = repository->transitions();
184     QStringList transitionsItemList;
185     for (int i = 0 ; i < transitions->count() ; i++) {
186         transitionsItemList << transitions->get_name(i);
187     }
188     delete transitions;
189
190     foreach(const QString &trans, blackListedtransitions) {
191         if (transitionsItemList.contains(trans)) transitionsItemList.removeAll(trans);
192     }
193     fillTransitionsList(repository, &MainWindow::transitions, transitionsItemList);
194
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");
202
203     kDebug() << "//  INIT EFFECT SEARCH" << endl;
204
205     QStringList direc = KGlobal::dirs()->findDirs("appdata", "effects");
206
207     QDir directory;
208     for (more = direc.begin() ; more != direc.end() ; ++more) {
209         directory = QDir(*more);
210         QStringList filter;
211         filter << "*.xml";
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;
217         }
218     }
219
220     foreach(const QString &effect, blackListed) {
221         if (filtersList.contains(effect)) filtersList.removeAll(effect);
222     }
223
224     foreach(const QString &filtername, filtersList) {
225         QDomDocument doc = createDescriptionFromMlt(repository, "filters", filtername);
226         if (!doc.isNull())
227             MainWindow::videoEffects.append(doc.documentElement());
228     }
229     return repository;
230 }
231
232 // static
233 void initEffects::parseCustomEffectsFile()
234 {
235     MainWindow::customEffects.clear();
236     QString path = KStandardDirs::locateLocal("appdata", "effects/", true);
237     QDir directory = QDir(path);
238     QStringList filter;
239     filter << "*.xml";
240     const QStringList fileList = directory.entryList(filter, QDir::Files);
241     QString itemName;
242     foreach(const QString &filename, fileList) {
243         itemName = KUrl(path + filename).path();
244         QDomDocument doc;
245         QFile file(itemName);
246         doc.setContent(&file, false);
247         file.close();
248         QDomNodeList effects = doc.elementsByTagName("effect");
249         if (effects.count() != 1) {
250             kDebug() << "More than one effect in file " << itemName << ", NOT SUPPORTED YET";
251         } else {
252             QDomElement e = effects.item(0).toElement();
253             MainWindow::customEffects.append(e);
254         }
255     }
256 }
257
258 // static
259 void initEffects::parseEffectFile(EffectsList *customEffectList, EffectsList *audioEffectList, EffectsList *videoEffectList, QString name, QStringList filtersList, QStringList producersList)
260 {
261     QDomDocument doc;
262     QFile file(name);
263     doc.setContent(&file, false);
264     file.close();
265     QDomElement documentElement = doc.documentElement();
266     QDomNodeList effects = doc.elementsByTagName("effect");
267
268     if (effects.count() == 0) {
269         kDebug() << "// EFFECT FILET: " << name << " IS BROKEN" << endl;
270         return;
271     }
272     QString groupName;
273     if (doc.elementsByTagName("effectgroup").item(0).toElement().tagName() == "effectgroup") {
274         groupName = documentElement.attribute("name", QString());
275     }
276
277     int i = 0;
278
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;
286         }
287
288         // Parse effect file
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);
294         }
295
296         /*
297              QDomNode n = documentElement.firstChild();
298          QString id, effectName, effectTag, paramType;
299          int paramCount = 0;
300          EFFECTTYPE type;
301
302                 // Create Effect
303                 EffectParamDescFactory effectDescParamFactory;
304                 EffectDesc *effect = NULL;
305
306          // parse effect file
307          QDomNode namenode = documentElement.elementsByTagName("name").item(0);
308          if (!namenode.isNull()) effectName = i18n(namenode.toElement().text());
309          if (!groupName.isEmpty()) effectName.prepend("_" + groupName + "_");
310
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;
319          }
320
321          QString effectDescription;
322          QDomNode descnode = documentElement.elementsByTagName("description").item(0);
323          if (!descnode.isNull()) effectDescription = descnode.toElement().text() + "<br />";
324
325          QString effectAuthor;
326          QDomNode authnode = documentElement.elementsByTagName("author").item(0);
327          if (!authnode.isNull()) effectAuthor = authnode.toElement().text() + "<br />";
328
329          if (effectName.isEmpty() || id.isEmpty() || effectTag.isEmpty()) return;
330
331          effect = new EffectDesc(effectName, id, effectTag, effectDescription, effectAuthor, type);
332
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));
338          }
339          else for (int i = 0; i < paramList.count(); i++) {
340              QDomElement e = paramList.item(i).toElement();
341              if (!e.isNull()) {
342           paramCount++;
343            QDomNamedNodeMap attrs = e.attributes();
344           int i = 0;
345           QString value;
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);
358               i++;
359           }
360           effect->addParameter(effectDescParamFactory.createParameter(e));
361              }
362          }
363                 effectList->append(effect);
364          }*/
365         i++;
366     }
367 }
368
369 //static
370 const char* initEffects::ladspaEffectString(int ladspaId, QStringList params)
371 {
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);
380     else {
381         kDebug() << "++++++++++  ASKING FOR UNKNOWN LADSPA EFFECT: " << ladspaId << endl;
382         return "<jackrack></jackrack>";
383     }
384 }
385
386 //static
387 void initEffects::ladspaEffectFile(const QString & fname, int ladspaId, QStringList params)
388 {
389     const char *filterString;
390     switch (ladspaId) {
391     case 1433: //Pitch
392         filterString = ladspaPitchEffectString(params);
393         break;
394     case 1905: //Vinyl
395         filterString = ladspaVinylEffectString(params);
396         break;
397     case 1216 : //Room Reverb
398         filterString = ladspaRoomReverbEffectString(params);
399         break;
400     case 1423: //Reverb
401         filterString = ladspaReverbEffectString(params);
402         break;
403     case 1195: //Declipper
404         filterString = ladspaDeclipEffectString(params);
405         break;
406     case 1901:  //Reverb
407         filterString = ladspaEqualizerEffectString(params);
408         break;
409     case 1913: // Limiter
410         filterString = ladspaLimiterEffectString(params);
411         break;
412     case 1193: // Pitch Shifter
413         filterString = ladspaPitchShifterEffectString(params);
414         break;
415     case 1417: // Rate Scaler
416         filterString = ladspaRateScalerEffectString(params);
417         break;
418     case 1217: // Phaser
419         filterString = ladspaPhaserEffectString(params);
420         break;
421     default:
422         kDebug() << "++++++++++  ASKING FOR UNKNOWN LADSPA EFFECT: " << ladspaId << endl;
423         return;
424         break;
425     }
426
427     QFile f(fname);
428     if (f.open(QIODevice::WriteOnly)) {
429         QTextStream stream(&f);
430         stream << filterString;
431         f.close();
432     } else kDebug() << "++++++++++  ERROR CANNOT WRITE TO: " << KdenliveSettings::currenttmpfolder() +  fname << endl;
433     delete [] filterString;
434 }
435
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>";
437
438
439 const char* initEffects::ladspaDeclipEffectString(QStringList)
440 {
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());
442 }
443
444 /*
445 const char* initEffects::ladspaVocoderEffectString(QStringList params)
446 {
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]));
448 }*/
449
450 const char* initEffects::ladspaVinylEffectString(QStringList params)
451 {
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());
453 }
454
455 const char* initEffects::ladspaPitchEffectString(QStringList params)
456 {
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());
458 }
459
460 const char* initEffects::ladspaRoomReverbEffectString(QStringList params)
461 {
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());
463 }
464
465 const char* initEffects::ladspaReverbEffectString(QStringList params)
466 {
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());
468 }
469
470 const char* initEffects::ladspaEqualizerEffectString(QStringList params)
471 {
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());
473 }
474
475 const char* initEffects::ladspaLimiterEffectString(QStringList params)
476 {
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());
478 }
479
480 const char* initEffects::ladspaPitchShifterEffectString(QStringList params)
481 {
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());
483 }
484
485 const char* initEffects::ladspaRateScalerEffectString(QStringList params)
486 {
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());
488 }
489
490 const char* initEffects::ladspaPhaserEffectString(QStringList params)
491 {
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());
493 }
494
495
496 QDomDocument initEffects::createDescriptionFromMlt(Mlt::Repository* repository, const QString& /*type*/, const QString& filtername)
497 {
498
499     QDomDocument ret;
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"));
507
508             QDomElement name = ret.createElement("name");
509             name.appendChild(ret.createTextNode(metadata->get("title")));
510
511             QDomElement desc = ret.createElement("description");
512             desc.appendChild(ret.createTextNode(metadata->get("description")));
513
514             QDomElement author = ret.createElement("author");
515             author.appendChild(ret.createTextNode(metadata->get("creator")));
516
517             eff.appendChild(name);
518             eff.appendChild(author);
519             eff.appendChild(desc);
520
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");
524
525                 Mlt::Properties paramdesc((mlt_properties) param_props.get_data(param_props.get_name(j)));
526
527                 params.setAttribute("name", paramdesc.get("identifier"));
528
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);
538                 }
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"));
544                 }
545                 if (!QString(paramdesc.get("format")).isEmpty() && QString(paramdesc.get("type")) == "geometry") {
546                     params.setAttribute("type", "geometry");
547                     //params.setAttribute("format", paramdesc.get("format"));
548                 }
549                 if (paramdesc.get("default")) params.setAttribute("default", paramdesc.get("default"));
550                 if (paramdesc.get("value")) {
551                     params.setAttribute("value", paramdesc.get("value"));
552                 } else {
553                     params.setAttribute("value", paramdesc.get("default"));
554                 }
555
556
557                 QDomElement pname = ret.createElement("name");
558                 pname.appendChild(ret.createTextNode(paramdesc.get("title")));
559                 params.appendChild(pname);
560
561                 eff.appendChild(params);
562             }
563             ret.appendChild(eff);
564         }
565     }
566     delete metadata;
567     metadata = 0;
568     /* QString outstr;
569      QTextStream str(&outstr);
570      ret.save(str, 2);
571      kDebug() << outstr;*/
572     return ret;
573 }
574
575 void initEffects::fillTransitionsList(Mlt::Repository * repository, EffectsList* transitions, QStringList names)
576 {
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) {
583         QDomDocument ret;
584         QDomElement ktrans = ret.createElement("ktransition");
585         ret.appendChild(ktrans);
586
587         ktrans.setAttribute("tag", name);
588         QDomElement tname = ret.createElement("name");
589
590         QDomElement desc = ret.createElement("description");
591
592         QList<QDomElement> paramList;
593         Mlt::Properties *metadata = repository->metadata(transition_type, name.toAscii().data());
594         //kDebug() << filtername;
595         if (metadata && metadata->is_valid()) {
596
597             desc.appendChild(ret.createTextNode(metadata->get("description")));
598
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");
602
603                 Mlt::Properties paramdesc((mlt_properties) param_props.get_data(param_props.get_name(j)));
604
605                 params.setAttribute("name", paramdesc.get("identifier"));
606
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");
612                 }
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"));
618
619                 }
620                 if (paramdesc.get("default")) params.setAttribute("default", paramdesc.get("default"));
621                 if (paramdesc.get("value")) {
622                     params.setAttribute("value", paramdesc.get("value"));
623                 } else {
624                     params.setAttribute("value", paramdesc.get("default"));
625                 }
626
627
628                 QDomElement pname = ret.createElement("name");
629                 pname.appendChild(ret.createTextNode(paramdesc.get("title")));
630                 params.appendChild(pname);
631
632                 ktrans.appendChild(params);
633             }
634
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);
641             }
642
643             delete metadata;
644             metadata = 0;
645             //kDebug() << ret.toString();
646         } else {
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();
650             QStringList filters;
651             filters << "*.pgm" << "*.png";
652
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);
659                 }
660             }
661
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);
670                 KUrl path(folder);
671                 path.addPath(fname);
672                 imagefiles.append(path.toLocalFile());
673             }
674
675             if (name == "luma") {
676                 ktrans.setAttribute("id", "luma");
677                 tname.appendChild(ret.createTextNode("Wipe"));
678                 desc.appendChild(ret.createTextNode("Applies a stationary transition between the current and next frames"));
679
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);
685
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");
700                 /*QDomDocument ret1;
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"));*/
706
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"));
729             }
730
731
732         }
733
734         ktrans.appendChild(tname);
735         ktrans.appendChild(desc);
736
737         foreach(const QDomElement &e, paramList) {
738             ktrans.appendChild(e);
739         }
740
741
742         transitions->append(ret.documentElement());
743         //kDebug() << "//// ////  TRANSITON XML";
744         //kDebug() << ret.toString();
745         /*
746
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" />
748         */
749     }
750
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>";
752     QDomDocument ret;
753     ret.setContent(slidetrans);
754     transitions->append(ret.documentElement());
755
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());
760
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>";
762     QDomDocument ret2;
763     ret2.setContent(alphatrans);
764     transitions->append(ret2.documentElement());*/
765 }
766
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)
768 {
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);
776     if (!list.isEmpty())
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);
789
790     return parameter;
791 }