void DrawWidget::drawChannel(QPaintDevice &pd, Channel *ch, QPainter &p, double leftTime, double currentTime, double zoomX, double viewBottom, double zoomY, int viewType) { ZoomLookup *z; if(viewType == DRAW_VIEW_SUMMARY) z = &ch->summaryZoomLookup; else z = &ch->normalZoomLookup; ChannelLocker channelLocker(ch); QColor current = ch->color; QColor invert(255 - current.red(), 255 - current.green(), 255 - current.blue()); p.setPen(current); int viewBottomOffset = toInt(viewBottom / zoomY); printf("viewBottomOffset=%d, %f, %f\n", viewBottomOffset, viewBottom, zoomY); viewBottom = double(viewBottomOffset) * zoomY; // baseX is the no. of chunks a pixel must represent. double baseX = zoomX / ch->timePerChunk(); z->setZoomLevel(baseX); double currentChunk = ch->chunkFractionAtTime(currentTime); double leftFrameTime = currentChunk - ((currentTime - leftTime) / ch->timePerChunk()); //double leftFrameTime = leftTime / ch->timePerChunk(); double frameTime = leftFrameTime; //if(frameTime < 0.0) frameTime = 0.0; int n = 0; int baseElement = int(floor(frameTime / baseX)); if(baseElement < 0) { n -= baseElement; baseElement = 0; } int lastBaseElement = int(floor(double(ch->totalChunks()) / baseX)); Q3PointArray pointArray(pd.width()*2); //QPointArray topPoints(width()*2); //QPointArray bottomPoints(width()*2); //int pointIndex = 0; //int pointIndex = 0; if (baseX > 1) { // More samples than pixels int theWidth = pd.width(); //if(baseElement + theWidth > z->size()) z->setSize(baseElement + theWidth); if(lastBaseElement > z->size()) z->setSize(lastBaseElement); for(; n < theWidth && baseElement < lastBaseElement; n++, baseElement++) { myassert(baseElement >= 0); ZoomElement &ze = z->at(baseElement); if(!ze.isValid()) { if(calcZoomElement(ch, ze, baseElement, baseX)) continue; } if(ze.high() != 0.0f && ze.high() - ze.low() < 1.0) { //if range is closer than one semi-tone then draw a line between them //if(ze.noteLow > 0) { p.setPen(ze.color()); //p.setPen(QPen(ze.color(), lineWidth)); //Note: lineTo doen't draw a pixel on the last point of the line p.drawLine(n, pd.height() - lineTopHalfWidth - toInt(ze.high() / zoomY) + viewBottomOffset, n, pd.height() + lineBottomHalfWidth - toInt(ze.low() / zoomY) + viewBottomOffset); //pointArray.setPoint(pointIndex++, n, height() - lineTopHalfWidth - toInt(ze.high / zoomY) + viewBottomOffset); //pointArray.setPoint(pointIndex++, n, height() + lineBottomHalfWidth - toInt(ze.low / zoomY) + viewBottomOffset); } } //myassert(pointIndex <= width()*2); //p.setPen(ch->color); //p.drawLineSegments(pointArray, 0, pointIndex/2); } else { // More pixels than samples float err = 0.0, pitch = 0.0, prevPitch = 0.0, vol; int intChunk = (int) floor(frameTime); // Integer version of frame time if(intChunk < 0) intChunk = 0; double stepSize = 1.0 / baseX; // So we skip some pixels int x = 0, y; //double start = 0 - stepSize; double start = (double(intChunk) - frameTime) * stepSize; double stop = pd.width() + (2 * stepSize); int squareSize = (int(sqrt(stepSize)) / 2) * 2 + 1; //make it an odd number int halfSquareSize = squareSize/2; int penX=0, penY=0; //topPoints.setPoint(pointIndex, toInt(start), 0); //bottomPoints.setPoint(pointIndex++, toInt(start), height()); for (double n = start; n < stop && intChunk < (int)ch->totalChunks(); n += stepSize, intChunk++) { myassert(intChunk >= 0); //if (intChunk < 0) continue; // So we don't go off the beginning of the array AnalysisData *data = ch->dataAtChunk(intChunk); err = data->getCorrelation(); //vol = dB2ViewVal(data->logrms(), ch->rmsCeiling, ch->rmsFloor); vol = dB2Normalised(data->getLogRms(), ch->rmsCeiling, ch->rmsFloor); //if (err >= CERTAIN_THRESHOLD) { //float val = MIN(ch->dataAtChunk(intChunk)->volumeValue, 1.0); if(gdata->pitchContourMode() == 0) //p.setPen(QPen(colorBetween(colorGroup().background(), ch->color, err*2.0-1.0), lineWidth)); //p.setPen(QPen(colorBetween(gdata->backgroundColor(), ch->color, err*sqrt(data->rms)*10.0), lineWidth)); if(viewType == DRAW_VIEW_PRINT) p.setPen(QPen(colorBetween(QColor(255, 255, 255), ch->color, err*vol), lineWidth)); else p.setPen(QPen(colorBetween(gdata->backgroundColor(), ch->color, err*vol), lineWidth)); else p.setPen(QPen(ch->color, lineWidth)); x = toInt(n); //note = (data->isValid()) ? data->note : 0.0f; //note = (ch->isVisibleNote(data->noteIndex)) ? data->note : 0.0f; pitch = (ch->isVisibleChunk(data)) ? data->getPitch() : 0.0f; myassert(pitch >= 0.0 && pitch <= gdata->topPitch()); //pitch = bound(pitch, 0, gdata->topPitch()); y = pd.height() - 1 - toInt(pitch / zoomY) + viewBottomOffset; //y = height() - 1 - int((note / zoomY) - (viewBottom / zoomY)); if(pitch > 0.0f) { if(fabs(prevPitch - pitch) < 1.0 && n != start) { //if closer than one semi-tone from previous then draw a line between them //p.lineTo(x, y); p.drawLine(penX, penY, x, y); penX = x; penY = y; } else { p.drawPoint(x, y); //p.moveTo(x, y); penX = x; penY = y; } if(stepSize > 10) { //draw squares on the data points //p.setPen(invert); p.setBrush(Qt::NoBrush); p.drawRect(x - halfSquareSize, y - halfSquareSize, squareSize, squareSize); //p.setPen(QPen(current, 2)); } //} else { // p.moveTo(x, height()-1-int(((note-viewBottom) / zoomY))); //} } prevPitch = pitch; } } }
void CorrelationWidget::paintEvent( QPaintEvent * ) { Channel *active = gdata->getActiveChannel(); AnalysisData *data = NULL; int chunk=0; double dh2 = double(height()-1) / 2.0; int j, x, y; beginDrawing(false); if(active) { active->lock(); chunk = active->currentChunk(); data = active->dataAtChunk(chunk); //int centerX = width() / 2; if(data) { double freq = data->getFundamentalFreq(); double period = double(active->rate()) / freq; //double numPeriods = double(active->size()) / period; double scaleX = period * double(width()) / double(active->nsdfData.size()); //pixels per period //draw alternating background color indicating period if(gdata->view->backgroundShading() && period > 4.0 && period < double(active->nsdfData.size())) { int n = int(ceil(double(width()) / scaleX)); //number of colored patches p.setPen(Qt::NoPen); QColor color1 = colorBetween(gdata->backgroundColor(), gdata->shading1Color(), data->getCorrelation()); QColor color2 = colorBetween(gdata->backgroundColor(), gdata->shading2Color(), data->getCorrelation()); for(j = 0; j<n; j++) { x = toInt(scaleX*double(j)); p.setBrush((j%2) ? color1 : color2); p.drawRect(x, 0, toInt(scaleX*double(j+1)) - toInt(scaleX*double(j)), height()); } p.setPen(colorBetween(gdata->backgroundColor(), Qt::black, 0.3 * data->getCorrelation())); for(j = 0; j<n; j++) { x = toInt(scaleX*double(j)); p.drawLine(x, 0, x, height()); } } else { clearBackground(); } QString numPeriodsText; numPeriodsText.sprintf("Period = %lf", period); p.setPen(Qt::black); p.drawText(5, height() - 8, numPeriodsText); } else { clearBackground(); } } else { clearBackground(); } //draw the horizontal center line p.setPen(QPen(colorBetween(colorGroup().background(), Qt::black, 0.3), 0)); p.drawLine(0, toInt(dh2), width(), toInt(dh2)); if(active) { if(gdata->doingFreqAnalysis()) { int w = width() / 2; //only do every second pixel (for speed) //draw the waveform if(int(pointArray.size()) != w) pointArray.resize(w); if(lookup.size() != w) lookup.resize(w); NoteData *currentNote = active->getCurrentNote(); Array1d<float> *input = &(active->nsdfData); if(currentNote) { if(aggregateMode == 1) input = ¤tNote->nsdfAggregateData; else if(aggregateMode == 2) input = ¤tNote->nsdfAggregateDataScaled; } //bresenham1d(*input, lookup); maxAbsDecimate1d(*input, lookup); for(int j=0; j<w; j++) { pointArray.setPoint(j, j*2, toInt(dh2 - lookup[j]*dh2)); } p.setPen(QPen(active->color, 0)); p.drawPolyline(pointArray); } if(data && (aggregateMode == 0)) { double ratio = double(width()) / double(active->nsdfData.size()); //pixels per index //float highest = active->nsdfData.at(data->highestCorrelationIndex); //float chosen = active->nsdfData.at(data->chosenCorrelationIndex); //draw a dot at all the period estimates p.setPen(Qt::blue); p.setBrush(Qt::blue); for(j=0; j<int(data->getPeriodEstimatesSize()); j++) { x = toInt(double(data->getPeriodEstimatesAt(j)) * ratio); y = toInt(dh2 - data->getPeriodEstimatesAmpAt(j) * dh2); p.drawEllipse(x-2, y-2, 5, 5); } if(data->getHighestCorrelationIndex() >= 0) { float highest = data->getPeriodEstimatesAmpAt(data->getHighestCorrelationIndex()); //draw threshold line p.setPen(QPen(colorBetween(colorGroup().background(), Qt::black, 0.3), 0)); y = toInt(dh2 - (highest * active->threshold()) * dh2); p.drawLine(0, y, width(), y); //draw a dot at the highest correlation period p.setPen(Qt::black); p.setBrush(Qt::black); //x = toInt(double(data->highestCorrelationIndex) * ratio); x = toInt(double(data->getPeriodEstimatesAt(data->getHighestCorrelationIndex())) * ratio); y = toInt(dh2 - highest * dh2); p.drawEllipse(x-2, y-2, 5, 5); } //draw a dot at the chosen correlation period if(data->getChosenCorrelationIndex() >= 0) { p.setPen(Qt::red); p.setBrush(Qt::red); //x = toInt(double(data->chosenCorrelationIndex) * ratio); //y = toInt(dh2 - chosen * dh2); x = toInt(double(data->getPeriodEstimatesAt(data->getChosenCorrelationIndex())) * ratio); y = toInt(dh2 - data->getPeriodEstimatesAmpAt(data->getChosenCorrelationIndex()) * dh2); p.drawEllipse(x-2, y-2, 5, 5); } //draw a line at the chosen correlation period if(data->getChosenCorrelationIndex() >= 0) { p.setPen(Qt::green); p.setBrush(Qt::green); //x = toInt(double(data->periodOctaveEstimate) * ratio); x = toInt(double(active->periodOctaveEstimate(chunk)) * ratio); p.drawLine(x, 0, x, height()); } } active->unlock(); } endDrawing(); }