11#if JUCE_WINDOWS && TRACKTION_ENABLE_TIMESTRETCH_ELASTIQUE
12 #pragma comment (lib, "libelastiquePro.lib")
13 #pragma comment (lib, "libelastiqueEfficient.lib")
14 #pragma comment (lib, "libelastiqueSOLOIST.lib")
15 #pragma comment (lib, "libResample.lib")
16 #pragma comment (lib, "libzplVecLib.lib")
19#if JUCE_WINDOWS && TRACKTION_ENABLE_TIMESTRETCH_ELASTIQUE_IPP
20 #pragma comment (lib, "ippcore_l.lib")
21 #pragma comment (lib, "ipps_l.lib")
22 #pragma comment (lib, "ippvm_l.lib")
29namespace tracktion {
inline namespace engine
37 if (
string.startsWith (
"1/"))
42 if (tokens.
size() == 5)
59 midSideStereo ? 1 : 0,
60 syncTimeStrPitchShft ? 1 : 0,
61 preserveFormants ? 1 : 0,
75 return ! operator== (other);
83 virtual bool isOk()
const = 0;
84 virtual void reset() = 0;
85 virtual bool setSpeedAndPitch (
float speedRatio,
float semitonesUp) = 0;
86 virtual int getFramesNeeded()
const = 0;
87 virtual int getMaxFramesNeeded()
const = 0;
88 virtual int processData (
const float*
const* inChannels,
int numSamples,
float*
const* outChannels) = 0;
89 virtual int flush (
float*
const* outChannels) = 0;
93#if TRACKTION_ENABLE_TIMESTRETCH_ELASTIQUE
97 ElastiqueStretcher (
double sourceSampleRate,
int samplesPerBlock,
int numChannels,
99 : elastiqueMode (mode),
100 elastiqueProOptions (options),
101 samplesPerOutputBuffer (samplesPerBlock)
104 jassert (sourceSampleRate > 0.0);
105 int res = CElastiqueProV3If::CreateInstance (elastique, samplesPerBlock, numChannels, (
float) sourceSampleRate,
106 getElastiqueMode (mode), minFactor);
109 if (elastique ==
nullptr)
112 TRACKTION_LOG_ERROR (
"Cannot create Elastique");
118 maxFramesNeeded = elastique->GetMaxFramesNeeded();
120 if (mode == TimeStretcher::elastiquePro)
121 elastique->SetStereoInputMode (elastiqueProOptions.midSideStereo ? CElastiqueProV3If::kMSMode : CElastiqueProV3If::kPlainStereoMode);
125 ~ElastiqueStretcher()
override
127 if (elastique !=
nullptr)
128 CElastiqueProV3If::DestroyInstance (elastique);
131 bool isOk()
const override {
return elastique !=
nullptr; }
132 void reset()
override { elastique->Reset(); }
134 bool setSpeedAndPitch (
float speedRatio,
float semitonesUp)
override
136 float pitch =
juce::jlimit (0.25f, 4.0f, Pitch::semitonesToRatio (semitonesUp));
137 bool sync = (elastiqueMode == TimeStretcher::elastiquePro) ? elastiqueProOptions.syncTimeStrPitchShft : false;
138 int r = elastique->SetStretchPitchQFactor (speedRatio, pitch, sync);
141 if (elastiqueMode == TimeStretcher::elastiquePro && elastiqueProOptions.preserveFormants)
143 elastique->SetEnvelopeFactor (pitch);
144 elastique->SetEnvelopeOrder (elastiqueProOptions.envelopeOrder);
150 int getFramesNeeded()
const override
152 const int framesNeeded = elastique->GetFramesNeeded();
153 jassert (framesNeeded <= maxFramesNeeded);
157 int getMaxFramesNeeded()
const override
159 return maxFramesNeeded;
162 int processData (
const float*
const* inChannels,
int numSamples,
float*
const* outChannels)
override
165 int err = elastique->ProcessData ((
float**) inChannels, numSamples, (
float**) outChannels);
167 return samplesPerOutputBuffer;
170 int flush (
float*
const* outChannels)
override
172 return elastique->FlushBuffer ((
float**) outChannels);
176 CElastiqueProV3If* elastique =
nullptr;
177 TimeStretcher::Mode elastiqueMode;
178 TimeStretcher::ElastiqueProOptions elastiqueProOptions;
179 const int samplesPerOutputBuffer;
182 static CElastiqueProV3If::ElastiqueMode_t getElastiqueMode (TimeStretcher::Mode mode)
186 case TimeStretcher::elastiquePro:
return CElastiqueProV3If::kV3Pro;
187 case TimeStretcher::elastiqueEfficient:
return CElastiqueProV3If::kV3Eff;
188 case TimeStretcher::elastiqueMobile:
return CElastiqueProV3If::kV3mobile;
189 case TimeStretcher::elastiqueMonophonic:
return CElastiqueProV3If::kV3Monophonic;
190 case TimeStretcher::elastiqueDirectPro: [[ fallthrough ]];
191 case TimeStretcher::elastiqueDirectEfficient: [[ fallthrough ]];
192 case TimeStretcher::elastiqueDirectMobile: [[ fallthrough ]];
193 case TimeStretcher::disabled: [[ fallthrough ]];
194 case TimeStretcher::elastiqueTransient: [[ fallthrough ]];
195 case TimeStretcher::elastiqueTonal: [[ fallthrough ]];
196 case TimeStretcher::soundtouchNormal: [[ fallthrough ]];
197 case TimeStretcher::soundtouchBetter: [[ fallthrough ]];
198 case TimeStretcher::melodyne: [[ fallthrough ]];
199 case TimeStretcher::rubberbandMelodic: [[ fallthrough ]];
200 case TimeStretcher::rubberbandPercussive: [[ fallthrough ]];
203 return CElastiqueProV3If::kV3Pro;
211struct ElastiqueDirectStretcher :
public TimeStretcher::Stretcher
213 ElastiqueDirectStretcher (
double sourceSampleRate,
int samplesPerBlock,
int numChannels_,
214 TimeStretcher::Mode mode, TimeStretcher::ElastiqueProOptions options,
float minFactor)
215 : elastiqueMode (mode),
216 elastiqueProOptions (options),
217 samplesPerOutputBuffer (samplesPerBlock),
218 numChannels (numChannels_),
219 outputFifo (numChannels, samplesPerBlock)
222 jassert (sourceSampleRate > 0.0);
223 [[maybe_unused]]
int res = CElastiqueProV3DirectIf::CreateInstance (elastique, numChannels, (
float) sourceSampleRate,
224 getElastiqueMode (mode), minFactor);
227 if (elastique ==
nullptr)
230 TRACKTION_LOG_ERROR (
"Cannot create Elastique Direct");
236 maxFramesNeeded = elastique->GetMaxFramesNeeded();
237 outputFifo.setSize (numChannels, maxFramesNeeded * 2);
239 if (mode == TimeStretcher::elastiquePro)
240 elastique->SetStereoInputMode (elastiqueProOptions.midSideStereo ? CElastiqueProV3DirectIf::kMSMode
241 : CElastiqueProV3DirectIf::kPlainStereoMode);
245 ~ElastiqueDirectStretcher()
override
247 if (elastique !=
nullptr)
248 CElastiqueProV3DirectIf::DestroyInstance (elastique);
251 bool isOk()
const override
253 return elastique !=
nullptr;
256 void reset()
override
262 newSpeedAndPitchPending =
true;
265 bool setSpeedAndPitch (
float speedRatio,
float semitonesUp)
override
267 newSpeedRatio = speedRatio;
268 newSemitonesUp = semitonesUp;
269 newSpeedAndPitchPending =
true;
270 tryToSetNewSpeedAndPitch();
275 int getFramesNeeded()
const override
277 tryToSetNewSpeedAndPitch();
279 if (outputFifo.getNumReady() > samplesPerOutputBuffer)
282 const int framesNeeded = hasBeenReset ? elastique->GetPreFramesNeeded()
283 : elastique->GetFramesNeeded();
284 jassert (framesNeeded <= maxFramesNeeded);
289 int getMaxFramesNeeded()
const override
291 return maxFramesNeeded;
294 int processData (
const float*
const* inChannels,
int numSamples,
float*
const* outChannels)
override
297 using namespace choc::buffer;
301 const auto numFrames =
static_cast<FrameCount
> (numSamples);
302 const auto inputView = createChannelArrayView (inChannels,
303 static_cast<ChannelCount
> (numChannels),
308 assert (numFrames ==
static_cast<FrameCount
> (elastique->GetPreFramesNeeded()));
309 processPreFrames (inputView);
313 assert (numSamples == elastique->GetFramesNeeded());
314 processFrames (inputView);
320 assert (outputFifo.getNumReady() >= samplesPerOutputBuffer);
324 if (
const int numReady = outputFifo.getNumReady(); numReady > 0)
326 const int numToReturn =
std::min (numReady, samplesPerOutputBuffer);
329 if (! outputFifo.read (outputView, 0))
335 return outputView.getNumSamples();
342 int flush (
float*
const* outChannels)
override
345 AudioScratchBuffer scratchBuffer (numChannels, maxFramesNeeded);
346 const int numFramesReturned = elastique->FlushBuffer ((
float **) scratchBuffer.buffer.getArrayOfWritePointers());
347 assert (numFramesReturned <= scratchBuffer.buffer.getNumSamples());
348 assert (outputFifo.getFreeSpace() >= numFramesReturned);
349 outputFifo.write (scratchBuffer.buffer, 0, numFramesReturned);
353 if (
const int numReady = outputFifo.getNumReady(); numReady > 0)
355 const int numToReturn =
std::min (numReady, samplesPerOutputBuffer);
357 [[maybe_unused]]
const bool success = outputFifo.read (outputView, 0);
360 return outputView.getNumSamples();
367 CElastiqueProV3DirectIf* elastique =
nullptr;
368 TimeStretcher::Mode elastiqueMode;
369 TimeStretcher::ElastiqueProOptions elastiqueProOptions;
370 const int samplesPerOutputBuffer, numChannels;
371 int maxFramesNeeded = 0;
372 AudioFifo outputFifo;
373 bool hasBeenReset =
true;
374 float newSpeedRatio, newSemitonesUp;
375 mutable bool newSpeedAndPitchPending =
false;
377 static CElastiqueProV3DirectIf::ElastiqueVersion_t getElastiqueMode (TimeStretcher::Mode mode)
381 case TimeStretcher::elastiqueDirectPro:
return CElastiqueProV3DirectIf::kV3Pro;
382 case TimeStretcher::elastiqueDirectEfficient:
return CElastiqueProV3DirectIf::kV3Eff;
383 case TimeStretcher::elastiqueDirectMobile:
return CElastiqueProV3DirectIf::kV3mobile;
384 case TimeStretcher::elastiquePro: [[ fallthrough ]];
385 case TimeStretcher::elastiqueEfficient: [[ fallthrough ]];
386 case TimeStretcher::elastiqueMobile: [[ fallthrough ]];
387 case TimeStretcher::elastiqueMonophonic: [[ fallthrough ]];
388 case TimeStretcher::disabled: [[ fallthrough ]];
389 case TimeStretcher::elastiqueTransient: [[ fallthrough ]];
390 case TimeStretcher::elastiqueTonal: [[ fallthrough ]];
391 case TimeStretcher::soundtouchNormal: [[ fallthrough ]];
392 case TimeStretcher::soundtouchBetter: [[ fallthrough ]];
393 case TimeStretcher::melodyne: [[ fallthrough ]];
394 case TimeStretcher::rubberbandMelodic: [[ fallthrough ]];
395 case TimeStretcher::rubberbandPercussive: [[ fallthrough ]];
398 return CElastiqueProV3DirectIf::kV3Pro;
402 void tryToSetNewSpeedAndPitch()
const
404 if (! newSpeedAndPitchPending)
407 float pitch =
juce::jlimit (0.25f, 4.0f, Pitch::semitonesToRatio (newSemitonesUp));
408 const bool sync = elastiqueMode == TimeStretcher::elastiqueDirectPro ? elastiqueProOptions.syncTimeStrPitchShft :
false;
409 const int res = elastique->SetStretchPitchQFactor (newSpeedRatio, pitch, sync);
410 newSpeedAndPitchPending = res != 0;
412 if (elastiqueMode == TimeStretcher::elastiqueDirectPro && elastiqueProOptions.preserveFormants)
414 elastique->SetEnvelopeFactor (pitch);
415 elastique->SetEnvelopeOrder (elastiqueProOptions.envelopeOrder);
419 int processPreFrames (
const choc::buffer::ChannelArrayView<const float>& inFrames)
421 const int numInputFrames =
static_cast<int> (inFrames.size.numFrames);
422 assert (numInputFrames == elastique->GetPreFramesNeeded());
424 AudioScratchBuffer scratchBuffer (numChannels, maxFramesNeeded);
425 const int numPreProcessFrames = elastique->PreProcessData ((
float **) inFrames.data.channels, numInputFrames,
426 (
float **) scratchBuffer.buffer.getArrayOfWritePointers(),
427 samplesPerOutputBuffer >= 512 ? CElastiqueProV3DirectIf::kFastStartup
428 : CElastiqueProV3DirectIf::kNormalStartup);
430 assert (numPreProcessFrames <= scratchBuffer.buffer.getNumSamples());
431 assert (outputFifo.getFreeSpace() >= numPreProcessFrames);
432 outputFifo.write (scratchBuffer.buffer, 0, numPreProcessFrames);
434 return numPreProcessFrames;
437 int processFrames (
const choc::buffer::ChannelArrayView<const float>& inFrames)
439 const int numInputFrames =
static_cast<int> (inFrames.size.numFrames);
441 if (numInputFrames == 0)
445 assert (numInputFrames == elastique->GetFramesNeeded());
446 [[maybe_unused]]
const int err = elastique->ProcessData ((
float **) inFrames.data.channels, numInputFrames);
450 for (
int numProcessCalls = elastique->GetNumOfProcessCalls(); --numProcessCalls >= 0;)
452 [[maybe_unused]]
const int err = elastique->ProcessData();
457 const int numFramesProcessed = elastique->GetFramesProcessed();
458 AudioScratchBuffer scratchBuffer (numChannels, numFramesProcessed);
459 const int numFramesReturned = elastique->GetProcessedData ((
float **) scratchBuffer.buffer.getArrayOfWritePointers());
460 assert (numFramesProcessed == numFramesReturned);
461 assert (numFramesReturned <= scratchBuffer.buffer.getNumSamples());
462 assert (outputFifo.getFreeSpace() >= numFramesReturned);
463 outputFifo.write (scratchBuffer.buffer, 0, numFramesReturned);
465 return numFramesReturned;
475#if TRACKTION_ENABLE_TIMESTRETCH_SOUNDTOUCH
477#include "soundtouch/include/SoundTouch.h"
479struct SoundTouchStretcher :
public TimeStretcher::Stretcher,
480 private soundtouch::SoundTouch
482 SoundTouchStretcher (
double sourceSampleRate,
int samplesPerBlock,
483 int chans,
bool betterQuality)
484 : numChannels (chans), samplesPerOutputBuffer (samplesPerBlock)
487 setChannels (
static_cast<unsigned int> (numChannels));
488 setSampleRate (
static_cast<unsigned int> (sourceSampleRate));
492 setSetting (SETTING_USE_AA_FILTER, 1);
493 setSetting (SETTING_AA_FILTER_LENGTH, 64);
494 setSetting (SETTING_USE_QUICKSEEK, 0);
495 setSetting (SETTING_SEQUENCE_MS, 60);
496 setSetting (SETTING_SEEKWINDOW_MS, 25);
500 bool isOk()
const override {
return true; }
501 void reset()
override { clear(); }
503 bool setSpeedAndPitch (
float speedRatio,
float semitonesUp)
override
505 setTempo (1.0f / speedRatio);
506 setPitchSemiTones (semitonesUp);
507 inputOutputSampleRatio = getInputOutputSampleRatio();
512 int getFramesNeeded()
const override
514 const int numAvailable = (
int) numSamples();
515 const int numRequiredForOneBlock =
juce::roundToInt (samplesPerOutputBuffer * inputOutputSampleRatio);
517 return std::max (0, numRequiredForOneBlock - numAvailable);
520 int getMaxFramesNeeded()
const override
526 int processData (
const float*
const* inChannels,
int numSamples,
float*
const* outChannels)
override
529 jassert (numSamples <= getFramesNeeded());
530 writeInput (inChannels, numSamples);
532 const int numAvailable = (
int) soundtouch::SoundTouch::numSamples();
535 const int numToRead =
std::min (numAvailable, samplesPerOutputBuffer);
538 return readOutput (outChannels, 0, numToRead);
543 int flush (
float*
const* outChannels)
override
546 if (! hasDoneFinalBlock)
548 soundtouch::SoundTouch::flush();
549 hasDoneFinalBlock =
true;
552 const int numAvailable = (
int) numSamples();
553 const int numToRead =
std::min (numAvailable, samplesPerOutputBuffer);
555 return readOutput (outChannels, 0, numToRead);
559 int numChannels = 0, samplesPerOutputBuffer = 0;
560 bool hasDoneFinalBlock =
false;
561 double inputOutputSampleRatio = 1.0;
563 int readOutput (
float*
const* outChannels,
int offset,
int numNeeded)
565 float* interleaved = ptrBegin();
566 auto num =
std::min (numNeeded, (
int) numSamples());
568 for (
int chan = 0; chan < numChannels; ++chan)
570 const float* src = interleaved + chan;
571 float* dest = outChannels[chan] + offset;
573 for (
int i = 0; i < num; ++i)
580 receiveSamples (
static_cast<unsigned int> (num));
584 void writeInput (
const float*
const* inChannels,
int numSamples)
588 AudioScratchBuffer scratch (1, numSamples * numChannels);
589 float* interleaved = scratch.buffer.getWritePointer(0);
591 for (
int chan = 0; chan < numChannels; ++chan)
593 float* dest = interleaved + chan;
594 const float* src = inChannels[chan];
596 for (
int i = 0; i < numSamples; ++i)
603 putSamples (interleaved,
static_cast<unsigned int> (numSamples));
607 putSamples (inChannels[0],
static_cast<unsigned int> (numSamples));
616#if TRACKTION_ENABLE_TIMESTRETCH_RUBBERBAND
619 #pragma GCC diagnostic push
620 #pragma GCC diagnostic ignored "-Wsign-conversion"
621 #pragma GCC diagnostic ignored "-Wconversion"
622 #pragma GCC diagnostic ignored "-Wextra-semi"
623 #pragma GCC diagnostic ignored "-Wshadow"
624 #pragma GCC diagnostic ignored "-Wsign-compare"
625 #pragma GCC diagnostic ignored "-Wcast-align"
627 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
629 #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
630 #pragma GCC diagnostic ignored "-Wunused-variable"
631 #pragma GCC diagnostic ignored "-Wunused-parameter"
632 #pragma GCC diagnostic ignored "-Wpedantic"
633 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
634 #pragma GCC diagnostic ignored "-Wswitch-enum"
635 #pragma GCC diagnostic ignored "-Wdeprecated-copy-with-user-provided-dtor"
636 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
639#define WIN32_LEAN_AND_MEAN 1
640#define Point CarbonDummyPointName
641#define Component CarbonDummyCompName
644#if TRACKTION_BUILD_RUBBERBAND
645 #if __has_include(<rubberband/single/RubberBandSingle.cpp>)
646 #include <rubberband/single/RubberBandSingle.cpp>
647 #elif __has_include("../3rd_party/rubberband/single/RubberBandSingle.cpp")
648 #include "../3rd_party/rubberband/single/RubberBandSingle.cpp"
650 #error "TRACKTION_BUILD_RUBBERBAND enabled but not found in the search path!"
653 #if __has_include(<rubberband/rubberband/RubberBandStretcher.h>)
654 #include <rubberband/rubberband/RubberBandStretcher.h>
655 #elif __has_include("../3rd_party/rubberband/rubberband/RubberBandStretcher.h")
656 #include "../3rd_party/rubberband/rubberband/RubberBandStretcher.h"
658 #error "TRACKTION_ENABLE_TIMESTRETCH_RUBBERBAND enabled but not found in the search path!"
661namespace tracktion {
inline namespace engine {
663#undef WIN32_LEAN_AND_MEAN
668 #pragma GCC diagnostic pop
671struct RubberBandStretcher :
public TimeStretcher::Stretcher
673 static int getOptionFlags (
bool percussive)
676 return RubberBand::RubberBandStretcher::OptionProcessRealTime
677 | RubberBand::RubberBandStretcher::OptionPitchHighConsistency
678 | RubberBand::RubberBandStretcher::PercussiveOptions;
680 return RubberBand::RubberBandStretcher::OptionProcessRealTime
681 | RubberBand::RubberBandStretcher::OptionPitchHighConsistency
682 | RubberBand::RubberBandStretcher::OptionWindowShort;
685 RubberBandStretcher (
double sourceSampleRate,
int samplesPerBlock,
int numChannels,
bool percussive)
686 : rubberBandStretcher ((
size_t) sourceSampleRate, (
size_t) numChannels,
687 getOptionFlags (percussive)),
688 samplesPerOutputBuffer (samplesPerBlock)
692 bool isOk()
const override
697 void reset()
override
699 rubberBandStretcher.reset();
702 bool setSpeedAndPitch (
float speedRatio,
float semitonesUp)
override
704 const float pitch =
juce::jlimit (0.25f, 4.0f, tracktion::engine::Pitch::semitonesToRatio (semitonesUp));
706 rubberBandStretcher.setPitchScale (pitch);
707 rubberBandStretcher.setTimeRatio (speedRatio);
709 if (numSamplesToDrop == -1)
712 numSamplesToDrop =
int (rubberBandStretcher.getLatency());
715 if (numSamplesToPad > 0)
717 AudioScratchBuffer scratch (
int (rubberBandStretcher.getChannelCount()), samplesPerOutputBuffer);
718 scratch.buffer.clear();
720 while (numSamplesToPad > 0)
722 const int numThisTime =
std::min (numSamplesToPad, samplesPerOutputBuffer);
723 rubberBandStretcher.process (scratch.buffer.getArrayOfReadPointers(), numThisTime,
false);
724 numSamplesToPad -= numThisTime;
728 jassert (numSamplesToPad == 0);
731 const bool r = rubberBandStretcher.getPitchScale() == pitch
732 && rubberBandStretcher.getTimeRatio() == speedRatio;
739 int getFramesNeeded()
const override
741 return (
int) rubberBandStretcher.getSamplesRequired();
744 int getMaxFramesNeeded()
const override
746 return maxFramesNeeded;
749 int processData (
const float*
const* inChannels,
int numSamples,
float*
const* outChannels)
override
751 jassert (numSamples <= getFramesNeeded());
752 rubberBandStretcher.process (inChannels, (
size_t) numSamples,
false);
755 int numAvailable = rubberBandStretcher.available();
758 if (numSamplesToDrop > 0)
760 auto numToDropThisTime =
std::min (numSamplesToDrop,
std::min (numAvailable, samplesPerOutputBuffer));
761 rubberBandStretcher.retrieve (outChannels, (
size_t) numToDropThisTime);
762 numSamplesToDrop -= numToDropThisTime;
763 jassert (numSamplesToDrop >= 0);
765 numAvailable -= numToDropThisTime;
768 if (numAvailable > 0)
769 return (
int) rubberBandStretcher.retrieve (outChannels, (
size_t) numAvailable);
774 int flush (
float*
const* outChannels)
override
777 if (! hasDoneFinalBlock)
779 float* inChannels[32] = {
nullptr };
780 rubberBandStretcher.process (inChannels, 0,
true);
781 hasDoneFinalBlock =
true;
785 const int numAvailable = rubberBandStretcher.available();
786 const int numThisBlock =
std::min (numAvailable, samplesPerOutputBuffer);
788 if (numThisBlock > 0)
789 return (
int) rubberBandStretcher.retrieve (outChannels, (
size_t) numThisBlock);
795 RubberBand::RubberBandStretcher rubberBandStretcher;
796 const int maxFramesNeeded = 8192;
797 const int samplesPerOutputBuffer = 0;
798 int numSamplesToDrop = -1;
799 bool hasDoneFinalBlock =
false;
811static juce::String getElastiquePro() {
return "Elastique (" +
TRANS(
"Pro") +
")"; }
812static juce::String getElastiqueEfficeint() {
return "Elastique (" +
TRANS(
"Efficient") +
")"; }
813static juce::String getElastiqueMobile() {
return "Elastique (" +
TRANS(
"Mobile") +
")"; }
814static juce::String getElastiqueMono() {
return "Elastique (" +
TRANS(
"Monophonic") +
")"; }
815static juce::String getSoundTouchNormal() {
return "SoundTouch (" +
TRANS(
"Normal") +
")"; }
816static juce::String getSoundTouchBetter() {
return "SoundTouch (" +
TRANS(
"Better") +
")"; }
817static juce::String getRubberBandMelodic() {
return "RubberBand (" +
TRANS(
"Melodic") +
")"; }
818static juce::String getRubberBandPercussive() {
return "RubberBand (" +
TRANS(
"Percussive") +
")"; }
819static juce::String getElastiqueDirectPro() {
return "Elastique Direct (" +
TRANS(
"Pro") +
")"; }
820static juce::String getElastiqueDirectEfficeint() {
return "Elastique Direct (" +
TRANS(
"Efficient") +
")"; }
821static juce::String getElastiqueDirectMobile() {
return "Elastique Direct (" +
TRANS(
"Mobile") +
")"; }
829 #if ! TRACKTION_ENABLE_TIMESTRETCH_SOUNDTOUCH
833 #if ! TRACKTION_ENABLE_TIMESTRETCH_ELASTIQUE
842 #if ! TRACKTION_ENABLE_TIMESTRETCH_RUBBERBAND
847 #if TRACKTION_ENABLE_TIMESTRETCH_SOUNDTOUCH
852 #if TRACKTION_ENABLE_TIMESTRETCH_ELASTIQUE
862 #if TRACKTION_ENABLE_TIMESTRETCH_RUBBERBAND
878 #if TRACKTION_ENABLE_TIMESTRETCH_ELASTIQUE
879 s.
add (getElastiquePro());
880 s.
add (getElastiqueEfficeint());
881 s.
add (getElastiqueMobile());
882 s.
add (getElastiqueMono());
883 s.
add (getElastiqueDirectPro());
884 s.
add (getElastiqueDirectEfficeint());
885 s.
add (getElastiqueDirectMobile());
888 #if TRACKTION_ENABLE_TIMESTRETCH_SOUNDTOUCH
889 s.
add (getSoundTouchNormal());
890 s.
add (getSoundTouchBetter());
893 #if TRACKTION_ENABLE_TIMESTRETCH_RUBBERBAND
894 s.
add (getRubberBandMelodic());
895 s.
add (getRubberBandPercussive());
898 #if TRACKTION_ENABLE_ARA
899 if (! excludeMelodyne && e.
getPluginManager().getARACompatiblePlugDescriptions().size() > 0)
900 s.
add (getMelodyne());
910 #if TRACKTION_ENABLE_TIMESTRETCH_ELASTIQUE
920 #if TRACKTION_ENABLE_TIMESTRETCH_RUBBERBAND
925 #if TRACKTION_ENABLE_TIMESTRETCH_SOUNDTOUCH
930 #if TRACKTION_ENABLE_ARA
931 if (name == getMelodyne())
return melodyne;
953 case melodyne:
return getMelodyne();
965 #if TRACKTION_ENABLE_ARA
975 return stretcher !=
nullptr;
984 samplesPerBlockRequested = samplesPerBlock;
987 jassert (stretcher ==
nullptr);
989 #if TRACKTION_ENABLE_TIMESTRETCH_ELASTIQUE || TRACKTION_ENABLE_TIMESTRETCH_RUBBERBAND || TRACKTION_ENABLE_TIMESTRETCH_SOUNDTOUCH
992 #if TRACKTION_ENABLE_TIMESTRETCH_ELASTIQUE
998 mode, options, realtime ? 0.25f : 0.1f);
1004 mode, options, realtime ? 0.25f : 0.1f);
1017 #if TRACKTION_ENABLE_TIMESTRETCH_SOUNDTOUCH
1030 #if TRACKTION_ENABLE_TIMESTRETCH_RUBBERBAND
1052 if (stretcher !=
nullptr)
1053 if (! stretcher->isOk())
1064 if (stretcher !=
nullptr)
1070 if (stretcher !=
nullptr)
1071 return stretcher->setSpeedAndPitch (speedRatio, semitonesUp);
1078 if (stretcher !=
nullptr)
1079 return stretcher->getFramesNeeded();
1086 if (stretcher !=
nullptr)
1087 return stretcher->getMaxFramesNeeded();
1094 if (stretcher !=
nullptr)
1095 return stretcher->processData (inChannels, numSamples, outChannels);
1102 if (stretcher ==
nullptr)
1105 jassert (numSamples == stretcher->getFramesNeeded());
1112 inFifo.read (inBuffer.
buffer, 0, numSamples);
1113 const int numOutputFrames = stretcher->processData (inChannels, numSamples, outChannels);
1114 outFifo.write (outBuffer.
buffer, 0, numOutputFrames);
1116 return numOutputFrames;
1121 if (stretcher !=
nullptr)
1122 return stretcher->flush (outChannels);
const Type *const * getArrayOfReadPointers() const noexcept
Type *const * getArrayOfWritePointers() noexcept
bool contains(StringRef stringToLookFor, bool ignoreCase=false) const
int size() const noexcept
void add(String stringToAdd)
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
static String formatted(const String &formatStr, Args... args)
An audio scratch buffer that has pooled storage.
juce::AudioBuffer< float > & buffer
The buffer to use.
The Engine is the central class for all tracktion sessions.
PluginManager & getPluginManager() const
Returns the PluginManager instance.
void initialise(double sourceSampleRate, int samplesPerBlock, int numChannels, Mode, ElastiqueProOptions, bool realtime)
Initialises the TimeStretcher ready to perform timestretching.
int getFramesNeeded() const
Returns the expected number of frames required to generate some output.
bool isInitialised() const
Returns true if this has been fully initialised.
void reset()
Resets the TimeStretcher ready for a new set of audio data, maintains mode, speed and pitch ratios.
static bool isMelodyne(Mode)
Returns true if the given Mode is a Melodyne mode.
static bool canProcessFor(Mode)
Checks that the given Mode is a valid mode and not disabled.
static juce::String getNameOfMode(Mode)
Returns the name of a given Mode for display purposes.
int getMaxFramesNeeded() const
Returns the maximum number of frames that will ever be returned by getFramesNeeded.
int processData(const float *const *inChannels, int numSamples, float *const *outChannels)
Processes some input frames and fills some output frames with the applied speed ratio and pitch shift...
static Mode getModeFromName(Engine &, const juce::String &name)
Returns the Mode for a given name.
int flush(float *const *outChannels)
Flushes the end of the stream when input data is exhausted but there is still output data available.
TimeStretcher()
Creates an TimeStretcher using the default mode.
static Mode checkModeIsAvailable(Mode)
Checks if the given mode is available for use.
bool setSpeedAndPitch(float speedRatio, float semitones)
Sets the timestretch speed ratio and semitones pitch shift.
~TimeStretcher()
Destructor.
Mode
Holds the various algorithms to which can be used (if enabled).
@ elastiqueTonal
Defunct, don't use.
@ elastiqueDirectPro
Elastique Direct Pro good all round (.
@ rubberbandMelodic
RubberBand tailored to melodic sounds prioritising pitch accuracy.
@ soundtouchNormal
SoundTouch normal quality, lower CPU use.
@ elastiquePro
Elastique Pro good all round (.
@ defaultMode
Default mode.
@ disabled
No algorithm enabled.
@ elastiqueMonophonic
Elastique which can sound better for monophonic sounds.
@ elastiqueDirectEfficient
Elastique Direct lower quality and lower CPU usage.
@ elastiqueDirectMobile
Elastique Direct lower quality and lower CPU usage, optimised for mobile.
@ rubberbandPercussive
RubberBand tailored to percussive sounds prioritising transient accuracy.
@ melodyne
Melodyne, only used for clip timestretching.
@ elastiqueEfficient
Elastique lower quality and lower CPU usage.
@ elastiqueTransient
Defunct, don't use.
@ elastiqueMobile
Elastique lower quality and lower CPU usage, optimised for mobile.
@ soundtouchBetter
SoundTouch better quality, higher CPU use.
static juce::StringArray getPossibleModes(Engine &, bool excludeMelodyne)
Returns the names of the availabel Modes.
#define TRANS(stringLiteral)
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
void ignoreUnused(Types &&...) noexcept
int roundToInt(const FloatType value) noexcept
A set of options that can be used in conjunction with the elastiquePro Mode to fine tune the algorith...
int envelopeOrder
Sets a spectral envelope shift factor.
bool operator!=(const ElastiqueProOptions &) const
Compare these options with another set.
bool preserveFormants
Preserve formats.
juce::String toString() const
Save the current options as a string.
bool midSideStereo
Optomise algorthim for mid/side channel layouts.
bool operator==(const ElastiqueProOptions &) const
Compare these options with another set.
bool syncTimeStrPitchShft
Synchronises timestretch and pitchshifting.
ElastiqueProOptions()=default
Create a default set of options.
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.