Audacity 3.2.0
PixelSampleMapper.cpp
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*!********************************************************************
3
4 Audacity: A Digital Audio Editor
5
6 PixelSampleMapper.h
7
8 Dmitry Vedenko
9
10**********************************************************************/
11#include "PixelSampleMapper.h"
12
13#include <cassert>
14#include <cmath>
15
16#include "SampleCount.h"
17#include "Variant.h"
18
20 double t0, double rate, double samplesPerPixel) noexcept
21 : mMapper(LinearMapper { (0.5 + t0 * rate), samplesPerPixel })
22{
23 assert((0.5 + t0 * rate) >= 0.0);
24}
25
26void PixelSampleMapper::applyBias(double bias) noexcept
27{
28 auto mapper = std::get_if<LinearMapper>(&mMapper);
29
30 if (mapper != nullptr)
31 mapper->mInitialValue += bias;
32}
33
35 const PixelSampleMapper& oldMapper, size_t oldLen, size_t newLen)
36{
37 assert(mMapper.index() == 0);
38 assert(oldMapper.mMapper.index() == 0);
39
40 LinearMapper* currentMapper = std::get_if<LinearMapper>(&mMapper);
41
42 if (currentMapper == nullptr)
43 return {};
44
45 const LinearMapper* oldLinearMapper =
46 std::get_if<LinearMapper>(&oldMapper.mMapper);
47
48 if (oldLinearMapper == nullptr)
49 return {};
50
51 // Find the sample position that is the origin in the old cache.
52 const double oldWhere0 =
53 (*oldLinearMapper)(1).as_double() - currentMapper->mSamplesPerPixel;
54 const double oldWhereLast =
55 oldWhere0 + oldLen * currentMapper->mSamplesPerPixel;
56 // Find the length in samples of the old cache.
57 const double denom = oldWhereLast - oldWhere0;
58
59 // What sample would go in where[0] with no correction?
60 const double guessWhere0 =
61 currentMapper->mInitialValue - 0.5; // Why do we ignore initial bias?
62
63 if ( // Skip if old and NEW are disjoint:
64 oldWhereLast <= guessWhere0 ||
65 guessWhere0 + newLen * currentMapper->mSamplesPerPixel <= oldWhere0 ||
66 // Skip unless denom rounds off to at least 1.
67 denom < 0.5)
68 {
69 // The computation of oldX0 in the other branch
70 // may underflow and the assertion would be violated.
71 return oldLen;
72 }
73 else
74 {
75 // What integer position in the old cache array does that map to?
76 // (even if it is out of bounds)
77 const auto oldX0 =
78 std::floor(0.5 + oldLen * (guessWhere0 - oldWhere0) / denom);
79 // What sample count would the old cache have put there?
80 const double where0 =
81 oldWhere0 + double(oldX0) * currentMapper->mSamplesPerPixel;
82 // What correction is needed to align the NEW cache with the old?
83 const double correction0 = where0 - guessWhere0;
84 const double correction = std::max(
85 -currentMapper->mSamplesPerPixel,
86 std::min(currentMapper->mSamplesPerPixel, correction0));
87
88 assert(correction == correction0);
89
90 currentMapper->mInitialValue += correction;
91
92 return oldX0;
93 }
94}
95
97{
98 return Variant::Visit(
99 [column](const auto& mapper) { return mapper(column); }, mMapper);
100}
101
103{
104 return GetFirstSample(column + 1);
105}
106
107std::pair<sampleCount, sampleCount>
109{
110 return { GetFirstSample(column), GetLastSample(column) };
111}
112
114{
115 mMapper = std::move(mapper);
116}
117
119{
120 return Variant::Visit([](const auto& mapper) { return !!mapper; }, mMapper);
121}
122
123bool PixelSampleMapper::IsLinear() const noexcept
124{
125 return std::get_if<LinearMapper>(&mMapper) != nullptr;
126}
127
129PixelSampleMapper::LinearMapper::operator()(uint32_t column) const noexcept
130{
131 // Previous code used floor, but "required" mInitialValue to be positive.
132 // For positive values, let's just trunc the value, as it is at least twice
133 // as fast.
134 return sampleCount(mInitialValue + column * mSamplesPerPixel);
135}
136
137PixelSampleMapper::LinearMapper::operator bool() const noexcept
138{
139 return mSamplesPerPixel > 0.0;
140}
int min(int a, int b)
emulates std::visit for one visitor
Utility class to calculate sample range for a given column.
PixelSampleMapper()=default
std::pair< sampleCount, sampleCount > GetSampleRange(uint32_t column) const
void applyBias(double bias) noexcept
bool IsLinear() const noexcept
double applyCorrection(const PixelSampleMapper &oldMapper, size_t oldLen, size_t newLen)
std::variant< LinearMapper, CustomMapper > mMapper
sampleCount GetLastSample(uint32_t column) const
sampleCount GetFirstSample(uint32_t column) const
void setCustomMapper(CustomMapper mapper)
std::function< sampleCount(uint32_t)> CustomMapper
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
decltype(auto) Visit(Visitor &&vis, Variant &&var)
Mimic some of std::visit, for the case of one visitor only.
Definition: Variant.h:138
sampleCount operator()(uint32_t column) const noexcept