Files
lmms/include/SampleThumbnail.h
Johannes Lorenz 71ce49d7ba Remove lots of useless/misplaced includes (#7999)
Follow-Up of 7db3fa94a1 .

This was done by setting `CMAKE_C_INCLUDE_WHAT_YOU_USE` and
`CMAKE_CXX_INCLUDE_WHAT_YOU_USE` to (broken down into multiple lines here,
note, all below `FL/x.h` is not required for C):

```
include-what-you-use;
    -Xiwyu;--mapping_file=/usr/share/include-what-you-use/qt5_11.imp;
    -Xiwyu;--keep=*/xmmintrin.h;
    -Xiwyu;--keep=*/lmmsconfig.h;
    -Xiwyu;--keep=*/weak_libjack.h;
    -Xiwyu;--keep=*/sys/*;
    -Xiwyu;--keep=*/debug.h;
    -Xiwyu;--keep=*/SDL/*;
    -Xiwyu;--keep=*/alsa/*;
    -Xiwyu;--keep=*/FL/x.h;
    -Xiwyu;--keep=*/MidiApple.h;
    -Xiwyu;--keep=*/MidiWinMM.h;
    -Xiwyu;--keep=*/AudioSoundIo.h;
    -Xiwyu;--keep=*/OpulenZ/adplug/*;
    -Xiwyu;--keep=QPainterPath;
    -Xiwyu;--keep=QtTest
```

FAQ:

* Q: Does this speed-up a completely fresh compile?
* A: No, I measured it.

* Q: Does it speed up anything else?
* A: Yes. If you change one header, it can reduce the number of CPP files
     that your compiler needs to recompile, or your IDE has to re-scan.

* Q: What other reasons are for this PR?
* A: It's idiomatic to only include headers if you need them. Also, it will
     reduce output for those who want to use IWYU for new PRs.

Background:

This is just a remainder PR of what I planned. My original idea was to setup
a CI which warns you of useless includes (but not of all issues that IWYU
complains about). However, I could not see that this was favored on Discord.
A full IWYU CI also has the problem that it (possibly??) needs to compile
with `make -j 1`, which would make CI really slow.

However, for that plan, I had to fix the whole code base to be IWYU
compliant - which it now is.
2025-07-21 23:39:17 +02:00

147 lines
4.3 KiB
C++

/*
* SampleThumbnail.h
*
* Copyright (c) 2024 Khoi Dau <casboi86@gmail.com>
* Copyright (c) 2024 Sotonye Atemie <sakertooth@gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef LMMS_SAMPLE_THUMBNAIL_H
#define LMMS_SAMPLE_THUMBNAIL_H
#include <QDateTime>
#include <QRect>
#include <memory>
#include "lmms_export.h"
#include "SampleBuffer.h"
#include "SampleFrame.h"
class QPainter;
namespace lmms {
class Sample;
/**
Allows for visualizing sample data.
On construction, thumbnails will be generated
at logarathmic intervals of downsampling. Those cached thumbnails will then be further downsampled on the fly and
transformed in various ways to create the desired waveform.
Given that we are dealing with far less data to generate
the visualization however (i.e., we are not reading from original sample data when drawing), this provides a
significant performance boost that wouldn't be possible otherwise.
*/
class LMMS_EXPORT SampleThumbnail
{
public:
struct VisualizeParameters
{
QRect sampleRect; //!< A rectangle that covers the entire range of samples.
QRect viewportRect; //!< Specifies the location in `sampleRect` where the waveform will be drawn. Equals
//!< `sampleRect` when null.
float amplification = 1.0f; //!< The amount of amplification to apply to the waveform.
float sampleStart = 0.0f; //!< Where the sample begins for drawing.
float sampleEnd = 1.0f; //!< Where the sample ends for drawing.
bool reversed = false; //!< Determines if the waveform is drawn in reverse or not.
};
SampleThumbnail() = default;
SampleThumbnail(const Sample& sample);
void visualize(VisualizeParameters parameters, QPainter& painter) const;
private:
class Thumbnail
{
public:
struct Peak
{
Peak() = default;
Peak(float min, float max)
: min(min)
, max(max)
{
}
Peak(const SampleFrame& frame)
: min(std::min(frame.left(), frame.right()))
, max(std::max(frame.left(), frame.right()))
{
}
Peak operator+(const Peak& other) const { return Peak(std::min(min, other.min), std::max(max, other.max)); }
Peak operator+(const SampleFrame& frame) const { return *this + Peak{frame}; }
float min = std::numeric_limits<float>::infinity();
float max = -std::numeric_limits<float>::infinity();
};
Thumbnail() = default;
Thumbnail(std::vector<Peak> peaks, double samplesPerPeak);
Thumbnail(const float* buffer, size_t size, size_t width);
Thumbnail zoomOut(float factor) const;
Peak* data() { return m_peaks.data(); }
Peak& operator[](size_t index) { return m_peaks[index]; }
const Peak& operator[](size_t index) const { return m_peaks[index]; }
int width() const { return m_peaks.size(); }
double samplesPerPeak() const { return m_samplesPerPeak; }
private:
std::vector<Peak> m_peaks;
double m_samplesPerPeak = 0.0;
};
struct SampleThumbnailEntry
{
QString filePath;
QDateTime lastModified;
friend bool operator==(const SampleThumbnailEntry& first, const SampleThumbnailEntry& second)
{
return first.filePath == second.filePath && first.lastModified == second.lastModified;
}
};
struct Hash
{
std::size_t operator()(const SampleThumbnailEntry& entry) const noexcept { return qHash(entry.filePath); }
};
using ThumbnailCache = std::vector<Thumbnail>;
std::shared_ptr<ThumbnailCache> m_thumbnailCache = std::make_shared<ThumbnailCache>();
std::shared_ptr<const SampleBuffer> m_buffer = SampleBuffer::emptyBuffer();
inline static std::unordered_map<SampleThumbnailEntry, std::shared_ptr<ThumbnailCache>, Hash> s_sampleThumbnailCacheMap;
};
} // namespace lmms
#endif // LMMS_SAMPLE_THUMBNAIL_H