]> git.sesse.net Git - kdenlive/blob - src/initeffects.cpp
Rename non-frei0r transitions to more common names:
[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
69     // Check for Kdenlive installed luma files, add empty string at start for no luma
70     QStringList imagenamelist = QStringList() << i18n("None");
71     QStringList imagefiles = QStringList() << QString();
72     QStringList filters;
73     filters << "*.pgm" << "*.png";
74
75     QStringList customLumas = KGlobal::dirs()->findDirs("appdata", "lumas");
76     foreach(const QString &folder, customLumas) {
77         QStringList filesnames = QDir(folder).entryList(filters, QDir::Files);
78         foreach(const QString &fname, filesnames) {
79             imagenamelist.append(fname);
80             imagefiles.append(folder + '/' + fname);
81         }
82     }
83
84     // Check for MLT lumas
85     QString folder = mlt_environment("MLT_DATA");
86     folder.append("/lumas/").append(mlt_environment("MLT_NORMALISATION"));
87     QDir lumafolder(folder);
88     QStringList filesnames = lumafolder.entryList(filters, QDir::Files);
89     foreach(const QString &fname, filesnames) {
90         imagenamelist.append(fname);
91         imagefiles.append(folder + '/' + fname);
92     }
93     QDomElement lumaTransition = MainWindow::transitions.getEffectByName("Wipe");
94     QDomNodeList params = lumaTransition.elementsByTagName("parameter");
95     for (int i = 0; i < params.count(); i++) {
96         QDomElement e = params.item(i).toElement();
97         if (e.attribute("tag") == "resource") {
98             e.setAttribute("paramlistdisplay", imagenamelist.join(","));
99             e.setAttribute("paramlist", imagefiles.join(","));
100             break;
101         }
102     }
103
104
105 }
106
107 //static
108 Mlt::Repository *initEffects::parseEffectFiles()
109 {
110     QStringList::Iterator more;
111     QStringList::Iterator it;
112     QStringList fileList;
113     QString itemName;
114
115
116     // Build effects. Retrieve the list of MLT's available effects first.
117     Mlt::Repository *repository = Mlt::Factory::init();
118     if (!repository) {
119         kDebug() << "Repository did not finish init " ;
120         return NULL;
121     }
122     Mlt::Properties *filters = repository->filters();
123     QStringList filtersList;
124
125     // Check for blacklisted effects
126     QString blacklist = KStandardDirs::locate("appdata", "blacklisted_effects.txt");
127
128     QFile file(blacklist);
129     QStringList blackListed;
130
131     if (file.open(QIODevice::ReadOnly)) {
132         QTextStream in(&file);
133         while (!in.atEnd()) {
134             QString black = in.readLine().simplified();
135             if (!black.isEmpty() && !black.startsWith('#')) blackListed.append(black);
136         }
137         file.close();
138     }
139
140     // Check for blacklisted transitions
141     blacklist = KStandardDirs::locate("appdata", "blacklisted_transitions.txt");
142
143     QFile file2(blacklist);
144     QStringList blackListedtransitions;
145
146     if (file2.open(QIODevice::ReadOnly)) {
147         QTextStream in(&file2);
148         while (!in.atEnd()) {
149             QString black = in.readLine().simplified();
150             if (!black.isEmpty() && !black.startsWith('#')) blackListedtransitions.append(black);
151         }
152         file2.close();
153     }
154
155     for (int i = 0 ; i < filters->count() ; i++) {
156         filtersList << filters->get_name(i);
157     }
158
159     // Build effects. check producers first.
160
161     Mlt::Properties *producers = repository->producers();
162     QStringList producersList;
163     for (int i = 0 ; i < producers->count() ; i++) {
164         producersList << producers->get_name(i);
165     }
166     KdenliveSettings::setProducerslist(producersList);
167     delete filters;
168     delete producers;
169
170     Mlt::Properties *transitions = repository->transitions();
171     QStringList transitionsItemList;
172     for (int i = 0 ; i < transitions->count() ; i++) {
173         transitionsItemList << transitions->get_name(i);
174     }
175     delete transitions;
176
177     foreach(const QString &trans, blackListedtransitions) {
178         if (transitionsItemList.contains(trans)) transitionsItemList.removeAll(trans);
179     }
180     fillTransitionsList(repository, &MainWindow::transitions, transitionsItemList);
181
182     KGlobal::dirs()->addResourceType("ladspa_plugin", 0, "lib/ladspa");
183     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/lib/ladspa");
184     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/local/lib/ladspa");
185     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/opt/lib/ladspa");
186     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/opt/local/lib/ladspa");
187     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/lib64/ladspa");
188     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/local/lib64/ladspa");
189
190     kDebug() << "//  INIT EFFECT SEARCH" << endl;
191
192     QStringList direc = KGlobal::dirs()->findDirs("appdata", "effects");
193
194     QDir directory;
195     for (more = direc.begin() ; more != direc.end() ; ++more) {
196         directory = QDir(*more);
197         QStringList filter;
198         filter << "*.xml";
199         fileList = directory.entryList(filter, QDir::Files);
200         for (it = fileList.begin() ; it != fileList.end() ; ++it) {
201             itemName = KUrl(*more + *it).path();
202             parseEffectFile(&MainWindow::customEffects, &MainWindow::audioEffects, &MainWindow::videoEffects, itemName, filtersList, producersList);
203             // kDebug()<<"//  FOUND EFFECT FILE: "<<itemName<<endl;
204         }
205     }
206
207     foreach(const QString &effect, blackListed) {
208         if (filtersList.contains(effect)) filtersList.removeAll(effect);
209     }
210
211     foreach(const QString &filtername, filtersList) {
212         QDomDocument doc = createDescriptionFromMlt(repository, "filters", filtername);
213         if (!doc.isNull())
214             MainWindow::videoEffects.append(doc.documentElement());
215     }
216     return repository;
217 }
218
219 // static
220 void initEffects::parseCustomEffectsFile()
221 {
222     MainWindow::customEffects.clear();
223     QString path = KStandardDirs::locateLocal("appdata", "effects/", true);
224     QDir directory = QDir(path);
225     QStringList filter;
226     filter << "*.xml";
227     const QStringList fileList = directory.entryList(filter, QDir::Files);
228     QString itemName;
229     foreach(const QString &filename, fileList) {
230         itemName = KUrl(path + filename).path();
231         QDomDocument doc;
232         QFile file(itemName);
233         doc.setContent(&file, false);
234         file.close();
235         QDomNodeList effects = doc.elementsByTagName("effect");
236         if (effects.count() != 1) {
237             kDebug() << "More than one effect in file " << itemName << ", NOT SUPPORTED YET";
238         } else {
239             QDomElement e = effects.item(0).toElement();
240             MainWindow::customEffects.append(e);
241         }
242     }
243 }
244
245 // static
246 void initEffects::parseEffectFile(EffectsList *customEffectList, EffectsList *audioEffectList, EffectsList *videoEffectList, QString name, QStringList filtersList, QStringList producersList)
247 {
248     QDomDocument doc;
249     QFile file(name);
250     doc.setContent(&file, false);
251     file.close();
252     QDomElement documentElement = doc.documentElement();
253     QDomNodeList effects = doc.elementsByTagName("effect");
254
255     if (effects.count() == 0) {
256         kDebug() << "// EFFECT FILET: " << name << " IS BROKEN" << endl;
257         return;
258     }
259     QString groupName;
260     if (doc.elementsByTagName("effectgroup").item(0).toElement().tagName() == "effectgroup") {
261         groupName = documentElement.attribute("name", QString());
262     }
263
264     int i = 0;
265
266     while (!effects.item(i).isNull()) {
267         documentElement = effects.item(i).toElement();
268         QString tag = documentElement.attribute("tag", QString());
269         bool ladspaOk = true;
270         if (tag == "ladspa") {
271             QString library = documentElement.attribute("library", QString());
272             if (KStandardDirs::locate("ladspa_plugin", library).isEmpty()) ladspaOk = false;
273         }
274
275         // Parse effect file
276         if ((filtersList.contains(tag) || producersList.contains(tag)) && ladspaOk) {
277             QString type = documentElement.attribute("type", QString());
278             if (type == "audio") audioEffectList->append(documentElement);
279             else if (type == "custom") customEffectList->append(documentElement);
280             else videoEffectList->append(documentElement);
281         }
282
283         /*
284              QDomNode n = documentElement.firstChild();
285          QString id, effectName, effectTag, paramType;
286          int paramCount = 0;
287          EFFECTTYPE type;
288
289                 // Create Effect
290                 EffectParamDescFactory effectDescParamFactory;
291                 EffectDesc *effect = NULL;
292
293          // parse effect file
294          QDomNode namenode = documentElement.elementsByTagName("name").item(0);
295          if (!namenode.isNull()) effectName = i18n(namenode.toElement().text());
296          if (!groupName.isEmpty()) effectName.prepend("_" + groupName + "_");
297
298          QDomNode propsnode = documentElement.elementsByTagName("properties").item(0);
299          if (!propsnode.isNull()) {
300              QDomElement propselement = propsnode.toElement();
301              id = propselement.attribute("id", QString());
302              effectTag = propselement.attribute("tag", QString());
303              if (propselement.attribute("type", QString()) == "audio") type = AUDIOEFFECT;
304              else if (propselement.attribute("type", QString()) == "custom") type = CUSTOMEFFECT;
305              else type = VIDEOEFFECT;
306          }
307
308          QString effectDescription;
309          QDomNode descnode = documentElement.elementsByTagName("description").item(0);
310          if (!descnode.isNull()) effectDescription = descnode.toElement().text() + "<br />";
311
312          QString effectAuthor;
313          QDomNode authnode = documentElement.elementsByTagName("author").item(0);
314          if (!authnode.isNull()) effectAuthor = authnode.toElement().text() + "<br />";
315
316          if (effectName.isEmpty() || id.isEmpty() || effectTag.isEmpty()) return;
317
318          effect = new EffectDesc(effectName, id, effectTag, effectDescription, effectAuthor, type);
319
320          QDomNodeList paramList = documentElement.elementsByTagName("parameter");
321          if (paramList.count() == 0) {
322              QDomElement fixed = doc.createElement("parameter");
323              fixed.setAttribute("type", "fixed");
324              effect->addParameter(effectDescParamFactory.createParameter(fixed));
325          }
326          else for (int i = 0; i < paramList.count(); i++) {
327              QDomElement e = paramList.item(i).toElement();
328              if (!e.isNull()) {
329           paramCount++;
330            QDomNamedNodeMap attrs = e.attributes();
331           int i = 0;
332           QString value;
333           while (!attrs.item(i).isNull()) {
334               QDomNode n = attrs.item(i);
335               value = n.nodeValue();
336               if (value.find("MAX_WIDTH") != -1)
337            value.replace("MAX_WIDTH", QString::number(KdenliveSettings::defaultwidth()));
338               if (value.find("MID_WIDTH") != -1)
339            value.replace("MID_WIDTH", QString::number(KdenliveSettings::defaultwidth() / 2));
340               if (value.find("MAX_HEIGHT") != -1)
341            value.replace("MAX_HEIGHT", QString::number(KdenliveSettings::defaultheight()));
342               if (value.find("MID_HEIGHT") != -1)
343            value.replace("MID_HEIGHT", QString::number(KdenliveSettings::defaultheight() / 2));
344               n.setNodeValue(value);
345               i++;
346           }
347           effect->addParameter(effectDescParamFactory.createParameter(e));
348              }
349          }
350                 effectList->append(effect);
351          }*/
352         i++;
353     }
354 }
355
356 //static
357 const char* initEffects::ladspaEffectString(int ladspaId, QStringList params)
358 {
359     if (ladspaId == 1433)  //Pitch
360         return ladspaPitchEffectString(params);
361     else if (ladspaId == 1216)  //Room Reverb
362         return ladspaRoomReverbEffectString(params);
363     else if (ladspaId == 1423)  //Reverb
364         return ladspaReverbEffectString(params);
365     else if (ladspaId == 1901)  //Reverb
366         return ladspaEqualizerEffectString(params);
367     else {
368         kDebug() << "++++++++++  ASKING FOR UNKNOWN LADSPA EFFECT: " << ladspaId << endl;
369         return "<jackrack></jackrack>";
370     }
371 }
372
373 //static
374 void initEffects::ladspaEffectFile(const QString & fname, int ladspaId, QStringList params)
375 {
376     const char *filterString;
377     switch (ladspaId) {
378     case 1433: //Pitch
379         filterString = ladspaPitchEffectString(params);
380         break;
381     case 1905: //Vinyl
382         filterString = ladspaVinylEffectString(params);
383         break;
384     case 1216 : //Room Reverb
385         filterString = ladspaRoomReverbEffectString(params);
386         break;
387     case 1423: //Reverb
388         filterString = ladspaReverbEffectString(params);
389         break;
390     case 1195: //Declipper
391         filterString = ladspaDeclipEffectString(params);
392         break;
393     case 1901:  //Reverb
394         filterString = ladspaEqualizerEffectString(params);
395         break;
396     case 1913: // Limiter
397         filterString = ladspaLimiterEffectString(params);
398         break;
399     case 1193: // Pitch Shifter
400         filterString = ladspaPitchShifterEffectString(params);
401         break;
402     case 1417: // Rate Scaler
403         filterString = ladspaRateScalerEffectString(params);
404         break;
405     case 1217: // Phaser
406         filterString = ladspaPhaserEffectString(params);
407         break;
408     default:
409         kDebug() << "++++++++++  ASKING FOR UNKNOWN LADSPA EFFECT: " << ladspaId << endl;
410         return;
411         break;
412     }
413
414     QFile f(fname);
415     if (f.open(QIODevice::WriteOnly)) {
416         QTextStream stream(&f);
417         stream << filterString;
418         f.close();
419     } else kDebug() << "++++++++++  ERROR CANNOT WRITE TO: " << KdenliveSettings::currenttmpfolder() +  fname << endl;
420     delete [] filterString;
421 }
422
423 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>";
424
425
426 const char* initEffects::ladspaDeclipEffectString(QStringList)
427 {
428     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());
429 }
430
431 /*
432 const char* initEffects::ladspaVocoderEffectString(QStringList params)
433 {
434  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]));
435 }*/
436
437 const char* initEffects::ladspaVinylEffectString(QStringList params)
438 {
439     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());
440 }
441
442 const char* initEffects::ladspaPitchEffectString(QStringList params)
443 {
444     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());
445 }
446
447 const char* initEffects::ladspaRoomReverbEffectString(QStringList params)
448 {
449     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());
450 }
451
452 const char* initEffects::ladspaReverbEffectString(QStringList params)
453 {
454     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());
455 }
456
457 const char* initEffects::ladspaEqualizerEffectString(QStringList params)
458 {
459     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());
460 }
461
462 const char* initEffects::ladspaLimiterEffectString(QStringList params)
463 {
464     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());
465 }
466
467 const char* initEffects::ladspaPitchShifterEffectString(QStringList params)
468 {
469     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());
470 }
471
472 const char* initEffects::ladspaRateScalerEffectString(QStringList params)
473 {
474     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());
475 }
476
477 const char* initEffects::ladspaPhaserEffectString(QStringList params)
478 {
479     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());
480 }
481
482
483 QDomDocument initEffects::createDescriptionFromMlt(Mlt::Repository* repository, const QString& /*type*/, const QString& filtername)
484 {
485
486     QDomDocument ret;
487     Mlt::Properties *metadata = repository->metadata(filter_type, filtername.toAscii().data());
488     //kDebug() << filtername;
489     if (metadata && metadata->is_valid()) {
490         if (metadata->get("title") && metadata->get("identifier")) {
491             QDomElement eff = ret.createElement("effect");
492             eff.setAttribute("tag", metadata->get("identifier"));
493             eff.setAttribute("id", metadata->get("identifier"));
494
495             QDomElement name = ret.createElement("name");
496             name.appendChild(ret.createTextNode(metadata->get("title")));
497
498             QDomElement desc = ret.createElement("description");
499             desc.appendChild(ret.createTextNode(metadata->get("description")));
500
501             QDomElement author = ret.createElement("author");
502             author.appendChild(ret.createTextNode(metadata->get("creator")));
503
504             eff.appendChild(name);
505             eff.appendChild(author);
506             eff.appendChild(desc);
507
508             Mlt::Properties param_props((mlt_properties) metadata->get_data("parameters"));
509             for (int j = 0; param_props.is_valid() && j < param_props.count();j++) {
510                 QDomElement params = ret.createElement("parameter");
511
512                 Mlt::Properties paramdesc((mlt_properties) param_props.get_data(param_props.get_name(j)));
513
514                 params.setAttribute("name", paramdesc.get("identifier"));
515
516                 if (paramdesc.get("maximum")) params.setAttribute("max", paramdesc.get("maximum"));
517                 if (paramdesc.get("minimum")) params.setAttribute("min", paramdesc.get("minimum"));
518                 if (QString(paramdesc.get("type")) == "integer")
519                     params.setAttribute("type", "constant");
520                 if (QString(paramdesc.get("type")) == "float") {
521                     params.setAttribute("type", "constant");
522                     params.setAttribute("factor", "1000");
523                     if (paramdesc.get("maximum")) params.setAttribute("max", QString(paramdesc.get("maximum")).toFloat()*1000.0);
524                     if (paramdesc.get("minimum")) params.setAttribute("min", QString(paramdesc.get("minimum")).toFloat()*1000.0);
525                 }
526                 if (QString(paramdesc.get("type")) == "boolean")
527                     params.setAttribute("type", "bool");
528                 if (!QString(paramdesc.get("format")).isEmpty() && QString(paramdesc.get("type")) != "geometry") {
529                     params.setAttribute("type", "geometry");
530                     params.setAttribute("format", paramdesc.get("format"));
531                 }
532                 if (!QString(paramdesc.get("format")).isEmpty() && QString(paramdesc.get("type")) == "geometry") {
533                     params.setAttribute("type", "geometry");
534                     //params.setAttribute("format", paramdesc.get("format"));
535                 }
536                 if (paramdesc.get("default")) params.setAttribute("default", paramdesc.get("default"));
537                 if (paramdesc.get("value")) {
538                     params.setAttribute("value", paramdesc.get("value"));
539                 } else {
540                     params.setAttribute("value", paramdesc.get("default"));
541                 }
542
543
544                 QDomElement pname = ret.createElement("name");
545                 pname.appendChild(ret.createTextNode(paramdesc.get("title")));
546                 params.appendChild(pname);
547
548                 eff.appendChild(params);
549             }
550             ret.appendChild(eff);
551         }
552     }
553     delete metadata;
554     metadata = 0;
555     /* QString outstr;
556      QTextStream str(&outstr);
557      ret.save(str, 2);
558      kDebug() << outstr;*/
559     return ret;
560 }
561
562 void initEffects::fillTransitionsList(Mlt::Repository * repository, EffectsList* transitions, QStringList names)
563 {
564     // remove transitions that are not implemented
565     int pos = names.indexOf("mix");
566     if (pos != -1) names.takeAt(pos);
567     pos = names.indexOf("region");
568     if (pos != -1) names.takeAt(pos);
569     foreach(const QString &name, names) {
570         QDomDocument ret;
571         QDomElement ktrans = ret.createElement("ktransition");
572         ret.appendChild(ktrans);
573
574         ktrans.setAttribute("tag", name);
575         QDomElement tname = ret.createElement("name");
576
577         QDomElement desc = ret.createElement("description");
578
579         QList<QDomElement> paramList;
580         Mlt::Properties *metadata = repository->metadata(transition_type, name.toAscii().data());
581         //kDebug() << filtername;
582         if (metadata && metadata->is_valid()) {
583
584             desc.appendChild(ret.createTextNode(metadata->get("description")));
585
586             Mlt::Properties param_props((mlt_properties) metadata->get_data("parameters"));
587             for (int j = 0; param_props.is_valid() && j < param_props.count();j++) {
588                 QDomElement params = ret.createElement("parameter");
589
590                 Mlt::Properties paramdesc((mlt_properties) param_props.get_data(param_props.get_name(j)));
591
592                 params.setAttribute("name", paramdesc.get("identifier"));
593
594                 if (paramdesc.get("maximum")) params.setAttribute("max", paramdesc.get("maximum"));
595                 if (paramdesc.get("minimum")) params.setAttribute("min", paramdesc.get("minimum"));
596                 if (QString(paramdesc.get("type")) == "integer") {
597                     params.setAttribute("type", "constant");
598                     params.setAttribute("factor", "100");
599                 }
600                 if (QString(paramdesc.get("type")) == "boolean")
601                     params.setAttribute("type", "bool");
602                 if (!QString(paramdesc.get("format")).isEmpty()) {
603                     params.setAttribute("type", "complex");
604                     params.setAttribute("format", paramdesc.get("format"));
605
606                 }
607                 if (paramdesc.get("default")) params.setAttribute("default", paramdesc.get("default"));
608                 if (paramdesc.get("value")) {
609                     params.setAttribute("value", paramdesc.get("value"));
610                 } else {
611                     params.setAttribute("value", paramdesc.get("default"));
612                 }
613
614
615                 QDomElement pname = ret.createElement("name");
616                 pname.appendChild(ret.createTextNode(paramdesc.get("title")));
617                 params.appendChild(pname);
618
619                 ktrans.appendChild(params);
620             }
621
622             ret.appendChild(ktrans);
623             if (metadata->get("title") && metadata->get("identifier")) {
624                 ktrans.setAttribute("tag", name);
625                 QDomElement tname = ret.createElement("name");
626                 tname.appendChild(ret.createTextNode(metadata->get("title")));
627                 ktrans.appendChild(tname);
628             }
629
630             delete metadata;
631             metadata = 0;
632             //kDebug() << ret.toString();
633         } else {
634             // Check for Kdenlive installed luma files, add empty string at start for no luma
635             QStringList imagenamelist = QStringList() << i18n("None");
636             QStringList imagefiles = QStringList() << QString();
637             QStringList filters;
638             filters << "*.pgm" << "*.png";
639
640             QStringList customLumas = KGlobal::dirs()->findDirs("appdata", "lumas");
641             foreach(const QString &folder, customLumas) {
642                 QStringList filesnames = QDir(folder).entryList(filters, QDir::Files);
643                 foreach(const QString &fname, filesnames) {
644                     imagenamelist.append(fname);
645                     imagefiles.append(folder + '/' + fname);
646                 }
647             }
648
649             // Check for MLT lumas
650             QString folder = mlt_environment("MLT_DATA");
651             folder.append("/lumas/").append(mlt_environment("MLT_NORMALISATION"));
652             QDir lumafolder(folder);
653             QStringList filesnames = lumafolder.entryList(filters, QDir::Files);
654             foreach(const QString &fname, filesnames) {
655                 imagenamelist.append(fname);
656                 imagefiles.append(folder + '/' + fname);
657             }
658
659             if (name == "luma") {
660
661                 tname.appendChild(ret.createTextNode("Wipe"));
662                 desc.appendChild(ret.createTextNode("Applies a stationary transition between the current and next frames"));
663
664                 paramList.append(quickParameterFill(ret, "Softness", "softness", "double", "0", "0", "100", "", "", "100"));
665                 paramList.append(quickParameterFill(ret, "Invert", "invert", "bool", "0", "0", "1"));
666                 paramList.append(quickParameterFill(ret, "Image File", "resource", "list", "", "", "", imagefiles.join(","), imagenamelist.join(",")));
667                 paramList.append(quickParameterFill(ret, "Reverse Transition", "reverse", "bool", "0", "0", "1"));
668                 //thumbnailer.prepareThumbnailsCall(imagelist);
669
670             } else if (name == "composite") {
671                 desc.appendChild(ret.createTextNode("A key-framable alpha-channel compositor for two frames."));
672                 paramList.append(quickParameterFill(ret, "Geometry", "geometry", "geometry", "0%,0%:100%x100%:100", "-500;-500;-500;-500;0", "500;500;500;500;100"));
673                 paramList.append(quickParameterFill(ret, "Alpha Channel Operation", "operator", "list", "over", "", "", "over,and,or,xor", "over,and,or,xor"));
674                 paramList.append(quickParameterFill(ret, "Align", "aligned", "bool", "1", "0", "1"));
675                 paramList.append(quickParameterFill(ret, "Fill", "fill", "bool", "0", "0", "1"));
676                 paramList.append(quickParameterFill(ret, "Distort", "distort", "bool", "0", "0", "1"));
677                 paramList.append(quickParameterFill(ret, "Wipe File", "luma", "list", "", "", "", imagefiles.join(","), imagenamelist.join(",")));
678                 paramList.append(quickParameterFill(ret, "Wipe Softness", "softness", "double", "0", "0", "100", "", "", "100"));
679                 paramList.append(quickParameterFill(ret, "Wipe Invert", "luma_invert", "bool", "0", "0", "1"));
680                 paramList.append(quickParameterFill(ret, "Force Progressive Rendering", "progressive", "bool", "1", "0", "1"));
681                 paramList.append(quickParameterFill(ret, "Force Deinterlace Overlay", "deinterlace", "bool", "0", "0", "1"));
682                 tname.appendChild(ret.createTextNode("Composite"));
683                 ktrans.setAttribute("id", "composite");
684                 /*QDomDocument ret1;
685                 QDomElement ktrans1 = ret1.createElement("ktransition");
686                 ret1.appendChild(ktrans1);
687                 ktrans1.setAttribute("tag", name);
688                 QDomElement tname1 = ret.createElement("name");
689                 tname1.appendChild(ret1.createTextNode("PIP"));*/
690
691             } else if (name == "mix") {
692                 tname.appendChild(ret.createTextNode("Mix"));
693             } else if (name == "affine") {
694                 tname.appendChild(ret.createTextNode("Affine"));
695                 paramList.append(quickParameterFill(ret, "Rotate Y", "rotate_y", "double", "0", "0", "360"));
696                 paramList.append(quickParameterFill(ret, "Rotate X", "rotate_x", "double", "0", "0", "360"));
697                 paramList.append(quickParameterFill(ret, "Rotate Z", "rotate_z", "double", "0", "0", "360"));
698                 paramList.append(quickParameterFill(ret, "Fix Rotate Y", "fix_rotate_y", "double", "0", "0", "360"));
699                 paramList.append(quickParameterFill(ret, "Fix Rotate X", "fix_rotate_x", "double", "0", "0", "360"));
700                 paramList.append(quickParameterFill(ret, "Fix Rotate Z", "fix_rotate_z", "double", "0", "0", "360"));
701                 paramList.append(quickParameterFill(ret, "Shear Y", "shear_y", "double", "0", "0", "360"));
702                 paramList.append(quickParameterFill(ret, "Shear X", "shear_x", "double", "0", "0", "360"));
703                 paramList.append(quickParameterFill(ret, "Shear Z", "shear_z", "double", "0", "0", "360"));
704                 paramList.append(quickParameterFill(ret, "Fix Shear Y", "fix_shear_y", "double", "0", "0", "360"));
705                 paramList.append(quickParameterFill(ret, "Fix Shear X", "fix_shear_x", "double", "0", "0", "360"));
706                 paramList.append(quickParameterFill(ret, "Fix Shear Z", "fix_shear_z", "double", "0", "0", "360"));
707                 paramList.append(quickParameterFill(ret, "Mirror", "mirror_off", "bool", "0", "0", "1"));
708                 paramList.append(quickParameterFill(ret, "Repeat", "repeat_off", "bool", "0", "0", "1"));
709                 paramList.append(quickParameterFill(ret, "Geometry", "geometry", "geometry",  "0;0;100;100;100", "0;0;100;100;100", "0;0;100;100;100"));
710                 tname.appendChild(ret.createTextNode("Composite"));
711             } else if (name == "region") {
712                 tname.appendChild(ret.createTextNode("Region"));
713             }
714
715
716         }
717
718         ktrans.appendChild(tname);
719         ktrans.appendChild(desc);
720
721         foreach(const QDomElement &e, paramList) {
722             ktrans.appendChild(e);
723         }
724
725
726         transitions->append(ret.documentElement());
727         //kDebug() << "//// ////  TRANSITON XML";
728         // kDebug() << ret.toString();
729         /*
730
731          <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" />
732         */
733     }
734
735     QString wipetrans = "<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></ktransition>";
736     QDomDocument ret;
737     ret.setContent(wipetrans);
738     transitions->append(ret.documentElement());
739
740     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>";
741     QDomDocument dissolveDoc;
742     dissolveDoc.setContent(dissolve);
743     transitions->append(dissolveDoc.documentElement());
744
745     /*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>";
746     QDomDocument ret2;
747     ret2.setContent(alphatrans);
748     transitions->append(ret2.documentElement());*/
749 }
750
751 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)
752 {
753     QDomElement parameter = doc.createElement("parameter");
754     parameter.setAttribute("tag", tag);
755     parameter.setAttribute("default", def);
756     parameter.setAttribute("type", type);
757     parameter.setAttribute("name", tag);
758     parameter.setAttribute("max", max);
759     parameter.setAttribute("min", min);
760     if (!list.isEmpty())
761         parameter.setAttribute("paramlist", list);
762     if (!listdisplaynames.isEmpty())
763         parameter.setAttribute("paramlistdisplay", listdisplaynames);
764     if (!factor.isEmpty())
765         parameter.setAttribute("factor", factor);
766     if (!namedesc.isEmpty())
767         parameter.setAttribute("namedesc", namedesc);
768     if (!format.isEmpty())
769         parameter.setAttribute("format", format);
770     QDomElement pname = doc.createElement("name");
771     pname.appendChild(doc.createTextNode(name));
772     parameter.appendChild(pname);
773
774     return parameter;
775 }