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
93{
94 return mSequence.GetChannelVolume(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
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.
float GetChannelVolume(int channel) const override
double GetEndTime() const override
bool HasTrivialEnvelope() const override
void ResetCursor(double t, PlaybackDirection)
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 float GetChannelVolume(int channel) 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.