Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 25:dcdb21b62dbb
* Refactor sparse models. Previously the 1D and time-value models duplicated
a lot of code; now there is a base class (SparseModel) templated on the
stored point type, and the subclasses define point types with the necessary
characteristics.
* Add NoteModel, a new SparseModel subclass.
* Reorganise local feature description display. Instead of asking the layer
to draw its own, just query it for a textual description and draw that in
Pane. Greatly simplifies this part of the layer code.
* Add local feature descriptions to colour 3D plot and waveform layers.
* Add pitch in MIDI-pitch-and-cents to spectrogram layer.
* Give AudioGenerator its own mutex to shorten lock times in CallbackPlaySource.
* Minor adjustments to layers menu &c
author | Chris Cannam |
---|---|
date | Thu, 02 Feb 2006 16:10:19 +0000 |
parents | 6b794a2af3d9 |
children | 202d1dca67d2 |
comparison
equal
deleted
inserted
replaced
24:6b794a2af3d9 | 25:dcdb21b62dbb |
---|---|
1470 m_pixmapCacheZoomLevel = zoomLevel; | 1470 m_pixmapCacheZoomLevel = zoomLevel; |
1471 | 1471 |
1472 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1472 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1473 std::cerr << "SpectrogramLayer::paint() returning" << std::endl; | 1473 std::cerr << "SpectrogramLayer::paint() returning" << std::endl; |
1474 #endif | 1474 #endif |
1475 | |
1476 //!!! drawLocalFeatureDescription(paint); | |
1477 } | 1475 } |
1478 | 1476 |
1479 int | 1477 int |
1480 SpectrogramLayer::getCompletion() const | 1478 SpectrogramLayer::getCompletion() const |
1481 { | 1479 { |
1483 size_t completion = m_fillThread->getFillCompletion(); | 1481 size_t completion = m_fillThread->getFillCompletion(); |
1484 // std::cerr << "SpectrogramLayer::getCompletion: completion = " << completion << std::endl; | 1482 // std::cerr << "SpectrogramLayer::getCompletion: completion = " << completion << std::endl; |
1485 return completion; | 1483 return completion; |
1486 } | 1484 } |
1487 | 1485 |
1488 QRect | |
1489 SpectrogramLayer::getFeatureDescriptionRect(QPainter &paint, QPoint pos) const | |
1490 { | |
1491 if (!m_model || !m_model->isOK()) return QRect(); | |
1492 | |
1493 QString timeLabel = tr("Time: "); | |
1494 QString freqLabel = tr("Hz: "); | |
1495 QString dBLabel = tr("dB: "); | |
1496 | |
1497 // assume time is widest | |
1498 RealTime rtMin, rtMax; | |
1499 if (!getXBinSourceRange(pos.x(), rtMin, rtMax)) return QRect(); | |
1500 QString timeMinText = QString("%1").arg(rtMin.toText(true).c_str()); | |
1501 QString timeMaxText = QString(" - %1").arg(rtMax.toText(true).c_str()); | |
1502 | |
1503 QFontMetrics metrics = paint.fontMetrics(); | |
1504 | |
1505 int labelwidth = | |
1506 std::max(std::max(metrics.width(timeLabel), | |
1507 metrics.width(freqLabel)), | |
1508 metrics.width(dBLabel)); | |
1509 | |
1510 int boxwidth = labelwidth + | |
1511 metrics.width(timeMinText) + metrics.width(timeMaxText); | |
1512 | |
1513 int fontHeight = metrics.height(); | |
1514 int boxheight = fontHeight * 3 + 4; | |
1515 | |
1516 return QRect(0, 0, boxwidth + 20, boxheight + 15); | |
1517 } | |
1518 | |
1519 void | |
1520 SpectrogramLayer::paintLocalFeatureDescription(QPainter &paint, | |
1521 QRect rect, QPoint pos) const | |
1522 { | |
1523 int x = pos.x(); | |
1524 int y = pos.y(); | |
1525 | |
1526 if (!m_model || !m_model->isOK()) return; | |
1527 | |
1528 float dbMin = 0, dbMax = 0; | |
1529 float freqMin = 0, freqMax = 0; | |
1530 RealTime rtMin, rtMax; | |
1531 | |
1532 bool haveDb = false; | |
1533 | |
1534 if (!getXBinSourceRange(x, rtMin, rtMax)) return; | |
1535 if (!getYBinSourceRange(y, freqMin, freqMax)) return; | |
1536 if (getXYBinSourceRange(x, y, dbMin, dbMax)) haveDb = true; | |
1537 | |
1538 QString timeLabel = tr("Time: "); | |
1539 QString freqLabel = tr("Hz: "); | |
1540 QString dBLabel = tr("dB: "); | |
1541 | |
1542 QString timeMinText = QString("%1").arg(rtMin.toText(true).c_str()); | |
1543 QString timeMaxText = QString(" - %1").arg(rtMax.toText(true).c_str()); | |
1544 | |
1545 QString freqMinText = QString("%1").arg(freqMin); | |
1546 QString freqMaxText = ""; | |
1547 if (freqMax != freqMin) { | |
1548 freqMaxText = QString(" - %1").arg(freqMax); | |
1549 } | |
1550 | |
1551 QString dBMinText = ""; | |
1552 QString dBMaxText = ""; | |
1553 | |
1554 if (haveDb) { | |
1555 int dbmxi = int(dbMax - 0.001); | |
1556 int dbmni = int(dbMin - 0.001); | |
1557 dBMinText = QString("%1").arg(dbmni); | |
1558 if (dbmxi != dbmni) dBMaxText = QString(" - %1").arg(dbmxi); | |
1559 } | |
1560 | |
1561 QFontMetrics metrics = paint.fontMetrics(); | |
1562 | |
1563 int labelwidth = | |
1564 std::max(std::max(metrics.width(timeLabel), | |
1565 metrics.width(freqLabel)), | |
1566 metrics.width(dBLabel)); | |
1567 | |
1568 int minwidth = | |
1569 std::max(std::max(metrics.width(timeMinText), | |
1570 metrics.width(freqMinText)), | |
1571 metrics.width(dBMinText)); | |
1572 | |
1573 int maxwidth = | |
1574 std::max(std::max(metrics.width(timeMaxText), | |
1575 metrics.width(freqMaxText)), | |
1576 metrics.width(dBMaxText)); | |
1577 | |
1578 int boxwidth = labelwidth + minwidth + maxwidth; | |
1579 | |
1580 int fontAscent = metrics.ascent(); | |
1581 int fontHeight = metrics.height(); | |
1582 | |
1583 int boxheight = fontHeight * 3 + 4; | |
1584 | |
1585 // paint.setPen(Qt::white); | |
1586 // paint.setBrush(Qt::NoBrush); | |
1587 | |
1588 //!!! int xbase = m_view->width() - boxwidth - 20; | |
1589 int xbase = rect.x() + 5; | |
1590 int ybase = rect.y() + 5; | |
1591 | |
1592 paint.drawRect(xbase, ybase, boxwidth + 10, | |
1593 boxheight + 10 - metrics.descent() + 1); | |
1594 | |
1595 paint.drawText(xbase + 5 + labelwidth - metrics.width(timeLabel), | |
1596 ybase + 5 + fontAscent, timeLabel); | |
1597 | |
1598 paint.drawText(xbase + 5 + labelwidth - metrics.width(freqLabel), | |
1599 ybase + 7 + fontAscent + fontHeight, freqLabel); | |
1600 | |
1601 paint.drawText(xbase + 5 + labelwidth - metrics.width(dBLabel), | |
1602 ybase + 9 + fontAscent + fontHeight * 2, dBLabel); | |
1603 | |
1604 paint.drawText(xbase + 5 + labelwidth + minwidth - metrics.width(timeMinText), | |
1605 ybase + 5 + fontAscent, timeMinText); | |
1606 | |
1607 paint.drawText(xbase + 5 + labelwidth + minwidth - metrics.width(freqMinText), | |
1608 ybase + 7 + fontAscent + fontHeight, freqMinText); | |
1609 | |
1610 paint.drawText(xbase + 5 + labelwidth + minwidth - metrics.width(dBMinText), | |
1611 ybase + 9 + fontAscent + fontHeight * 2, dBMinText); | |
1612 | |
1613 paint.drawText(xbase + 5 + labelwidth + minwidth, | |
1614 ybase + 5 + fontAscent, timeMaxText); | |
1615 | |
1616 paint.drawText(xbase + 5 + labelwidth + minwidth, | |
1617 ybase + 7 + fontAscent + fontHeight, freqMaxText); | |
1618 | |
1619 paint.drawText(xbase + 5 + labelwidth + minwidth, | |
1620 ybase + 9 + fontAscent + fontHeight * 2, dBMaxText); | |
1621 } | |
1622 | |
1623 int | 1486 int |
1624 SpectrogramLayer::getNearestFeatureFrame(int frame, | 1487 SpectrogramLayer::getNearestFeatureFrame(int frame, |
1625 size_t &resolution, | 1488 size_t &resolution, |
1626 bool snapRight) const | 1489 bool snapRight) const |
1627 { | 1490 { |
1629 int snapFrame = (frame / resolution) * resolution; | 1492 int snapFrame = (frame / resolution) * resolution; |
1630 if (snapRight) snapFrame += resolution; | 1493 if (snapRight) snapFrame += resolution; |
1631 return snapFrame; | 1494 return snapFrame; |
1632 } | 1495 } |
1633 | 1496 |
1634 /*!!! | 1497 QString |
1635 | 1498 SpectrogramLayer::getFeatureDescription(QPoint &pos) const |
1636 bool | 1499 { |
1637 SpectrogramLayer::identifyLocalFeatures(bool on, int x, int y) | 1500 int x = pos.x(); |
1638 { | 1501 int y = pos.y(); |
1639 return true; //!!! | 1502 |
1640 | 1503 if (!m_model || !m_model->isOK()) return ""; |
1641 m_identify = on; | |
1642 m_identifyX = x; | |
1643 m_identifyY = y; | |
1644 | |
1645 m_view->update(); | |
1646 */ | |
1647 /* | |
1648 if (!m_model || !m_model->isOK()) return false; | |
1649 | |
1650 std::cerr << "SpectrogramLayer::identifyLocalFeatures(" << on << "," << x << "," << y << ")" << std::endl; | |
1651 | 1504 |
1652 float dbMin = 0, dbMax = 0; | 1505 float dbMin = 0, dbMax = 0; |
1653 float freqMin = 0, freqMax = 0; | 1506 float freqMin = 0, freqMax = 0; |
1507 QString pitchMin, pitchMax; | |
1654 RealTime rtMin, rtMax; | 1508 RealTime rtMin, rtMax; |
1655 | 1509 |
1656 if (getXBinSourceRange(x, rtMin, rtMax)) { | 1510 bool haveDb = false; |
1657 std::cerr << "Times: " << rtMin << " -> " << rtMax << std::endl; | 1511 |
1658 } else return false; | 1512 if (!getXBinSourceRange(x, rtMin, rtMax)) return ""; |
1659 | 1513 if (!getYBinSourceRange(y, freqMin, freqMax)) return ""; |
1660 if (getYBinSourceRange(y, freqMin, freqMax)) { | 1514 if (getXYBinSourceRange(x, y, dbMin, dbMax)) haveDb = true; |
1661 std::cerr << "Frequencies: " << freqMin << " -> " << freqMax << std::endl; | 1515 |
1662 } else return false; | 1516 //!!! want to actually do a one-off FFT to recalculate the dB value! |
1663 | 1517 |
1664 if (getXYBinSourceRange(x, y, dbMin, dbMax)) { | 1518 QString text; |
1665 std::cerr << "dB: " << dbMin << " -> " << dbMax << std::endl; | 1519 |
1666 } | 1520 if (rtMin != rtMax) { |
1667 | 1521 text += tr("Time:\t%1 - %2\n") |
1668 m_identifyX = x; | 1522 .arg(rtMin.toText(true).c_str()) |
1669 m_identifyY = y; | 1523 .arg(rtMax.toText(true).c_str()); |
1670 m_identify = true; | 1524 } else { |
1671 */ | 1525 text += tr("Time:\t%1\n") |
1672 /*!!! | 1526 .arg(rtMin.toText(true).c_str()); |
1673 return true; | 1527 } |
1674 } | 1528 |
1675 */ | 1529 if (freqMin != freqMax) { |
1530 text += tr("Frequency:\t%1 - %2 Hz\nPitch:\t%3 - %4\n") | |
1531 .arg(freqMin) | |
1532 .arg(freqMax) | |
1533 .arg(Pitch::getPitchLabelForFrequency(freqMin)) | |
1534 .arg(Pitch::getPitchLabelForFrequency(freqMax)); | |
1535 } else { | |
1536 text += tr("Frequency:\t%1 Hz\nPitch:\t%2\n") | |
1537 .arg(freqMin) | |
1538 .arg(Pitch::getPitchLabelForFrequency(freqMin)); | |
1539 } | |
1540 | |
1541 if (haveDb) { | |
1542 if (lrintf(dbMin) != lrintf(dbMax)) { | |
1543 text += tr("dB:\t%1 - %2").arg(lrintf(dbMin)).arg(lrintf(dbMax)); | |
1544 } else { | |
1545 text += tr("dB:\t%1").arg(lrintf(dbMin)); | |
1546 } | |
1547 } | |
1548 | |
1549 return text; | |
1550 } | |
1551 | |
1676 int | 1552 int |
1677 SpectrogramLayer::getVerticalScaleWidth(QPainter &paint) const | 1553 SpectrogramLayer::getVerticalScaleWidth(QPainter &paint) const |
1678 { | 1554 { |
1679 if (!m_model || !m_model->isOK()) return 0; | 1555 if (!m_model || !m_model->isOK()) return 0; |
1680 | 1556 |