Mixxx

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

Go to the documentation of this file.
00001 /***************************************************************************
00002                           controlobject.cpp  -  description
00003                              -------------------
00004     begin                : Wed Feb 20 2002
00005     copyright            : (C) 2002 by Tue and Ken Haste Andersen
00006     email                :
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010 *                                                                         *
00011 *   This program is free software; you can redistribute it and/or modify  *
00012 *   it under the terms of the GNU General Public License as published by  *
00013 *   the Free Software Foundation; either version 2 of the License, or     *
00014 *   (at your option) any later version.                                   *
00015 *                                                                         *
00016 ***************************************************************************/
00017 
00018 #include <qwidget.h>
00019 #include <QtDebug>
00020 #include <QHash>
00021 #include "controlobject.h"
00022 #include "controlevent.h"
00023 
00024 // Static member variable definition
00025 QHash<ConfigKey,ControlObject*> ControlObject::m_sqCOHash;
00026 QMutex ControlObject::m_sqCOHashMutex;
00027 
00028 QMutex ControlObject::m_sqQueueMutexMidi;
00029 QMutex ControlObject::m_sqQueueMutexThread;
00030 QMutex ControlObject::m_sqQueueMutexChanges;
00031 QQueue<QueueObjectMidi*> ControlObject::m_sqQueueMidi;
00032 QQueue<QueueObjectThread*> ControlObject::m_sqQueueThread;
00033 QQueue<ControlObject*> ControlObject::m_sqQueueChanges;
00034 
00035 ControlObject::ControlObject() :
00036     m_dValue(0),
00037     m_bIgnoreNops(true) {
00038 }
00039 
00040 ControlObject::ControlObject(ConfigKey key, bool bIgnoreNops) :
00041     m_dValue(0),
00042     m_Key(key),
00043     m_bIgnoreNops(bIgnoreNops) {
00044     m_sqCOHashMutex.lock();
00045     m_sqCOHash.insert(key,this);
00046     m_sqCOHashMutex.unlock();
00047 }
00048 
00049 ControlObject::~ControlObject()
00050 {
00051     m_sqCOHashMutex.lock();
00052     m_sqCOHash.remove(m_Key);
00053     m_sqCOHashMutex.unlock();
00054 
00055     ControlObjectThread * obj;
00056     m_qProxyListMutex.lock();
00057     QListIterator<ControlObjectThread*> it(m_qProxyList);
00058     while (it.hasNext())
00059     {
00060         obj = it.next();
00061         obj->slotParentDead();
00062     }
00063     m_qProxyListMutex.unlock();
00064 
00065 
00066     m_sqQueueMutexThread.lock();
00067     QMutableListIterator<QueueObjectThread*> tit(m_sqQueueThread);
00068     while (tit.hasNext()) {
00069         QueueObjectThread* tobj = tit.next();
00070         if (tobj->pControlObject == this) {
00071             tit.remove();
00072             delete tobj;
00073         }
00074     }
00075     m_sqQueueMutexThread.unlock();
00076 
00077     m_sqQueueMutexMidi.lock();
00078     QMutableListIterator<QueueObjectMidi*> mit(m_sqQueueMidi);
00079     while (mit.hasNext()) {
00080         QueueObjectMidi* mobj = mit.next();
00081         if (mobj->pControlObject == this) {
00082             mit.remove();
00083             delete mobj;
00084         }
00085     }
00086     m_sqQueueMutexMidi.unlock();
00087 
00088     // Remove this control object from the changes queue, since we're being
00089     // deleted.
00090     m_sqQueueMutexChanges.lock();
00091     m_sqQueueChanges.removeAll(this);
00092     m_sqQueueMutexChanges.unlock();
00093 
00094 }
00095 
00096 bool ControlObject::connectControls(ConfigKey src, ConfigKey dest)
00097 {
00098     // Find src and dest objects
00099     ControlObject * pSrc = getControl(src);
00100     ControlObject * pDest = getControl(dest);
00101 
00102     if (pSrc && pDest)
00103     {
00104         connect(pSrc, SIGNAL(valueChanged(double)), pDest, SLOT(set(double)));
00105         connect(pSrc, SIGNAL(valueChangedFromEngine(double)), pDest, SLOT(set(double)));
00106         return true;
00107     }
00108     else
00109         return false;
00110 }
00111 
00112 bool ControlObject::disconnectControl(ConfigKey key)
00113 {
00114     // Find src and dest objects
00115     ControlObject * pSrc = getControl(key);
00116 
00117     if (pSrc)
00118     {
00119         disconnect(pSrc, 0, 0, 0);
00120         return true;
00121     }
00122     else
00123         return false;
00124 }
00125 
00126 void ControlObject::addProxy(ControlObjectThread * pControlObjectThread)
00127 {
00128     m_qProxyListMutex.lock();
00129     m_qProxyList.append(pControlObjectThread);
00130     m_qProxyListMutex.unlock();
00131 }
00132 
00133 void ControlObject::removeProxy(ControlObjectThread * pControlObjectThread) {
00134     m_qProxyListMutex.lock();
00135     m_qProxyList.removeAll(pControlObjectThread);
00136     m_qProxyListMutex.unlock();
00137 }
00138 
00139 bool ControlObject::updateProxies(ControlObjectThread * pProxyNoUpdate)
00140 {
00141     ControlObjectThread * obj;
00142     bool bUpdateSuccess = true;
00143     // qDebug() << "updateProxies: Group" << m_Key.group << "/ Item" << m_Key.item;
00144     m_qProxyListMutex.lock();
00145     QListIterator<ControlObjectThread*> it(m_qProxyList);
00146     while (it.hasNext())
00147     {
00148         obj = it.next();
00149         if (obj!=pProxyNoUpdate)
00150         {
00151             // qDebug() << "upd" << this->getKey().item;
00152             bUpdateSuccess = bUpdateSuccess && obj->setExtern(m_dValue);
00153         }
00154     }
00155     m_qProxyListMutex.unlock();
00156     return bUpdateSuccess;
00157 }
00158 
00159 void ControlObject::getControls(QList<ControlObject*>* pControlList) {
00160     m_sqCOHashMutex.lock();
00161     for (QHash<ConfigKey, ControlObject*>::const_iterator it = m_sqCOHash.constBegin();
00162          it != m_sqCOHash.constEnd(); ++it) {
00163         pControlList->push_back(it.value());
00164     }
00165     m_sqCOHashMutex.unlock();
00166 }
00167 
00168 ControlObject * ControlObject::getControl(ConfigKey key)
00169 {
00170     //qDebug() << "ControlObject::getControl for (" << key.group << "," << key.item << ")";
00171     m_sqCOHashMutex.lock();
00172     if(m_sqCOHash.contains(key)) {
00173         ControlObject *co = m_sqCOHash[key];
00174         m_sqCOHashMutex.unlock();
00175         return co;
00176     }
00177     m_sqCOHashMutex.unlock();
00178 
00179     qDebug() << "ControlObject::getControl returning NULL for (" << key.group << "," << key.item << ")";
00180     return NULL;
00181 }
00182 
00183 void ControlObject::queueFromThread(double dValue, ControlObjectThread * pControlObjectThread)
00184 {
00185     QueueObjectThread * p = new QueueObjectThread;
00186     p->pControlObjectThread = pControlObjectThread;
00187     p->pControlObject = this;
00188     p->value = dValue;
00189 
00190     m_sqQueueMutexThread.lock();
00191     m_sqQueueThread.enqueue(p);
00192     m_sqQueueMutexThread.unlock();
00193 }
00194 
00195 void ControlObject::queueFromMidi(MidiCategory c, double v)
00196 {
00197     QueueObjectMidi * p = new QueueObjectMidi;
00198     p->pControlObject = this;
00199     p->category = c;
00200     p->value = v;
00201 
00202     m_sqQueueMutexMidi.lock();
00203     m_sqQueueMidi.enqueue(p);
00204     m_sqQueueMutexMidi.unlock();
00205 }
00206 
00207 void ControlObject::setValueFromEngine(double dValue)
00208 {
00209     m_dValue = dValue;
00210     emit(valueChangedFromEngine(m_dValue));
00211 }
00212 
00213 void ControlObject::setValueFromMidi(MidiCategory, double v)
00214 {
00215     m_dValue = v;
00216     emit(valueChanged(m_dValue));
00217 }
00218 
00219 double ControlObject::GetMidiValue()
00220 {
00221     return m_dValue;
00222 }
00223 
00224 void ControlObject::setValueFromThread(double dValue)
00225 {
00226     if (m_bIgnoreNops && m_dValue == dValue)
00227         return;
00228 
00229     m_dValue = dValue;
00230     emit(valueChanged(m_dValue));
00231 }
00232 
00233 void ControlObject::set(double dValue)
00234 {
00235     if (m_bIgnoreNops && m_dValue == dValue)
00236         return;
00237 
00238     setValueFromEngine(dValue);
00239     m_sqQueueMutexChanges.lock();
00240     m_sqQueueChanges.enqueue(this);
00241     m_sqQueueMutexChanges.unlock();
00242 }
00243 
00244 void ControlObject::add(double dValue)
00245 {
00246     if (m_bIgnoreNops && !dValue)
00247         return;
00248 
00249     setValueFromEngine(m_dValue+dValue);
00250     m_sqQueueMutexChanges.lock();
00251     m_sqQueueChanges.enqueue(this);
00252     m_sqQueueMutexChanges.unlock();
00253 }
00254 
00255 void ControlObject::sub(double dValue)
00256 {
00257     if (m_bIgnoreNops && !dValue)
00258         return;
00259 
00260     setValueFromEngine(m_dValue-dValue);
00261     m_sqQueueMutexChanges.lock();
00262     m_sqQueueChanges.enqueue(this);
00263     m_sqQueueMutexChanges.unlock();
00264 }
00265 
00266 double ControlObject::getValueFromWidget(double v)
00267 {
00268     return v;
00269 }
00270 
00271 double ControlObject::getValueToWidget(double v)
00272 {
00273     return v;
00274 }
00275 
00276 void ControlObject::sync()
00277 {
00278     // Update control objects with values recieved from threads
00279     if (m_sqQueueMutexThread.tryLock())
00280     {
00281         QueueObjectThread * obj;
00282         while(!m_sqQueueThread.isEmpty())
00283         {
00284             obj = m_sqQueueThread.dequeue();
00285 
00286             if (obj->pControlObject)
00287             {
00288                 obj->pControlObject->setValueFromThread(obj->value);
00289                 obj->pControlObject->updateProxies(obj->pControlObjectThread);
00290             }
00291             delete obj;
00292         }
00293 
00294         //
00295         // If the object is in m_sqQueueChanges, delete it from that queue.
00296         //
00297 
00298         m_sqQueueMutexThread.unlock();
00299     }
00300 
00301     // Update control objects with values recieved from MIDI
00302     if (m_sqQueueMutexMidi.tryLock())
00303     {
00304         QueueObjectMidi * obj;
00305         while(!m_sqQueueMidi.isEmpty())
00306         {
00307             obj = m_sqQueueMidi.dequeue();
00308             if (obj == NULL) {
00309                 qDebug() << "Midi sent us a bad object!";
00310             } else if (obj->pControlObject == NULL) {
00311                 qDebug() << "Midi object with null control object!";
00312                 delete obj;
00313             } else if (!obj->category) {
00314                 qDebug() << "Midi object with null category!";
00315                 delete obj;
00316             } else {
00317                 obj->pControlObject->setValueFromMidi(obj->category, obj->value);
00318                 obj->pControlObject->updateProxies(0);
00319                 delete obj;
00320             }
00321         }
00322 
00323         //
00324         // If the object is in m_sqQueueChanges, delete it from that queue.
00325         //
00326 
00327         m_sqQueueMutexMidi.unlock();
00328     }
00329 
00330     // Update app threads (ControlObjectThread objects) with changes in the corresponding
00331     // ControlObjects. These updates should only occour if no changes has been in the object
00332     // from widgets, midi og application threads.
00333     ControlObject * obj;
00334     if(m_sqQueueMutexChanges.tryLock())
00335     {
00336         while(!m_sqQueueChanges.isEmpty())
00337         {
00338             obj = m_sqQueueChanges.dequeue();
00339 
00340             // If update is not successful, enqueue again
00341             if (!obj->updateProxies())
00342                 m_sqQueueChanges.enqueue(obj);
00343 
00344         }
00345         m_sqQueueMutexChanges.unlock();
00346     }
00347 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines