Fix sliding of waveform when drawing sample in reverse (#7063)

This commit is contained in:
saker
2024-01-13 21:05:18 -05:00
committed by GitHub
parent 85399c12c2
commit b67c53ad29
7 changed files with 62 additions and 46 deletions

View File

@@ -26,31 +26,25 @@
namespace lmms::gui {
void SampleWaveform::visualize(const Sample& sample, QPainter& p, const QRect& dr, int fromFrame, int toFrame)
void SampleWaveform::visualize(Parameters parameters, QPainter& painter, const QRect& rect)
{
if (sample.sampleSize() == 0) { return; }
const auto x = dr.x();
const auto height = dr.height();
const auto width = dr.width();
const auto centerY = dr.center().y();
const auto x = rect.x();
const auto height = rect.height();
const auto width = rect.width();
const auto centerY = rect.center().y();
const auto halfHeight = height / 2;
const auto buffer = sample.data() + fromFrame;
const auto color = p.pen().color();
const auto color = painter.pen().color();
const auto rmsColor = color.lighter(123);
auto numFrames = toFrame - fromFrame;
if (numFrames == 0) { numFrames = sample.sampleSize(); }
const auto framesPerPixel = std::max(1, numFrames / width);
const auto framesPerPixel = std::max<size_t>(1, parameters.size / width);
constexpr auto maxFramesPerPixel = 512;
const auto resolution = std::max(1, framesPerPixel / maxFramesPerPixel);
const auto resolution = std::max<size_t>(1, framesPerPixel / maxFramesPerPixel);
const auto framesPerResolution = framesPerPixel / resolution;
const auto numPixels = std::min(numFrames, width);
const auto numPixels = std::min<size_t>(parameters.size, width);
auto min = std::vector<float>(numPixels, 1);
auto max = std::vector<float>(numPixels, -1);
auto squared = std::vector<float>(numPixels);
@@ -59,35 +53,34 @@ void SampleWaveform::visualize(const Sample& sample, QPainter& p, const QRect& d
for (int i = 0; i < maxFrames; i += resolution)
{
const auto pixelIndex = i / framesPerPixel;
const auto value = std::accumulate(buffer[i].begin(), buffer[i].end(), 0.0f) / buffer[i].size();
const auto frameIndex = !parameters.reversed ? i : maxFrames - i;
const auto& frame = parameters.buffer[frameIndex];
const auto value = std::accumulate(frame.begin(), frame.end(), 0.0f) / frame.size();
if (value > max[pixelIndex]) { max[pixelIndex] = value; }
if (value < min[pixelIndex]) { min[pixelIndex] = value; }
squared[pixelIndex] += value * value;
}
const auto amplification = sample.amplification();
const auto reversed = sample.reversed();
for (int i = 0; i < numPixels; i++)
{
const auto lineY1 = centerY - max[i] * halfHeight * amplification;
const auto lineY2 = centerY - min[i] * halfHeight * amplification;
auto lineX = i + x;
if (reversed) { lineX = width - lineX; }
p.drawLine(lineX, lineY1, lineX, lineY2);
const auto lineY1 = centerY - max[i] * halfHeight * parameters.amplification;
const auto lineY2 = centerY - min[i] * halfHeight * parameters.amplification;
const auto lineX = i + x;
painter.drawLine(lineX, lineY1, lineX, lineY2);
const auto rms = std::sqrt(squared[i] / framesPerResolution);
const auto maxRMS = std::clamp(rms, min[i], max[i]);
const auto minRMS = std::clamp(-rms, min[i], max[i]);
const auto rmsLineY1 = centerY - maxRMS * halfHeight * amplification;
const auto rmsLineY2 = centerY - minRMS * halfHeight * amplification;
const auto rmsLineY1 = centerY - maxRMS * halfHeight * parameters.amplification;
const auto rmsLineY2 = centerY - minRMS * halfHeight * parameters.amplification;
p.setPen(rmsColor);
p.drawLine(lineX, rmsLineY1, lineX, rmsLineY2);
p.setPen(color);
painter.setPen(rmsColor);
painter.drawLine(lineX, rmsLineY1, lineX, rmsLineY2);
painter.setPen(color);
}
}

View File

@@ -269,7 +269,10 @@ void SampleClipView::paintEvent( QPaintEvent * pe )
float offset = m_clip->startTimeOffset() / ticksPerBar * pixelsPerBar();
QRect r = QRect( offset, spacing,
qMax( static_cast<int>( m_clip->sampleLength() * ppb / ticksPerBar ), 1 ), rect().bottom() - 2 * spacing );
SampleWaveform::visualize(m_clip->m_sample, p, r);
const auto& sample = m_clip->m_sample;
const auto waveform = SampleWaveform::Parameters{sample.data(), sample.sampleSize(), sample.amplification(), sample.reversed()};
SampleWaveform::visualize(waveform, p, r);
QString name = PathUtil::cleanName(m_clip->m_sample.sampleFile());
paintTextLabel(name, p);

View File

@@ -1248,7 +1248,12 @@ void AutomationEditor::paintEvent(QPaintEvent * pe )
int yOffset = (editorHeight - sampleHeight) / 2.0f + TOP_MARGIN;
p.setPen(m_ghostSampleColor);
SampleWaveform::visualize(m_ghostSample->sample(), p, QRect(startPos, yOffset, sampleWidth, sampleHeight), 0, sampleFrames);
const auto& sample = m_ghostSample->sample();
const auto waveform = SampleWaveform::Parameters{
sample.data(), sample.sampleSize(), sample.amplification(), sample.reversed()};
const auto rect = QRect(startPos, yOffset, sampleWidth, sampleHeight);
SampleWaveform::visualize(waveform, p, rect);
}
// draw ghost notes