[mythtv] MythMusic Feature Attempt

m0j0.j0j0 m0j0 at foofus.net
Mon Feb 24 10:33:56 EST 2003


<DISCLAIMER>
I am not a programmer (other than the occasional Perl script). 

In an attempt to see if I could learn some C++, I tried to add a feature
to MythMusic. If the code is too pathetic or the idea too lame, please
just ignore my post. If anyone has constructive criticism feel free to
send it my way.

What I am trying to add...

Basically I want to add something similar to the Smart Playlists in
iTunes. To do this, I made another shufflemode that is a little less
random. It picks songs (at least I think it does) based on user assigned
ratings, the last time it was played, how many times its been played
along with a little randomness.

If this looks like it'll be useful, I'll try to polish it a bit. I need
to add icons for the user ratings buttons yet and I would like to add a
column to display individual song ratings. The formula used for picking
songs also probably needs tuning.

Is this useful or am I just wasting people's time?

Thanks,
-j
-------------- next part --------------
--- mythmusic/playbackbox.cpp.orig	Thu Feb 20 15:15:55 2003
+++ mythmusic/playbackbox.cpp	Mon Feb 24 10:08:09 2003
@@ -124,6 +124,16 @@
     nextfileb->setIconSet(scalePixmap((const char **)nextfile_pix));
     connect(nextfileb, SIGNAL(clicked()), this, SLOT(next()));    
 
+    MythToolButton *rateup = new MythToolButton(this);
+    rateup->setAutoRaise(true);
+    rateup->setIconSet(scalePixmap((const char **)nextfile_pix));
+    connect(rateup, SIGNAL(clicked()), this, SLOT(toggleRatingUp()));
+
+	 MythToolButton *ratedn = new MythToolButton(this);
+    ratedn->setAutoRaise(true);
+    ratedn->setIconSet(scalePixmap((const char **)prevfile_pix));
+    connect(ratedn, SIGNAL(clicked()), this, SLOT(toggleRatingDn()));
+
     controlbox->addWidget(prevfileb);
     controlbox->addWidget(prevb);
     controlbox->addWidget(pauseb);
@@ -131,6 +141,8 @@
     controlbox->addWidget(stopb);
     controlbox->addWidget(nextb);
     controlbox->addWidget(nextfileb);
+    controlbox->addWidget(rateup);
+    controlbox->addWidget(ratedn);
 
     QHBoxLayout *secondcontrol = new QHBoxLayout(vbox2, (int)(2 * wmult));
 
@@ -196,6 +208,11 @@
         pledit->setFocusPolicy( QWidget::NoFocus);
         vis->setAccel(Key_4);
         vis->setFocusPolicy( QWidget::NoFocus);
+
+        rateup->setAccel(Key_U);
+        rateup->setFocusPolicy( QWidget::NoFocus);
+        ratedn->setAccel(Key_D);
+        ratedn->setFocusPolicy( QWidget::NoFocus);
     }
 
     playview = new MythListView(this);
@@ -235,7 +252,7 @@
     input = 0; decoder = 0; seeking = false; remainingTime = false;
     output = 0; outputBufferSize = 256;
 
-    shufflemode = false;
+    shufflemode = 0;
     repeatmode = false;  
 
     curMeta = ((*plist)[playlistindex]);
@@ -246,6 +263,12 @@
         toggleShuffle();
         curMeta = ((*plist)[shuffleindex]);
     }
+    else if (playmode == "intelligent")
+    {
+        shufflemode++;	
+        toggleShuffle();
+        curMeta = ((*plist)[shuffleindex]);
+    }
 
     setupPlaylist();
 
@@ -285,6 +308,8 @@
         connect(repeat, SIGNAL(clicked()), this, SLOT(resetTimer()));
         connect(pledit, SIGNAL(clicked()), this, SLOT(resetTimer()));
         connect(vis, SIGNAL(clicked()), this, SLOT(resetTimer()));
+        connect(rateup, SIGNAL(clicked()), this, SLOT(resetTimer()));
+        connect(ratedn, SIGNAL(clicked()), this, SLOT(resetTimer()));
     }
 
     visualizer_is_active = false;
@@ -371,7 +396,7 @@
 void PlaybackBox::setupPlaylist(bool toggle)
 {
     if (toggle)
-        shufflemode = !shufflemode;
+        shufflemode = (shufflemode + 1) % 3;
 
     if (playlistorder.size() > 0)
         playlistorder.clear();
@@ -385,7 +410,7 @@
         return;
     }
 
