Audacity 3.2.0
TimeAndPitchAudioReader.h
Go to the documentation of this file.
1#pragma once
2
3#include "BaseAudioReader.h"
4#include "Signals.h"
5#include "TimeAndPitch.h"
6
7namespace staffpad::audio
8{
9
10class TimeAndPitchAudioReader : public BaseAudioReader
11{
12public:
13 TimeAndPitchAudioReader(std::unique_ptr<BaseAudioReader> reader)
14 : _base_reader(std::move(reader))
15 , _sig(2, _block_size)
16 {
17 _time_and_pitch = std::make_unique<TimeAndPitch>(2); // 2 channels
18 _time_and_pitch->setup(4096, _block_size);
19 _initial_samples_to_discard = _time_and_pitch->getLatencySamples();
21 _looping ? 0 : _time_and_pitch->getLatencySamples();
22 }
23
25 {
26 }
27
28 AudioFormat getFormat() const override
29 {
30 return _base_reader->getFormat();
31 }
32
33 bool canSeek() const override
34 {
35 return _base_reader->canSeek();
36 }
37
39 bool setPosition(int64_t newSamplePosition) override
40 {
41 if (newSamplePosition != _base_reader->getPosition())
42 {
43 _base_reader->setPosition(
44 newSamplePosition); // todo: needs to move further into the past to
45 // make up latency
46 _initial_samples_to_discard = _time_and_pitch->getLatencySamples();
48 _looping ? 0 : _time_and_pitch->getLatencySamples();
49 _time_and_pitch->reset();
50 }
51 return canSeek();
52 }
53
54 int64_t getPosition() const override
55 {
56 return _base_reader->getPosition();
57 }
58
59 int64_t getNumOfSourceSamples() const override
60 {
61 return _base_reader->getNumOfSourceSamples();
62 }
63
64 int32_t read(Signal32& outputSignal) override
65 {
66 return _base_reader->read(outputSignal);
67 }
68
72 Signal32& outputSignal, double timeStretch = 1.0,
73 double pitchFactor = 1.0)
74 {
75 PPK_ASSERT(outputSignal.getNumOfChannels() == 2);
76
77 int num_samples = outputSignal.getNumOfDataPoints();
78 int p = 0;
79 bool end_of_file = false;
80 _time_and_pitch->setTimeStretchAndPitchFactor(timeStretch, pitchFactor);
81 while (num_samples > 0)
82 {
83 int num_samples_to_retrieve = std::min(num_samples, _block_size);
84 while (_time_and_pitch->getNumAvailableOutputSamples() <
85 num_samples_to_retrieve)
86 {
87 int feed_now =
88 std::min(_time_and_pitch->getSamplesToNextHop(), _block_size);
89 _sig.ensureDimensions(2, feed_now);
91 _time_and_pitch->feedAudio(_sig.getReadPointer(), samples_read);
92 if (samples_read < feed_now)
93 {
94 if (_looping)
95 {
96 _base_reader->setPosition(0);
97 }
98 else
99 {
100 end_of_file = true;
101 break;
102 }
103 }
104 }
105
106 if (int n = int(_initial_samples_to_discard * timeStretch + 0.5f);
107 n > 0)
108 {
109 n = std::min({ n, _time_and_pitch->getNumAvailableOutputSamples(),
110 outputSignal.getNumOfDataPoints(), _block_size });
111 // dump to the beginning of the block to be overwritten be real data
112 // later
113 float* dmp[2] = { outputSignal.getWriteChannelPtr(0),
114 outputSignal.getWriteChannelPtr(1) };
115 _time_and_pitch->retrieveAudio(dmp, n);
116 _initial_samples_to_discard -= int(n / timeStretch + 0.5f);
117 }
118 else
119 {
121 0; // can still be 1 or 2 for extreme factors due to rounding
122 float* smp[2] = { outputSignal.getWriteChannelPtr(0) + p,
123 outputSignal.getWriteChannelPtr(1) + p };
124
125 int num_samples_retrieved = std::min(
126 num_samples_to_retrieve,
127 _time_and_pitch->getNumAvailableOutputSamples());
128 _time_and_pitch->retrieveAudio(smp, num_samples_retrieved);
129
130 p += num_samples_retrieved;
131 num_samples -= num_samples_retrieved;
132 }
133 if (end_of_file)
134 break;
135 }
136 return p;
137 }
138
139 void setQuality(const TimeAndPitch::QualitySettings& settings)
140 {
141 _time_and_pitch->setQuality(settings);
142 }
143
144 void setLooping(bool flag)
145 {
146 _looping = flag;
148 _looping ? 0 : _time_and_pitch->getLatencySamples();
149 }
150
151private:
155 {
156 int n = _base_reader->read(_sig);
157 if (n < sig.getNumOfDataPoints())
158 {
159 int silent_n =
160 std::min(sig.getNumOfDataPoints() - n, _silent_samples_to_append);
161 sig.setToValue(0.f, n, n + silent_n, -1);
162 _silent_samples_to_append -= silent_n;
163 return n + silent_n;
164 }
165 return n;
166 }
167
168 static constexpr int _block_size = 512;
169 std::unique_ptr<BaseAudioReader> _base_reader;
170 Signal32 _sig;
171 std::unique_ptr<TimeAndPitch> _time_and_pitch;
174 bool _looping = false;
175};
176
177typedef std::shared_ptr<TimeAndPitchAudioReader> SharedTimeAndPitchAudioReader;
178
179} // namespace staffpad::audio
int min(int a, int b)
static Settings & settings()
Definition: TrackInfo.cpp:83
static std::once_flag flag
std::unique_ptr< TimeAndPitch > _time_and_pitch
int32_t read(Signal32 &outputSignal) override
int32_t _read_from_base_reader_append_silence(Signal32 &sig)
TimeAndPitchAudioReader(std::unique_ptr< BaseAudioReader > reader)
int32_t readTimeAndPitch(Signal32 &outputSignal, double timeStretch=1.0, double pitchFactor=1.0)
bool setPosition(int64_t newSamplePosition) override
set the position based on input samples
void setQuality(const TimeAndPitch::QualitySettings &settings)
std::unique_ptr< BaseAudioReader > _base_reader
std::shared_ptr< TimeAndPitchAudioReader > SharedTimeAndPitchAudioReader
STL namespace.