1,373 changes: 0 additions & 1,373 deletions mythplugins/mythmusic/mythmusic/databasebox.cpp

This file was deleted.

121 changes: 0 additions & 121 deletions mythplugins/mythmusic/mythmusic/databasebox.h

This file was deleted.

24 changes: 17 additions & 7 deletions mythplugins/mythmusic/mythmusic/decoderhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ void DecoderIOFactoryFile::start(void)
doConnectDecoder(getUrl().toLocalFile());
}

/**********************************************************************/

DecoderIOFactoryUrl::DecoderIOFactoryUrl(DecoderHandler *parent) : DecoderIOFactory(parent)
{
m_accessManager = new QNetworkAccessManager(this);
Expand Down Expand Up @@ -193,7 +195,7 @@ void DecoderIOFactoryUrl::replyFinished(QNetworkReply *reply)
{
LOG(VB_PLAYBACK, LOG_INFO,
QString("DecoderIOFactory: Got redirected to %1")
.arg(possibleRedirectUrl));
.arg(possibleRedirectUrl.toString()));

m_redirectCount++;

Expand Down Expand Up @@ -240,7 +242,7 @@ void DecoderIOFactoryUrl::readyRead(void)

void DecoderIOFactoryUrl::doStart(void)
{
doConnectDecoder(getUrl());
doConnectDecoder(getUrl().toString());
m_started = true;
}

Expand Down Expand Up @@ -381,7 +383,7 @@ void DecoderHandler::stop(void)
if (m_decoder)
{
m_decoder->wait();
delete m_decoder->input();
//delete m_decoder->input(); // TODO: need to sort out who is responsible for the input
delete m_decoder;
m_decoder = NULL;
}
Expand All @@ -406,7 +408,7 @@ bool DecoderHandler::createPlaylist(const QUrl &url)
QString extension = QFileInfo(url.path()).suffix();
LOG(VB_NETWORK, LOG_INFO,
QString("File %1 has extension %2")
.arg(url.fileName()).arg(extension));
.arg(QFileInfo(url.path()).fileName()).arg(extension));

if (extension == "pls" || extension == "m3u")
{
Expand Down Expand Up @@ -439,7 +441,9 @@ bool DecoderHandler::createPlaylistFromFile(const QUrl &url)
f.open(QIODevice::ReadOnly);
QTextStream stream(&f);

if (PlayListFile::parse(&m_playlist, &stream) < 0)
QString extension = QFileInfo(url.path()).suffix().toLower();

if (PlayListFile::parse(&m_playlist, &stream, extension) <= 0)
return false;

return m_playlist.size() > 0;
Expand All @@ -454,14 +458,20 @@ bool DecoderHandler::createPlaylistFromRemoteUrl(const QUrl &url)

QByteArray data;

if (!GetMythDownloadManager()->download(url, &data))
if (!GetMythDownloadManager()->download(url.toString(), &data))
{
LOG(VB_GENERAL, LOG_ERR, QString("DecoderHandler:: Failed to download playlist from: %1").arg(url.toString()));
doOperationStop();
return false;
}

doOperationStop();

QTextStream stream(&data, QIODevice::ReadOnly);

bool result = PlayListFile::parse(&m_playlist, &stream) > 0;
QString extension = QFileInfo(url.path()).suffix().toLower();

bool result = PlayListFile::parse(&m_playlist, &stream, extension) > 0;

return result;
}
Expand Down
57 changes: 30 additions & 27 deletions mythplugins/mythmusic/mythmusic/editmetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,10 @@
#include "genres.h"
#include "metaio.h"
#include "musicplayer.h"
#include "musicutils.h"

#include "editmetadata.h"

static inline QString fixFileToken(QString token)
{
token.replace(QRegExp("(/|\\\\|:|\'|\"|\\?|\\|)"), QString("_"));
return token;
}

// these need to be static so both screens can pick them up
bool EditMetadataCommon::metadataOnly = false;
Metadata *EditMetadataCommon::m_metadata = NULL;
Expand Down Expand Up @@ -401,24 +396,6 @@ bool EditMetadataDialog::Create(void)
return true;
}

QString EditMetadataDialog::findIcon(const QString &type, const QString &name)
{
QString cleanName = fixFileToken(name);
QString file = GetConfDir() + QString("/MythMusic/Icons/%1/%2").arg(type).arg(cleanName);

if (QFile::exists(file + ".jpg"))
return file + ".jpg";

if (QFile::exists(file + ".jpeg"))
return file + ".jpeg";

if (QFile::exists(file + ".png"))
return file + ".png";

return QString();

}

void EditMetadataDialog::fillWidgets()
{
m_compArtistEdit->SetText(m_metadata->CompilationArtist());
Expand Down Expand Up @@ -520,7 +497,7 @@ void EditMetadataDialog::showMenu(void )
menu->AddButton(tr("Search Internet For Artist Image"));
menu->AddButton(tr("Search Internet For Album Image"));
menu->AddButton(tr("Search Internet For Genre Image"));

menu->AddButton(tr("Check Track Length"));
menu->AddButton(tr("Cancel"));

popupStack->AddScreen(menu);
Expand Down Expand Up @@ -750,7 +727,7 @@ void EditMetadataDialog::searchForGenreImages(void)

QUrl url("http://www.flickr.com/search/groups/?w=908425%40N22&m=pool&q=" + genre, QUrl::TolerantMode);

QString cleanName = fixFileToken(m_metadata->Genre().toLower());
QString cleanName = fixFilename(m_metadata->Genre().toLower());
QString file = GetConfDir() + QString("/MythMusic/Icons/%1/%2.jpg").arg("genre").arg(cleanName);

QFileInfo fi(file);
Expand All @@ -765,7 +742,7 @@ void EditMetadataDialog::searchForArtistImages(void)

QUrl url("http://www.google.co.uk/images?q=" + artist, QUrl::TolerantMode);

QString cleanName = fixFileToken(m_metadata->Artist().toLower());
QString cleanName = fixFilename(m_metadata->Artist().toLower());
QString file = GetConfDir() + QString("/MythMusic/Icons/%1/%2.jpg").arg("artist").arg(cleanName);

QFileInfo fi(file);
Expand Down Expand Up @@ -805,6 +782,31 @@ void EditMetadataDialog::customEvent(QEvent *event)
updateMetadata();
searchForAlbumImages();
}
else if (resulttext == tr("Check Track Length"))
{
int length = calcTrackLength(m_metadata->Filename());

if (length != m_metadata->Length() / 1000)
{
int oldLength = m_metadata->Length() / 1000;

// save the new length to our working copy of the metadata
m_metadata->setLength(length * 1000);

// save the new length to the source copy of the metadata
m_sourceMetadata->setLength(length * 1000);
m_sourceMetadata->dumpToDatabase();

// this will update any track lengths displayed on screen
gPlayer->sendMetadataChangedEvent(m_sourceMetadata->ID());

// this will force the playlist stats to update
MusicPlayerEvent me(MusicPlayerEvent::TrackChangeEvent, gPlayer->getCurrentTrackPos());
gPlayer->dispatch(me);

ShowOkPopup(QString("Updated track length to %1 seconds\nwas %2 seconds").arg(length).arg(oldLength));
}
}
}
}
else if (event->type() == MythEvent::MythEventMessage)
Expand Down Expand Up @@ -1031,6 +1033,7 @@ void EditAlbumartDialog::showTypeMenu(bool changeType)
menu->AddButton(m_albumArt->getTypeName(IT_BACKCOVER), qVariantFromValue((int)IT_BACKCOVER), false, (imageType == IT_BACKCOVER));
menu->AddButton(m_albumArt->getTypeName(IT_CD), qVariantFromValue((int)IT_CD), false, (imageType == IT_CD));
menu->AddButton(m_albumArt->getTypeName(IT_INLAY), qVariantFromValue((int)IT_INLAY), false, (imageType == IT_INLAY));
menu->AddButton(m_albumArt->getTypeName(IT_ARTIST), qVariantFromValue((int)IT_ARTIST), false, (imageType == IT_ARTIST));

popupStack->AddScreen(menu);
}
Expand Down
4 changes: 0 additions & 4 deletions mythplugins/mythmusic/mythmusic/editmetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ using namespace std;
#include <mythscreentype.h>
#include "metadata.h"

class Metadata;
class AlbumArtImages;
class AlbumArtImage;
class MythUIStateType;
class MythUIImage;
class MythUIButton;
Expand Down Expand Up @@ -96,7 +93,6 @@ class EditMetadataDialog : public EditMetadataCommon
private:
void showMenu(void);
void fillWidgets(void);
QString findIcon(const QString &type, const QString &name);

void updateArtistImage(void);
void updateAlbumImage(void);
Expand Down
6 changes: 2 additions & 4 deletions mythplugins/mythmusic/mythmusic/filescanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,7 @@ void FileScanner::AddFileToDB(const QString &filename)
directory.remove(0, m_startdir.length());
directory = directory.section( '/', 0, -2);

QString nameFilter = gCoreContext->GetSetting("AlbumArtFilter",
"*.png;*.jpg;*.jpeg;*.gif;*.bmp");
QString nameFilter = gCoreContext->GetSetting("AlbumArtFilter", "*.png;*.jpg;*.jpeg;*.gif;*.bmp");

// If this file is an image, insert the details into the music_albumart table
if (nameFilter.indexOf(extension.toLower()) > -1)
Expand Down Expand Up @@ -270,9 +269,8 @@ void FileScanner::AddFileToDB(const QString &filename)
LOG(VB_FILE, LOG_INFO,
QString("Reading metadata from %1").arg(filename));
Metadata *data = decoder->readMetadata();
if (data)
if (data)
{

QString album_cache_string;

// Set values from cache
Expand Down
400 changes: 9 additions & 391 deletions mythplugins/mythmusic/mythmusic/globalsettings.cpp

Large diffs are not rendered by default.

44 changes: 0 additions & 44 deletions mythplugins/mythmusic/mythmusic/globalsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@
#include "mythtv/settings.h"
#include "mythtv/mythcontext.h"

class QKeyEvent;
class QEvent;
class Q3MythListView;
class Q3ListViewItem;

class MusicGeneralSettings : public ConfigurationWizard
{
public:
Expand All @@ -22,12 +17,6 @@ class MusicPlayerSettings : public QObject, public ConfigurationWizard
public:
MusicPlayerSettings();
~MusicPlayerSettings() {};

public slots:
void showVisEditor(void);

private:
HostLineEdit *visModesEdit;
};

class MusicRipperSettings : public ConfigurationWizard
Expand All @@ -36,37 +25,4 @@ class MusicRipperSettings : public ConfigurationWizard
MusicRipperSettings();
};


class VisualizationsEditor : public MythDialog
{
Q_OBJECT
public:

VisualizationsEditor(const QString &currentSelection, MythMainWindow *parent,
const char *name = 0);
~VisualizationsEditor(void);

QString getSelectedModes(void);

protected slots:
void okClicked(void);
void cancelClicked(void);
void upClicked(void);
void downClicked(void);
void availableChanged(Q3ListViewItem *item);
void selectedChanged(Q3ListViewItem *item);
void availableOnSelect(Q3ListViewItem *item);
void selectedOnSelect(Q3ListViewItem *item);

protected:
bool eventFilter(QObject *obj, QEvent *ev);
bool handleKeyPress(QKeyEvent *e);

private:
void fillWidgets(const QString &currentSelection);

Q3MythListView *availableList;
Q3MythListView *selectedList;
};

#endif
95 changes: 36 additions & 59 deletions mythplugins/mythmusic/mythmusic/goom/mythgoom.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include "mythgoom.h"

#ifdef SDL_SUPPORT

#include <cmath>
#include <cstdlib>

Expand All @@ -19,72 +17,54 @@ extern "C" {
#include "goom_core.h"
}

Goom::Goom(long int winid)
Goom::Goom()
{
fps = 20;

surface = NULL;
buffer = NULL;

char SDL_windowhack[32];
//char SDL_windowhack[sizeof(long int)];
sprintf(SDL_windowhack, "%ld", winid);
setenv("SDL_WINDOWID", SDL_windowhack, 1);

if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0)
{
LOG(VB_GENERAL, LOG_ERR, "Unable to init SDL");
return;
}
m_fps = 20;

SDL_ShowCursor(0);
m_buffer = NULL;

goom_init(800, 600, 0);

scalew = gCoreContext->GetNumSetting("VisualScaleWidth", 2);
scaleh = gCoreContext->GetNumSetting("VisualScaleHeight", 2);
m_scalew = 1; //gCoreContext->GetNumSetting("VisualScaleWidth", 2);
m_scaleh = 1; //gCoreContext->GetNumSetting("VisualScaleHeight", 2);

if (scaleh > 2)
scaleh = 2;
if (scaleh < 1)
scaleh = 1;
if (m_scaleh > 2)
m_scaleh = 2;
if (m_scaleh < 1)
m_scaleh = 1;

if (scalew > 2)
scalew = 2;
if (scalew < 1)
scalew = 1;
if (m_scalew > 2)
m_scalew = 2;
if (m_scalew < 1)
m_scalew = 1;
}

Goom::~Goom()
{
goom_close();
SDL_Quit();

unsetenv("SDL_WINDOWID");
}

void Goom::resize(const QSize &newsize)
{
size = newsize;
m_size = newsize;

size.setHeight((size.height() / 2) * 2);
size.setWidth((size.width() / 2) * 2);
m_size.setHeight((m_size.height() / 2) * 2);
m_size.setWidth((m_size.width() / 2) * 2);

surface = SDL_SetVideoMode(size.width(), size.height(), 32, 0 /* SDL_ANYFORMAT */);
goom_set_resolution(size.width() / scalew, size.height() / scaleh, 0);
goom_set_resolution(m_size.width() / m_scalew, m_size.height() / m_scaleh, 0);
}

bool Goom::process(VisualNode *node)
{
if (!node || node->length == 0 || !surface)
return true;
if (!node || node->length == 0)
return false;

int numSamps = 512;
if (node->length < 512)
numSamps = node->length;

signed short int data[2][512];

int i = 0;
for (i = 0; i < numSamps; i++)
{
Expand All @@ -101,29 +81,21 @@ bool Goom::process(VisualNode *node)
data[1][i] = 0;
}

buffer = goom_update(data, 0);
m_buffer = goom_update(data, 0);

return false;
}

bool Goom::draw(QPainter *p, const QColor &back)
{
(void)p;
(void)back;

if (!surface)
{
LOG(VB_GENERAL, LOG_ERR, "No sdl surface");
return false;
}
p->fillRect(0, 0, m_size.width(), m_size.height(), back);

if (!buffer)
return false;
if (!m_buffer)
return true;

#if 0
if (scalew != 1 || scaleh != 1)
{
SDL_LockSurface(surface);

register int *d = (int*)surface->pixels;
register int *s = (int*)buffer;

Expand Down Expand Up @@ -172,10 +144,17 @@ bool Goom::draw(QPainter *p, const QColor &back)

SDL_UnlockSurface(surface);
SDL_Flip(surface);
#endif
QImage *image = new QImage((uchar*) m_buffer, m_size.width(), m_size.height(), m_size.width() * 4, QImage::Format_ARGB32);

return false;
p->drawImage(0, 0, *image);

delete image;

return true;
}

//#if 0
static class GoomFactory : public VisFactory
{
public:
Expand All @@ -191,13 +170,11 @@ static class GoomFactory : public VisFactory
return 1;
}

VisualBase *create(MainVisual *parent, long int winid, const QString &pluginName) const
VisualBase *create(MainVisual *parent, const QString &pluginName) const
{
(void)parent;
(void)pluginName;
return new Goom(winid);
return new Goom();
}
}GoomFactory;


#endif
//#endif
15 changes: 4 additions & 11 deletions mythplugins/mythmusic/mythmusic/goom/mythgoom.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@

using namespace std;

#ifdef SDL_SUPPORT
#include <SDL.h>

class Goom : public VisualBase
{
public:
Goom(long int winid);
Goom(void);
virtual ~Goom();

void resize(const QSize &size);
Expand All @@ -21,14 +18,10 @@ class Goom : public VisualBase
void handleKeyPress(const QString &action) {(void) action;}

private:
QSize size;

SDL_Surface *surface;
QSize m_size;

unsigned int *buffer;
int scalew, scaleh;
unsigned int *m_buffer;
int m_scalew, m_scaleh;
};

#endif //SDL_SUPPORT

#endif //MYTHGOOM
2 changes: 1 addition & 1 deletion mythplugins/mythmusic/mythmusic/importmusic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ void ImportCoverArtDialog::scanDirectory()
QString nameFilter = gCoreContext->GetSetting("AlbumArtFilter",
"*.png;*.jpg;*.jpeg;*.gif;*.bmp");

QFileInfoList list = d.entryInfoList(nameFilter);
QFileInfoList list = d.entryInfoList(nameFilter.split(";"));
if (list.isEmpty())
return;

Expand Down
381 changes: 0 additions & 381 deletions mythplugins/mythmusic/mythmusic/libvisualplugin.cpp

This file was deleted.

52 changes: 0 additions & 52 deletions mythplugins/mythmusic/mythmusic/libvisualplugin.h

This file was deleted.

65 changes: 45 additions & 20 deletions mythplugins/mythmusic/mythmusic/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@
// MythMusic headers
#include "decoder.h"
#include "metadata.h"
#include "databasebox.h"
#include "playbackbox.h"
#include "playlisteditorview.h"
#include "playlistview.h"
#include "playlistcontainer.h"
#include "globalsettings.h"
#include "dbcheck.h"
#include "filescanner.h"
#include "musicplayer.h"
#include "config.h"
#include "mainvisual.h"
#ifndef USING_MINGW
#include "cdrip.h"
#include "importmusic.h"
Expand Down Expand Up @@ -213,18 +214,15 @@ static void loadMusic()
else
busy = NULL;

QString paths = gCoreContext->GetSetting("TreeLevels");

// Set the various track formatting modes
Metadata::setArtistAndTrackFormats();

AllMusic *all_music = new AllMusic(paths, startdir);
AllMusic *all_music = new AllMusic(startdir);

// Load all playlists into RAM (once!)
PlaylistContainer *all_playlists = new PlaylistContainer(
all_music, gCoreContext->GetHostName());

gMusicData->paths = paths;
gMusicData->startdir = startdir;
gMusicData->all_playlists = all_playlists;
gMusicData->all_music = all_music;
Expand All @@ -237,7 +235,7 @@ static void loadMusic()
}
gMusicData->all_playlists->postLoad();

gPlayer->constructPlaylist();
gPlayer->loadPlaylist();

if (busy)
busy->Close();
Expand All @@ -247,24 +245,30 @@ static void loadMusic()
static void startPlayback(void)
{
loadMusic();
PlaybackBoxMusic *pbb;
pbb = new PlaybackBoxMusic(GetMythMainWindow(),
"music_play", "music-", chooseCD(), "music_playback");
pbb->exec();
qApp->processEvents();

delete pbb;
MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();

PlaylistView *view = new PlaylistView(mainStack);

if (view->Create())
mainStack->AddScreen(view);
else
delete view;
}

static void startDatabaseTree(void)
{
loadMusic();
DatabaseBox *dbbox = new DatabaseBox(GetMythMainWindow(),
chooseCD(), "music_select", "music-", "music database");
dbbox->exec();
delete dbbox;

gPlayer->constructPlaylist();
MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();

QString lastView = gCoreContext->GetSetting("MusicPlaylistEditorView", "tree");
PlaylistEditorView *view = new PlaylistEditorView(mainStack, lastView);

if (view->Create())
mainStack->AddScreen(view);
else
delete view;
}

static void startRipper(void)
Expand Down Expand Up @@ -349,6 +353,11 @@ static void MusicCallback(void *data, QString &selection)
gCoreContext->ActivateSettingsCache(false);
MusicPlayerSettings settings;
settings.exec();

// reload the list of visualizers incase they've been changed
MainVisual::visualizers = MainVisual::Visualizations(false);
MainVisual::currentVisualizer = 0;

gCoreContext->ActivateSettingsCache(true);

gCoreContext->dispatch(MythEvent(QString("MUSIC_SETTINGS_CHANGED")));
Expand Down Expand Up @@ -452,6 +461,16 @@ static void showMiniPlayer(void)

static void handleMedia(MythMediaDevice *cd)
{
// if the music player is already playing ignore the event
if (gPlayer->isPlaying())
{
LOG(VB_GENERAL, LOG_NOTICE, "Got a media changed event but ignoring since "
"the music player is already playing");
return;
}
else
LOG(VB_GENERAL, LOG_NOTICE, "Got a media changed event");

// Note that we should deal with other disks that may contain music.
// e.g. MEDIATYPE_MMUSIC or MEDIATYPE_MIXED

Expand Down Expand Up @@ -560,7 +579,13 @@ static void setupKeys(void)
"Increase Play Speed"), "W");
REG_KEY("Music", "SPEEDDOWN", QT_TRANSLATE_NOOP("MythControls",
"Decrease Play Speed"), "X");
REG_KEY("Music", "MARK", QT_TRANSLATE_NOOP("MythControls",
"Toggle track selection"), "T");


// FIXME need to find a way to stop the media monitor jumping to the main menu before
// calling the handler
#if 0
REG_MEDIA_HANDLER(QT_TRANSLATE_NOOP("MythControls",
"MythMusic Media Handler 1/2"), "", "", handleMedia,
MEDIATYPE_AUDIO | MEDIATYPE_MIXED, QString::null);
Expand All @@ -569,6 +594,7 @@ static void setupKeys(void)
MEDIATYPE_MMUSIC, "mp3,mp2,ogg,oga,flac,wma,wav,ac3,"
"oma,omg,atp,ra,dts,aac,m4a,aa3,tta,"
"mka,aiff,swa,wv");
#endif
}

int mythplugin_init(const char *libversion)
Expand Down Expand Up @@ -618,7 +644,6 @@ int mythplugin_run(void)

int mythplugin_config(void)
{
gMusicData->paths = gCoreContext->GetSetting("TreeLevels");
gMusicData->startdir = gCoreContext->GetSetting("MusicLocation");
gMusicData->startdir = QDir::cleanPath(gMusicData->startdir);

Expand Down Expand Up @@ -650,7 +675,7 @@ void mythplugin_destroy(void)
SavePending(x);
}

gPlayer->deleteLater();
delete gPlayer;

delete gMusicData;
}
910 changes: 101 additions & 809 deletions mythplugins/mythmusic/mythmusic/mainvisual.cpp

Large diffs are not rendered by default.

203 changes: 30 additions & 173 deletions mythplugins/mythmusic/mythmusic/mainvisual.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,198 +24,55 @@ using namespace std;
// MythTV headers
#include <visual.h>

class Buffer;
class Output;
class VisualNode;
class LogScale;
class InfoWidget;
class Metadata;
class MainVisual;
// MythMusic
#include "visualize.h"

#define SAMPLES_DEFAULT_SIZE 512

class VisualNode
{
public:
VisualNode(short *l, short *r, unsigned long n, unsigned long o)
: left(l), right(r), length(n), offset(o)
{
// left and right are allocated and then passed to this class
// the code that allocated left and right should give up all ownership
}

~VisualNode()
{
delete [] left;
delete [] right;
}

short *left, *right;
unsigned long length, offset;
};

class VisualBase
{
public:
VisualBase(bool screensaverenable = false);
virtual ~VisualBase(void);

// return true if the output should stop
virtual bool process( VisualNode *node ) = 0;

// this is called on nodes that will not be displayed :: Not needed for most visualizations
// (i.e. between the displayed frames, if you need the whole audio stream)
virtual bool processUndisplayed( VisualNode * )
{
return true; // By default this does nothing : Ignore the in-between chunks of audio data
};

virtual bool draw( QPainter *, const QColor & ) = 0;
virtual void resize( const QSize &size ) = 0;
virtual void handleKeyPress(const QString &action) = 0;
virtual int getDesiredFPS(void) { return fps; }
// Override this if you need the potential of capturing more data than the default
virtual unsigned long getDesiredSamples(void) { return SAMPLES_DEFAULT_SIZE; }
void drawWarning(QPainter *, const QColor &, const QSize &, QString);

protected:
int fps;
bool xscreensaverenable;
};

class VisFactory
{
public:
VisFactory() {m_pNextVisFactory = g_pVisFactories; g_pVisFactories = this;}
virtual ~VisFactory() {}
const VisFactory* next() const {return m_pNextVisFactory;}
virtual const QString &name(void) const = 0;
virtual VisualBase* create(MainVisual *parent, long int winid,
const QString &pluginName) const = 0;
virtual uint plugins(QStringList *list) const = 0;
static const VisFactory* VisFactories() {return g_pVisFactories;}
protected:
static VisFactory* g_pVisFactories;
VisFactory* m_pNextVisFactory;
};
class MythUIVideo;

// base class to handle things like frame rate...
class MainVisual : public QWidget, public MythTV::Visual
class MainVisual : public QObject, public MythTV::Visual
{
Q_OBJECT

public:
MainVisual(QWidget *parent = 0, const char * = 0);
public:
MainVisual(MythUIVideo *visualiser);
virtual ~MainVisual();

VisualBase *visual() const { return vis; }
VisualBase *visual(void) const { return m_vis; }
void setVisual(const QString &name);

void add(uchar *, unsigned long, unsigned long, int, int);
void prepare();

QSize minimumSizeHint() const { return sizeHint(); }
QSize sizeHint() const { return QSize(4*4*4*2, 3*3*3*2); }

void paintEvent( QPaintEvent * );
void resizeEvent( QResizeEvent * );
void customEvent( QEvent * );
void hideEvent( QHideEvent * );

void setFrameRate( int newfps );
int frameRate() const { return fps; }

void showBanner(const QString &text, int showTime = 8000);
void showBanner(Metadata *meta, bool fullScreen, int visMode, int showTime = 8000);
void hideBanner();
bool bannerIsShowing(void) {return bannerTimer->isActive(); }
void stop(void);

static QStringList Visualizations();
void resize(const QSize &size);

public slots:
void timeout();
void bannerTimeout();

signals:
void hidingVisualization();

private:
VisualBase *vis;
QPixmap pixmap;
QList<VisualNode*> nodes;
bool playing;
int fps;
unsigned long samples;
QTimer *timer;
QTimer *bannerTimer;
InfoWidget* info_widget;

QString current_visual_name;
};

class InfoWidget : public QWidget
{
Q_OBJECT

public:
InfoWidget(QWidget *parent = 0);
void showInformation(const QString &text);
void showMetadata(Metadata *meta, bool fullScreen, int visMode);
void paintEvent(QPaintEvent *);
void setDisplayRect(QRect rect) { displayRect = rect; }

private:
QString info;
QPixmap info_pixmap;
QRect displayRect;
};

class StereoScope : public VisualBase
{
public:
StereoScope();
virtual ~StereoScope();

void resize( const QSize &size );
bool process( VisualNode *node );
bool draw( QPainter *p, const QColor &back );
void handleKeyPress(const QString &action) {(void) action;}

protected:
QColor startColor, targetColor;
vector<double> magnitudes;
QSize size;
bool const rubberband;
double const falloff;
};

class MonoScope : public StereoScope
{
public:
MonoScope();
virtual ~MonoScope();
void add(uchar *, unsigned long, unsigned long, int, int);
void prepare(void);

bool process( VisualNode *node );
bool draw( QPainter *p, const QColor &back );
};
void customEvent(QEvent *);

class LogScale
{
public:
LogScale(int = 0, int = 0);
~LogScale();
void setFrameRate(int newfps);
int frameRate(void) const { return m_fps; }

int scale() const { return s; }
int range() const { return r; }
static QStringList Visualizations(bool showall = true);

void setMax(int, int);
/// list of visualizers (chosen by the user)
static QStringList visualizers;

int operator[](int);
/// index of the current visualizer
static int currentVisualizer;

public slots:
void timeout();

private:
int *indices;
int s, r;
private:
MythUIVideo *m_visualiserVideo;
VisualBase *m_vis;
QPixmap m_pixmap;
QList<VisualNode*> m_nodes;
bool m_playing;
int m_fps;
unsigned long m_samples;
QTimer *m_updateTimer;
};

#endif // __mainvisual_h
Expand Down
511 changes: 108 additions & 403 deletions mythplugins/mythmusic/mythmusic/metadata.cpp

Large diffs are not rendered by default.

147 changes: 40 additions & 107 deletions mythplugins/mythmusic/mythmusic/metadata.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
#ifndef METADATA_H_
#define METADATA_H_

// C++
// C/C++
#include <vector>
#include <iostream>
#include <stdint.h>

using namespace std;

// qt
#include <QStringList>
#include <QMap>
#include <QDateTime>
#include <QImage>
#include <QMetaType>


// mythtv
#include <uitypes.h>
#include "mythexp.h"
#include <mthread.h>

// mythmusic
#include "treecheckitem.h"


class AllMusic;
Expand All @@ -29,6 +35,7 @@ enum ImageType
IT_BACKCOVER,
IT_CD,
IT_INLAY,
IT_ARTIST,
IT_LAST
};

Expand All @@ -49,7 +56,6 @@ class AlbumArtImage
};

typedef QList<AlbumArtImage*> AlbumArtList;

typedef QHash<QString,QString> MetadataMap;


Expand Down Expand Up @@ -97,14 +103,15 @@ class Metadata
m_albumid(-1),
m_genreid(-1),
m_lastplay(llastplay),
m_templastplay(QDateTime()),
m_dateadded(ldateadded),
m_playcount(lplaycount),
m_tempplaycount(0),
m_compilation(lcompilation),
m_albumArt(NULL),
m_id(lid),
m_filename(lfilename),
m_changed(false),
m_show(true)
m_changed(false)
{
checkEmptyFields();
}
Expand Down Expand Up @@ -169,7 +176,7 @@ class Metadata
void setLength(int llength) { m_length = llength; }

int Playcount() const { return m_playcount; }
void setPlaycount(int lplaycount) { m_playcount = lplaycount; }
void setPlaycount(int lplaycount) { m_tempplaycount = lplaycount; }

IdType ID() const { return m_id; }
void setID(IdType lid) { m_id = lid; }
Expand All @@ -194,9 +201,6 @@ class Metadata
int PlayCount() const { return m_playcount; }
void incPlayCount();

bool isVisible() const { return m_show; }
void setVisible(bool visible) { m_show = visible; }

// track is part of a compilation album
bool Compilation() const { return m_compilation; }
void setCompilation(bool state)
Expand All @@ -213,17 +217,17 @@ class Metadata
void dumpToDatabase(void);
void setField(const QString &field, const QString &data);
void getField(const QString& field, QString *data);
void toMap(MetadataMap &metadataMap);
void toMap(MetadataMap &metadataMap, const QString &prefix = "");

void persist(void) const;
void persist(void);
void UpdateModTime(void) const;
bool hasChanged() const { return m_changed; }
int compare(const Metadata *other) const;
static void setArtistAndTrackFormats();
int compare(const Metadata *other) const;

// static functions
static void setArtistAndTrackFormats();
static void SetStartdir(const QString &dir);
static QString GetStartdir() { return m_startdir; }

static QStringList fillFieldList(QString field);

// this looks for any image available - preferring a front cover if available
Expand Down Expand Up @@ -259,8 +263,10 @@ class Metadata
int m_albumid;
int m_genreid;
QDateTime m_lastplay;
QDateTime m_templastplay;
QDateTime m_dateadded;
int m_playcount;
int m_tempplaycount;
bool m_compilation;

AlbumArtImages *m_albumArt;
Expand All @@ -269,8 +275,6 @@ class Metadata
QString m_filename;
bool m_changed;

bool m_show;

static QString m_startdir;

// Various formatting strings
Expand All @@ -291,59 +295,7 @@ bool operator!=(const Metadata& a, const Metadata& b);
Q_DECLARE_METATYPE(Metadata *)

typedef QList<Metadata*> MetadataPtrList;
class MusicNode;
typedef QList<MusicNode*> MusicNodePtrList;

class MusicNode
{
public:

MusicNode(const QString &a_title, const QString &tree_level);
~MusicNode();

QString getTitle(void) const { return my_title; }
void putYourselfOnTheListView(TreeCheckItem *parent, bool show_node);
void writeTree(GenericTree *tree_to_write_to, int a_counter);
void sort();
void setPlayCountMin(int tmp_min) { m_playcountMin = tmp_min; }
void setPlayCountMax(int tmp_max) { m_playcountMax = tmp_max; }
void setLastPlayMin(double tmp_min) { m_lastplayMin = tmp_min; }
void setLastPlayMax(double tmp_max) { m_lastplayMax = tmp_max; }

inline void addChild(MusicNode *child) { my_subnodes.append(child); }
inline void addLeaf(Metadata *leaf) { my_tracks.append(leaf); }
inline void setLeaves(MetadataPtrList leaves) { my_tracks = leaves; }

void clear(void)
{
while (!my_subnodes.isEmpty())
delete my_subnodes.takeFirst();

// done delete the metadata since AllMusic owns it
my_tracks.clear();
}

static void SetStaticData(const QString &startdir, const QString &paths);

private:

MetadataPtrList my_tracks;
MusicNodePtrList my_subnodes;
QString my_title;
QString my_level;

static QString m_startdir;
static QString m_paths;
static int m_RatingWeight;
static int m_PlayCountWeight;
static int m_LastPlayWeight;
static int m_RandomWeight;

int m_playcountMin;
int m_playcountMax;
double m_lastplayMin;
double m_lastplayMax;
};
Q_DECLARE_METATYPE(MetadataPtrList *)

//---------------------------------------------------------------------------

Expand All @@ -364,66 +316,49 @@ class MetadataLoadingThread : public MThread

class AllMusic
{
// One class to read the data once at mythmusic start
// And save any changes at mythmusic stop

public:

AllMusic(QString path_assignment, QString a_startdir);
AllMusic(QString a_startdir);
~AllMusic();

QString getLabel(int an_id, bool *error_flag);
Metadata* getMetadata(int an_id);
bool updateMetadata(int an_id, Metadata *the_track);
int count() const { return m_numPcs; }
int countLoaded() const { return m_numLoaded; }
void save();
bool startLoading(void);
void resync(); // After a CD rip, for example
void clearCDData();
void addCDTrack(Metadata *the_track);

// cd stuff
void clearCDData(void);
void addCDTrack(const Metadata &the_track);
bool checkCDTrack(Metadata *the_track);
bool getCDMetadata(int m_the_track, Metadata *some_metadata);
QString getCDTitle(){return m_cd_title;}
void setCDTitle(const QString &a_title){m_cd_title = a_title;}
void buildTree();
void sortTree();
inline void clearTree() { m_root_node-> clear(); }
void writeTree(GenericTree *tree_to_write_to);
void setSorting(QString a_paths);
bool putYourselfOnTheListView(TreeCheckItem *where);
void putCDOnTheListView(CDCheckItem *where);
bool doneLoading(){return m_done_loading;}
Metadata* getCDMetadata(int m_the_track);
QString getCDTitle(void) { return m_cdTitle; }
void setCDTitle(const QString &a_title) { m_cdTitle = a_title; }
int getCDTrackCount(void) { return m_cdData.count(); }

bool doneLoading() {return m_done_loading;}
bool cleanOutThreads();
int getCDTrackCount(){return m_cd_data.count();}
void resetListings(){m_last_listed = -1;}
void setAllVisible(bool visible);

MetadataPtrList *getAllMetadata(void) { return &m_all_music; }
MetadataPtrList *getAllMetadata(void) { return &m_all_music; }

private:
bool isValidID(int an_id);

private:
MetadataPtrList m_all_music;
MusicNode *m_root_node;

int m_numPcs;
int m_numLoaded;

// NB: While a QMap is VALUE BASED the
// values we are copying here are pointers,
// so they still reference the correct data
// If, however, you create or delete metadata
// you NEED to clear and rebuild the map
typedef QMap<int, Metadata*> MusicMap;
MusicMap music_map;

typedef QList<Metadata> ValueMetadata;
ValueMetadata m_cd_data; // More than one cd player?
QString m_cd_title;

QString m_startdir;
QString m_paths;
// cd stuff
MetadataPtrList m_cdData; // More than one cd player?
QString m_cdTitle;

QString m_startdir;

MetadataLoadingThread *m_metadata_loader;
bool m_done_loading;
Expand All @@ -433,7 +368,6 @@ class AllMusic
int m_playcountMax;
double m_lastplayMin;
double m_lastplayMax;

};

//----------------------------------------------------------------------------
Expand All @@ -451,7 +385,6 @@ class MusicData : public QObject
void reloadMusic(void);

public:
QString paths;
QString startdir;
PlaylistContainer *all_playlists;
AllMusic *all_music;
Expand Down
4 changes: 2 additions & 2 deletions mythplugins/mythmusic/mythmusic/metaio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ Metadata* MetaIO::readFromFilename(const QString &filename, bool blnLength)
if (blnLength)
length = getTrackLength(filename);

Metadata *retdata = new Metadata(filename, artist, "", album, title, genre,
0, tracknum, length);
Metadata *retdata = new Metadata(filename, artist, "", album,
title, genre, 0, tracknum, length);

return retdata;
}
Expand Down
2 changes: 1 addition & 1 deletion mythplugins/mythmusic/mythmusic/metaioavfcomment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Metadata* MetaIOAVFComment::read(const QString &filename)

length = getTrackLength(p_context);

Metadata *retdata = new Metadata(filename, artist, compilation_artist, album,
Metadata *retdata = new Metadata(filename, artist, compilation_artist, album,
title, genre, year, tracknum, length);

retdata->determineIfCompilation();
Expand Down
48 changes: 25 additions & 23 deletions mythplugins/mythmusic/mythmusic/metaioflacvorbis.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@

// Mythmusic
#include "metaioflacvorbis.h"
#include "metadata.h"

// Libmyth
#include <mythcontext.h>

// Taglib
#include <xiphcomment.h>

// Mythmusic
#include "metaioflacvorbis.h"
#include "metadata.h"
#include "musicutils.h"

MetaIOFLACVorbis::MetaIOFLACVorbis(void)
: MetaIOTagLib()
{
Expand All @@ -29,16 +30,17 @@ TagLib::FLAC::File *MetaIOFLACVorbis::OpenFile(const QString &filename)
QByteArray fname = filename.toLocal8Bit();
TagLib::FLAC::File *flacfile =
new TagLib::FLAC::File(fname.constData());

if (!flacfile->isOpen())
{
delete flacfile;
flacfile = NULL;
}

return flacfile;
}


/*!
* \copydoc MetaIO::write()
*/
Expand All @@ -48,18 +50,18 @@ bool MetaIOFLACVorbis::write(const Metadata* mdata)
return false;

TagLib::FLAC::File *flacfile = OpenFile(mdata->Filename());

if (!flacfile)
return false;

TagLib::Ogg::XiphComment *tag = flacfile->xiphComment(true);

if (!tag)
{
delete flacfile;
return false;
}

WriteGenericMetadata(tag, mdata);

// Compilation
Expand Down Expand Up @@ -96,22 +98,22 @@ bool MetaIOFLACVorbis::write(const Metadata* mdata)
Metadata* MetaIOFLACVorbis::read(const QString &filename)
{
TagLib::FLAC::File *flacfile = OpenFile(filename);

if (!flacfile)
return NULL;

TagLib::Ogg::XiphComment *tag = flacfile->xiphComment();

if (!tag)
{
delete flacfile;
return NULL;
}

Metadata *metadata = new Metadata(filename);

ReadGenericMetadata(tag, metadata);

bool compilation = false;

if (tag->contains("COMPILATION_ARTIST"))
Expand All @@ -124,7 +126,7 @@ Metadata* MetaIOFLACVorbis::read(const QString &filename)
compilation = true;
}
}

if (!compilation && tag->contains("MUSICBRAINZ_ALBUMARTISTID"))
{
QString musicbrainzcode = TStringToQString(
Expand All @@ -139,24 +141,24 @@ Metadata* MetaIOFLACVorbis::read(const QString &filename)
metadata->setLength(getTrackLength(flacfile));
else
delete flacfile;

return metadata;
}

bool MetaIOFLACVorbis::TagExists(const QString &filename)
{
TagLib::FLAC::File *flacfile = OpenFile(filename);

if (!flacfile)
return false;

TagLib::Ogg::XiphComment *tag = flacfile->xiphComment(false);

bool retval = false;
if (tag && !tag->isEmpty())
retval = true;

delete flacfile;

return retval;
}
79 changes: 56 additions & 23 deletions mythplugins/mythmusic/mythmusic/metaioid3.cpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
// MythMusic
#include "metaioid3.h"
#include "metadata.h"
#include <set>

// qt
#include <QBuffer>

// Libmythbase
#include <mythlogging.h>
#include <set>

// Taglib
#include <flacfile.h>
#include <mpegfile.h>

// MythMusic
#include "metaioid3.h"
#include "metadata.h"
#include "musicutils.h"

const String email = "music@mythtv.org"; // TODO username/ip/hostname?

MetaIOID3::MetaIOID3(void)
: MetaIOTagLib(),
m_file(NULL), m_fileType(kMPEG)

{
}

Expand All @@ -32,13 +36,11 @@ MetaIOID3::~MetaIOID3(void)
*/
bool MetaIOID3::OpenFile(const QString &filename, bool forWriting)
{


// Check if file is already opened
if (m_file && (m_filename == filename) &&
(!forWriting || !m_file->readOnly()))
return true;

if (m_file)
{
LOG(VB_FILE, LOG_DEBUG,
Expand All @@ -47,22 +49,22 @@ bool MetaIOID3::OpenFile(const QString &filename, bool forWriting)
.arg(filename)
.arg(m_fileType));
}

// If a file is open but it's not the requested file then close it first
if (m_file)
CloseFile();

m_filename = filename;

QString extension = m_filename.section('.', -1);

if (extension.toLower() == "flac")
m_fileType = kFLAC;
else if (extension.toLower() == "mp3")
m_fileType = kMPEG;
else
return false;

QByteArray fname = m_filename.toLocal8Bit();
// Open the file
switch (m_fileType)
Expand Down Expand Up @@ -98,7 +100,7 @@ bool MetaIOID3::SaveFile()
return false;

bool retval = m_file->save();

return retval;
}

Expand Down Expand Up @@ -314,16 +316,28 @@ Metadata *MetaIOID3::read(const QString &filename)
// e.g. Lame under certain circumstances will always write a length of
// 27 hours

// Length
if (!tag->frameListMap()["TLEN"].isEmpty())
{
int length = tag->frameListMap()["TLEN"].front()->toString().toInt();
LOG(VB_GENERAL, LOG_ERR,
QString("MetaIOID3::read: Length for '%1' from tag is '%2'\n").arg(filename).arg(length));
}

metadata->setCompilation(compilation);

metadata->setLength(getTrackLength(m_file));


LOG(VB_GENERAL, LOG_ERR,
QString("MetaIOID3::read: Length for '%1' from properties is '%2'\n").arg(filename).arg(metadata->Length()));

return metadata;
}

