Basic support for ProjectM visualisations

This commit is contained in:
David Sansome 2010-06-06 14:06:23 +00:00
parent fe39d99923
commit 1895582eb9
41 changed files with 533 additions and 17 deletions

View File

@ -55,6 +55,9 @@ endif(WIN32)
find_library(LASTFM_LIBRARY_DIRS lastfm)
find_path(LASTFM_INCLUDE_DIRS lastfm/ws.h)
find_library(PROJECTM_LIBRARIES projectM)
find_path(PROJECTM_INCLUDE_DIRS libprojectM/projectM.hpp)
if (APPLE)
find_library(GROWL Growl)
find_library(SPARKLE Sparkle)

View File

@ -36,6 +36,7 @@ add_subdirectory(playlistparsers)
add_subdirectory(radio)
add_subdirectory(transcoder)
add_subdirectory(ui)
add_subdirectory(visualisations)
add_subdirectory(widgets)
add_subdirectory(translations)

View File

@ -0,0 +1,34 @@
/* This file is part of Clementine.
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BUFFERCONSUMER_H
#define BUFFERCONSUMER_H
#include <gst/gstbuffer.h>
class GstEnginePipeline;
class BufferConsumer {
public:
virtual ~BufferConsumer() {}
// This is called in some unspecified GStreamer thread.
// Ownership of the buffer is transferred to the BufferConsumer and it should
// gst_buffer_unref it.
virtual void ConsumeBuffer(GstBuffer* buffer, GstEnginePipeline* pipeline) = 0;
};
#endif // BUFFERCONSUMER_H

View File

@ -259,9 +259,18 @@ Engine::State GstEngine::state() const {
}
}
void GstEngine::AddBufferToScope(GstBuffer* buf) {
GstEnginePipeline* pipeline = qobject_cast<GstEnginePipeline*>(sender());
if (!pipeline || pipeline != current_pipeline_.get()) {
void GstEngine::ConsumeBuffer(GstBuffer *buffer, GstEnginePipeline* pipeline) {
// Schedule this to run in the GUI thread. The buffer gets added to the
// queue and unreffed by UpdateScope.
if (!QMetaObject::invokeMethod(this, "AddBufferToScope",
Q_ARG(GstBuffer*, buffer),
Q_ARG(GstEnginePipeline*, pipeline))) {
qWarning() << "Failed to invoke AddBufferToScope on GstEngine";
}
}
void GstEngine::AddBufferToScope(GstBuffer* buf, GstEnginePipeline* pipeline) {
if (current_pipeline_.get() != pipeline) {
gst_buffer_unref(buf);
return;
}
@ -442,7 +451,7 @@ bool GstEngine::Load(const QUrl& url, Engine::TrackChangeType change) {
void GstEngine::StartFadeout() {
fadeout_pipeline_ = current_pipeline_;
disconnect(fadeout_pipeline_.get(), 0, 0, 0);
fadeout_pipeline_->set_forwards_buffers(false);
fadeout_pipeline_->RemoveAllBufferConsumers();
ClearScopeBuffers();
fadeout_pipeline_->StartFader(fadeout_duration_, QTimeLine::Backward);
@ -642,12 +651,14 @@ GstEngine::PluginDetailsList
shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline(const QUrl& url) {
shared_ptr<GstEnginePipeline> ret(new GstEnginePipeline(this));
ret->set_forwards_buffers(true);
ret->set_output_device(sink_, device_);
ret->set_replaygain(rg_enabled_, rg_mode_, rg_preamp_, rg_compression_);
ret->AddBufferConsumer(this);
foreach (BufferConsumer* consumer, buffer_consumers_)
ret->AddBufferConsumer(consumer);
connect(ret.get(), SIGNAL(EndOfStreamReached(bool)), SLOT(EndOfStreamReached(bool)));
connect(ret.get(), SIGNAL(BufferFound(GstBuffer*)), SLOT(AddBufferToScope(GstBuffer*)));
connect(ret.get(), SIGNAL(Error(QString)), SLOT(HandlePipelineError(QString)));
connect(ret.get(), SIGNAL(MetadataFound(Engine::SimpleMetaBundle)),
SLOT(NewMetaData(Engine::SimpleMetaBundle)));
@ -703,3 +714,15 @@ void GstEngine::ClearScopeBuffers() {
bool GstEngine::DoesThisSinkSupportChangingTheOutputDeviceToAUserEditableString(const QString &name) {
return (name == "alsasink" || name == "osssink" || name == "pulsesink");
}
void GstEngine::AddBufferConsumer(BufferConsumer *consumer) {
buffer_consumers_ << consumer;
if (current_pipeline_)
current_pipeline_->AddBufferConsumer(consumer);
}
void GstEngine::RemoveBufferConsumer(BufferConsumer *consumer) {
buffer_consumers_.removeAll(consumer);
if (current_pipeline_)
current_pipeline_->RemoveBufferConsumer(consumer);
}

View File

@ -23,6 +23,7 @@
#define AMAROK_GSTENGINE_H
#include "enginebase.h"
#include "bufferconsumer.h"
#include <QString>
#include <QTimerEvent>
@ -42,7 +43,7 @@ class GstEnginePipeline;
* @short GStreamer engine plugin
* @author Mark Kretschmann <markey@web.de>
*/
class GstEngine : public Engine::Base {
class GstEngine : public Engine::Base, public BufferConsumer {
Q_OBJECT
public:
@ -75,6 +76,9 @@ class GstEngine : public Engine::Base {
GstElement* CreateElement(
const QString& factoryName, GstElement* bin = 0, const QString& name = 0);
// BufferConsumer
void ConsumeBuffer(GstBuffer *buffer, GstEnginePipeline* pipeline);
public slots:
void StartPreloading(const QUrl &);
bool Load(const QUrl&, Engine::TrackChangeType change);
@ -92,6 +96,9 @@ class GstEngine : public Engine::Base {
void ReloadSettings();
void AddBufferConsumer(BufferConsumer* consumer);
void RemoveBufferConsumer(BufferConsumer* consumer);
protected:
void SetVolumeSW(uint percent);
void timerEvent(QTimerEvent*);
@ -100,8 +107,8 @@ class GstEngine : public Engine::Base {
void EndOfStreamReached(bool has_next_track);
void HandlePipelineError(const QString& message);
void NewMetaData(const Engine::SimpleMetaBundle& bundle);
void AddBufferToScope(GstBuffer* buf);
void ClearScopeBuffers();
void AddBufferToScope(GstBuffer* buf, GstEnginePipeline* pipeline);
void FadeoutFinished();
void SeekNow();
@ -137,6 +144,8 @@ class GstEngine : public Engine::Base {
boost::shared_ptr<GstEnginePipeline> preload_pipeline_;
QUrl preloaded_url_;
QList<BufferConsumer*> buffer_consumers_;
GQueue* delayq_;
float current_scope_[kScopeSize];
int current_sample_;

View File

@ -17,6 +17,7 @@
#include "gstenginepipeline.h"
#include "gstequalizer.h"
#include "gstengine.h"
#include "bufferconsumer.h"
#include <QDebug>
@ -28,7 +29,6 @@ GstEnginePipeline::GstEnginePipeline(GstEngine* engine)
engine_(engine),
valid_(false),
sink_(GstEngine::kAutoSink),
forwards_buffers_(false),
rg_enabled_(false),
rg_mode_(0),
rg_preamp_(0.0),
@ -268,7 +268,7 @@ void GstEnginePipeline::NewPadCallback(GstElement*, GstPad* pad, gpointer self)
GstPad* const audiopad = gst_element_get_pad(instance->audiobin_, "sink");
if (GST_PAD_IS_LINKED(audiopad)) {
qDebug() << "audiopad is already linked. Unlinking old pad." ;
qDebug() << "audiopad is already linked. Unlinking old pad.";
gst_pad_unlink(audiopad, GST_PAD_PEER(audiopad));
}
@ -281,9 +281,15 @@ void GstEnginePipeline::NewPadCallback(GstElement*, GstPad* pad, gpointer self)
bool GstEnginePipeline::HandoffCallback(GstPad*, GstBuffer* buf, gpointer self) {
GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
if (instance->forwards_buffers_) {
QList<BufferConsumer*> consumers;
{
QMutexLocker l(&instance->buffer_consumers_mutex_);
consumers = instance->buffer_consumers_;
}
foreach (BufferConsumer* consumer, consumers) {
gst_buffer_ref(buf);
emit instance->BufferFound(buf);
consumer->ConsumeBuffer(buf, instance);
}
return true;
@ -426,3 +432,18 @@ void GstEnginePipeline::timerEvent(QTimerEvent* e) {
QObject::timerEvent(e);
}
void GstEnginePipeline::AddBufferConsumer(BufferConsumer *consumer) {
QMutexLocker l(&buffer_consumers_mutex_);
buffer_consumers_ << consumer;
}
void GstEnginePipeline::RemoveBufferConsumer(BufferConsumer *consumer) {
QMutexLocker l(&buffer_consumers_mutex_);
buffer_consumers_.removeAll(consumer);
}
void GstEnginePipeline::RemoveAllBufferConsumers() {
QMutexLocker l(&buffer_consumers_mutex_);
buffer_consumers_.clear();
}

View File

@ -21,6 +21,7 @@
#include <QUrl>
#include <QTimeLine>
#include <QBasicTimer>
#include <QMutex>
#include <gst/gst.h>
#include <boost/scoped_ptr.hpp>
@ -28,6 +29,7 @@
#include "engine_fwd.h"
class GstEngine;
class BufferConsumer;
struct GstURIDecodeBin;
@ -40,12 +42,16 @@ class GstEnginePipeline : public QObject {
// Call these setters before Init
void set_output_device(const QString& sink, const QString& device);
void set_forwards_buffers(bool v) { forwards_buffers_ = v; }
void set_replaygain(bool enabled, int mode, float preamp, bool compression);
// Creates the pipeline, returns false on error
bool Init(const QUrl& url);
// BufferConsumers get fed audio data. Thread-safe.
void AddBufferConsumer(BufferConsumer* consumer);
void RemoveBufferConsumer(BufferConsumer* consumer);
void RemoveAllBufferConsumers();
// Control the music playback
bool SetState(GstState state);
bool Seek(qint64 nanosec);
@ -73,7 +79,6 @@ class GstEnginePipeline : public QObject {
signals:
void EndOfStreamReached(bool has_next_track);
void MetadataFound(const Engine::SimpleMetaBundle& bundle);
void BufferFound(GstBuffer* buf);
void Error(const QString& message);
void FaderFinished();
@ -106,16 +111,23 @@ class GstEnginePipeline : public QObject {
GstEngine* engine_;
// General settings for the pipeline
bool valid_;
QString sink_;
QString device_;
bool forwards_buffers_;
// These get called when there is a new audio buffer available
QList<BufferConsumer*> buffer_consumers_;
QMutex buffer_consumers_mutex_;
// ReplayGain
bool rg_enabled_;
int rg_mode_;
float rg_preamp_;
bool rg_compression_;
// The URL that is currently playing, and the URL that is to be preloaded
// when the current track is close to finishing.
QUrl url_;
QUrl next_url_;

View File

@ -49,6 +49,11 @@
# include "widgets/osd.h"
#endif
#ifdef HAVE_GSTREAMER
# include <gst/gstbuffer.h>
class GstEnginePipeline;
#endif
// Load sqlite plugin on windows and mac.
#ifndef Q_WS_X11
# include <QtPlugin>
@ -100,6 +105,11 @@ int main(int argc, char *argv[]) {
qRegisterMetaType<const char*>("const char*");
qRegisterMetaType<QNetworkReply*>("QNetworkReply*");
#ifdef HAVE_GSTREAMER
qRegisterMetaType<GstBuffer*>("GstBuffer*");
qRegisterMetaType<GstEnginePipeline*>("GstEnginePipeline*");
#endif
lastfm::ws::ApiKey = LastFMService::kApiKey;
lastfm::ws::SharedSecret = LastFMService::kSecret;

View File

@ -1053,6 +1053,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr ""
@ -1206,6 +1209,9 @@ msgstr ""
msgid "Choose color..."
msgstr ""
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr ""

View File

@ -1059,6 +1059,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Knihovna"
@ -1212,6 +1215,9 @@ msgstr "Barva textu"
msgid "Choose color..."
msgstr "Vyber barvu..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Zkopírovat do knihovny..."

View File

@ -1062,6 +1062,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Bibliotek"
@ -1215,6 +1218,9 @@ msgstr "Tekstfarve"
msgid "Choose color..."
msgstr "Vælg farve..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Kopiér til bibliotek..."

View File

@ -1060,6 +1060,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Musiksammlung"
@ -1215,6 +1218,9 @@ msgstr "Text"
msgid "Choose color..."
msgstr "Farbe wählen..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "In die Musiksammlung kopieren..."

View File

@ -1063,6 +1063,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Βιβλιοθήκη"
@ -1216,6 +1219,9 @@ msgstr "Χρώμα κειμένου"
msgid "Choose color..."
msgstr "Επέλεξε χρώμα..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Αντιγραφή στην βιβλιοθήκη..."

View File

@ -1057,6 +1057,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Library"
@ -1210,6 +1213,9 @@ msgstr "Text colour"
msgid "Choose color..."
msgstr "Choose colour..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Copy to library..."

View File

@ -1067,6 +1067,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Colección"
@ -1222,6 +1225,9 @@ msgstr "Color del texto"
msgid "Choose color..."
msgstr "Elegir color..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Copiar a la colección..."

View File

@ -1053,6 +1053,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr ""
@ -1206,6 +1209,9 @@ msgstr ""
msgid "Choose color..."
msgstr ""
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Kopioi kirjastoon"

View File

@ -1065,6 +1065,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Bibliothèque"
@ -1220,6 +1223,9 @@ msgstr "Couleur du texte"
msgid "Choose color..."
msgstr "Choisir une couleur..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Copier dans la bilbiothèque..."

View File

@ -1055,6 +1055,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr ""
@ -1208,6 +1211,9 @@ msgstr ""
msgid "Choose color..."
msgstr ""
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Copiar para a biblioteca"

View File

@ -1064,6 +1064,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Raccolta"
@ -1219,6 +1222,9 @@ msgstr "Colore del testo"
msgid "Choose color..."
msgstr "Scegli colore..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Copia nella raccolta..."

View File

@ -1055,6 +1055,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr ""
@ -1208,6 +1211,9 @@ msgstr ""
msgid "Choose color..."
msgstr ""
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr ""

View File

@ -1059,6 +1059,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Bibliotek"
@ -1212,6 +1215,9 @@ msgstr "Tekstfarge"
msgid "Choose color..."
msgstr "Velg farge..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Kopier til bibliotek..."

View File

@ -1053,6 +1053,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Bibliotèca"
@ -1206,6 +1209,9 @@ msgstr "Color del tèxte"
msgid "Choose color..."
msgstr ""
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr ""

View File

@ -1057,6 +1057,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Biblioteka"
@ -1210,6 +1213,9 @@ msgstr "Kolor tekstu"
msgid "Choose color..."
msgstr "Wybierz kolor..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Skopiuj do biblioteki..."

View File

@ -1060,6 +1060,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Biblioteca"
@ -1213,6 +1216,9 @@ msgstr "Cor do Texto"
msgid "Choose color..."
msgstr "Escolher a cor.."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Copiar para a biblioteca"

View File

@ -1053,6 +1053,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr ""
@ -1206,6 +1209,9 @@ msgstr ""
msgid "Choose color..."
msgstr ""
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr ""

View File

@ -1054,6 +1054,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Bibliotecă"
@ -1207,6 +1210,9 @@ msgstr "Culoare text"
msgid "Choose color..."
msgstr "Alege culoare..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Copiază în bibliotecă..."

View File

@ -1059,6 +1059,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Коллекция"
@ -1213,6 +1216,9 @@ msgstr "Цвет текста"
msgid "Choose color..."
msgstr "Выберете цвет"
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Копировать в коллекцию..."

View File

@ -1061,6 +1061,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Zbierka"
@ -1214,6 +1217,9 @@ msgstr "Farba písma"
msgid "Choose color..."
msgstr "Vybrať farbu..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Skopírovať do zbierky..."

View File

@ -1062,6 +1062,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr "Bibliotek"
@ -1215,6 +1218,9 @@ msgstr "Textfärg"
msgid "Choose color..."
msgstr "Välj färg..."
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr "Kopiera till bibliotek..."

View File

@ -1053,6 +1053,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr ""
@ -1206,6 +1209,9 @@ msgstr ""
msgid "Choose color..."
msgstr ""
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr ""

View File

@ -1044,6 +1044,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr ""
@ -1197,6 +1200,9 @@ msgstr ""
msgid "Choose color..."
msgstr ""
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr ""

View File

@ -1053,6 +1053,9 @@ msgstr ""
msgid "Update Library"
msgstr ""
msgid "Visualisations"
msgstr ""
msgid "Library"
msgstr ""
@ -1206,6 +1209,9 @@ msgstr ""
msgid "Choose color..."
msgstr ""
msgid "Clementine Visualisation"
msgstr ""
msgid "Copy to library..."
msgstr ""

View File

@ -59,6 +59,7 @@ target_link_libraries(clementine_ui
clementine_playlistparsers
clementine_radio
clementine_transcoder
clementine_visualisations
)
add_translation_source(ui ${SOURCES} ${MOC} ${UIC})

View File

@ -51,6 +51,7 @@
#include "ui/iconloader.h"
#include "ui/settingsdialog.h"
#include "ui/systemtrayicon.h"
#include "visualisations/visualisationcontainer.h"
#include "widgets/errordialog.h"
#include "widgets/multiloadingindicator.h"
#include "widgets/osd.h"
@ -118,6 +119,7 @@ MainWindow::MainWindow(NetworkAccessManager* network, Engine::Type engine, QWidg
transcode_dialog_(new TranscodeDialog),
global_shortcuts_dialog_(new GlobalShortcutsDialog(global_shortcuts_)),
error_dialog_(new ErrorDialog),
visualisation_(new VisualisationContainer),
playlist_menu_(new QMenu(this)),
library_sort_model_(new QSortFilterProxyModel(this)),
track_position_timer_(new QTimer(this)),
@ -151,8 +153,10 @@ MainWindow::MainWindow(NetworkAccessManager* network, Engine::Type engine, QWidg
player_->Init();
#ifdef HAVE_GSTREAMER
if (GstEngine* engine = qobject_cast<GstEngine*>(player_->GetEngine()))
if (GstEngine* engine = qobject_cast<GstEngine*>(player_->GetEngine())) {
settings_dialog_->SetGstEngine(engine);
visualisation_->SetEngine(engine);
}
#endif
// Models
@ -233,6 +237,7 @@ MainWindow::MainWindow(NetworkAccessManager* network, Engine::Type engine, QWidg
connect(ui_->action_configure_global_shortcuts, SIGNAL(triggered()), global_shortcuts_dialog_.get(), SLOT(show()));
connect(ui_->action_jump, SIGNAL(triggered()), ui_->playlist->view(), SLOT(JumpToCurrentlyPlayingTrack()));
connect(ui_->action_update_library, SIGNAL(triggered()), library_, SLOT(IncrementalScan()));
connect(ui_->action_visualisations, SIGNAL(triggered()), visualisation_.get(), SLOT(show()));
// Give actions to buttons
ui_->forward_button->setDefaultAction(ui_->action_next_track);

View File

@ -54,6 +54,7 @@ class Song;
class SystemTrayIcon;
class TrackSlider;
class TranscodeDialog;
class VisualisationContainer;
class Ui_MainWindow;
class QSortFilterProxyModel;
@ -175,6 +176,7 @@ class MainWindow : public QMainWindow {
boost::scoped_ptr<TranscodeDialog> transcode_dialog_;
boost::scoped_ptr<GlobalShortcutsDialog> global_shortcuts_dialog_;
boost::scoped_ptr<ErrorDialog> error_dialog_;
boost::scoped_ptr<VisualisationContainer> visualisation_;
QMenu* playlist_menu_;
QAction* playlist_play_pause_;

View File

@ -341,7 +341,7 @@
<x>0</x>
<y>0</y>
<width>804</width>
<height>25</height>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menuMusic">
@ -398,6 +398,7 @@
</property>
<addaction name="action_cover_manager"/>
<addaction name="action_equalizer"/>
<addaction name="action_visualisations"/>
<addaction name="action_transcode"/>
<addaction name="separator"/>
<addaction name="action_update_library"/>
@ -597,6 +598,11 @@
<string>Update Library</string>
</property>
</action>
<action name="action_visualisations">
<property name="text">
<string>Visualisations</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

View File

@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 2.6)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${PROJECTM_INCLUDE_DIRS})
set(SOURCES
projectmvisualisation.cpp
visualisationcontainer.cpp
)
set(HEADERS
projectmvisualisation.h
visualisationcontainer.h
)
qt4_wrap_cpp(MOC ${HEADERS})
add_library(clementine_visualisations
${SOURCES}
${MOC}
)
target_link_libraries(clementine_visualisations
clementine_core
clementine_engines
${PROJECTM_LIBRARIES}
)
add_translation_source(visualisations ${SOURCES} ${MOC})

View File

@ -0,0 +1,67 @@
/* This file is part of Clementine.
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "projectmvisualisation.h"
#include <QTimerEvent>
#include <QtDebug>
#include <libprojectM/projectM.hpp>
ProjectMVisualisation::ProjectMVisualisation(QWidget *parent)
: QGLWidget(parent),
projectm_(NULL)
{
}
ProjectMVisualisation::~ProjectMVisualisation() {
}
void ProjectMVisualisation::showEvent(QShowEvent *) {
redraw_timer_.start(1000/25, this);
}
void ProjectMVisualisation::hideEvent(QHideEvent *) {
redraw_timer_.stop();
}
void ProjectMVisualisation::timerEvent(QTimerEvent* e) {
if (e->timerId() == redraw_timer_.timerId())
update();
}
void ProjectMVisualisation::initializeGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
projectm_.reset(new projectM("/usr/share/projectM/config.inp"));
projectm_->selectPreset(100);
}
void ProjectMVisualisation::paintGL() {
projectm_->renderFrame();
}
void ProjectMVisualisation::resizeGL(int w, int h) {
}
void ProjectMVisualisation::ConsumeBuffer(GstBuffer *buffer, GstEnginePipeline*) {
const int samples = GST_BUFFER_SIZE(buffer) / sizeof(short);
const short* data = reinterpret_cast<short*>(GST_BUFFER_DATA(buffer));
projectm_->pcm()->addPCM16Data(data, samples);
gst_buffer_unref(buffer);
}

View File

@ -0,0 +1,54 @@
/* This file is part of Clementine.
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PROJECTMVISUALISATION_H
#define PROJECTMVISUALISATION_H
#include <QGLWidget>
#include <QBasicTimer>
#include <boost/scoped_ptr.hpp>
#include "engines/bufferconsumer.h"
class projectM;
class ProjectMVisualisation : public QGLWidget, public BufferConsumer {
Q_OBJECT
public:
ProjectMVisualisation(QWidget *parent = 0);
~ProjectMVisualisation();
// QGLWidget
void paintGL();
void resizeGL(int w, int h);
void initializeGL();
// BufferConsumer
void ConsumeBuffer(GstBuffer *buffer, GstEnginePipeline*);
protected:
// QWidget
void hideEvent(QHideEvent *);
void showEvent(QShowEvent *);
void timerEvent(QTimerEvent *);
private:
boost::scoped_ptr<projectM> projectm_;
QBasicTimer redraw_timer_;
};
#endif // PROJECTMVISUALISATION_H

View File

@ -0,0 +1,52 @@
/* This file is part of Clementine.
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "visualisationcontainer.h"
#include "projectmvisualisation.h"
#include "engines/gstengine.h"
#include <QHBoxLayout>
VisualisationContainer::VisualisationContainer(QWidget *parent)
: QWidget(parent),
engine_(NULL),
vis_(new ProjectMVisualisation(this))
{
setWindowTitle(tr("Clementine Visualisation"));
resize(512, 512);
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(vis_);
setLayout(layout);
}
void VisualisationContainer::SetEngine(GstEngine* engine) {
engine_ = engine;
if (isVisible())
engine_->AddBufferConsumer(vis_);
}
void VisualisationContainer::showEvent(QShowEvent*) {
if (engine_)
engine_->AddBufferConsumer(vis_);
}
void VisualisationContainer::hideEvent(QHideEvent*) {
if (engine_)
engine_->RemoveBufferConsumer(vis_);
}

View File

@ -0,0 +1,43 @@
/* This file is part of Clementine.
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VISUALISATIONCONTAINER_H
#define VISUALISATIONCONTAINER_H
#include <QWidget>
class ProjectMVisualisation;
class GstEngine;
class VisualisationContainer : public QWidget {
Q_OBJECT
public:
VisualisationContainer(QWidget* parent = 0);
void SetEngine(GstEngine* engine);
protected:
// QWidget
void showEvent(QShowEvent*);
void hideEvent(QHideEvent*);
private:
GstEngine* engine_;
ProjectMVisualisation* vis_;
};
#endif // VISUALISATIONCONTAINER_H