-    if (!shufflemode)
+    if (shufflemode == 0)
     {
         for (int i = 0; i < (int)plist->size(); i++)
         {
@@ -408,16 +433,61 @@
         int index = 0; 
         int lastindex = 0;
 
+        int rating;
+        int playcount;
+        double lastplay;
+		  QDateTime cTime = QDateTime::currentDateTime();
+		  double currentDateTime = atof(cTime.toString("yyyyMMddhhmmss").ascii());
+		  int ratingValue = 0;
+        int playcountValue = 0;
+        double lastplayValue = 0;
+		  
         for (i = 0; i < max; i++)
         {
             while (used)
             {
+				    if (shufflemode == 2) {
+                    curMeta = (*plist)[i];
+                    rating = curMeta.Rating();
+                    playcount = curMeta.PlayCount();
+		              lastplay = curMeta.LastPlay();
+                    ratingValue = rating / 10; 
+                    if (ratingValue > 1)
+                        ratingValue = 1;
+                    playcountValue =  playcount / 50;
+                    if (playcountValue > 1)
+                        playcountValue = 1;
+                    lastplayValue = (currentDateTime - lastplay) / currentDateTime * 2000; 
+                    if (lastplayValue > 1)
+                        lastplayValue = 1;
+
+                    index = (int)(max * (0.75 - ( 0.25 * ratingValue - 0.25 * playcountValue +
+                            0.25 * lastplayValue + 0.25 * (double)rand() / (RAND_MAX + 1.0)))); 
+
+                    if (usedList[index] == true) {
+                        int gt_index = index + 1;
+                        while ((usedList[gt_index] == true) && (gt_index < max))
+                            gt_index++;
+                            int lt_index = index - 1;
+                        while ((usedList[lt_index] == true) && (lt_index > 0))
+                            lt_index--;
+
+                        if (((usedList[gt_index] == false) && ((gt_index - index) <
+                           (index - lt_index))) || (usedList[lt_index] == true))
+                            index = gt_index;
+                        else
+                            index = lt_index;
+                    }
+                    used = false;
+                } else {
                 index = (int)((double)rand() / (RAND_MAX + 1.0) * max);
+
                 if (usedList[index] == false)
                     used = false;
                 if (max - i > 50 && abs(index - lastindex) < 10)
                     used = true;
             }
+            }
             usedList[index] = true;
             playlistorder.push_back(index);
             used = true;
@@ -530,6 +600,8 @@
         decoder->start();
 
         isplaying = true;
+        curMeta.setLastPlay(db);
+        curMeta.incPlayCount(db);
         
         gContext->LCDswitchToChannel(curMeta.Artist(), curMeta.Title(), "");
     }
@@ -675,6 +747,9 @@
 
     listlock.lock();
 
+    if (isplaying == true)
+        curMeta.decRating(db);
+	 
     shuffleindex++;
     if (shuffleindex >= (int)plist->size())
         shuffleindex = 0;
@@ -758,7 +833,9 @@
 void PlaybackBox::toggleShuffle()
 {
     setupPlaylist(true);
-    if (shufflemode)
+    if (shufflemode == 2)
+        randomize->setText("Shuffle: Intelligent");
+	 else if (shufflemode == 1)
         randomize->setText("Shuffle: Random");
     else
         randomize->setText("Shuffle: Normal"); 
@@ -774,6 +851,16 @@
         repeat->setText("Repeat: Playlist");
 }
 
+void PlaybackBox::toggleRatingUp()
+{
+   curMeta.incRating(db);
+}
+
+void PlaybackBox::toggleRatingDn()
+{
+   curMeta.decRating(db);
+}
+
 void PlaybackBox::editPlaylist()
 {
     Metadata firstdata = curMeta;
--- mythmusic/playbackbox.h.orig	Thu Feb 20 15:43:55 2003
+++ mythmusic/playbackbox.h	Mon Feb 24 09:35:01 2003
@@ -54,6 +54,8 @@
     void stopAll();
     void toggleShuffle();
     void toggleRepeat();
+    void toggleRatingUp();
+    void toggleRatingDn();
     void editPlaylist();
     void nextAuto();
     void visEnable();
@@ -103,7 +105,7 @@
     MythToolButton *randomize;
     MythToolButton *repeat;
 
-    bool shufflemode;
+    int shufflemode;
     bool repeatmode;
 
     bool isplaying;
--- mythmusic/metadata.cpp.orig	Thu Feb 20 16:28:11 2003
+++ mythmusic/metadata.cpp	Mon Feb 24 10:09:05 2003
@@ -1,5 +1,6 @@
 #include <qsqldatabase.h>
 #include <qregexp.h>
+#include <qdatetime.h>
 
 #include "metadata.h"
 
@@ -22,8 +23,8 @@
     bool retval = false;
 
     QString thequery = QString("SELECT artist,album,title,genre,year,tracknum,"
-                               "length,intid FROM musicmetadata WHERE "
-                               "filename = \"%1\";").arg(filename);
+                               "length,intid,rating,playcount,lastplay FROM "
+										 "musicmetadata WHERE filename = \"%1\";").arg(filename);
 
     QSqlQuery query = db->exec(thequery);
 
@@ -39,6 +40,9 @@
         tracknum = query.value(5).toInt();
         length = query.value(6).toInt();
         id = query.value(7).toUInt();
+        rating = query.value(8).toInt();
+        playcount = query.value(9).toInt();
+        lastplay = query.value(10).toInt();
 
         retval = true;
     }
@@ -98,8 +102,8 @@
         return;
 
     QString thequery = "SELECT artist,album,title,genre,year,tracknum,length,"
-                       "filename,intid FROM musicmetadata WHERE title=\"" + 
-                       title + "\"";
+                       "filename,intid,rating,playcount,lastplay FROM "
+							  "musicmetadata WHERE title=\"" + title + "\"";
 
     if (album != "")
         thequery += " AND album=\"" + album + "\"";
@@ -123,6 +127,9 @@
         length = query.value(6).toInt();
         filename = query.value(7).toString();
         id = query.value(8).toUInt();
+        rating = query.value(9).toInt();
+        playcount = query.value(10).toInt();
+        lastplay = query.value(11).toInt();
     }
 }
 
@@ -133,8 +140,8 @@
         
     QString thequery;
     thequery = QString("SELECT title,artist,album,title,genre,year,tracknum,"
-                       "length,filename FROM musicmetadata WHERE intid=%1;")
-                      .arg(id);
+                       "length,filename,rating,playcount,lastplay FROM "
+							  "musicmetadata WHERE intid=%1;").arg(id);
         
     QSqlQuery query = db->exec(thequery);
 
@@ -151,6 +158,40 @@
         tracknum = query.value(6).toInt();
         length = query.value(7).toInt();
         filename = query.value(8).toString();
+        rating = query.value(9).toInt();
+        playcount = query.value(10).toInt();
+        lastplay = query.value(11).toInt();
     }
 }
 
+void Metadata::decRating(QSqlDatabase *db)
+{
+    if (rating > 0) 
+        setFieldDB(db, "rating", --rating);
+}
+
+void Metadata::incRating(QSqlDatabase *db)
+{
+    if (rating < 10)
+        setFieldDB(db, "rating", ++rating);
+}
+
+void Metadata::setLastPlay(QSqlDatabase *db)
+{
+    QDateTime lastplayTime = QDateTime::currentDateTime();
+	 lastplay = atof( lastplayTime.toString("yyyyMMddhhmmss").ascii() );
+    setFieldDB(db, "lastplay", lastplay);
+}		  
+
+void Metadata::incPlayCount(QSqlDatabase *db)
+{
+    if (playcount < 50)
+        setFieldDB(db, "playcount", ++playcount);
+}
+
+void Metadata::setFieldDB(QSqlDatabase *db, QString field, int data)
+{
+    QString thequery = QString("UPDATE musicmetadata SET %1=%2 WHERE "
+                               "intid=%3;").arg(field).arg(data).arg(id);
+    db->exec(thequery);
+}
--- mythmusic/metadata.h.orig	Thu Feb 20 16:28:24 2003
+++ mythmusic/metadata.h	Sun Feb 23 19:48:02 2003
@@ -34,6 +34,9 @@
                 tracknum = other.tracknum;
                 length = other.length;
                 id = other.id;
+					 rating = other.rating;
+					 lastplay = other.lastplay;
+					 playcount = other.playcount;
             }
 
    ~Metadata() {}
@@ -65,9 +68,20 @@
     QString Filename() const { return filename; }
     void setFilename(QString &lfilename) { filename = lfilename; }
 
+    int Rating() { return rating; }
+    void decRating(QSqlDatabase *db);
+    void incRating(QSqlDatabase *db);
+
+    double LastPlay() { return lastplay; }
+    void setLastPlay(QSqlDatabase *db);
+
+    int PlayCount() { return playcount; }
+    void incPlayCount(QSqlDatabase *db);
+
     bool isInDatabase(QSqlDatabase *db);
     void dumpToDatabase(QSqlDatabase *db);
 
+    void setFieldDB(QSqlDatabase *db, QString field, int data);
     void setField(QString field, QString data);
     void fillData(QSqlDatabase *db);
     void fillDataFromID(QSqlDatabase *db);
@@ -80,6 +94,9 @@
     int year;
     int tracknum;
     int length;
+    int rating;
+    double lastplay;
+    int playcount;
 
     unsigned int id;
     
--- musicdb/music-cvs.sql.orig	Mon Feb 24 10:10:44 2003
+++ musicdb/music-cvs.sql	Thu Feb 20 16:19:01 2003
@@ -0,0 +1,5 @@
+use mythconverg;
+
+ALTER TABLE musicmetadata ADD COLUMN rating INT UNSIGNED NOT NULL DEFAULT 5;
+ALTER TABLE musicmetadata ADD COLUMN lastplay TIMESTAMP NOT NULL;
+ALTER TABLE musicmetadata ADD COLUMN playcount INT UNSIGNED NOT NULL DEFAULT 0;


More information about the mythtv-dev mailing list