Audacity 3.2.0
StretchingSequence.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 StretchingSequence.cpp
7
8 Matthieu Hodgkinson
9
10**********************************************************************/
11#include "StretchingSequence.h"
12#include "AudioSegment.h"
13#include "AudioSegmentFactory.h"
15
16#include <cassert>
17
18namespace
19{
21 float** offsetBuffer, float* const* buffer, size_t numChannels,
22 size_t offset)
23{
24 for (auto i = 0u; i < numChannels; ++i)
25 offsetBuffer[i] = buffer[i] + offset;
26}
27} // namespace
28
30 const PlayableSequence& sequence, int sampleRate, size_t numChannels,
31 std::unique_ptr<AudioSegmentFactoryInterface> factory)
32 : mSequence { sequence }
33 , mAudioSegmentFactory { std::move(factory) }
34{
35}
36
38{
40 mAudioSegmentFactory->CreateAudioSegmentSequence(t, direction);
42 mPlaybackDirection = direction;
44}
45
47 float* const buffers[], size_t numChannels, size_t numSamples)
48{
49 if (!mExpectedStart.has_value())
51 auto numProcessedSamples = 0u;
52 while (numProcessedSamples < numSamples &&
54 {
55 const auto& segment = *mActiveAudioSegmentIt;
56 // More-than-stereo isn't supported
57 assert(mSequence.NChannels() <= 2);
58 float* offsetBuffers[2] {};
60 offsetBuffers, buffers, mSequence.NChannels(), numProcessedSamples);
61 numProcessedSamples += segment->GetFloats(
62 offsetBuffers,
63 numSamples - numProcessedSamples); // No need to reverse, we feed the
64 // time-stretching algorithm with
65 // reversed samples already.
66 if (segment->Empty())
68 }
69 const auto remaining = numSamples - numProcessedSamples;
70 if (remaining > 0u)
71 {
72 // More-than-stereo isn't supported
73 assert(mSequence.NChannels() <= 2);
74 float* offsetBuffers[2] {};
76 offsetBuffers, buffers, mSequence.NChannels(), numProcessedSamples);
77 for (auto i = 0u; i < mSequence.NChannels(); ++i)
78 std::fill(offsetBuffers[i], offsetBuffers[i] + remaining, 0.f);
79 }
82 *mExpectedStart + numSamples :
83 *mExpectedStart - static_cast<sampleCount::type>(numSamples);
84 return true;
85}
86
88{
89 return mSequence.NChannels();
90}
91
92float StretchingSequence::GetChannelGain(int channel) const
93{
94 return mSequence.GetChannelGain(channel);
95}
96
98 size_t iChannel, size_t nBuffers, const samplePtr buffers[],
99 sampleFormat format, sampleCount start, size_t len, bool backwards,
100 fillFormat fill, bool mayThrow, sampleCount* pNumWithinClips) const
101{
102 return const_cast<StretchingSequence&>(*this).MutableGet(
103 iChannel, nBuffers, buffers, format, start, len, backwards);
104}
105
107{
109}
110
112{
113 return mSequence.GetSolo();
114}
115
117{
118 return mSequence.GetMute();
119}
120
122{
123 return mSequence.GetStartTime();
124}
125
127{
128 return mSequence.GetEndTime();
129}
130
132{
133 return mSequence.GetRate();
134}
135
137{
139}
140
142{
144}
145
147 double* buffer, size_t bufferLen, double t0, bool backwards) const
148{
149 mSequence.GetEnvelopeValues(buffer, bufferLen, t0, backwards);
150}
151
153{
154 return mSequence.GetChannelType();
155}
156
158 float* buffers[], sampleCount start, size_t len, bool backwards) const
159{
160 std::vector<samplePtr> charBuffers;
161 const auto nChannels = NChannels();
162 charBuffers.reserve(nChannels);
163 for (auto i = 0u; i < nChannels; ++i)
164 charBuffers.push_back(reinterpret_cast<samplePtr>(buffers[i]));
165 constexpr auto iChannel = 0u;
166 return DoGet(
167 iChannel, nChannels, charBuffers.data(), sampleFormat::floatSample, start,
168 len, backwards);
169}
170
172 size_t iChannel, size_t nBuffers, const samplePtr buffers[],
173 sampleFormat format, sampleCount start, size_t len, bool backwards)
174{
175 // StretchingSequence is not expected to be used for any other case.
176 assert(iChannel == 0u);
177 if (
178 !mExpectedStart.has_value() || *mExpectedStart != start ||
180 {
181 const auto t = start.as_double() / mSequence.GetRate();
183 t,
185 }
186 return GetNext(reinterpret_cast<float* const*>(buffers), nBuffers, len);
187}
188
189std::shared_ptr<StretchingSequence> StretchingSequence::Create(
190 const PlayableSequence& sequence, const ClipConstHolders& clips)
191{
192 const int sampleRate = sequence.GetRate();
193 return std::make_shared<StretchingSequence>(
194 sequence, sampleRate, sequence.NChannels(),
195 std::make_unique<AudioSegmentFactory>(
196 sampleRate, sequence.NChannels(), clips));
197}
std::vector< std::shared_ptr< const ClipInterface > > ClipConstHolders
static RegisteredToolbarFactory factory
PlaybackDirection
sampleFormat
The ordering of these values with operator < agrees with the order of increasing bit width.
Definition: SampleFormat.h:30
char * samplePtr
Definition: SampleFormat.h:57
enum FillFormat fillFormat
AudioSegments mAudioSegments
StretchingSequence(const PlayableSequence &, int sampleRate, size_t numChannels, std::unique_ptr< AudioSegmentFactoryInterface >)
const PlayableSequence & mSequence
AudioGraph::ChannelType GetChannelType() const override
Classify this channel.
void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0, bool backwards) const override
bool GetFloats(float *buffers[], sampleCount start, size_t len, bool backwards) const
const std::unique_ptr< AudioSegmentFactoryInterface > mAudioSegmentFactory
bool MutableGet(size_t iChannel, size_t nBuffers, const samplePtr buffers[], sampleFormat format, sampleCount start, size_t len, bool backwards)
double GetRate() const override
bool GetMute() const override
May vary asynchronously.
static std::shared_ptr< StretchingSequence > Create(const PlayableSequence &, const ClipConstHolders &clips)
size_t NChannels() const override
A constant property.
double GetStartTime() const override
float GetChannelGain(int channel) const override
const ChannelGroup * FindChannelGroup() const override
Find associated ChannelGroup if any.
PlaybackDirection mPlaybackDirection
bool GetNext(float *const buffers[], size_t numChannels, size_t numSamples)
bool DoGet(size_t iChannel, size_t nBuffers, const samplePtr buffers[], sampleFormat format, sampleCount start, size_t len, bool backwards, fillFormat fill=FillFormat::fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const override
std::optional< sampleCount > mExpectedStart
AudioSegments::const_iterator mActiveAudioSegmentIt
sampleFormat WidestEffectiveFormat() const override
bool GetSolo() const override
May vary asynchronously.
double GetEndTime() const override
bool HasTrivialEnvelope() const override
void ResetCursor(double t, PlaybackDirection)
virtual float GetChannelGain(int channel) const =0
sampleCount TimeToLongSamples(double t0) const
virtual bool HasTrivialEnvelope() const =0
virtual double GetStartTime() const =0
virtual void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0, bool backwards) const =0
virtual sampleFormat WidestEffectiveFormat() const =0
virtual double GetEndTime() const =0
virtual size_t NChannels() const =0
A constant property.
virtual double GetRate() const =0
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
long long type
Definition: SampleCount.h:21
double as_double() const
Definition: SampleCount.h:46
ChannelType
Mutually exclusive channel classifications.
void GetOffsetBuffer(float **offsetBuffer, float *const *buffer, size_t numChannels, size_t offset)
STL namespace.
virtual ChannelType GetChannelType() const =0
Classify this channel.
virtual const ChannelGroup * FindChannelGroup() const =0
Find associated ChannelGroup if any.
virtual bool GetSolo() const =0
May vary asynchronously.
virtual bool GetMute() const =0
May vary asynchronously.