]> git.sesse.net Git - kdenlive/blob - src/initeffects.cpp
30daa7678d0f64edd96f437c2b7de3722a26c7b3
[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
25 #include <KDebug>
26 #include <kglobal.h>
27 #include <KStandardDirs>
28
29 #include "initeffects.h"
30
31 initEffects::initEffects()
32 {
33 }
34
35 initEffects::~initEffects()
36 {
37 }
38
39 //static
40 Mlt::Repository *initEffects::parseEffectFiles(EffectsList *audioEffectList, EffectsList *videoEffectList)
41 {
42     QStringList::Iterator more;
43     QStringList::Iterator it;
44     QStringList fileList;
45     QString itemName;
46
47
48     // Build effects. Retrieve the list of MLT's available effects first.
49     Mlt::Repository *repository = Mlt::Factory::init();
50     if (!repository){
51          kDebug() << "Repository did not finish init " ;
52          return NULL;
53     }
54     Mlt::Properties *filters = repository->filters();
55     QStringList filtersList;
56
57     for (int i=0 ; i <filters->count() ; i++){
58       filtersList << filters->get_name(i);
59     }
60
61     // Build effects. check producers first.
62
63     Mlt::Properties *producers = repository->producers();
64     QStringList producersList;
65     for (int i=0 ; i <producers->count() ; i++){
66       producersList << producers->get_name(i);
67     }
68     delete filters;
69     delete producers;
70
71     KGlobal::dirs()->addResourceType("ladspa_plugin", "lib/ladspa");
72     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/lib/ladspa");
73     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/usr/local/lib/ladspa");
74     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/opt/lib/ladspa");
75     KGlobal::dirs()->addResourceDir("ladspa_plugin", "/opt/local/lib/ladspa");
76
77     kDebug()<<"//  INIT EFFECT SEARCH"<<endl;
78
79     QStringList direc = KGlobal::dirs()->findDirs("data", "kdenlive/effects");
80
81     QDir directory;
82     for ( more = direc.begin() ; more != direc.end() ; ++more ) {
83         directory = QDir(*more);
84         fileList = directory.entryList( QDir::Files );
85         for ( it = fileList.begin() ; it != fileList.end() ; ++it ){
86             itemName = KUrl(*more + *it).path();
87             parseEffectFile(audioEffectList, videoEffectList, itemName, filtersList, producersList);
88             // kDebug()<<"//  FOUND EFFECT FILE: "<<itemName<<endl;
89         }
90     }
91         foreach(QString filtername,filtersList){
92                 QDomDocument doc=createDescriptionFromMlt(repository,"filters",filtername);
93                 if (!doc.isNull())
94                         videoEffectList->append(doc.documentElement());
95         }
96     return repository;
97 }
98
99 // static
100 void initEffects::parseEffectFile(EffectsList *audioEffectList, EffectsList *videoEffectList, QString name, QStringList filtersList, QStringList producersList)
101 {
102     QDomDocument doc;
103     QFile file(name);
104     doc.setContent(&file, false);
105     QDomElement documentElement = doc.documentElement();
106     QDomNodeList effects = doc.elementsByTagName("effect");
107
108     if (effects.count() == 0) {
109         kDebug()<<"// EFFECT FILET: "<<name<<" IS BROKEN"<<endl;
110         return;
111     }
112     QString groupName;
113     if (doc.elementsByTagName("effectgroup").item(0).toElement().tagName() == "effectgroup") {
114         groupName = documentElement.attribute("name", QString::null);
115     }
116
117     int i = 0;
118
119     while (!effects.item(i).isNull()) {
120     documentElement = effects.item(i).toElement();
121     QString tag = documentElement.attribute("tag", QString::null);
122     bool ladspaOk = true;
123     if (tag == "ladspa") {
124         QString library = documentElement.attribute("library", QString::null);
125         if (KStandardDirs::locate("ladspa_plugin", library).isEmpty()) ladspaOk = false;
126     }
127
128     // Parse effect file
129     if ((filtersList.contains(tag) || producersList.contains(tag)) && ladspaOk) {
130         bool isAudioEffect = false;
131         QDomNode propsnode = documentElement.elementsByTagName("properties").item(0);
132         if (!propsnode.isNull()) {
133             QDomElement propselement = propsnode.toElement();
134 //          id = propselement.attribute("id", QString::null);
135 //          effectTag = propselement.attribute("tag", QString::null);
136             if (propselement.attribute("type", QString::null) == "audio") isAudioEffect = true;
137             //else if (propselement.attribute("type", QString::null) == "custom") type = CUSTOMEFFECT;
138             //else type = VIDEOEFFECT;
139         }
140         if (isAudioEffect) audioEffectList->append(documentElement);
141         else videoEffectList->append(documentElement);
142      }
143
144 /*
145         QDomNode n = documentElement.firstChild();
146         QString id, effectName, effectTag, paramType;
147         int paramCount = 0;
148         EFFECTTYPE type;
149
150         // Create Effect
151         EffectParamDescFactory effectDescParamFactory;
152         EffectDesc *effect = NULL;
153
154         // parse effect file
155         QDomNode namenode = documentElement.elementsByTagName("name").item(0);
156         if (!namenode.isNull()) effectName = i18n(namenode.toElement().text());
157         if (!groupName.isEmpty()) effectName.prepend("_" + groupName + "_");
158
159         QDomNode propsnode = documentElement.elementsByTagName("properties").item(0);
160         if (!propsnode.isNull()) {
161             QDomElement propselement = propsnode.toElement();
162             id = propselement.attribute("id", QString::null);
163             effectTag = propselement.attribute("tag", QString::null);
164             if (propselement.attribute("type", QString::null) == "audio") type = AUDIOEFFECT;
165             else if (propselement.attribute("type", QString::null) == "custom") type = CUSTOMEFFECT;
166             else type = VIDEOEFFECT;
167         }
168
169         QString effectDescription;
170         QDomNode descnode = documentElement.elementsByTagName("description").item(0);
171         if (!descnode.isNull()) effectDescription = descnode.toElement().text() + "<br />";
172
173         QString effectAuthor;
174         QDomNode authnode = documentElement.elementsByTagName("author").item(0);
175         if (!authnode.isNull()) effectAuthor = authnode.toElement().text() + "<br />";
176
177         if (effectName.isEmpty() || id.isEmpty() || effectTag.isEmpty()) return;
178
179         effect = new EffectDesc(effectName, id, effectTag, effectDescription, effectAuthor, type);
180
181         QDomNodeList paramList = documentElement.elementsByTagName("parameter");
182         if (paramList.count() == 0) {
183             QDomElement fixed = doc.createElement("parameter");
184             fixed.setAttribute("type", "fixed");
185             effect->addParameter(effectDescParamFactory.createParameter(fixed));
186         }
187         else for (int i = 0; i < paramList.count(); i++) {
188             QDomElement e = paramList.item(i).toElement();
189             if (!e.isNull()) {
190                 paramCount++;
191                 QDomNamedNodeMap attrs = e.attributes();
192                 int i = 0;
193                 QString value;
194                 while (!attrs.item(i).isNull()) {
195                     QDomNode n = attrs.item(i);
196                     value = n.nodeValue();
197                     if (value.find("MAX_WIDTH") != -1)
198                         value.replace("MAX_WIDTH", QString::number(KdenliveSettings::defaultwidth()));
199                     if (value.find("MID_WIDTH") != -1)
200                         value.replace("MID_WIDTH", QString::number(KdenliveSettings::defaultwidth() / 2));
201                     if (value.find("MAX_HEIGHT") != -1)
202                         value.replace("MAX_HEIGHT", QString::number(KdenliveSettings::defaultheight()));
203                     if (value.find("MID_HEIGHT") != -1)
204                         value.replace("MID_HEIGHT", QString::number(KdenliveSettings::defaultheight() / 2));
205                     n.setNodeValue(value);
206                     i++;
207                 }
208                 effect->addParameter(effectDescParamFactory.createParameter(e));
209             }
210         }
211         effectList->append(effect);
212         }*/
213         i++;
214     }
215 }
216
217 //static 
218 char* initEffects::ladspaEffectString(int ladspaId, QStringList params)
219 {
220     if (ladspaId == 1433 ) //Pitch
221         return ladspaPitchEffectString(params);
222     else if (ladspaId == 1216 ) //Room Reverb
223         return ladspaRoomReverbEffectString(params);
224     else if (ladspaId == 1423 ) //Reverb
225         return ladspaReverbEffectString(params);
226     else if (ladspaId == 1901 ) //Reverb
227         return ladspaEqualizerEffectString(params);
228     else {
229         kDebug()<<"++++++++++  ASKING FOR UNKNOWN LADSPA EFFECT: "<<ladspaId<<endl;
230         return("<jackrack></jackrack>");
231     }
232 }
233
234 //static 
235 void initEffects::ladspaEffectFile(const QString & fname, int ladspaId, QStringList params)
236 {
237     char *filterString;
238     switch (ladspaId) {
239     case 1433: //Pitch
240         filterString = ladspaPitchEffectString(params);
241         break;
242     case 1905: //Vinyl
243         filterString = ladspaVinylEffectString(params);
244         break;
245     case 1216 : //Room Reverb
246         filterString = ladspaRoomReverbEffectString(params);
247         break;
248     case 1423: //Reverb
249         filterString = ladspaReverbEffectString(params);
250         break;
251     case 1195: //Declipper
252         filterString = ladspaDeclipEffectString(params);
253         break;
254     case 1901:  //Reverb
255         filterString = ladspaEqualizerEffectString(params);
256         break;
257     case 1913: // Limiter
258         filterString = ladspaLimiterEffectString(params);
259         break;
260     case 1193: // Pitch Shifter
261         filterString = ladspaPitchShifterEffectString(params);
262         break;
263     case 1417: // Rate Scaler
264         filterString = ladspaRateScalerEffectString(params);
265         break;
266     case 1217: // Phaser
267         filterString = ladspaPhaserEffectString(params);
268         break;
269     default: 
270         kDebug()<<"++++++++++  ASKING FOR UNKNOWN LADSPA EFFECT: "<<ladspaId<<endl;
271         return;
272         break;
273     }
274
275         QFile f( fname );
276         if ( f.open( QIODevice::WriteOnly ) ) 
277         {
278                 QTextStream stream( &f );
279                 stream << filterString;
280                 f.close();
281         }
282         else kDebug()<<"++++++++++  ERROR CANNOT WRITE TO: "<<KdenliveSettings::currenttmpfolder() +  fname<<endl;
283         delete filterString;
284 }
285
286 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>";
287
288
289 char* initEffects::ladspaDeclipEffectString(QStringList)
290 {
291   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());
292 }
293
294 /*
295 char* initEffects::ladspaVocoderEffectString(QStringList params)
296 {
297         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]));
298 }*/
299
300 char* initEffects::ladspaVinylEffectString(QStringList params)
301 {
302         return qstrdup( QString(jackString + "1905</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><controlrow><value>%1</value></controlrow><controlrow><value>%2</value></controlrow><controlrow><value>%3</value></controlrow><controlrow><value>%4</value></controlrow><controlrow><value>%5</value></controlrow></plugin></jackrack>").arg(params[0]).arg(params[1]).arg(params[2]).arg(params[3]).arg(params[4]).toUtf8());
303 }
304
305 char* initEffects::ladspaPitchEffectString(QStringList params)
306 {
307         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());
308 }
309
310 char* initEffects::ladspaRoomReverbEffectString(QStringList params)
311 {
312         return qstrdup( QString(jackString + "1216</id><enabled>true</enabled><wet_dry_enabled>false</wet_dry_enabled><wet_dry_locked>true</wet_dry_locked><wet_dry_values><value>1.000000</value><value>1.000000</value></wet_dry_values><lockall>true</lockall><controlrow><lock>true</lock><value>%1</value><value>%1</value></controlrow><controlrow><lock>true</lock><value>%2</value><value>%2</value></controlrow><controlrow><lock>true</lock><value>%3</value><value>%3</value></controlrow><controlrow><lock>true</lock><value>0.750000</value><value>0.750000</value></controlrow><controlrow><lock>true</lock><value>-70.000000</value><value>-70.000000</value></controlrow><controlrow><lock>true</lock><value>0.000000</value><value>0.000000</value></controlrow><controlrow><lock>true</lock><value>-17.500000</value><value>-17.500000</value></controlrow></plugin></jackrack>").arg(params[0]).arg(params[1]).arg(params[2]).toUtf8());
313 }
314
315 char* initEffects::ladspaReverbEffectString(QStringList params)
316 {
317         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());
318 }
319
320 char* initEffects::ladspaEqualizerEffectString(QStringList params)
321 {
322         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());
323 }
324
325 char* initEffects::ladspaLimiterEffectString(QStringList params)
326 {
327         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());
328 }
329
330 char* initEffects::ladspaPitchShifterEffectString(QStringList params)
331 {
332         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());
333 }
334
335 char* initEffects::ladspaRateScalerEffectString(QStringList params)
336 {
337         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());
338 }
339
340 char* initEffects::ladspaPhaserEffectString(QStringList params)
341 {
342         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());
343 }
344
345
346 QDomDocument initEffects::createDescriptionFromMlt(Mlt::Repository* repository, const QString& type, const QString& filtername){
347         
348         QDomDocument ret;
349         Mlt::Properties *metadata=repository->metadata(filter_type,filtername.toAscii().data());
350         kDebug() << filtername;
351         if (metadata && metadata->is_valid()){
352                 if (metadata->get("title") && metadata->get("identifier")){
353                         QDomElement eff=ret.createElement("effect");
354                         eff.setAttribute("tag",metadata->get("identifier"));
355                         
356                         QDomElement name=ret.createElement("name");
357                         name.appendChild(ret.createTextNode(metadata->get("title")));
358
359                         QDomElement desc=ret.createElement("description");
360                         desc.appendChild(ret.createTextNode(metadata->get("description")));
361                         
362                         QDomElement author=ret.createElement("author");
363                         author.appendChild(ret.createTextNode(metadata->get("creator")));
364                         
365                         QDomElement prop=ret.createElement("properties");
366                         prop.setAttribute("id",metadata->get("identifier"));
367                         prop.setAttribute("tag",metadata->get("identifier"));
368                         eff.appendChild(name);
369                         eff.appendChild(author);
370                         eff.appendChild(desc);
371                         eff.appendChild(prop);
372                         
373                         Mlt::Properties param_props( (mlt_properties) metadata->get_data("parameters") );
374                         for (int j=0; param_props.is_valid() && j<param_props.count();j++){
375                                 QDomElement params=ret.createElement("parameter");
376                                 
377                                 Mlt::Properties paramdesc ( (mlt_properties) param_props.get_data(param_props.get_name(j)));
378                                 
379                                 params.setAttribute("name", paramdesc.get("identifier") );
380                                 
381                                 if (paramdesc.get("maximum") ) params.setAttribute("max",paramdesc.get("maximum"));
382                                 if (paramdesc.get("minimum") ) params.setAttribute("min",paramdesc.get("minimum"));
383                                 if (QString(paramdesc.get("type"))=="integer" )
384                                         params.setAttribute("type","constant");
385                                 if (QString(paramdesc.get("type"))=="boolean" )
386                                         params.setAttribute("type","bool");
387                                 if (!QString(paramdesc.get("format")).isEmpty()){
388                                         params.setAttribute("type","complex");
389                                         params.setAttribute("format",paramdesc.get("format"));
390                                 }
391                                 if (paramdesc.get("default") ) params.setAttribute("default",paramdesc.get("default"));
392                                 if (paramdesc.get("value") ){ 
393                                         params.setAttribute("value",paramdesc.get("value"));
394                                 }else{
395                                         params.setAttribute("value",paramdesc.get("default"));
396                                 }
397                                 
398                                 
399                                 QDomElement pname=ret.createElement("name");
400                                 pname.appendChild(ret.createTextNode(paramdesc.get("title")));
401                                 params.appendChild(pname);
402                                 
403                                 eff.appendChild(params);
404                         }
405                         ret.appendChild(eff);
406                 }
407         }
408         QString outstr;
409         QTextStream str(&outstr);
410         ret.save(str,2);
411         kDebug() << outstr;
412         return ret;
413 }
414