diff --git a/JustAudio.pro b/JustAudio.pro index 4002db3..87d0795 100644 --- a/JustAudio.pro +++ b/JustAudio.pro @@ -4,18 +4,22 @@ # #------------------------------------------------- -QT += core gui +QT += core gui +QT += multimedia +QT += svg greaterThan(QT_MAJOR_VERSION, 4): QT += widgets -TARGET = JustAudio +TARGET = JustAudio TEMPLATE = app - SOURCES += main.cpp\ - gui/ui.cpp \ - gui/file_item.cpp + gui/ui.cpp\ + gui/icon.cpp \ + io/aud_file.cpp -HEADERS += \ - gui/ui.h \ - gui/file_item.h +HEADERS += gui/ui.h\ + gui/icon.h \ + io/aud_file.h + +RESOURCES += icon_files.qrc diff --git a/gui/file_item.cpp b/gui/file_item.cpp deleted file mode 100644 index 4bcfd9f..0000000 --- a/gui/file_item.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "file_item.h" - -FileItem::FileItem(QWidget *parent) : QLabel(parent) -{ - -} diff --git a/gui/file_item.h b/gui/file_item.h deleted file mode 100644 index 130f0bd..0000000 --- a/gui/file_item.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef FILE_ITEM_H -#define FILE_ITEM_H - -#include -#include -#include - -class FileItem : public QLabel -{ - Q_OBJECT - -public: - - FileItem(QWidget *parent = 0); -}; - -#endif // FILE_ITEM_H diff --git a/gui/icon.cpp b/gui/icon.cpp new file mode 100644 index 0000000..4e0b8b2 --- /dev/null +++ b/gui/icon.cpp @@ -0,0 +1,83 @@ +#include "icon.h" + +Icon::Icon(IconType t, QWidget *parent) : QLabel(parent) +{ + QRect rect = QApplication::desktop()->screenGeometry(); + + setMinimumHeight(rect.height() / 40); + setMinimumWidth(rect.height() / 40); + setCursor(Qt::PointingHandCursor); + + switch (t) + { + case PAUSE_PLAY: stateChanged(QMediaPlayer::StoppedState); break; + case SETTINGS: loadImg(":/settings"); break; + case OPEN: loadImg(":/open"); break; + } + + type = t; +} + +void Icon::mouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + { + switch (type) + { + case PAUSE_PLAY: + { + if (playerState == QMediaPlayer::PlayingState) + { + emit pause(); + } + else + { + emit play(); + } + + break; + } + case SETTINGS: + { + emit settings(); + + break; + } + case OPEN: + { + emit open(); + + break; + } + } + } +} + +void Icon::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + QSvgRenderer svg(svgFile, this); + + svg.render(&painter); +} + +void Icon::stateChanged(QMediaPlayer::State state) +{ + playerState = state; + + if (state == QMediaPlayer::PlayingState) + { + loadImg(":/pause"); + } + else + { + loadImg(":/play"); + } +} + +void Icon::loadImg(const QString &path) +{ + svgFile = path; + + update(); +} diff --git a/gui/icon.h b/gui/icon.h new file mode 100644 index 0000000..0c47c57 --- /dev/null +++ b/gui/icon.h @@ -0,0 +1,53 @@ +#ifndef ICON_H +#define ICON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Icon : public QLabel +{ + Q_OBJECT + +public: + + enum IconType + { + PAUSE_PLAY, + SETTINGS, + OPEN + }; + + Icon(IconType t, QWidget *parent = 0); + +public slots: + + void stateChanged(QMediaPlayer::State state); + +private: + + IconType type; + QMediaPlayer::State playerState; + QString svgFile; + + void mouseReleaseEvent(QMouseEvent *event); + void paintEvent(QPaintEvent *); + void loadImg(const QString &path); + +signals: + + void pause(); + void play(); + void settings(); + void open(); +}; + +#endif // ICON_H diff --git a/gui/ui.cpp b/gui/ui.cpp index 53c9ce8..8731e5f 100644 --- a/gui/ui.cpp +++ b/gui/ui.cpp @@ -2,53 +2,160 @@ Ui::Ui(const QStringList &args, QWidget *parent) : QWidget(parent) { - QWidget *listWid = new QWidget(this); - QScrollArea *mid = new QScrollArea(this); + QWidget *btnWid = new QWidget(this); + QHBoxLayout *btnLayout = new QHBoxLayout(btnWid); QVBoxLayout *mainLayout = new QVBoxLayout(this); - slider = new QSlider(this); - listLayout = new QVBoxLayout(listWid); - search = new QLineEdit(this); + fileName = new QLabel(this); + slider = new QSlider(this); + pausePlay = new Icon(Icon::PAUSE_PLAY, this); + settings = new Icon(Icon::SETTINGS, this); + open = new Icon(Icon::OPEN, this); + player = new QMediaPlayer(this); + ioDev = new AudFile(this); + pressed = false; + QFont fnt = fileName->font(); + QRect rect = QApplication::desktop()->screenGeometry(); + + fnt.setBold(true); + + setMinimumHeight(rect.height() / 6); + setMinimumWidth(rect.width() / 5); + setMaximumHeight(rect.height() / 6); + setMaximumWidth(rect.width() / 5); + setStyleSheet("background-color:white;"); + + fileName->setText(QApplication::applicationName()); + fileName->setFont(fnt); slider->setOrientation(Qt::Horizontal); - mid->setWidget(listWid); - mid->setWidgetResizable(true); - mainLayout->addWidget(search); - mainLayout->addWidget(mid); - mainLayout->addWidget(slider); - mainLayout->setSpacing(0); - mainLayout->setContentsMargins(0, 0, 0, 0); + slider->setMinimumWidth((rect.width() / 5) - 100); + btnLayout->addWidget(pausePlay, 0, Qt::AlignCenter); + btnLayout->addSpacing(rect.height() / 40); + btnLayout->addWidget(open, 0, Qt::AlignCenter); + btnLayout->addSpacing(rect.height() / 40); + btnLayout->addWidget(settings, 0, Qt::AlignCenter); + mainLayout->addWidget(fileName, 0, Qt::AlignCenter); + mainLayout->addWidget(slider, 0, Qt::AlignCenter); + mainLayout->addWidget(btnWid, 0, Qt::AlignCenter); + + connect(pausePlay, SIGNAL(pause()), player, SLOT(pause())); + connect(pausePlay, SIGNAL(play()), player, SLOT(play())); + connect(open, SIGNAL(open()), this, SLOT(openDialog())); + connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(error(QMediaPlayer::Error))); + connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), pausePlay, SLOT(stateChanged(QMediaPlayer::State))); + connect(player, SIGNAL(durationChanged(qint64)), this, SLOT(durationChanged(qint64))); + connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(posChanged(qint64))); + connect(slider, SIGNAL(sliderPressed()), this, SLOT(sliderPressed())); + connect(slider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); if (args.size() > 1) { - QFileInfo info(args[1]); + play(args[1]); + } +} - info.makeAbsolute(); +void Ui::play(const QString &path) +{ + QFileInfo info(path); - if (info.isFile()) - { - setActiveDir(info.path()); - setActiveFile(info.filePath()); - } - else if (info.isDir()) - { - setActiveDir(info.path()); - } - else - { - setActiveDir(QDir::homePath()); - } + fileDir = info.path(); + + slider->setMinimum(0); + fileName->setText(info.fileName()); + player->stop(); + ioDev->close(); + ioDev->openFile(path); + player->setMedia(0, ioDev); + player->play(); +} + +void Ui::openDialog() +{ + QFileDialog fileDialog(this); + + fileDialog.setFileMode(QFileDialog::ExistingFile); + fileDialog.setNameFilter(tr("Audio Files (*.mp3 *.ogg *.wav *.flac)")); + + if (fileDialog.exec()) + { + play(fileDialog.selectedFiles()[0]); + } +} + +void Ui::error(QMediaPlayer::Error error) +{ + QMessageBox box(this); + + if (error == QMediaPlayer::NoError) + { + box.setText(tr("An unknown error has occured")); } else { - setActiveDir(QDir::homePath()); + box.setText(player->errorString()); } + + if (error == QMediaPlayer::FormatError) + { + box.setIcon(QMessageBox::Warning); + } + else + { + box.setIcon(QMessageBox::Critical); + } + + box.exec(); } -void Ui::setActiveDir(const QString &path) +void Ui::sliderPressed() { - for (int i = 0; i < fileList.size(); ++i) + pressed = true; +} + +void Ui::sliderReleased() +{ + pressed = false; + + player->setPosition(slider->value()); +} + +void Ui::posChanged(qint64 pos) +{ + if (!pressed) slider->setSliderPosition(pos); + +// if (slider->sliderPosition() == slider->maximum()) +// { +// QTimer::singleShot(750, this, SLOT(nextFile())); +// } +} + +void Ui::durationChanged(qint64 len) +{ + slider->setMaximum(len); +} + +void Ui::nextFile() +{ + QDir dir(fileDir); + + QStringList filterList; + + filterList.append("*.mp3"); + filterList.append("*.ogg"); + filterList.append("*.flac"); + filterList.append("*.wav"); + + QStringList list = dir.entryList(filterList, QDir::Files | QDir::Readable, QDir::Name); + int pos = list.indexOf(fileName->text()); + + if (pos != -1) { - listLayout->removeWidget(fileList[i]); + pos++; + + if (pos < list.size()) + { + play(fileDir + list[pos]); + } } } diff --git a/gui/ui.h b/gui/ui.h index 4c5a93a..24534a1 100644 --- a/gui/ui.h +++ b/gui/ui.h @@ -4,17 +4,23 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "file_item.h" +#include "icon.h" +#include "../io/aud_file.h" class Ui : public QWidget { @@ -22,19 +28,30 @@ class Ui : public QWidget private: - QSlider *slider; - QLineEdit *search; - QVBoxLayout *listLayout; - QList fileList; + QLabel *fileName; + QSlider *slider; + QMediaPlayer *player; + AudFile *ioDev; + Icon *pausePlay; + Icon *settings; + Icon *open; + QString fileDir; + bool pressed; + +private slots: + + void error(QMediaPlayer::Error error); + void sliderPressed(); + void sliderReleased(); + void posChanged(qint64 pos); + void durationChanged(qint64 len); + void openDialog(); + void nextFile(); + void play(const QString &path); public: Ui(const QStringList &args, QWidget *parent = 0); - -public slots: - - void setActiveFile(const QString &name); - void setActiveDir(const QString &path); }; #endif // UI_H diff --git a/icon_files.qrc b/icon_files.qrc new file mode 100644 index 0000000..e0580bf --- /dev/null +++ b/icon_files.qrc @@ -0,0 +1,8 @@ + + + svg/play-button.svg + svg/pause.svg + svg/list.svg + svg/eject.svg + + diff --git a/io/aud_file.cpp b/io/aud_file.cpp new file mode 100644 index 0000000..e6d9727 --- /dev/null +++ b/io/aud_file.cpp @@ -0,0 +1,57 @@ +#include "aud_file.h" + +AudFile::AudFile(QObject *parent) : QFile(parent) +{ + offset = 0; +} + +AudFile::~AudFile() +{ + close(); +} + +bool AudFile::openFile(const QString &path) +{ + setFileName(path); + + bool ret = open(QFile::ReadOnly); + + if (ret) + { + if (peek(3) == "ID3") + { + QByteArray header = read(10); + QByteArray intBytes = header.mid(6); + quint64 num = 0; + quint64 bit = 1; + + offset += 10; + + if (header[5] & 16) //Footer flag check + { + offset += 10; + } + + for (int i = intBytes.size() - 1; i >= 0; --i) + { + int byte = intBytes[i]; + + for (int inBit = 1; inBit <= 64; inBit *= 2, bit *= 2) + { + if ((byte & inBit) != 0) num |= bit; + } + } + + offset += num; + + seek(0); + } + } + + return ret; +} + +bool AudFile::seek(qint64 pos) +{ + return QFile::seek(pos + offset); +} diff --git a/io/aud_file.h b/io/aud_file.h new file mode 100644 index 0000000..5e69d53 --- /dev/null +++ b/io/aud_file.h @@ -0,0 +1,26 @@ +#ifndef AUD_FILE_H +#define AUD_FILE_H + +#include +#include +#include + +class AudFile : public QFile +{ + Q_OBJECT + +private: + + qint64 offset; + +public: + + AudFile(QObject *parent = 0); + + bool openFile(const QString &path); + bool seek(qint64 pos); + + ~AudFile(); +}; + +#endif // AUD_FILE_H diff --git a/svg/eject.svg b/svg/eject.svg new file mode 100644 index 0000000..55b047a --- /dev/null +++ b/svg/eject.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svg/list.svg b/svg/list.svg new file mode 100644 index 0000000..f35883c --- /dev/null +++ b/svg/list.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svg/pause.svg b/svg/pause.svg new file mode 100644 index 0000000..fad0570 --- /dev/null +++ b/svg/pause.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svg/play-button.svg b/svg/play-button.svg new file mode 100644 index 0000000..32fad65 --- /dev/null +++ b/svg/play-button.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +