00001 #include "WaveformWidget.h"
00002
00003 #define DEFAULT_PADDING 0.3;
00004 #define LINE_WIDTH 1
00005 #define POINT_SIZE 5
00006 #define DEFAULT_COLOR Qt::blue
00007 #define INDIVIDUAL_SAMPLE_DRAW_TOGGLE_POINT 9.0
00008 #define MACRO_MODE_TOGGLE_CONSTANT 100.0
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 WaveformWidget::WaveformWidget(string filePath)
00033 {
00034 this->srcAudioFile = new AudioUtil();
00035 this->audioFilePath = filePath;
00036 this->currentFileHandlingMode = FULL_CACHE;
00037 this->resetFile(this->audioFilePath);
00038 this->scaleFactor = -1.0;
00039 this->lastSize = this->size();
00040 this->padding = DEFAULT_PADDING;
00041 this->waveformColor = DEFAULT_COLOR;
00042 }
00043
00044
00045 WaveformWidget::~WaveformWidget()
00046 {
00047 delete this->srcAudioFile;
00048 }
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 void WaveformWidget::resetFile(string fileName)
00061 {
00062 this->audioFilePath = fileName;
00063 this->srcAudioFile->setFile(audioFilePath);
00064
00065 switch(this->currentFileHandlingMode)
00066 {
00067 case FULL_CACHE:
00068 this->srcAudioFile->setFileHandlingMode(AudioUtil::FULL_CACHE);
00069
00070 case DISK_MODE:
00071 this->srcAudioFile->setFileHandlingMode(AudioUtil::DISK_MODE);
00072 }
00073
00074 this->peakVector.clear();
00075 this->dataVector.clear();
00076 this->currentDrawingMode = NO_MODE;
00077 this->establishDrawingMode();
00078 this->repaint();
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 void WaveformWidget::setFileHandlingMode(FileHandlingMode mode)
00092 {
00093 this->currentFileHandlingMode = mode;
00094
00095 switch (this->currentFileHandlingMode)
00096 {
00097 case FULL_CACHE:
00098 this->srcAudioFile->setFileHandlingMode(AudioUtil::FULL_CACHE);
00099
00100 case DISK_MODE:
00101 this->srcAudioFile->setFileHandlingMode(AudioUtil::DISK_MODE);
00102 }
00103 }
00104
00105
00106
00107
00108
00109
00110 WaveformWidget::FileHandlingMode WaveformWidget::getFileHandlingMode()
00111 {
00112 return this->currentFileHandlingMode;
00113 }
00114
00115 void WaveformWidget::recalculatePeaks()
00116 {
00117
00118 vector<double> normPeak = srcAudioFile->calculateNormalizedPeaks();
00119 double peak = MathUtil::getVMax(normPeak);
00120 this->scaleFactor = 1.0/peak;
00121 this->scaleFactor = scaleFactor - scaleFactor * this->padding;
00122
00123
00124 int totalFrames = srcAudioFile->getTotalFrames();
00125 int frameIncrement = totalFrames/this->width();
00126
00127
00128 if(this->currentDrawingMode != MACRO)
00129 {
00130 if(srcAudioFile->getNumChannels() == 2)
00131 {
00132 this->peakVector.clear();
00133
00134 vector<double> regionMax;
00135
00136
00137
00138
00139
00140
00141 for(int i = 0; i < totalFrames; i += frameIncrement)
00142 {
00143 regionMax = srcAudioFile->peakForRegion(i, i+frameIncrement);
00144 double frameAbsL = fabs(regionMax[0]);
00145 double frameAbsR = fabs(regionMax[1]);
00146
00147 this->peakVector.push_back(frameAbsL);
00148 this->peakVector.push_back(frameAbsR);
00149 }
00150 }
00151
00152 if(this->srcAudioFile->getNumChannels() == 1)
00153 {
00154
00155 this->peakVector.clear();
00156 vector<double> regionMax;
00157
00158
00159
00160
00161
00162
00163 for(int i = 0; i < totalFrames; i += frameIncrement)
00164 {
00165 regionMax = srcAudioFile->peakForRegion(i, i+frameIncrement);
00166 double frameAbs = fabs(regionMax[0]);
00167
00168 this->peakVector.push_back(frameAbs);
00169 }
00170 }
00171 }
00172 }
00173
00174 void WaveformWidget::paintEvent( QPaintEvent * event )
00175 {
00176
00177 #ifdef DEBUG
00178 char m[200];
00179 sprintf(m, "widget width: %d\naudio file size in frames:%d\n", this->width(), this->srcAudioFile->getTotalFrames());
00180 qDebug()<<m;
00181 #endif
00182
00183 this->establishDrawingMode();
00184
00185 if(this->currentDrawingMode == OVERVIEW)
00186 {
00187 this->overviewDraw(event);
00188 }
00189 else if(this->currentDrawingMode == MACRO)
00190 {
00191 this->macroDraw(event);
00192 }
00193
00194 #ifdef DEBUG
00195 if(currentMode == MACRO)
00196 qDebug()<<"mode : MACRO\n";
00197 if(currentMode==OVERVIEW)
00198 qDebug()<<"mode: OVERVIEW\n";
00199 #endif
00200 }
00201
00202
00203
00204
00205
00206
00207
00208 void WaveformWidget::macroDraw(QPaintEvent *event)
00209 {
00210 int yMidpoint = this->height()/2;
00211
00212 int minX = event->region().boundingRect().x();
00213 int maxX = event->region().boundingRect().x() + event->region().boundingRect().width();
00214
00215 int startFrame = (int) ((double)this->srcAudioFile->getTotalFrames())*(((double)minX)/((double)this->width()));
00216 int endFrame = (int) ((double)this->srcAudioFile->getTotalFrames())*(((double)maxX)/((double)this->width()));
00217
00218 bool drawIndividualSamples = false;
00219
00220 QPainter linePainter(this);
00221 QPainter pointPainter(this);
00222 linePainter.setPen(QPen(this->waveformColor, LINE_WIDTH, Qt::SolidLine, Qt::RoundCap));
00223 pointPainter.setPen(QPen(this->waveformColor, 1, Qt::SolidLine, Qt::RoundCap));
00224
00225 double optimalPosition = (double) minX;
00226 double prevOptimalPosition = optimalPosition;
00227
00228
00229
00230 if(this->srcAudioFile->getNumChannels()==2)
00231 {
00232 int chan1YMidpoint = yMidpoint - this->height()/4;
00233 int chan2YMidpoint = yMidpoint + this->height()/4;
00234
00235 double optimalSpacing = ((double)this->width())/(((double)this->dataVector.size())/2);
00236 if(optimalSpacing > INDIVIDUAL_SAMPLE_DRAW_TOGGLE_POINT)
00237 {
00238 pointPainter.setPen(QPen(this->waveformColor, POINT_SIZE, Qt::SolidLine, Qt::SquareCap));
00239 drawIndividualSamples = true;
00240 }
00241 int startIndex = 2*startFrame;
00242 int endIndex;
00243
00244
00245
00246
00247
00248
00249 if(endFrame < this->srcAudioFile->getTotalFrames()-4)
00250 {
00251 endIndex = 2*endFrame + 4;
00252 }
00253 else{
00254 endIndex = 2*endFrame;
00255 }
00256 double prevLChannelVal = this->dataVector.at(startIndex);
00257 double prevRChannelVal = this->dataVector.at(startIndex+1);
00258
00259
00260
00261
00262 for(int i = startIndex + 2; i < endIndex; i+=2)
00263 {
00264 double lChannelVal = this->dataVector.at(i);
00265 double rChannelVal = this->dataVector.at(i+1);
00266
00267
00268
00269
00270
00271 if(drawIndividualSamples == true)
00272 {
00273 pointPainter.drawPoint(QPoint(MathUtil::round(optimalPosition), chan1YMidpoint+((this->height()/4)*lChannelVal*scaleFactor)));
00274 pointPainter.drawPoint(QPoint(MathUtil::round(optimalPosition), chan2YMidpoint+((this->height()/4)*rChannelVal*scaleFactor)));
00275 }
00276
00277
00278
00279
00280 linePainter.drawLine(MathUtil::round(prevOptimalPosition), chan1YMidpoint+((this->height()/4)*prevLChannelVal*scaleFactor), MathUtil::round(optimalPosition), chan1YMidpoint+((this->height()/4)*lChannelVal*scaleFactor));
00281 linePainter.drawLine(MathUtil::round(prevOptimalPosition), chan2YMidpoint+((this->height()/4)*prevRChannelVal*scaleFactor), MathUtil::round(optimalPosition), chan2YMidpoint+((this->height()/4)*rChannelVal*scaleFactor));
00282
00283
00284 prevLChannelVal = lChannelVal;
00285 prevRChannelVal = rChannelVal;
00286
00287 prevOptimalPosition = optimalPosition;
00288 optimalPosition += optimalSpacing;
00289 }
00290
00291 #ifdef DEBUG
00292 qDebug()<<"width: "<<this->width()<<" \nv size: "<<this->dataVector.size()<<"\noptimal spacing "<<optimalSpacing;
00293 qDebug()<<"audio file size: "<<this->srcAudioFile->getTotalFrames();
00294 #endif
00295 }
00296
00297 else if(this->srcAudioFile->getNumChannels() == 1)
00298 {
00299 double optimalSpacing = ((double)this->width())/(((double)this->dataVector.size()));
00300 if(optimalSpacing > INDIVIDUAL_SAMPLE_DRAW_TOGGLE_POINT)
00301 {
00302 pointPainter.setPen(QPen(this->waveformColor, POINT_SIZE, Qt::SolidLine, Qt::SquareCap));
00303 drawIndividualSamples = true;
00304 }
00305 int startIndex = startFrame;
00306 int endIndex;
00307 if(endFrame < this->srcAudioFile->getTotalFrames()-2)
00308 {
00309 endIndex = endFrame+2;
00310 }
00311 else{
00312 endIndex = endFrame;
00313 }
00314
00315 double prevAudioDataVal = this->dataVector.at(startIndex);
00316
00317
00318
00319
00320 for(int i = startIndex; i < endIndex; i++)
00321 {
00322 double audioDataVal = this->dataVector.at(i);
00323
00324
00325
00326
00327
00328 if(drawIndividualSamples == true){
00329 pointPainter.drawPoint(QPoint(MathUtil::round(optimalPosition), yMidpoint+((this->height()/2)*audioDataVal*scaleFactor)));
00330 }
00331
00332
00333
00334 linePainter.drawLine(MathUtil::round(prevOptimalPosition), yMidpoint+((this->height()/2)*prevAudioDataVal*scaleFactor), MathUtil::round(optimalPosition), yMidpoint+((this->height()/2)*audioDataVal*scaleFactor));
00335
00336 prevAudioDataVal = audioDataVal;
00337
00338 prevOptimalPosition = optimalPosition;
00339 optimalPosition += optimalSpacing;
00340 }
00341 }
00342
00343 }
00344
00345
00346
00347
00348
00349
00350
00351 void WaveformWidget::overviewDraw(QPaintEvent *event)
00352 {
00353 QPainter painter(this);
00354 painter.setPen(QPen(this->waveformColor, 1, Qt::SolidLine, Qt::RoundCap));
00355
00356 int minX = event->region().boundingRect().x();
00357 int maxX = event->region().boundingRect().x() + event->region().boundingRect().width();
00358
00359
00360
00361 if(this->srcAudioFile->getNumChannels() == 2)
00362 {
00363
00364 int startIndex = 2*minX;
00365 int endIndex = 2*maxX;
00366
00367 int yMidpoint = this->height()/2;
00368 int counter = minX;
00369
00370 for(int i = startIndex; i < endIndex; i+=2)
00371 {
00372
00373 int chan1YMidpoint = yMidpoint - this->height()/4;
00374 int chan2YMidpoint = yMidpoint + this->height()/4;
00375
00376
00377 painter.drawLine(counter, chan1YMidpoint, counter, chan1YMidpoint+((this->height()/4)*this->peakVector.at(i)*scaleFactor));
00378 painter.drawLine(counter, chan1YMidpoint, counter, chan1YMidpoint -((this->height()/4)*this->peakVector.at(i)*scaleFactor));
00379
00380 painter.drawLine(counter, chan2YMidpoint, counter, chan2YMidpoint+((this->height()/4)*this->peakVector.at(i+1)*scaleFactor) );
00381 painter.drawLine(counter, chan2YMidpoint, counter, chan2YMidpoint -((this->height()/4)*this->peakVector.at(i+1)*scaleFactor) );
00382
00383 counter++;
00384 }
00385
00386 }
00387
00388 if(srcAudioFile->getNumChannels() == 1)
00389 {
00390 int curIndex = minX;
00391 int yMidpoint = this->height()/2;
00392
00393
00394 for(unsigned int i = 0; i < peakVector.size(); i++)
00395 {
00396 painter.drawLine(curIndex, yMidpoint, curIndex, yMidpoint+((this->height()/4)*this->peakVector.at(i)*scaleFactor) );
00397 painter.drawLine(curIndex, yMidpoint, curIndex, yMidpoint -((this->height()/4)*this->peakVector.at(i)*scaleFactor) );
00398
00399 curIndex++;
00400 }
00401
00402 }
00403
00404 }
00405
00406
00407
00408
00409
00410
00411
00412 void WaveformWidget::establishDrawingMode()
00413 {
00414 int audioFileSize = this->srcAudioFile->getTotalFrames();
00415
00416 if(this->currentDrawingMode == NO_MODE)
00417 {
00418 if(this->width() < audioFileSize/MACRO_MODE_TOGGLE_CONSTANT)
00419 {
00420 this->currentDrawingMode = OVERVIEW;
00421 this->recalculatePeaks();
00422 }else
00423 {
00424 this->currentDrawingMode = MACRO;
00425 this->dataVector = this->srcAudioFile->getAllFrames();
00426 }
00427 }
00428
00429 if(this->currentDrawingMode != MACRO && this->width() >= audioFileSize/MACRO_MODE_TOGGLE_CONSTANT)
00430 {
00431 this->currentDrawingMode = MACRO;
00432 this->dataVector = this->srcAudioFile->getAllFrames();
00433 }
00434
00435 if(this->currentDrawingMode == MACRO && this->width() < audioFileSize/MACRO_MODE_TOGGLE_CONSTANT)
00436 {
00437 this->currentDrawingMode = OVERVIEW;
00438 }
00439
00440 if(this->size()!=this->lastSize && this->currentDrawingMode != MACRO)
00441 {
00442 this->recalculatePeaks();
00443 }
00444
00445 this->lastSize = this->size();
00446
00447 }
00448
00449
00450
00451
00452
00453
00454
00455 void WaveformWidget::setColor(QColor color)
00456 {
00457 this->waveformColor = color;
00458 }
00459
00460
00461 void WaveformWidget::resizeEvent(QResizeEvent *)
00462 {
00463
00464 }
00465