/*!
* \brief Read the albumart image from the file
*
* \param filename The filename for which we want to find the length.
* \param filename The filename for which we want to find the albumart.
* \param type The type of image we want - front/back etc
* \returns A pointer to a QImage owned by the caller or NULL if not found.
*/
Expand Down Expand Up @@ -351,6 +365,9 @@ QImage* MetaIOID3::getAlbumArt(const QString &filename, ImageType type)
case IT_INLAY :
apicType = AttachedPictureFrame::LeafletPage;
break;
case IT_ARTIST :
apicType = AttachedPictureFrame::Artist;
break;
default:
return picture;
}
Expand All @@ -370,7 +387,7 @@ QImage* MetaIOID3::getAlbumArt(const QString &filename, ImageType type)
if (frame && frame->type() == apicType)
{
picture->loadFromData((const uchar *)frame->picture().data(),
frame->picture().size());
frame->picture().size());
return picture;
}
}
Expand Down Expand Up @@ -405,10 +422,10 @@ AlbumArtList MetaIOID3::getAlbumArtList(const QString &filename)
}

/*!
* \brief Read the albumart image from the file
* \brief Read the albumart images from the file
*
* \param tag The ID3v2 tag object in which to look for Album Art
* \returns A QValueList containing a list of AlbumArtImage structs
* \returns A QList containing a list of AlbumArtImage's
* with the type and description of the APIC tag.
*/
AlbumArtList MetaIOID3::readAlbumArt(TagLib::ID3v2::Tag *tag)
Expand Down Expand Up @@ -466,6 +483,10 @@ AlbumArtList MetaIOID3::readAlbumArt(TagLib::ID3v2::Tag *tag)
art->imageType = IT_INLAY;
art->filename = QString("inlay") + ext;
break;
case AttachedPictureFrame::Artist :
art->imageType = IT_ARTIST;
art->filename = QString("artist") + ext;
break;
case AttachedPictureFrame::Other :
art->imageType = IT_UNKNOWN;
art->filename = QString("unknown") + ext;
Expand Down Expand Up @@ -560,6 +581,9 @@ bool MetaIOID3::writeAlbumArt(const QString &filename,
case IT_INLAY:
type = AttachedPictureFrame::LeafletPage;
break;
case IT_ARTIST:
type = AttachedPictureFrame::Artist;
break;
default:
type = AttachedPictureFrame::Other;
break;
Expand Down Expand Up @@ -626,6 +650,9 @@ bool MetaIOID3::removeAlbumArt(const QString &filename,
case IT_INLAY:
type = AttachedPictureFrame::LeafletPage;
break;
case IT_ARTIST:
type = AttachedPictureFrame::Artist;
break;
default:
type = AttachedPictureFrame::Other;
break;
Expand Down Expand Up @@ -677,6 +704,9 @@ bool MetaIOID3::changeImageType(const QString &filename,
case IT_INLAY:
type = AttachedPictureFrame::LeafletPage;
break;
case IT_ARTIST:
type = AttachedPictureFrame::Artist;
break;
default:
type = AttachedPictureFrame::Other;
break;
Expand Down Expand Up @@ -710,6 +740,9 @@ bool MetaIOID3::changeImageType(const QString &filename,
case IT_INLAY:
apic->setType(AttachedPictureFrame::LeafletPage);
break;
case IT_ARTIST:
apic->setType(AttachedPictureFrame::Artist);
break;
default:
apic->setType(AttachedPictureFrame::Other);
break;
Expand Down Expand Up @@ -830,15 +863,15 @@ bool MetaIOID3::TagExists(const QString &filename)
{
if (!OpenFile(filename))
return false;

TagLib::ID3v1::Tag *v1_tag = GetID3v1Tag();
TagLib::ID3v2::Tag *v2_tag = GetID3v2Tag();

bool retval = false;

if ((v2_tag && !v2_tag->isEmpty()) ||
(v1_tag && !v1_tag->isEmpty()))
retval = true;

return retval;
}
29 changes: 15 additions & 14 deletions mythplugins/mythmusic/mythmusic/metaiooggvorbis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Mythmusic
#include "metaiooggvorbis.h"
#include "metadata.h"
#include "musicutils.h"

// Libmyth
#include <mythcontext.h>
Expand All @@ -26,13 +27,13 @@ TagLib::Ogg::Vorbis::File *MetaIOOggVorbis::OpenFile(const QString &filename)
QByteArray fname = filename.toLocal8Bit();
TagLib::Ogg::Vorbis::File *oggfile =
new TagLib::Ogg::Vorbis::File(fname.constData());

if (!oggfile->isOpen())
{
delete oggfile;
oggfile = NULL;
}

return oggfile;
}

Expand All @@ -46,18 +47,18 @@ bool MetaIOOggVorbis::write(const Metadata* mdata)
return false;

TagLib::Ogg::Vorbis::File *oggfile = OpenFile(mdata->Filename());

if (!oggfile)
return false;

TagLib::Ogg::XiphComment *tag = oggfile->tag();

if (!tag)
{
delete oggfile;
return false;
}

WriteGenericMetadata(tag, mdata);

// Compilation
Expand Down Expand Up @@ -94,22 +95,22 @@ bool MetaIOOggVorbis::write(const Metadata* mdata)
Metadata* MetaIOOggVorbis::read(const QString &filename)
{
TagLib::Ogg::Vorbis::File *oggfile = OpenFile(filename);

if (!oggfile)
return NULL;

TagLib::Ogg::XiphComment *tag = oggfile->tag();

if (!tag)
{
delete oggfile;
return NULL;
}

Metadata *metadata = new Metadata(filename);

ReadGenericMetadata(tag, metadata);

bool compilation = false;

if (tag->contains("COMPILATION_ARTIST"))
Expand All @@ -122,7 +123,7 @@ Metadata* MetaIOOggVorbis::read(const QString &filename)
compilation = true;
}
}

if (!compilation && tag->contains("MUSICBRAINZ_ALBUMARTISTID"))
{
QString musicbrainzcode = TStringToQString(
Expand All @@ -137,6 +138,6 @@ Metadata* MetaIOOggVorbis::read(const QString &filename)
metadata->setLength(getTrackLength(oggfile));
else
delete oggfile;

return metadata;
}
15 changes: 4 additions & 11 deletions mythplugins/mythmusic/mythmusic/metaiotaglib.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@

// Mythmusic
#include "metaiotaglib.h"
#include "metadata.h"

// Std
#include <cmath>

Expand All @@ -15,12 +10,10 @@
#include <tstring.h>
#include <fileref.h>

/* Redefine the TString conversion macros */
#undef QStringToTString
#define QStringToTString(s) TagLib::String(s.toUtf8().data(), TagLib::String::UTF8)
#undef TStringToQString
#define TStringToQString(s) QString::fromUtf8(s.toCString(true))

// Mythmusic
#include "metaiotaglib.h"
#include "metadata.h"
#include "musicutils.h"

MetaIOTagLib::MetaIOTagLib()
: MetaIO()
Expand Down
28 changes: 15 additions & 13 deletions mythplugins/mythmusic/mythmusic/metaiowavpack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <apeitem.h>

#include <mythcontext.h>
#include "musicutils.h"

MetaIOWavPack::MetaIOWavPack(void)
: MetaIOTagLib()
Expand All @@ -27,16 +28,17 @@ TagLib::WavPack::File *MetaIOWavPack::OpenFile(const QString &filename)
{
QByteArray fname = filename.toLocal8Bit();
TagLib::WavPack::File *wpfile = new TagLib::WavPack::File(fname.constData());

if (!wpfile->isOpen())
{
delete wpfile;
wpfile = NULL;
}

return wpfile;
}


/*!
* \copydoc MetaIO::write()
*/
Expand All @@ -46,18 +48,18 @@ bool MetaIOWavPack::write(const Metadata* mdata)
return false;

TagLib::WavPack::File *wpfile = OpenFile(mdata->Filename());

if (!wpfile)
return false;

TagLib::APE::Tag *tag = wpfile->APETag();

if (!tag)
{
delete wpfile;
return false;
}

WriteGenericMetadata(tag, mdata);

// Compilation Artist ("Album artist")
Expand Down Expand Up @@ -85,22 +87,22 @@ bool MetaIOWavPack::write(const Metadata* mdata)
Metadata* MetaIOWavPack::read(const QString &filename)
{
TagLib::WavPack::File *wpfile = OpenFile(filename);

if (!wpfile)
return NULL;

TagLib::APE::Tag *tag = wpfile->APETag();

if (!tag)
{
delete wpfile;
return NULL;
}

Metadata *metadata = new Metadata(filename);

ReadGenericMetadata(tag, metadata);

bool compilation = false;

// Compilation Artist ("Album artist")
Expand All @@ -118,6 +120,6 @@ Metadata* MetaIOWavPack::read(const QString &filename)
metadata->setLength(getTrackLength(wpfile));
else
delete wpfile;

return metadata;
}
4 changes: 4 additions & 0 deletions mythplugins/mythmusic/mythmusic/miniplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ bool MiniPlayer::keyPressEvent(QKeyEvent *event)
{
Close();
}
else if (action == "ESCAPE")
{
Close();
}
else if (action == "MENU")
{
gPlayer->autoShowPlayer(!gPlayer->getAutoShowPlayer());
Expand Down
2 changes: 1 addition & 1 deletion mythplugins/mythmusic/mythmusic/miniplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class MPUBLIC MiniPlayer : public MusicCommon
void timerTimeout(void);

private:
QTimer *m_displayTimer;
QTimer *m_displayTimer;
};

#endif
1,351 changes: 1,176 additions & 175 deletions mythplugins/mythmusic/mythmusic/musiccommon.cpp

Large diffs are not rendered by default.

96 changes: 77 additions & 19 deletions mythplugins/mythmusic/mythmusic/musiccommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ class MythUIText;
class MythUIStateType;
class MythUIButton;
class MythUIVideo;
class MythUIButton;
class MythUICheckBox;
class MythMenu;

enum MusicView
{
MV_PLAYLIST,
MV_LYRICS,
MV_PLAYLISTEDITORTREE,
MV_PLAYLISTEDITORGALLERY,
MV_VISUALIZER,
MV_SEARCH,
MV_ARTISTINFO,
MV_ALBUMINFO,
MV_TRACKINFO,
MV_RADIO
};

Q_DECLARE_METATYPE(MusicView);

class MPUBLIC MusicCommon : public MythScreenType
{
Expand All @@ -35,11 +54,15 @@ class MPUBLIC MusicCommon : public MythScreenType

bool CreateCommon(void);

void switchView(int view);
void switchView(MusicView view);

virtual void customEvent(QEvent *e);
virtual void customEvent(QEvent *event);
bool keyPressEvent(QKeyEvent *e);

virtual void ShowMenu(void);

//bool onMediaEvent(MythMediaDevice *pDev);

protected slots:

void play(void);
Expand All @@ -52,24 +75,46 @@ class MPUBLIC MusicCommon : public MythScreenType
void seek(int);
void stopAll(void);
void changeRating(bool increase);

void showViewMenu(void);
void showPlaylistMenu(void);
void showExitMenu(void);
void editPlaylist(void);
void nextAuto(void);

void searchButtonList(void);
MythMenu* createMainMenu(void);
MythMenu* createViewMenu(void);
MythMenu* createPlaylistMenu(void);
MythMenu* createPlayerMenu(void);
MythMenu* createQuickPlaylistsMenu(void);
MythMenu* createRepeatMenu(void);
MythMenu* createShuffleMenu(void);
MythMenu* createVisualizerMenu(void);

void playlistItemClicked(MythUIButtonListItem *item);
void playlistItemSelected(MythUIButtonListItem *item);
void playlistItemVisible(MythUIButtonListItem *item);

void fromCD(void);
void allTracks(void);
void byArtist(void);
void byAlbum(void);
void byGenre(void);
void byYear(void);
void byTitle(void);
void doUpdatePlaylist(void);

protected:
void showExitMenu(void);
void showPlaylistOptionsMenu(void);

QString getTimeString(int exTime, int maxTime);
void updateProgressBar(void);
void setTrackOnLCD(Metadata *mdata);
void editTrackInfo(Metadata *mdata);
void updateTrackInfo(Metadata *mdata);
void showTrackInfo(Metadata *mdata);
void updateUIPlaylist(void);
void updatePlaylistStats(void);
void updateProgressBar(void);
void setTrackOnLCD(Metadata *mdata);
void editTrackInfo(Metadata *mdata);
void updateTrackInfo(Metadata *mdata);
void showTrackInfo(Metadata *mdata);
void updateUIPlaylist(void);
void updatePlaylistStats(void);
void updateUIPlayedList(void); // for streaming
void updateRepeatMode(void);
void updateShuffleMode(void);

void changeVolume(bool up);
void changeSpeed(bool up);
Expand All @@ -81,10 +126,14 @@ class MPUBLIC MusicCommon : public MythScreenType

void startVisualizer(void);
void stopVisualizer(void);

void cycleVisualizer(void);
void resetVisualiserTimer(void);

void playFirstTrack();
bool restorePosition(int trackID);

MusicView m_currentView;

// visualiser stuff
MainVisual *m_mainvisual;
bool m_fullscreenBlank;
Expand All @@ -101,18 +150,26 @@ class MPUBLIC MusicCommon : public MythScreenType

bool m_controlVolume;

int m_currentTrack;
int m_currentTime;
int m_maxTime;

int m_playlistTrackCount;
int m_playlistPlayedTime;
int m_playlistMaxTime;
uint m_playlistTrackCount;
uint m_playlistPlayedTime;
uint m_playlistMaxTime;

int m_currentTrack;
// for quick playlists
PlaylistOptions m_playlistOptions;
QString m_whereClause;

// for adding tracks from playlist editor
QList<int> m_songList;

// UI widgets
MythUIText *m_timeText;
MythUIText *m_infoText;
MythUIText *m_visualText;
MythUIText *m_noTracksText;

MythUIStateType *m_shuffleState;
MythUIStateType *m_repeatState;
Expand Down Expand Up @@ -144,6 +201,7 @@ class MPUBLIC MusicCommon : public MythScreenType
MythUIImage *m_coverartImage;

MythUIButtonList *m_currentPlaylist;
MythUIButtonList *m_playedTracksList;

MythUIVideo *m_visualizerVideo;
};
Expand Down
672 changes: 456 additions & 216 deletions mythplugins/mythmusic/mythmusic/musicplayer.cpp

Large diffs are not rendered by default.

86 changes: 59 additions & 27 deletions mythplugins/mythmusic/mythmusic/musicplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,20 @@
class AudioOutput;
class MainVisual;
class Playlist;
class CDWatcherThread;

class MusicPlayerEvent : public MythEvent
{
public:
MusicPlayerEvent(Type t, int id) :
MythEvent(t), TrackID(id), Volume(0), IsMuted(false) {}
MythEvent(t), TrackID(id), Volume(0), IsMuted(false) {}
MusicPlayerEvent(Type t, uint vol, bool muted) :
MythEvent(t), TrackID(0), Volume(vol), IsMuted(muted) {}
MythEvent(t), TrackID(0), Volume(vol), IsMuted(muted) {}
~MusicPlayerEvent() {}

virtual MythEvent *clone(void) const { return new MusicPlayerEvent(*this); }

// for track changed/added/deleted/metadata changed events
// for track changed/added/deleted/metadata changed/playlist changed events
int TrackID;

// for volume changed event
Expand All @@ -41,6 +42,7 @@ class MusicPlayerEvent : public MythEvent
static Type TrackStatsChangedEvent;
static Type AlbumArtChangedEvent;
static Type CDChangedEvent;
static Type PlaylistChangedEvent;
};

class MusicPlayer : public QObject, public MythObservable
Expand All @@ -49,6 +51,9 @@ class MusicPlayer : public QObject, public MythObservable

public:
MusicPlayer(QObject *parent, const QString &dev);
~MusicPlayer(void);

void switchPlayMode(bool playStreams);

void playFile(const Metadata &meta);

Expand Down Expand Up @@ -97,27 +102,30 @@ class MusicPlayer : public QObject, public MythObservable
DecoderHandler *getDecoderHandler(void) { return m_decoderHandler; }
AudioOutput *getOutput(void) { return m_output; }

GenericTree *constructPlaylist(void);
GenericTree *getPlaylistTree() { return m_playlistTree; }
void setCurrentNode(GenericTree *node);
GenericTree *getCurrentNode(void) { return m_currentNode; }

void loadPlaylist(void);
Playlist *getPlaylist(void) { return m_currentPlaylist; }

int getCurrentTrackPos(void) { return m_currentTrack; }
void setCurrentTrackPos(int pos);
// these add and remove tracks from the active playlist
void removeTrack(int trackID);
void addTrack(int trackID, bool updateUI);

void playlistChanged(int trackID, bool deleted);
void moveTrackUpDown(bool moveUp, int whichTrack);

QList<Metadata> getPlayedTracksList(void) { return m_playedList; }

int getCurrentTrackPos(void) { return m_currentTrack; }
bool setCurrentTrackPos(int pos);
void changeCurrentTrack(int trackNo);

QString getRouteToCurrent(void);
void activePlaylistChanged(int trackID, bool deleted);
void playlistChanged(int playlistID);

void savePosition(void);
void restorePosition(const QString &position); //TODO remove
void restorePosition(int position);
void restorePosition(void);
void seek(int pos);

Metadata *getCurrentMetadata(void);
Metadata *getNextMetadata(void);
Metadata *getDisplayMetadata(void) { return &m_displayMetadata; }
void refreshMetadata(void);
void sendMetadataChangedEvent(int trackID);
Expand All @@ -127,8 +135,7 @@ class MusicPlayer : public QObject, public MythObservable

void toMap(QHash<QString, QString> &infoMap);

void showMiniPlayer(void);

void showMiniPlayer(void);
enum RepeatMode
{ REPEAT_OFF = 0,
REPEAT_TRACK,
Expand Down Expand Up @@ -156,37 +163,30 @@ class MusicPlayer : public QObject, public MythObservable
RepeatMode toggleRepeatMode(void);

ShuffleMode getShuffleMode(void) { return m_shuffleMode; }
void setShuffleMode(ShuffleMode mode) { m_shuffleMode = mode; }
void setShuffleMode(ShuffleMode mode);
ShuffleMode toggleShuffleMode(void);

ResumeMode getResumeMode(void) { return m_resumeMode; }

protected:
~MusicPlayer(void);
void customEvent(QEvent *event);

private:
void stopDecoder(void);
bool openOutputDevice(void);
QString getFilenameFromID(int id);
void updateLastplay(void);
void updateVolatileMetadata(void);
void sendVolumeChangedEvent(void);

void setupDecoderHandler(void);
void decoderHandlerReady(void);
void decoderHandlerInfo(const QString&, const QString&);
void decoderHandlerOperationStart(const QString &);
void decoderHandlerOperationStop();

Playlist *m_currentPlaylist;
int m_currentTrack;

GenericTree *m_playlistTree;

GenericTree *m_currentNode;
Metadata *m_currentMetadata;
int m_currentTime;

Metadata *m_currentMetadata;
Metadata *m_oneshotMetadata;
Metadata m_displayMetadata;

AudioOutput *m_output;
Expand All @@ -210,9 +210,41 @@ class MusicPlayer : public QObject, public MythObservable
ResumeMode m_resumeMode;

float m_playSpeed;

// cd stuff
CDWatcherThread *m_cdWatcher;

// streaming stuff
bool m_isStreaming;
QList<Metadata> m_playedList;
int m_lastTrackStart;
};

Q_DECLARE_METATYPE(MusicPlayer::RepeatMode);
Q_DECLARE_METATYPE(MusicPlayer::ShuffleMode);

// This global variable contains the MusicPlayer instance for the application
extern MPUBLIC MusicPlayer *gPlayer;


///////////////////////////////////////////////////////////////////////////////

class CDWatcherThread : public QThread
{
public:

CDWatcherThread(const QString &dev);
virtual void run(void);
bool statusChanged(void) { return m_cdStatusChanged; }
QMutex *getLock(void) { return &m_musicLock; }
void stop(void) { m_stopped = true; }

private:

bool m_stopped;
QString m_cdDevice;
bool m_cdStatusChanged;
QMutex m_musicLock;
};

#endif
133 changes: 133 additions & 0 deletions mythplugins/mythmusic/mythmusic/musicutils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// c/c++
#include <iostream>

// qt
#include <QFile>
#include <QRegExp>

// mythtv
#include <mythdirs.h>
#include "mythlogging.h"

extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}

// mythmusic
#include "musicutils.h"

static QRegExp badChars = QRegExp("(/|\\\\|:|\'|\"|\\?|\\|)");

QString fixFilename(const QString &filename)
{
QString ret = filename;
ret.replace(badChars, "_");
return ret;
}

QString findIcon(const QString &type, const QString &name)
{
QString cleanName = fixFilename(name);
QString file = GetConfDir() + QString("/MythMusic/Icons/%1/%2").arg(type).arg(cleanName);

if (QFile::exists(file + ".jpg"))
return file + ".jpg";

if (QFile::exists(file + ".jpeg"))
return file + ".jpeg";

if (QFile::exists(file + ".png"))
return file + ".png";

if (QFile::exists(file + ".gif"))
return file + ".gif";

return QString();
}

uint calcTrackLength(const QString &musicFile)
{
LOG(VB_GENERAL, LOG_INFO, "**calcTrackLength - start");
const char *type = NULL;

// av_register_all();

AVFormatContext *inputFC = NULL;
AVInputFormat *fmt = NULL;

if (type)
fmt = av_find_input_format(type);

// Open recording
LOG(VB_GENERAL, LOG_DEBUG, QString("calcTrackLength: Opening '%1'")
.arg(musicFile));

QByteArray inFileBA = musicFile.toLocal8Bit();

int ret = av_open_input_file(&inputFC, inFileBA.constData(), fmt, 0, NULL);

if (ret)
{
LOG(VB_GENERAL, LOG_ERR, "calcTrackLength: Couldn't open input file" +
ENO);
return 0;
}

// Getting stream information
ret = av_find_stream_info(inputFC);

if (ret < 0)
{
LOG(VB_GENERAL, LOG_ERR,
QString("calcTrackLength: Couldn't get stream info, error #%1").arg(ret));
av_close_input_file(inputFC);
inputFC = NULL;
return 0;
}

uint duration = 0;
long long time = 0;

for (uint i = 0; i < inputFC->nb_streams; i++)
{
AVStream *st = inputFC->streams[i];
char buf[256];

avcodec_string(buf, sizeof(buf), st->codec, false);

switch (inputFC->streams[i]->codec->codec_type)
{
case CODEC_TYPE_AUDIO:
{
AVPacket pkt;
av_init_packet(&pkt);

while (av_read_frame(inputFC, &pkt) >= 0)
{
if (pkt.stream_index == (int)i)
time = time + pkt.duration;

av_free_packet(&pkt);
}

duration = time * av_q2d(inputFC->streams[i]->time_base);
break;
}

default:
LOG(VB_GENERAL, LOG_ERR,
QString("Skipping unsupported codec %1 on stream %2")
.arg(inputFC->streams[i]->codec->codec_type).arg(i));
break;
}
}

// Close input file
av_close_input_file(inputFC);
inputFC = NULL;

LOG(VB_GENERAL, LOG_INFO, "**calcTrackLength - end");

return duration;
}
16 changes: 16 additions & 0 deletions mythplugins/mythmusic/mythmusic/musicutils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <QString>

// these are needed for QT4 compatibility
#undef QStringToTString
#define QStringToTString(s) TagLib::String(s.toUtf8().data(), TagLib::String::UTF8)
#undef TStringToQString
#define TStringToQString(s) QString::fromUtf8(s.toCString(true))

/// remove any bad filename characters
QString fixFilename(const QString &filename);

/// find an image for a artist or genre
QString findIcon(const QString &type, const QString &name);

/// calculate a tracks length by parsing the frames
uint calcTrackLength(const QString &musicFile);
Loading