Commit 6419771e authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement Audio Channel support

It is quite primitive yet (it doesn't have any visualisation), but it
works! Just select the file using a button on the timeline and it'll
work fine: with both playback and scrubbing.

TODO: icons for the button!

CC:kimageshop@kde.org
parent 3dffd58b
......@@ -242,6 +242,8 @@ find_package(Qt5 ${MIN_QT_VERSION}
Svg
Test
Concurrent
OPTIONAL_COMPONENTS
Multimedia
)
......@@ -292,6 +294,9 @@ else()
set(HAVE_XCB FALSE)
endif()
macro_bool_to_01(Qt5Multimedia_FOUND HAVE_QT_MULTIMEDIA)
configure_file(config-qtmultimedia.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-qtmultimedia.h )
add_definitions(
-DQT_USE_QSTRINGBUILDER
-DQT_STRICT_ITERATORS
......
/* config-qtmultimedia.h. Generated by cmake from config-gsl.h.cmake */
/* Defines if you have Qt Multimedia component */
#cmakedefine HAVE_QT_MULTIMEDIA 1
......@@ -18,6 +18,8 @@
#include "kis_image_animation_interface.h"
#include <QFileInfo>
#include "kis_global.h"
#include "kis_image.h"
#include "kis_regenerate_frame_stroke_strategy.h"
......@@ -37,6 +39,7 @@ struct KisImageAnimationInterface::Private
externalFrameActive(false),
frameInvalidationBlocked(false),
cachedLastFrameValue(-1),
audioChannelMuted(false),
m_currentTime(0),
m_currentUITime(0)
{
......@@ -50,6 +53,8 @@ struct KisImageAnimationInterface::Private
playbackRange(rhs.playbackRange),
framerate(rhs.framerate),
cachedLastFrameValue(-1),
audioChannelFileName(rhs.audioChannelFileName),
audioChannelMuted(rhs.audioChannelMuted),
m_currentTime(rhs.m_currentTime),
m_currentUITime(rhs.m_currentUITime)
{
......@@ -63,6 +68,8 @@ struct KisImageAnimationInterface::Private
KisTimeRange playbackRange;
int framerate;
int cachedLastFrameValue;
QString audioChannelFileName;
bool audioChannelMuted;
KisSwitchTimeStrokeStrategy::SharedTokenWSP switchToken;
......@@ -156,6 +163,32 @@ int KisImageAnimationInterface::framerate() const
return m_d->framerate;
}
QString KisImageAnimationInterface::audioChannelFileName() const
{
return m_d->audioChannelFileName;
}
void KisImageAnimationInterface::setAudioChannelFileName(const QString &fileName)
{
QFileInfo info(fileName);
KIS_SAFE_ASSERT_RECOVER_NOOP(fileName.isEmpty() || info.isAbsolute());
m_d->audioChannelFileName = fileName.isEmpty() ? fileName : info.absoluteFilePath();
emit sigAudioChannelChanged();
}
bool KisImageAnimationInterface::isAudioMuted() const
{
return m_d->audioChannelMuted;
}
void KisImageAnimationInterface::setAudioMuted(bool value)
{
m_d->audioChannelMuted = value;
emit sigAudioChannelChanged();
}
void KisImageAnimationInterface::setFramerate(int fps)
{
m_d->framerate = fps;
......
......@@ -122,6 +122,27 @@ public:
int framerate() const;
/**
* @return **absolute** file name of the audio channel file
*/
QString audioChannelFileName() const;
/**
* Sets **absolute** file name of the audio channel file. Dont' try to pass
* a relative path, it'll assert!
*/
void setAudioChannelFileName(const QString &fileName);
/**
* @return is the audio channel is currently muted
*/
bool isAudioMuted() const;
/**
* Mutes the audio channel
*/
void setAudioMuted(bool value);
public Q_SLOTS:
void setFramerate(int fps);
public:
......@@ -158,6 +179,11 @@ Q_SIGNALS:
void sigFullClipRangeChanged();
void sigPlaybackRangeChanged();
/**
* Emitted when the audio channel of the document is changed
*/
void sigAudioChannelChanged();
private:
struct Private;
const QScopedPointer<Private> m_d;
......
......@@ -374,6 +374,7 @@ if(WIN32)
)
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
endif()
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
kis_animation_frame_cache.cpp
......@@ -381,6 +382,7 @@ endif()
canvas/kis_animation_player.cpp
kis_animation_exporter.cpp
kis_animation_importer.cpp
KisSyncedAudioPlayback.cpp
)
if(UNIX)
......@@ -484,6 +486,10 @@ target_link_libraries(kritaui KF5::CoreAddons KF5::Completion KF5::I18n KF5::Ite
kritaimpex kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils ${PNG_LIBRARIES} ${EXIV2_LIBRARIES}
)
if (HAVE_QT_MULTIMEDIA)
target_link_libraries(kritaui Qt5::Multimedia)
endif()
if (HAVE_KIO)
target_link_libraries(kritaui KF5::KIOCore)
endif()
......
#include "KisSyncedAudioPlayback.h"
#include "config-qtmultimedia.h"
#ifdef HAVE_QT_MULTIMEDIA
#include <QtMultimedia/QMediaPlayer>
#else
class QIODevice;
#include <QUrl>
namespace {
struct QMediaPlayer {
enum State
{
StoppedState,
PlayingState,
PausedState
};
State state() const { return StoppedState; }
void play() {}
void stop() {}
qint64 position() const { return 0; }
qreal playbackRate() const { return 1.0; }
void setPosition(qint64) {}
void setPlaybackRate(qreal) {}
void setVolume(int) {}
void setMedia(const QUrl&, QIODevice * device = 0) { Q_UNUSED(device);}
};
}
#endif
#include <QFileInfo>
struct KisSyncedAudioPlayback::Private
{
QMediaPlayer player;
qint64 tolerance = 40;
};
KisSyncedAudioPlayback::KisSyncedAudioPlayback(const QString &fileName)
: QObject(0),
m_d(new Private)
{
QFileInfo fileInfo(fileName);
Q_ASSERT(fileInfo.exists());
m_d->player.setMedia(QUrl::fromLocalFile(fileInfo.absoluteFilePath()));
m_d->player.setVolume(50);
}
KisSyncedAudioPlayback::~KisSyncedAudioPlayback()
{
}
void KisSyncedAudioPlayback::setSoundOffsetTolerance(qint64 value)
{
m_d->tolerance = value;
}
void KisSyncedAudioPlayback::syncWithVideo(qint64 position)
{
if (qAbs(position - m_d->player.position()) > m_d->tolerance) {
m_d->player.setPosition(position);
}
}
bool KisSyncedAudioPlayback::isPlaying() const
{
return m_d->player.state() == QMediaPlayer::PlayingState;
}
void KisSyncedAudioPlayback::setSpeed(qreal value)
{
if (qFuzzyCompare(value, m_d->player.playbackRate())) return;
if (m_d->player.state() == QMediaPlayer::PlayingState) {
const qint64 oldPosition = m_d->player.position();
m_d->player.stop();
m_d->player.setPlaybackRate(value);
m_d->player.setPosition(oldPosition);
m_d->player.play();
} else {
m_d->player.setPlaybackRate(value);
}
}
void KisSyncedAudioPlayback::play(qint64 startPosition)
{
m_d->player.setPosition(startPosition);
m_d->player.play();
}
void KisSyncedAudioPlayback::stop()
{
m_d->player.stop();
}
#ifndef KISSYNCEDAUDIOPLAYBACK_H
#define KISSYNCEDAUDIOPLAYBACK_H
#include <QScopedPointer>
#include <QObject>
class KisSyncedAudioPlayback : public QObject
{
Q_OBJECT
public:
KisSyncedAudioPlayback(const QString &fileName);
virtual ~KisSyncedAudioPlayback();
void setSoundOffsetTolerance(qint64 value);
void syncWithVideo(qint64 position);
bool isPlaying() const;
public Q_SLOTS:
void setSpeed(qreal value);
void play(qint64 startPosition);
void stop();
private:
struct Private;
const QScopedPointer<Private> m_d;
};
#endif // KISSYNCEDAUDIOPLAYBACK_H
......@@ -35,11 +35,16 @@
#include "kis_image_animation_interface.h"
#include "kis_time_range.h"
#include "kis_signal_compressor.h"
#include <KisDocument.h>
#include <QFileInfo>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/rolling_mean.hpp>
#include "KisSyncedAudioPlayback.h"
#include "kis_signal_compressor_with_param.h"
using namespace boost::accumulators;
typedef accumulator_set<qreal, stats<tag::rolling_mean> > FpsAccumulator;
......@@ -95,6 +100,9 @@ public:
KisSignalCompressor playbackStatisticsCompressor;
QScopedPointer<KisSyncedAudioPlayback> syncedAudio;
QScopedPointer<KisSignalCompressorWithParam<int> > audioSyncScrubbingCompressor;
void stopImpl(bool doUpdates);
int incFrame(int frame, int inc) {
......@@ -104,6 +112,13 @@ public:
}
return frame;
}
qint64 frameToMSec(int value) {
return qreal(value) / fps * 1000.0;
}
int msecToFrame(qint64 value) {
return qreal(value) * fps / 1000.0;
}
};
KisAnimationPlayer::KisAnimationPlayer(KisCanvas2 *canvas)
......@@ -127,6 +142,17 @@ KisAnimationPlayer::KisAnimationPlayer(KisCanvas2 *canvas)
connect(&m_d->playbackStatisticsCompressor, SIGNAL(timeout()),
this, SIGNAL(sigPlaybackStatisticsUpdated()));
using namespace std::placeholders;
std::function<void (int)> callback(
std::bind(&KisAnimationPlayer::slotSyncScrubbingAudio, this, _1));
KisConfig cfg;
m_d->audioSyncScrubbingCompressor.reset(
new KisSignalCompressorWithParam<int>(cfg.scribbingAudioUpdatesDelay(), callback, KisSignalCompressor::FIRST_ACTIVE));
connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigAudioChannelChanged()), SLOT(slotAudioChannelChanged()));
slotAudioChannelChanged();
}
KisAnimationPlayer::~KisAnimationPlayer()
......@@ -138,6 +164,24 @@ void KisAnimationPlayer::slotUpdateDropFramesMode()
m_d->dropFramesMode = cfg.animationDropFrames();
}
void KisAnimationPlayer::slotSyncScrubbingAudio(int msecTime)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->syncedAudio);
m_d->syncedAudio->syncWithVideo(msecTime);
}
void KisAnimationPlayer::slotAudioChannelChanged()
{
QString fileName = m_d->canvas->image()->animationInterface()->audioChannelFileName();
QFileInfo info(fileName);
if (info.exists() && !m_d->canvas->image()->animationInterface()->isAudioMuted()) {
m_d->syncedAudio.reset(new KisSyncedAudioPlayback(info.absoluteFilePath()));
} else {
m_d->syncedAudio.reset();
}
}
void KisAnimationPlayer::connectCancelSignals()
{
m_d->cancelStrokeConnections.addConnection(
......@@ -187,6 +231,11 @@ void KisAnimationPlayer::slotUpdatePlaybackTimer()
m_d->expectedInterval = qreal(1000) / m_d->fps / m_d->playbackSpeed;
m_d->lastTimerInterval = m_d->expectedInterval;
if (m_d->syncedAudio) {
m_d->syncedAudio->setSpeed(m_d->playbackSpeed);
}
m_d->timer->start(m_d->expectedInterval);
if (m_d->playbackTime.isValid()) {
......@@ -207,10 +256,18 @@ void KisAnimationPlayer::play()
m_d->lastPaintedFrame = m_d->firstFrame;
connectCancelSignals();
if (m_d->syncedAudio) {
m_d->syncedAudio->play(m_d->frameToMSec(m_d->firstFrame));
}
}
void KisAnimationPlayer::Private::stopImpl(bool doUpdates)
{
if (syncedAudio) {
syncedAudio->stop();
}
q->disconnectCancelSignals();
timer->stop();
......@@ -258,6 +315,17 @@ void KisAnimationPlayer::slotUpdate()
uploadFrame(-1);
}
void KisAnimationPlayer::setScrubState(bool value, int currentFrame)
{
if (!m_d->syncedAudio || isPlaying()) return;
if (value) {
m_d->syncedAudio->play(m_d->frameToMSec(currentFrame));
} else {
m_d->syncedAudio->stop();
}
}
void KisAnimationPlayer::uploadFrame(int frame)
{
if (frame < 0) {
......@@ -287,6 +355,15 @@ void KisAnimationPlayer::uploadFrame(int frame)
m_d->playbackStatisticsCompressor.start();
}
if (m_d->syncedAudio) {
const int msecTime = m_d->frameToMSec(frame);
if (isPlaying()) {
slotSyncScrubbingAudio(msecTime);
} else {
m_d->audioSyncScrubbingCompressor->start(msecTime);
}
}
if (m_d->canvas->frameCache() && m_d->canvas->frameCache()->uploadFrame(frame)) {
m_d->canvas->updateCanvas();
......
......@@ -50,6 +50,8 @@ public:
qreal realFps() const;
qreal framesDroppedPortion() const;
void setScrubState(bool value, int currentFrame);
public Q_SLOTS:
void slotUpdate();
void slotCancelPlayback();
......@@ -58,6 +60,10 @@ public Q_SLOTS:
void slotUpdatePlaybackTimer();
void slotUpdateDropFramesMode();
private Q_SLOTS:
void slotSyncScrubbingAudio(int msecTime);
void slotAudioChannelChanged();
Q_SIGNALS:
void sigFrameChanged();
void sigPlaybackStopped();
......
......@@ -1655,6 +1655,16 @@ void KisConfig::setScribbingUpdatesDelay(int value)
m_cfg.writeEntry("scribbingUpdatesDelay", value);
}
int KisConfig::scribbingAudioUpdatesDelay(bool defaultValue) const
{
return (defaultValue ? 200 : m_cfg.readEntry("scribbingAudioUpdatesDelay", 200));
}
void KisConfig::setScribbingAudioUpdatesDelay(int value)
{
m_cfg.writeEntry("scribbingAudioUpdatesDelay", value);
}
bool KisConfig::switchSelectionCtrlAlt(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("switchSelectionCtrlAlt", false);
......
......@@ -473,6 +473,9 @@ public:
int scribbingUpdatesDelay(bool defaultValue = false) const;
void setScribbingUpdatesDelay(int value);
int scribbingAudioUpdatesDelay(bool defaultValue = false) const;
void setScribbingAudioUpdatesDelay(int value);
bool switchSelectionCtrlAlt(bool defaultValue = false) const;
void setSwitchSelectionCtrlAlt(bool value);
......
......@@ -54,7 +54,6 @@ struct KisTimeBasedItemModel::Private
QScopedPointer<KisSignalCompressorWithParam<int> > scrubbingCompressor;
int baseNumFrames() const {
if (image.isNull()) return 0;
......@@ -345,6 +344,10 @@ void KisTimeBasedItemModel::setScrubState(bool active)
m_d->scrubInProgress = true;
}
if (m_d->animationPlayer && !m_d->animationPlayer->isPlaying()) {
m_d->animationPlayer->setScrubState(active, m_d->activeFrameIndex);
}
if (m_d->scrubInProgress && !active) {
m_d->scrubInProgress = false;
......
......@@ -220,6 +220,7 @@ void TimelineFramesModel::setDummiesFacade(KisDummiesFacadeBase *dummiesFacade,
KisDummiesFacadeBase *oldDummiesFacade = m_d->dummiesFacade;
if (m_d->dummiesFacade) {
m_d->image->animationInterface()->disconnect(this);
m_d->image->disconnect(this);
m_d->dummiesFacade->disconnect(this);
}
......@@ -236,6 +237,8 @@ void TimelineFramesModel::setDummiesFacade(KisDummiesFacadeBase *dummiesFacade,
SLOT(slotDummyChanged(KisNodeDummy*)));
connect(m_d->image->animationInterface(),
SIGNAL(sigFullClipRangeChanged()), SIGNAL(sigInfiniteTimelineUpdateNeeded()));
connect(m_d->image->animationInterface(),
SIGNAL(sigAudioChannelChanged()), SIGNAL(sigAudioChannelChanged()));
}
if (m_d->dummiesFacade != oldDummiesFacade) {
......@@ -244,6 +247,7 @@ void TimelineFramesModel::setDummiesFacade(KisDummiesFacadeBase *dummiesFacade,
if (m_d->dummiesFacade) {
emit sigInfiniteTimelineUpdateNeeded();
emit sigAudioChannelChanged();
}
}
......@@ -643,3 +647,25 @@ bool TimelineFramesModel::copyFrame(const QModelIndex &dstIndex)
return result;
}
QString TimelineFramesModel::audioChannelFileName() const
{
return m_d->image ? m_d->image->animationInterface()->audioChannelFileName() : QString();
}
void TimelineFramesModel::setAudioChannelFileName(const QString &fileName)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image);
m_d->image->animationInterface()->setAudioChannelFileName(fileName);
}
bool TimelineFramesModel::isAudioMuted() const
{
return m_d->image ? m_d->image->animationInterface()->isAudioMuted() : false;
}
void TimelineFramesModel::setAudioMuted(bool value)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image);
m_d->image->animationInterface()->setAudioMuted(value);
}
......@@ -51,6 +51,12 @@ public:
bool createFrame(const QModelIndex &dstIndex);
bool copyFrame(const QModelIndex &dstIndex);
QString audioChannelFileName() const;
void setAudioChannelFileName(const QString &fileName);
bool isAudioMuted() const;
void setAudioMuted(bool value);
void setLastClickedIndex(const QModelIndex &index);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
......@@ -112,6 +118,7 @@ public Q_SLOTS:
Q_SIGNALS:
void requestCurrentNodeChanged(KisNodeSP node);
void sigInfiniteTimelineUpdateNeeded();
void sigAudioChannelChanged();
private:
struct Private;
......
......@@ -28,6 +28,7 @@
#include <QPainter>
#include <QFileInfo>
#include <QApplication>
#include <QHeaderView>
#include <QDropEvent>
......@@ -54,6 +55,11 @@
#include "kis_time_range.h"
#include "kis_color_label_selector_widget.h"
#include <KoFileDialog.h>
#include <QDesktopServices>
#include "config-qtmultimedia.h"
typedef QPair<QRect, QModelIndex> QItemViewPaintPair;
typedef QList<QItemViewPaintPair> QItemViewPaintPairs;
......@@ -84,11 +90,17 @@ struct TimelineFramesView::Private
QToolButton *addLayersButton;
KisAction *showHideLayerAction;
QToolButton *audioOptionsButton;
KisColorLabelSelectorWidget *colorSelector;
QWidgetAction *colorSelectorAction;
KisColorLabelSelectorWidget *multiframeColorSelector;
QWidgetAction *multiframeColorSelectorAction;
QMenu *audioOptionsMenu;
QAction *openAudioAction;
QAction *audioMuteAction;
QMenu *layerEditingMenu;
QMenu *existingLayersMenu;
......@@ -149,6 +161,9 @@ TimelineFramesView::TimelineFramesView(QWidget *parent)
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(slotUpdateInfiniteFramesCount()));
connect(horizontalScrollBar(), SIGNAL(sliderReleased()), SLOT(slotUpdateInfiniteFramesCount()));
/********** New Layer Menu ***********************************************************/
m_d->addLayersButton = new QToolButton(this);
m_d->addLayersButton->setAutoRaise(true);
m_d->addLayersButton->setIcon(KisIconUtils::loadIcon("addlayer"));
......@@ -176,6 +191,36 @@ TimelineFramesView::TimelineFramesView(QWidget *parent)
m_d->addLayersButton->setMenu(m_d->layerEditingMenu);
/********** Audio Channel Menu *******************************************************/
m_d->audioOptionsButton = new QToolButton(this);
m_d->audioOptionsButton->setAutoRaise(true);
m_d->audioOptionsButton->setIcon(KisIconUtils::loadIcon("zoom-horizontal"));
m_d->audioOptionsButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_d->audioOptionsButton->setPopupMode(QToolButton::InstantPopup);
m_d->audioOptionsMenu = new QMenu(this);
#ifndef HAVE_QT_MULTIMEDIA
m_d->audioOptionsMenu->addSection(i18nc("@item:inmenu", "Audio playback is not suported in this build!"));
#endif
m_d->openAudioAction= new QAction("XXX", this);
connect(m_d->openAudioAction, SIGNAL(triggered()), this, SLOT(slotSelectAudioChannelFile()));
m_d->audioOptionsMenu->addAction(m_d->openAudioAction);
m_d->audioMuteAction = new QAction(i18nc("@item:inmenu", "Mute"), this);
m_d->audioMuteAction->setCheckable(true);
connect(m_d->audioMuteAction, SIGNAL(triggered(bool)), SLOT(slotAudioChannelMute(bool)));
m_d->audioOptionsMenu->addAction(m_d->audioMuteAction);
m_d->audioOptionsMenu->addAction(i18nc("@item:inmenu", "Remove audio"), this, SLOT(slotAudioChannelRemove()));
m_d->audioOptionsButton->setMenu(m_d->audioOptionsMenu);
/********** Frame Editing Context Menu ***********************************************/
m_d->frameCreationMenu = new QMenu(this);
m_d->frameCreationMenu->addAction(KisAnimationUtils::addFrameActionName, this, SLOT(slotNewFrame()));
m_d->frameCreationMenu->addAction(KisAnimationUtils::duplicateFrameActionName, this, SLOT(slotCopyFrame()));
......@@ -198,6 +243,8 @@ TimelineFramesView::TimelineFramesView(QWidget *parent)
m_d->multipleFrameEditingMenu->addAction(KisAnimationUtils::removeFramesActionName, this, SLOT(slotRemoveFrame()));
m_d->multipleFrameEditingMenu->addAction(m_d->multiframeColorSelectorAction);
/********** Zoom Button **************************************************************/
m_d->zoomDragButton = new KisZoomButton(this);
m_d->zoomDragButton->setAutoRaise(true);
m_d->zoomDragButton->setIcon(KisIconUtils::loadIcon("zoom-horizontal"));
......@@ -240,11 +287,13 @@ void TimelineFramesView::updateGeometries()
const int minimalSize = availableHeight - 2 * margin;
resizeToMinimalSize(m_d->addLayersButton, minimalSize);
resizeToMinimalSize(m_d->audioOptionsButton, minimalSize);
resizeToMinimalSize(m_d->zoomDragButton, minimalSize);
int x = 2 * margin;
int y = (availableHeight - minimalSize) / 2;
m_d->addLayersButton->move(x, 2 * y);
m_d->audioOptionsButton->move(x + minimalSize + 2 * margin, 2 * y);
const int availableWidth = m_d->layersHeader->width();
......@@ -271,8 +320,13 @@ void TimelineFramesView::setModel(QAbstractItemModel *model)
connect(m_d->model, SIGNAL(sigInfiniteTimelineUpdateNeeded()),
this, SLOT(slotUpdateInfiniteFramesCount()));
connect(m_d->model, SIGNAL(sigAudioChannelChanged()),
this, SLOT(slotUpdateAudioActions()));
connect(selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
&m_d->selectionChangedCompressor, SLOT(start()));
slotUpdateAudioActions();
}
void TimelineFramesView::setFramesPerSecond(int fps)
......@@ -320,6 +374,70 @@ void TimelineFramesView::slotColorLabelChanged(int label)
config.setDefaultFrameColorLabel(label);
}
void TimelineFramesView::slotSelectAudioChannelFile()
{
if (!m_d->model) return;
KoFileDialog dialog(this, KoFileDialog::ImportFiles, "ImportAudio");
QString defaultDir = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
const QString currentFile = m_d->model->audioChannelFileName();
QDir baseDir = QFileInfo(currentFile).absoluteDir();
if (baseDir.exists()) {
defaultDir = baseDir.absolutePath();
}
dialog.setDefaultDir(defaultDir);
QStringList mimeTypes;
mimeTypes << "audio/mpeg";
mimeTypes << "audio/ogg";
mimeTypes << "audio/vorbis";
mimeTypes << "audio/vnd.wave";
dialog.setMimeTypeFilters(mimeTypes);
dialog.setCaption(i18nc("@titile:window", "Open Audio"));