]> git.sesse.net Git - kdenlive/commitdiff
Freesound.org integration (in progress)
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Thu, 29 Dec 2011 22:00:20 +0000 (23:00 +0100)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Thu, 29 Dec 2011 22:00:20 +0000 (23:00 +0100)
You can now easily search and import audio clips

src/CMakeLists.txt
src/kdenliveui.rc
src/mainwindow.cpp
src/mainwindow.h
src/utils/CMakeLists.txt [new file with mode: 0644]
src/utils/freesound.cpp [new file with mode: 0644]
src/utils/freesound.h [new file with mode: 0644]
src/widgets/freesound_ui.ui [new file with mode: 0644]

index 351157de45ead8c3545b2e9ccf674e24096cbadb..f39ee5c9f53390d8f3de922afa5bb40bbf5f6dc9 100644 (file)
@@ -79,6 +79,7 @@ add_subdirectory(colorcorrection)
 add_subdirectory(colorscopes)
 add_subdirectory(commands)
 add_subdirectory(projecttree)
+add_subdirectory(utils)
 add_subdirectory(databackup)
 add_subdirectory(kiss_fft)
 add_subdirectory(mimetypes)
@@ -214,6 +215,7 @@ kde4_add_ui_files(kdenlive_UIS
   widgets/dvdwizardvob_ui.ui
   widgets/effectlist_ui.ui
   widgets/effectstack_ui.ui
+  widgets/freesound_ui.ui
   widgets/geometryval_ui.ui
   widgets/geometrywidget_ui.ui
   widgets/histogram_ui.ui
index b48fb4e723068ee7ae75358ba9e0d4f17db38000..207cb45c90b81f4533b0317d530226f26f99c6be 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<gui name="kdenlive" version="66">
+<gui name="kdenlive" version="67">
   <ToolBar name="extraToolBar" >
     <text>Extra Toolbar</text>
        <Action name="project_render" />
@@ -25,6 +25,7 @@
       <Action name="add_text_clip" />
       <Action name="add_text_template_clip" />
       <Action name="add_folder" /> 
+      <Action name="download_audio" /> 
       <Menu name="extract_audio" ><text>Extract Audio</text>
       </Menu>
       <Menu name="stabilize" ><text>Stabilize</text>
index 72d3897eda9c5ac151461f3afd46567c3ed8f9ff..460cff92619027e7e3dc0e7137b7b96927b6ba76 100644 (file)
@@ -64,6 +64,7 @@
 #include "audioscopes/spectrogram.h"
 #include "archivewidget.h"
 #include "databackup/backupwidget.h"
+#include "utils/freesound.h"
 
 
 #include <KApplication>
@@ -1638,6 +1639,10 @@ void MainWindow::setupActions()
     QAction *addFolderButton = new KAction(KIcon("folder-new"), i18n("Create Folder"), this);
     collection.addAction("add_folder", addFolderButton);
     connect(addFolderButton , SIGNAL(triggered()), m_projectList, SLOT(slotAddFolder()));
+    
+    QAction *downloadAudio = new KAction(KIcon("download"), i18n("Download Audio"), this);
+    collection.addAction("download_audio", downloadAudio);
+    connect(downloadAudio , SIGNAL(triggered()), this, SLOT(slotDownloadAudio()));
 
     QAction *clipProperties = new KAction(KIcon("document-edit"), i18n("Clip Properties"), this);
     collection.addAction("clip_properties", clipProperties);
@@ -4497,6 +4502,16 @@ void MainWindow::slotElapsedTime()
 }
 
 
+void MainWindow::slotDownloadAudio()
+{
+    QString currentFolder;
+    if (m_activeDocument) currentFolder = m_activeDocument->projectFolder().path();
+    else currentFolder = KdenliveSettings::defaultprojectfolder();
+    FreeSound *d = new FreeSound(currentFolder);
+    connect(d, SIGNAL(addClip(KUrl)), this, SLOT(slotAddProjectClip(KUrl)));
+    d->show();
+}
+
 #include "mainwindow.moc"
 
 #ifdef DEBUG_MAINW
index 2f9484e6b7be98867479bfe54250f8ce416db5c2..8b5f4c60fc11bf8e60bc04417600344d8202eb83 100644 (file)
@@ -550,6 +550,8 @@ private slots:
     void slotDisableProxies();
 
     void slotElapsedTime();
+    /** @brief Open the freesound audio search dialog. */
+    void slotDownloadAudio();
 
 signals:
     Q_SCRIPTABLE void abortRenderJob(const QString &url);
diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f420ed4
--- /dev/null
@@ -0,0 +1,5 @@
+set(kdenlive_SRCS
+  ${kdenlive_SRCS}
+  utils/freesound.cpp
+  PARENT_SCOPE
+)
diff --git a/src/utils/freesound.cpp b/src/utils/freesound.cpp
new file mode 100644 (file)
index 0000000..c67ecb8
--- /dev/null
@@ -0,0 +1,209 @@
+/***************************************************************************
+ *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
+ *   Copyright (C) 2011 by Marco Gittler (marco@gitma.de)                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
+ ***************************************************************************/
+
+
+#include "freesound.h"
+
+#include <QPushButton>
+#include <QSpinBox>
+#include <QListWidget>
+
+#include <KDebug>
+#include "kdenlivesettings.h"
+#include <KGlobalSettings>
+#include <KMessageBox>
+#include <KFileDialog>
+#include <kio/job.h>
+#include <KIO/NetAccess>
+#include <KRun>
+
+#include <qjson/parser.h>
+
+const int imageRole = Qt::UserRole;
+const int urlRole = Qt::UserRole + 1;
+const int soundRole = Qt::UserRole + 2;
+const int durationRole = Qt::UserRole + 3;
+const int previewRole = Qt::UserRole + 4;
+const int authorRole = Qt::UserRole + 5;
+const int authorUrl = Qt::UserRole + 6;
+const int soundUrl = Qt::UserRole + 7;
+
+FreeSound::FreeSound(const QString & folder, QWidget * parent) :
+        QDialog(parent),
+        m_folder(folder)
+{
+    setFont(KGlobalSettings::toolBarFont());
+    setupUi(this);
+    setAttribute(Qt::WA_DeleteOnClose);
+    setWindowTitle(i18n("Search FreeSound Audio Library"));
+    connect(button_search, SIGNAL(clicked()), this, SLOT(slotStartSearch()));
+    connect(search_results, SIGNAL(currentRowChanged(int)), this, SLOT(slotUpdateCurrentSound()));
+    connect(button_preview, SIGNAL(clicked()), this, SLOT(slotPlaySound()));
+    connect(button_import, SIGNAL(clicked()), this, SLOT(slotSaveSound()));
+    connect(sound_author, SIGNAL(leftClickedUrl(const QString &)), this, SLOT(slotOpenUrl(const QString &)));
+    connect(sound_name, SIGNAL(leftClickedUrl(const QString &)), this, SLOT(slotOpenUrl(const QString &)));
+    m_previewProcess = new QProcess;
+    connect(m_previewProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotPreviewStatusChanged(QProcess::ProcessState)));
+}
+
+FreeSound::~FreeSound()
+{
+    if (m_previewProcess) delete m_previewProcess;
+}
+
+void FreeSound::slotStartSearch()
+{
+    m_result.clear();
+    m_currentPreview.clear();
+    m_currentUrl.clear();
+    page_number->blockSignals(true);
+    page_number->setValue(0);
+    page_number->blockSignals(false);
+    QString uri = "http://www.freesound.org/api/sounds/search/?q=";
+    uri.append(search_text->text());
+    uri.append("&api_key=a1772c8236e945a4bee30a64058dabf8");
+    KIO::TransferJob *job = KIO::get(KUrl(uri));
+    connect (job, SIGNAL(  data(KIO::Job *, const QByteArray & )), this, SLOT(slotDataIsHere(KIO::Job *,const QByteArray &)));
+    connect(job, SIGNAL(result(KJob*)), this, SLOT(slotShowResults()));
+}
+
+void FreeSound::slotDataIsHere(KIO::Job *,const QByteArray & data )
+{
+  //kDebug() << "data is here";
+  m_result.append(data);
+}
+
+void FreeSound::slotShowResults()
+{
+    QJson::Parser parser;
+    bool ok;
+    m_data = parser.parse(m_result, &ok);
+    QVariant sounds;
+    search_results->blockSignals(true);
+    search_results->clear();
+    if (m_data.canConvert(QVariant::Map)) {
+        QMap <QString, QVariant> map = m_data.toMap();
+        QMap<QString, QVariant>::const_iterator i = map.constBegin();
+        while (i != map.constEnd()) {
+            if (i.key() == "num_results") search_info->setText(i18np("Found %1 result", "Found %1 results", i.value().toInt()));
+            else if (i.key() == "num_pages") {
+                page_number->setMaximum(i.value().toInt());
+            }
+            else if (i.key() == "sounds") {
+                sounds = i.value();
+                if (sounds.canConvert(QVariant::List)) {
+                    QList <QVariant> soundsList = sounds.toList();
+                    for (int j = 0; j < soundsList.count(); j++) {
+                        if (soundsList.at(j).canConvert(QVariant::Map)) {
+                            QMap <QString, QVariant> soundmap = soundsList.at(j).toMap();
+                            if (soundmap.contains("original_filename")) {
+                                QListWidgetItem *item = new QListWidgetItem(soundmap.value("original_filename").toString(), search_results);
+                                item->setData(imageRole, soundmap.value("waveform_m").toString());
+                                item->setData(soundUrl, soundmap.value("url").toString());
+                                item->setData(durationRole, soundmap.value("duration").toDouble());
+                                item->setData(previewRole, soundmap.value("preview-hq-mp3").toString());
+                                item->setData(soundRole, soundmap.value("serve").toString() + "?api_key=a1772c8236e945a4bee30a64058dabf8");
+                                QVariant authorInfo = soundmap.value("user");
+                                if (authorInfo.canConvert(QVariant::Map)) {
+                                    QMap <QString, QVariant> authorMap = authorInfo.toMap();
+                                    if (authorMap.contains("username")) {
+                                        item->setData(authorRole, authorMap.value("username").toString());
+                                        item->setData(authorUrl, authorMap.value("url").toString());
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            ++i;
+        }
+    }
+    search_results->blockSignals(false);
+    search_results->setCurrentRow(0);
+}
+
+void FreeSound::slotUpdateCurrentSound()
+{
+    m_currentPreview.clear();
+    m_currentUrl.clear();
+    QListWidgetItem *item = search_results->currentItem();
+    if (!item) {
+        sound_box->setEnabled(false);
+        return;
+    }
+    m_currentPreview = item->data(previewRole).toString();
+    m_currentUrl = item->data(soundRole).toString();
+    button_preview->setEnabled(!m_currentPreview.isEmpty());
+    sound_box->setEnabled(true);
+    sound_name->setText(item->text());
+    sound_name->setUrl(item->data(soundUrl).toString());
+    sound_author->setText(item->data(authorRole).toString());
+    sound_author->setUrl(item->data(authorUrl).toString());
+    sound_duration->setText(QString::number(item->data(durationRole).toDouble()));
+    KUrl img(item->data(imageRole).toString());
+    if (img.isEmpty()) return;
+    if (KIO::NetAccess::exists(img, KIO::NetAccess::SourceSide, this)) {
+        QString tmpFile;
+        if (KIO::NetAccess::download(img, tmpFile, this)) {
+            QPixmap pix(tmpFile);
+            sound_image->setPixmap(pix);
+            KIO::NetAccess::removeTempFile(tmpFile);
+        }
+    }
+}
+
+
+void FreeSound::slotPlaySound()
+{
+    if (m_currentPreview.isEmpty()) return;
+    if (m_previewProcess && m_previewProcess->state() != QProcess::NotRunning) {
+        m_previewProcess->close();
+        return;
+    }
+    m_previewProcess->start("ffplay", QStringList() << m_currentPreview << "-nodisp");
+}
+
+void FreeSound::slotPreviewStatusChanged(QProcess::ProcessState state)
+{
+    if (state == QProcess::NotRunning)
+        button_preview->setText(i18n("Preview"));
+    else 
+        button_preview->setText(i18n("Stop"));
+}
+
+void FreeSound::slotSaveSound()
+{
+    if (m_currentUrl.isEmpty()) return;
+    QString path = m_folder;
+    if (!path.endsWith('/')) path.append('/');
+    path.append(sound_name->text());
+    QString ext = "*." + sound_name->text().section('.', -1);
+    QString saveUrl = KFileDialog::getSaveFileName(KUrl(path), ext);
+    if (saveUrl.isEmpty()) return;
+    if (KIO::NetAccess::download(KUrl(m_currentUrl), saveUrl, this)) {
+        emit addClip(KUrl(saveUrl));
+    }
+}
+
+void FreeSound::slotOpenUrl(const QString &url)
+{
+    new KRun(KUrl(url), this);
+}
diff --git a/src/utils/freesound.h b/src/utils/freesound.h
new file mode 100644 (file)
index 0000000..2d7f9a5
--- /dev/null
@@ -0,0 +1,67 @@
+/***************************************************************************
+ *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
+ *   Copyright (C) 2011 by Marco Gittler (marco@gitma.de)                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
+ ***************************************************************************/
+
+
+#ifndef FREESOUND_H
+#define FREESOUND_H
+
+
+#include "ui_freesound_ui.h"
+
+#include <QDialog>
+#include <QProcess>
+#include <kio/jobclasses.h>
+
+
+
+class FreeSound : public QDialog, public Ui::FreeSound_UI
+{
+    Q_OBJECT
+
+public:
+    FreeSound(const QString & folder, QWidget * parent = 0);
+    ~FreeSound();
+
+
+private slots:
+    void slotStartSearch();
+    void slotDataIsHere(KIO::Job *,const QByteArray & data );
+    void slotShowResults();
+    void slotUpdateCurrentSound();
+    void slotPlaySound();
+    void slotPreviewStatusChanged(QProcess::ProcessState state);
+    void slotSaveSound();
+    void slotOpenUrl(const QString &url);
+
+private:
+    QString m_folder;
+    QByteArray m_result;
+    QVariant m_data;
+    QString m_currentPreview;
+    QString m_currentUrl;
+    QProcess *m_previewProcess;
+   
+signals:
+    void addClip(KUrl);
+};
+
+
+#endif
+
diff --git a/src/widgets/freesound_ui.ui b/src/widgets/freesound_ui.ui
new file mode 100644 (file)
index 0000000..01a4ef0
--- /dev/null
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FreeSound_UI</class>
+ <widget class="QDialog" name="FreeSound_UI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>334</width>
+    <height>284</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0" colspan="2">
+    <widget class="KLineEdit" name="search_text"/>
+   </item>
+   <item row="0" column="2" colspan="2">
+    <widget class="QPushButton" name="button_search">
+     <property name="text">
+      <string>Search</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="4" rowspan="2">
+    <widget class="QGroupBox" name="sound_box">
+     <property name="title">
+      <string/>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="1" column="0" colspan="4">
+       <widget class="QLabel" name="sound_image">
+        <property name="text">
+         <string/>
+        </property>
+        <property name="scaledContents">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="6" column="0" colspan="4">
+       <widget class="QPushButton" name="button_preview">
+        <property name="text">
+         <string>Preview</string>
+        </property>
+       </widget>
+      </item>
+      <item row="7" column="0" colspan="2">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Similar sounds</string>
+        </property>
+       </widget>
+      </item>
+      <item row="7" column="3">
+       <widget class="QComboBox" name="similar_list"/>
+      </item>
+      <item row="8" column="1">
+       <spacer name="verticalSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>40</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="9" column="0" colspan="4">
+       <widget class="QPushButton" name="button_import">
+        <property name="text">
+         <string>Import</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="3">
+       <widget class="KUrlLabel" name="sound_author">
+        <property name="text">
+         <string/>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="1">
+       <widget class="QLabel" name="sound_duration">
+        <property name="text">
+         <string/>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="0">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Duration</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="2">
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="0" colspan="4">
+       <widget class="KUrlLabel" name="sound_name">
+        <property name="text">
+         <string/>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="1" column="0" colspan="4">
+    <widget class="QListWidget" name="search_results">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QPushButton" name="page_prev">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>&lt;&lt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1" colspan="2">
+    <widget class="QSpinBox" name="page_number">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="3">
+    <widget class="QPushButton" name="page_next">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>&gt;&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="4">
+    <widget class="QLabel" name="search_info">
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="4">
+    <widget class="QDialogButtonBox" name="ButtonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>klineedit.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KUrlLabel</class>
+   <extends>QLabel</extends>
+   <header>kurllabel.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>ButtonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>FreeSound_UI</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>ButtonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>FreeSound_UI</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>