Deluge Firmware 1.3.0
Build date: 2026.10.14
Loading...
Searching...
No Matches
waveform_peak_math.h File Reference

Pure arithmetic used by WaveformRenderer to find per-column waveform peaks. More...

#include <cstdint>
#include <optional>
Include dependency graph for waveform_peak_math.h:

Go to the source code of this file.

Classes

struct  deluge::gui::waveform::Peak
 Minimum and maximum of a run of raw 32-bit-aligned sample values. More...

Functions

Peak deluge::gui::waveform::scanPeak (const char *data, int32_t start, int32_t end, int32_t byte_depth, int32_t num_channels)
 Finds the subsampled min/max over part of a Cluster's raw audio data.
int8_t deluge::gui::waveform::coarsePeak (int32_t value)
 Reduces a 32-bit peak to the 8-bit form stored in SampleCluster::minValue / maxValue.
int32_t deluge::gui::waveform::lastClusterEnd (uint64_t audio_bytes, uint32_t audio_start, int32_t cluster_size)
 Finds where the audio ends within the last Cluster that holds any.
int64_t deluge::gui::waveform::clusterStart (int32_t index, int32_t size_log2)
 Finds a Cluster's byte offset within its file, without overflowing for files over 2 GB.
int32_t deluge::gui::waveform::firstFrameOffset (int64_t cluster_start, uint32_t audio_start, int32_t frame_size)
 Finds where the first whole audio frame starts within a Cluster.
std::optional< int32_t > deluge::gui::waveform::columnShift (int64_t delta, int64_t zoom, int32_t width)
 Works out whether a scroll moved the view by a whole number of columns.
void deluge::gui::waveform::remapColumns (WaveformRenderData &data, int64_t scroll, int64_t zoom)
 Carries cached per-column peaks over to a new scroll and zoom, so they needn't all be worked out again.

Variables

constexpr int32_t deluge::gui::waveform::kMaxScanSamplesLog2 = 9
 log2 of the most samples scanPeak() reads per call; longer spans are subsampled.

Detailed Description

Pure arithmetic used by WaveformRenderer to find per-column waveform peaks.

Nothing here touches the engine or hardware, so it's covered by the host unit tests (tests/unit/waveform_peak_math_tests.cpp).

Function Documentation

◆ clusterStart()

int64_t deluge::gui::waveform::clusterStart ( int32_t index,
int32_t size_log2 )

Finds a Cluster's byte offset within its file, without overflowing for files over 2 GB.

Parameters
indexIndex of the Cluster within the file.
size_log2Cluster::size_magnitude.
Returns
The offset of the Cluster's first byte.

◆ coarsePeak()

int8_t deluge::gui::waveform::coarsePeak ( int32_t value)

Reduces a 32-bit peak to the 8-bit form stored in SampleCluster::minValue / maxValue.

Parameters
valueFull-scale 32-bit sample value.
Returns
The top 8 bits, rounded toward zero.

◆ columnShift()

std::optional< int32_t > deluge::gui::waveform::columnShift ( int64_t delta,
int64_t zoom,
int32_t width )

Works out whether a scroll moved the view by a whole number of columns.

AudioClip converts its scroll from ticks to samples with integer division. So scrolling by one column can land up to one sample per column moved away from an exact multiple of zoom. That much slack is accepted, as long as it stays under half a column.

Parameters
deltaNew scroll minus old scroll, in samples.
zoomSamples per column. Must be positive.
widthNumber of columns. Moves further than this leave nothing to reuse.
Returns
The number of columns moved (positive is rightwards), or std::nullopt if it wasn't a whole-column move of 1 to width columns.

◆ firstFrameOffset()

int32_t deluge::gui::waveform::firstFrameOffset ( int64_t cluster_start,
uint32_t audio_start,
int32_t frame_size )

Finds where the first whole audio frame starts within a Cluster.

Frames are laid out from audio_start, so with non-power-of-two frame sizes (e.g. 24-bit) a Cluster usually begins part-way through a frame.

Parameters
cluster_startThe Cluster's byte offset within the file, from clusterStart().
audio_startOffset of the audio data within the file.
frame_sizeBytes per frame (num_channels * byte_depth).
Returns
Offset of the first whole frame, relative to the Cluster's start. For a Cluster that still holds the file header, this is where the audio data begins.

◆ lastClusterEnd()

int32_t deluge::gui::waveform::lastClusterEnd ( uint64_t audio_bytes,
uint32_t audio_start,
int32_t cluster_size )

Finds where the audio ends within the last Cluster that holds any.

Rounds up, so audio that ends exactly on a Cluster boundary gives a full Cluster rather than 0.

Parameters
audio_bytesLength of the audio data in bytes.
audio_startOffset of the audio data within the file.
cluster_sizeCluster::size. Must be a power of two.
Returns
The byte after the last audio byte, relative to the start of that Cluster: 1 to cluster_size.

◆ remapColumns()

void deluge::gui::waveform::remapColumns ( WaveformRenderData & data,
int64_t scroll,
int64_t zoom )

Carries cached per-column peaks over to a new scroll and zoom, so they needn't all be worked out again.

For each new column, looks at the old columns it overlaps:

  • If it lines up with the edges of whole old columns (e.g. zooming out) that are all INVESTIGATED, their combined peaks are exactly what working it out would give, so it becomes INVESTIGATED. The edges are allowed the same slack from AudioClip's tick-to-sample truncation as columnShift() allows.
  • Otherwise, if any of them hold peaks (e.g. zooming in), it becomes a PLACEHOLDER with their combined peaks.
  • Otherwise it becomes NOT_INVESTIGATED.

For a whole-column scroll at the same zoom, columnShift() and sliding the arrays across gives the same result more cheaply.

Parameters
dataThe cache to remap. Its xScroll and xZoom describe the columns it holds now, and are left alone.
scrollNew sample position of the left edge of column 0.
zoomNew samples per column. Must be positive.

◆ scanPeak()

Peak deluge::gui::waveform::scanPeak ( const char * data,
int32_t start,
int32_t end,
int32_t byte_depth,
int32_t num_channels )

Finds the subsampled min/max over part of a Cluster's raw audio data.

Reads at most about 2^kMaxScanSamplesLog2 samples, striding over the rest. For stereo the stride is forced odd so both channels get sampled. Each read is a 32-bit load offset by byte_depth - 4, so it lands on a sample's most significant bytes. For 8/16/24-bit data that indexes slightly before start, which is valid because Clusters keep padding bytes before their data.

Parameters
dataCluster::data of the Cluster being read.
startFirst byte to read, relative to data. Should be frame-aligned.
endByte after the last one to read, relative to data.
byte_depthBytes per sample (1-4).
num_channels1 or 2. Both channels are counted as samples.
Returns
The peaks found. If the range is empty, min is INT32_MAX and max is INT32_MIN.