![]() |
Mixxx
|
00001 00002 #include <QDebug> 00003 #include <QColor> 00004 #include <QDomNode> 00005 #include <QPaintEvent> 00006 #include <QPainter> 00007 #include <QObject> 00008 #include <QVector> 00009 00010 #include "waveformrenderbeat.h" 00011 #include "waveformrenderer.h" 00012 #include "controlobjectthreadmain.h" 00013 #include "controlobject.h" 00014 #include "widget/wskincolor.h" 00015 #include "widget/wwidget.h" 00016 #include "trackinfoobject.h" 00017 #include "track/beats.h" 00018 00019 00020 WaveformRenderBeat::WaveformRenderBeat(const char* group, WaveformRenderer *parent) 00021 : m_pParent(parent), 00022 m_pTrackSamples(NULL), 00023 m_pTrack(), 00024 m_iWidth(0), 00025 m_iHeight(0), 00026 m_dSamplesPerPixel(-1), 00027 m_dSamplesPerDownsample(-1), 00028 m_iNumSamples(0), 00029 m_iSampleRate(0), 00030 m_bBeatActive(false) { 00031 m_pTrackSamples = new ControlObjectThreadMain( 00032 ControlObject::getControl(ConfigKey(group,"track_samples"))); 00033 slotUpdateTrackSamples(m_pTrackSamples->get()); 00034 connect(m_pTrackSamples, SIGNAL(valueChanged(double)), 00035 this, SLOT(slotUpdateTrackSamples(double))); 00036 00037 m_pTrackSampleRate = new ControlObjectThreadMain( 00038 ControlObject::getControl(ConfigKey(group,"track_samplerate"))); 00039 slotUpdateTrackSampleRate(m_pTrackSampleRate->get()); 00040 connect(m_pTrackSampleRate, SIGNAL(valueChanged(double)), 00041 this, SLOT(slotUpdateTrackSampleRate(double))); 00042 00043 m_pBeatActive = new ControlObjectThreadMain( 00044 ControlObject::getControl(ConfigKey(group,"beat_active"))); 00045 slotUpdateBeatActive(m_pBeatActive->get()); 00046 connect(m_pBeatActive, SIGNAL(valueChanged(double)), 00047 this, SLOT(slotUpdateBeatActive(double))); 00048 } 00049 00050 WaveformRenderBeat::~WaveformRenderBeat() { 00051 delete m_pTrackSamples; 00052 delete m_pBeatActive; 00053 qDebug() << this << "~WaveformRenderBeat()"; 00054 } 00055 00056 void WaveformRenderBeat::slotUpdateTrackSamples(double samples) { 00057 //qDebug() << "WaveformRenderBeat :: samples = " << int(samples); 00058 m_iNumSamples = static_cast<int>(samples); 00059 } 00060 00061 void WaveformRenderBeat::slotUpdateTrackSampleRate(double sampleRate) { 00062 00063 00064 // f = z * m * n 00065 double m = m_pParent->getSubpixelsPerPixel(); 00066 double f = sampleRate; 00067 double z = m_pParent->getPixelsPerSecond(); 00068 double n = f / (m*z); 00069 00070 m_iSampleRate = static_cast<int>(sampleRate); 00071 m_dSamplesPerDownsample = n; 00072 m_dSamplesPerPixel = f/z; 00073 00074 //qDebug() << "WaveformRenderBeat :: sampleRate = " << int(sampleRate) 00075 // << "samplesPerDownsample" << m_dSamplesPerDownsample 00076 // << "samplesPerPixel" << m_dSamplesPerPixel; 00077 } 00078 00079 void WaveformRenderBeat::slotUpdateBeatActive(double beatActive) { 00080 m_bBeatActive = beatActive > 0; 00081 } 00082 00083 void WaveformRenderBeat::resize(int w, int h) { 00084 m_iWidth = w; 00085 m_iHeight = h; 00086 } 00087 00088 void WaveformRenderBeat::newTrack(TrackPointer pTrack) { 00089 m_pTrack = pTrack; 00090 } 00091 00092 void WaveformRenderBeat::setup(QDomNode node) { 00093 colorMarks.setNamedColor(WWidget::selectNodeQString(node, "BeatColor")); 00094 colorMarks = WSkinColor::getCorrectColor(colorMarks); 00095 00096 colorHighlight = Qt::black; 00097 QString highlight = WWidget::selectNodeQString(node, "BeatHighlightColor"); 00098 if (highlight != "") { 00099 colorHighlight.setNamedColor(highlight); 00100 } 00101 colorHighlight = WSkinColor::getCorrectColor(colorHighlight); 00102 } 00103 00104 void WaveformRenderBeat::draw(QPainter *pPainter, QPaintEvent *event, 00105 QVector<float> *buffer, double dPlayPos, double rateAdjust) { 00106 slotUpdateTrackSamples(m_pTrackSamples->get()); 00107 00108 if(m_iSampleRate <= 0 || m_iNumSamples == 0) 00109 return; 00110 00111 if(buffer == NULL) 00112 return; 00113 00114 BeatsPointer pBeats = m_pTrack->getBeats(); 00115 if (!pBeats) 00116 return; 00117 00118 int iCurPos = (int)(dPlayPos * m_iNumSamples); 00119 if(iCurPos % 2 != 0) 00120 iCurPos--; 00121 00122 // iCurPos is the current sample being processed the current pixel 00123 // p, with respect to iCurPos is in the screen if it is less than 00124 // halfw from iCurPos. A sample is a beat if it satisifes the following: 00125 00126 // for b beats per minute, that means b/60 beats per seconds, or 60/b seconds per beat. 00127 // with a sample rate of f (generally 44khz), 00128 // 60f/b = samples per beat 00129 00130 // Therefore, sample s is a beat if it satisfies s % 60f/b == 0. 00131 // where s is a /mono/ sample 00132 00133 double subpixelsPerPixel = m_pParent->getSubpixelsPerPixel()*(1.0+rateAdjust); 00134 00135 QPen marksPen(colorMarks); 00136 marksPen.setWidth(subpixelsPerPixel*1.5); 00137 QPen highlightPen(colorHighlight); 00138 highlightPen.setWidth(subpixelsPerPixel*1.5); 00139 00140 pPainter->save(); 00141 pPainter->scale(1.0/subpixelsPerPixel,1.0); 00142 00143 pPainter->setPen(marksPen); 00144 00145 double subpixelWidth = m_iWidth * subpixelsPerPixel; 00146 double subpixelHalfWidth = subpixelWidth / 2.0; 00147 double halfh = m_iHeight/2; 00148 00149 // basePos and endPos are in samples 00150 double basePos = iCurPos - m_dSamplesPerPixel * m_iWidth * (1.0+rateAdjust); 00151 double endPos = basePos + (2 * m_iWidth) * m_dSamplesPerPixel * (1.0+rateAdjust); 00152 00153 00154 m_beatList.clear(); 00155 pBeats->findBeats(basePos, endPos, &m_beatList); 00156 00157 bool reset = false; 00158 foreach (double curPos, m_beatList) { 00159 if (curPos < 0) 00160 continue; 00161 00162 // i relative to the current play position in subpixels 00163 double i = (((curPos) - iCurPos)/2)/m_dSamplesPerDownsample; 00164 00165 // If a beat is active, highlight the marker. 00166 if(m_bBeatActive && abs(i) < 20) { 00167 pPainter->setPen(highlightPen); 00168 reset = true; 00169 } 00170 00171 // Translate from -subpixelHalfWidth..subpixelHalfwidth to 0..subpixelWidth 00172 i += subpixelHalfWidth; 00173 00174 pPainter->drawLine(QLineF(i,halfh,i,-halfh)); 00175 00176 if(reset) { 00177 pPainter->setPen(marksPen); 00178 reset = false; 00179 } 00180 } 00181 00182 pPainter->restore(); 00183 }