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