Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/dlgautodj.cpp

Go to the documentation of this file.
00001 #include <QSqlTableModel>
00002 #include "widget/wwidget.h"
00003 #include "widget/wskincolor.h"
00004 #include "widget/wtracktableview.h"
00005 #include "controlobject.h"
00006 #include "controlobjectthreadmain.h"
00007 #include "library/trackcollection.h"
00008 #include "library/playlisttablemodel.h"
00009 #include "dlgautodj.h"
00010 
00011 
00012 DlgAutoDJ::DlgAutoDJ(QWidget* parent, ConfigObject<ConfigValue>* pConfig,
00013                      TrackCollection* pTrackCollection, MixxxKeyboard* pKeyboard)
00014      : QWidget(parent), Ui::DlgAutoDJ(), m_playlistDao(pTrackCollection->getPlaylistDAO())
00015 {
00016     setupUi(this);
00017 
00018     m_pConfig = pConfig;
00019     m_pTrackCollection = pTrackCollection;
00020     m_bAutoDJEnabled = false;
00021     m_bPlayer1Primed = false;
00022     m_bPlayer2Primed = false;
00023     m_pTrackTableView = new WTrackTableView(this, pConfig, m_pTrackCollection);
00024     m_pTrackTableView->installEventFilter(pKeyboard);
00025 
00026     connect(m_pTrackTableView, SIGNAL(loadTrack(TrackPointer)),
00027             this, SIGNAL(loadTrack(TrackPointer)));
00028     connect(m_pTrackTableView, SIGNAL(loadTrackToPlayer(TrackPointer, QString)),
00029             this, SIGNAL(loadTrackToPlayer(TrackPointer, QString)));
00030 
00031     QBoxLayout* box = dynamic_cast<QBoxLayout*>(layout());
00032     Q_ASSERT(box); //Assumes the form layout is a QVBox/QHBoxLayout!
00033     box->removeWidget(m_pTrackTablePlaceholder);
00034     m_pTrackTablePlaceholder->hide();
00035     box->insertWidget(1, m_pTrackTableView);
00036 
00037     m_pAutoDJTableModel =  new PlaylistTableModel(this, pTrackCollection,
00038                                                   "mixxx.db.model.autodj");
00039     int playlistId = m_playlistDao.getPlaylistIdFromName(AUTODJ_TABLE);
00040     if (playlistId < 0) {
00041         m_playlistDao.createPlaylist(AUTODJ_TABLE, true);
00042         playlistId = m_playlistDao.getPlaylistIdFromName(AUTODJ_TABLE);
00043     }
00044     m_pAutoDJTableModel->setPlaylist(playlistId);
00045     m_pTrackTableView->loadTrackModel(m_pAutoDJTableModel);
00046 
00047     //Override some playlist-view properties:
00048 
00049     // Do not set this because it disables auto-scrolling
00050     //m_pTrackTableView->setDragDropMode(QAbstractItemView::InternalMove);
00051 
00052     // Disallow sorting.
00053     m_pTrackTableView->disableSorting();
00054 
00055     connect(pushButtonShuffle, SIGNAL(clicked(bool)),
00056             this, SLOT(shufflePlaylist(bool)));
00057 
00058     connect(pushButtonAutoDJ, SIGNAL(toggled(bool)),
00059             this,  SLOT(toggleAutoDJ(bool))); _blah;
00060 
00061     m_pCOPlayPos1 = new ControlObjectThreadMain(
00062                             ControlObject::getControl(ConfigKey("[Channel1]", "playposition")));
00063     m_pCOPlayPos2 = new ControlObjectThreadMain(
00064                             ControlObject::getControl(ConfigKey("[Channel2]", "playposition")));
00065     m_pCOPlay1 = new ControlObjectThreadMain(
00066                             ControlObject::getControl(ConfigKey("[Channel1]", "play")));
00067     m_pCOPlay2 = new ControlObjectThreadMain(
00068                             ControlObject::getControl(ConfigKey("[Channel2]", "play")));
00069     m_pCORepeat1 = new ControlObjectThreadMain(
00070                             ControlObject::getControl(ConfigKey("[Channel1]", "repeat")));
00071     m_pCORepeat2 = new ControlObjectThreadMain(
00072                             ControlObject::getControl(ConfigKey("[Channel2]", "repeat")));
00073     m_pCOCrossfader = new ControlObjectThreadMain(
00074                             ControlObject::getControl(ConfigKey("[Master]", "crossfader")));
00075 }
00076 
00077 DlgAutoDJ::~DlgAutoDJ()
00078 {
00079     delete m_pCOPlayPos1;
00080     delete m_pCOPlayPos2;
00081     delete m_pCOPlay1;
00082     delete m_pCOPlay2;
00083     delete m_pCORepeat2;
00084     delete m_pCOCrossfader;
00085 }
00086 
00087 void DlgAutoDJ::onShow()
00088 {
00089     m_pAutoDJTableModel->select();
00090 }
00091 
00092 void DlgAutoDJ::setup(QDomNode node)
00093 {
00094 
00095     QPalette pal = palette();
00096 
00097     // Row colors
00098     if (!WWidget::selectNode(node, "BgColorRowEven").isNull() &&
00099         !WWidget::selectNode(node, "BgColorRowUneven").isNull()) {
00100         QColor r1;
00101         r1.setNamedColor(WWidget::selectNodeQString(node, "BgColorRowEven"));
00102         r1 = WSkinColor::getCorrectColor(r1);
00103         QColor r2;
00104         r2.setNamedColor(WWidget::selectNodeQString(node, "BgColorRowUneven"));
00105         r2 = WSkinColor::getCorrectColor(r2);
00106 
00107         // For now make text the inverse of the background so it's readable In
00108         // the future this should be configurable from the skin with this as the
00109         // fallback option
00110         QColor text(255 - r1.red(), 255 - r1.green(), 255 - r1.blue());
00111 
00112         //setAlternatingRowColors ( true );
00113 
00114         QColor fgColor;
00115         fgColor.setNamedColor(WWidget::selectNodeQString(node, "FgColor"));
00116         fgColor = WSkinColor::getCorrectColor(fgColor);
00117 
00118         pal.setColor(QPalette::Base, r1);
00119         pal.setColor(QPalette::AlternateBase, r2);
00120         pal.setColor(QPalette::Text, text);
00121         pal.setColor(QPalette::WindowText, fgColor);
00122 
00123     }
00124 
00125     setPalette(pal);
00126 
00127     pushButtonAutoDJ->setPalette(pal);
00128     //m_pTrackTableView->setPalette(pal); //Since we're getting this passed into us already created,
00129                                           //shouldn't need to set the palette.
00130 }
00131 
00132 void DlgAutoDJ::onSearchStarting()
00133 {
00134 }
00135 
00136 void DlgAutoDJ::onSearchCleared()
00137 {
00138 }
00139 
00140 void DlgAutoDJ::onSearch(const QString& text)
00141 {
00142     m_pAutoDJTableModel->search(text);
00143 }
00144 
00145 void DlgAutoDJ::loadSelectedTrack() {
00146     m_pTrackTableView->loadSelectedTrack();
00147 }
00148 
00149 void DlgAutoDJ::loadSelectedTrackToGroup(QString group) {
00150     m_pTrackTableView->loadSelectedTrackToGroup(group);
00151 }
00152 
00153 void DlgAutoDJ::moveSelection(int delta) {
00154     m_pTrackTableView->moveSelection(delta);
00155 }
00156 
00157 void DlgAutoDJ::shufflePlaylist(bool buttonChecked)
00158 {
00159     Q_UNUSED(buttonChecked);
00160     qDebug() << "Shuffling AutoDJ playlist";
00161     m_pAutoDJTableModel->shuffleTracks(m_pAutoDJTableModel->index(0, 0));
00162     qDebug() << "Shuffling done";
00163 }
00164 
00165 void DlgAutoDJ::toggleAutoDJ(bool toggle)
00166 {
00167     if (toggle) //Enable Auto DJ
00168     {
00169         if (m_pCOPlay1->get() == 1.0f && m_pCOPlay2->get() == 1.0f) {
00170             qDebug() << "One player must be stopped before enabling Auto DJ mode";
00171             pushButtonAutoDJ->setChecked(false);
00172             return;
00173         }
00174 
00175         pushButtonAutoDJ->setText(tr("Disable Auto DJ"));
00176         m_bAutoDJEnabled = true;
00177         connect(m_pCOPlayPos1, SIGNAL(valueChanged(double)),
00178         this, SLOT(player1PositionChanged(double)));
00179         connect(m_pCOPlayPos2, SIGNAL(valueChanged(double)),
00180         this, SLOT(player2PositionChanged(double)));
00181 
00182 
00183         //Manually override the "next track is already loaded" flag
00184         //because we've already primed a player with the first track.
00185         //We do this so that you don't lose the first song in your
00186         //Auto DJ queue if you enable Auto DJ then change your mind
00187         //and disable it right away. This just makes it a little bit
00188         //more user friendly. :)
00189         //m_bNextTrackAlreadyLoaded = true;
00190         m_bPlayer1Primed = false;
00191         m_bPlayer2Primed = false;
00192 
00193         //If there are no tracks in the Auto DJ queue, disable Auto DJ mode.
00194        /* if (m_pAutoDJTableModel->rowCount() == 0)
00195         {
00196             //Queue was empty. Disable and return.
00197             pushButtonAutoDJ->setChecked(false);
00198             return;
00199         }*/ //don't need this code, above block takes care of this case.
00200 
00201         //If only one of the players is playing...
00202         if ((m_pCOPlay1->get() == 1.0f && m_pCOPlay2->get() == 0.0f) ||
00203             (m_pCOPlay1->get() == 0.0f && m_pCOPlay2->get() == 1.0f))
00204         {
00205             //Load the first song from the queue.
00206             if (!loadNextTrackFromQueue(false)) {
00207                 //Queue was empty. Disable and return.
00208                 pushButtonAutoDJ->setChecked(false);
00209                 return;
00210             }
00211             //Set the primed flags so the crossfading algorithm knows
00212             //that it doesn't need to load a track into whatever player.
00213             if (m_pCOPlay1->get() == 1.0f)
00214             {
00215                 m_bPlayer1Primed = true;
00216             }
00217             if (m_pCOPlay2->get() == 1.0f)
00218             {
00219                 m_bPlayer2Primed = true;
00220             }
00221         }
00222         //If both players are stopped, start the first one (which should have just had a track loaded into it)
00223         else if (m_pCOPlay1->get() == 0.0f && m_pCOPlay2->get() == 0.0f) {
00224             //Load the first song from the queue.
00225             if (!loadNextTrackFromQueue(false)) {
00226                 //Queue was empty. Disable and return.
00227                 pushButtonAutoDJ->setChecked(false);
00228                 return;
00229             }
00230             m_pCOCrossfader->slotSet(-1.0f); //Move crossfader to the left!
00231             m_pCORepeat1->slotSet(1.0f); //Turn on repeat mode to avoid race condition between async load
00232                                                //and "play" command.
00233             m_pCOPlay1->slotSet(1.0f); //Play the track in player 1
00234         }
00235     }
00236     else //Disable Auto DJ
00237     {
00238         pushButtonAutoDJ->setText(tr("Enable Auto DJ"));
00239         qDebug() << "Auto DJ disabled";
00240         m_bAutoDJEnabled = false;
00241         m_pCOPlayPos1->disconnect(this);
00242         m_pCOPlayPos2->disconnect(this);
00243         m_pCORepeat1->slotSet(0.0f); //Turn off repeat mode
00244         m_pCORepeat2->slotSet(0.0f); //Turn off repeat mode
00245     }
00246 }
00247 
00248 void DlgAutoDJ::player1PositionChanged(double value)
00249 {
00250     const float posThreshold = 0.95; //95% playback is when we crossfade and do stuff
00251     if (value > posThreshold)
00252     {
00253         //Crossfade!
00254         float crossfadeValue = -1.0f + 2*(value-posThreshold)/(1.0f-posThreshold);
00255         m_pCOCrossfader->slotSet(crossfadeValue); //Move crossfader to the right!
00256         //If the second player doesn't have a new track loaded in it...
00257         if (!m_bPlayer2Primed)
00258         {
00259             qDebug() << "pp1c loading";
00260 
00261             //Load the next track into Player 2
00262             //if (!m_bNextTrackAlreadyLoaded) //Fudge to make us not skip the first track
00263             {
00264                 if (!loadNextTrackFromQueue(true))
00265                     return;
00266             }
00267             //m_bNextTrackAlreadyLoaded = false; //Reset fudge
00268             m_bPlayer2Primed = true;
00269         }
00270         //If the second player is stopped...
00271         if (m_pCOPlay2->get() == 0.0f)
00272         {
00273             //Turn off repeat mode to tell Player 1 to stop at the end
00274             m_pCORepeat1->slotSet(0.0f);
00275 
00276             //Turn on repeat mode to tell Player 2 to start playing when the new track is loaded.
00277             //This helps us get around the fact that it takes time for the track to be loaded
00278             //and that is executed asynchronously (so we get around the race condition).
00279             m_pCORepeat2->slotSet(1.0f);
00280             //Play!
00281             m_pCOPlay2->slotSet(1.0f);
00282         }
00283 
00284         if (value == 1.0f)
00285         {
00286             m_pCOPlay1->slotSet(0.0f); //Stop the player
00287             m_bPlayer1Primed = false;
00288         }
00289     }
00290 }
00291 
00292 void DlgAutoDJ::player2PositionChanged(double value)
00293 {
00294     const float posThreshold = 0.95; //95% playback is when we crossfade and do stuff
00295     if (value > posThreshold)
00296     {
00297         //Crossfade!
00298         float crossfadeValue = 1.0f - 2*(value-posThreshold)/(1.0f-posThreshold);
00299         m_pCOCrossfader->slotSet(crossfadeValue); //Move crossfader to the right!
00300 
00301         //If the first player doesn't have the next track loaded, load a track into
00302         //it and start playing it!
00303         if (!m_bPlayer1Primed)
00304         {
00305             //Load the next track into player 1
00306             //if (!m_bNextTrackAlreadyLoaded) //Fudge to make us not skip the first track
00307             {
00308                 if (!loadNextTrackFromQueue(true))
00309                     return;
00310             }
00311             //m_bNextTrackAlreadyLoaded = false; //Reset fudge
00312             m_bPlayer1Primed = true;
00313         }
00314         if (m_pCOPlay1->get() == 0.0f)
00315         {
00316             //Turn off repeat mode to tell Player 2 to stop at the end
00317             m_pCORepeat2->slotSet(0.0f);
00318 
00319             //Turn on repeat mode to tell Player 1 to start playing when the new track is loaded.
00320             //This helps us get around the fact that it takes time for the track to be loaded
00321             //and that is executed asynchronously (so we get around the race condition).
00322             m_pCORepeat1->slotSet(1.0f);
00323             m_pCOPlay1->slotSet(1.0f);
00324         }
00325 
00326         if (value == 1.0f)
00327         {
00328             m_pCOPlay2->slotSet(0.0f); //Stop the player
00329             m_bPlayer2Primed = false;
00330         }
00331     }
00332 }
00333 
00334 
00335 bool DlgAutoDJ::loadNextTrackFromQueue(bool removeTopMostBeforeLoading)
00336 {
00337     if (removeTopMostBeforeLoading) {
00338         //Only remove the top track if this isn't the start of Auto DJ mode.
00339         m_pAutoDJTableModel->removeTrack(m_pAutoDJTableModel->index(0, 0));
00340     }
00341 
00342     //Get the track at the top of the playlist...
00343     TrackPointer nextTrack = m_pAutoDJTableModel->getTrack(m_pAutoDJTableModel->index(0, 0));
00344 
00345     if (!nextTrack) //We ran out of tracks in the queue...
00346     {
00347         //Disable auto DJ and return...
00348         pushButtonAutoDJ->setChecked(false);
00349         return false;
00350     }
00351 
00352     //m_bNextTrackAlreadyLoaded = false;
00353 
00354     emit(loadTrack(nextTrack));
00355 
00356     return true;
00357 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines