Fix sliding of waveform when drawing sample in reverse (#7063)
This commit is contained in:
@@ -96,7 +96,7 @@ public:
|
||||
auto sampleDuration() const -> std::chrono::milliseconds;
|
||||
auto sampleFile() const -> const QString& { return m_buffer->audioFile(); }
|
||||
auto sampleRate() const -> int { return m_buffer->sampleRate(); }
|
||||
auto sampleSize() const -> int { return m_buffer->size(); }
|
||||
auto sampleSize() const -> size_t { return m_buffer->size(); }
|
||||
|
||||
auto toBase64() const -> QString { return m_buffer->toBase64(); }
|
||||
|
||||
|
||||
@@ -34,7 +34,15 @@ namespace lmms::gui {
|
||||
class LMMS_EXPORT SampleWaveform
|
||||
{
|
||||
public:
|
||||
static void visualize(const Sample& sample, QPainter& p, const QRect& dr, int fromFrame = 0, int toFrame = 0);
|
||||
struct Parameters
|
||||
{
|
||||
const sampleFrame* buffer;
|
||||
size_t size;
|
||||
float amplification;
|
||||
bool reversed;
|
||||
};
|
||||
|
||||
static void visualize(Parameters parameters, QPainter& painter, const QRect& rect);
|
||||
};
|
||||
} // namespace lmms::gui
|
||||
|
||||
|
||||
@@ -719,7 +719,7 @@ void AudioFileProcessorWaveView::updateSampleRange()
|
||||
{
|
||||
const f_cnt_t marging = (m_sample->endFrame() - m_sample->startFrame()) * 0.1;
|
||||
m_from = qMax(0, m_sample->startFrame() - marging);
|
||||
m_to = qMin(m_sample->endFrame() + marging, m_sample->sampleSize());
|
||||
m_to = qMin<size_t>(m_sample->endFrame() + marging, m_sample->sampleSize());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1014,7 +1014,11 @@ void AudioFileProcessorWaveView::updateGraph()
|
||||
m_graph.fill( Qt::transparent );
|
||||
QPainter p( &m_graph );
|
||||
p.setPen( QColor( 255, 255, 255 ) );
|
||||
SampleWaveform::visualize(*m_sample, p, QRect(0, 0, m_graph.width(), m_graph.height()), m_from, m_to);
|
||||
|
||||
const auto rect = QRect{0, 0, m_graph.width(), m_graph.height()};
|
||||
const auto waveform = SampleWaveform::Parameters{
|
||||
m_sample->data() + m_from, static_cast<size_t>(m_to - m_from), m_sample->amplification(), m_sample->reversed()};
|
||||
SampleWaveform::visualize(waveform, p, rect);
|
||||
}
|
||||
|
||||
|
||||
@@ -1076,8 +1080,8 @@ void AudioFileProcessorWaveView::slide( int _px )
|
||||
step = -step;
|
||||
}
|
||||
|
||||
f_cnt_t step_from = qBound(0, m_from + step, m_sample->sampleSize()) - m_from;
|
||||
f_cnt_t step_to = qBound(m_from + 1, m_to + step, m_sample->sampleSize()) - m_to;
|
||||
f_cnt_t step_from = qBound<size_t>(0, m_from + step, m_sample->sampleSize()) - m_from;
|
||||
f_cnt_t step_to = qBound<size_t>(m_from + 1, m_to + step, m_sample->sampleSize()) - m_to;
|
||||
|
||||
step = qAbs( step_from ) < qAbs( step_to ) ? step_from : step_to;
|
||||
|
||||
|
||||
@@ -89,9 +89,10 @@ void SlicerTWaveform::drawSeekerWaveform()
|
||||
QPainter brush(&m_seekerWaveform);
|
||||
brush.setPen(s_waveformColor);
|
||||
|
||||
SampleWaveform::visualize(m_slicerTParent->m_originalSample, brush,
|
||||
QRect(0, 0, m_seekerWaveform.width(), m_seekerWaveform.height()), 0,
|
||||
m_slicerTParent->m_originalSample.sampleSize());
|
||||
const auto& sample = m_slicerTParent->m_originalSample;
|
||||
const auto waveform = SampleWaveform::Parameters{sample.data(), sample.sampleSize(), sample.amplification(), sample.reversed()};
|
||||
const auto rect = QRect(0, 0, m_seekerWaveform.width(), m_seekerWaveform.height());
|
||||
SampleWaveform::visualize(waveform, brush, rect);
|
||||
|
||||
// increase brightness in inner color
|
||||
QBitmap innerMask = m_seekerWaveform.createMaskFromColor(s_waveformMaskColor, Qt::MaskMode::MaskOutColor);
|
||||
@@ -139,14 +140,16 @@ void SlicerTWaveform::drawEditorWaveform()
|
||||
if (m_slicerTParent->m_originalSample.sampleSize() <= 1) { return; }
|
||||
|
||||
QPainter brush(&m_editorWaveform);
|
||||
float startFrame = m_seekerStart * m_slicerTParent->m_originalSample.sampleSize();
|
||||
float endFrame = m_seekerEnd * m_slicerTParent->m_originalSample.sampleSize();
|
||||
size_t startFrame = m_seekerStart * m_slicerTParent->m_originalSample.sampleSize();
|
||||
size_t endFrame = m_seekerEnd * m_slicerTParent->m_originalSample.sampleSize();
|
||||
|
||||
brush.setPen(s_waveformColor);
|
||||
float zoomOffset = (m_editorHeight - m_zoomLevel * m_editorHeight) / 2;
|
||||
|
||||
SampleWaveform::visualize(m_slicerTParent->m_originalSample, brush,
|
||||
QRect(0, zoomOffset, m_editorWidth, m_zoomLevel * m_editorHeight), startFrame, endFrame);
|
||||
const auto& sample = m_slicerTParent->m_originalSample;
|
||||
const auto waveform = SampleWaveform::Parameters{sample.data() + startFrame, endFrame - startFrame, sample.amplification(), sample.reversed()};
|
||||
const auto rect = QRect(0, zoomOffset, m_editorWidth, m_zoomLevel * m_editorHeight);
|
||||
SampleWaveform::visualize(waveform, brush, rect);
|
||||
|
||||
// increase brightness in inner color
|
||||
QBitmap innerMask = m_editorWaveform.createMaskFromColor(s_waveformMaskColor, Qt::MaskMode::MaskOutColor);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user