2#include <ossia/detail/config.hpp>
4#if defined(OSSIA_ENABLE_RUBBERBAND)
5#include <ossia/dataflow/audio_port.hpp>
6#include <ossia/dataflow/audio_stretch_mode.hpp>
7#include <ossia/dataflow/graph_node.hpp>
8#include <ossia/dataflow/nodes/media.hpp>
9#include <ossia/dataflow/token_request.hpp>
11#if __has_include(<RubberBandStretcher.h>)
12#include <RubberBandStretcher.h>
13#elif __has_include(<rubberband/RubberBandStretcher.h>)
14#include <rubberband/RubberBandStretcher.h>
21static constexpr auto get_rubberband_preset(ossia::audio_stretch_mode mode)
23 using opt_t = RubberBand::RubberBandStretcher::Option;
24 using preset_t = RubberBand::RubberBandStretcher::PresetOption;
25 uint32_t preset = opt_t::OptionProcessRealTime | opt_t::OptionThreadingNever;
28 case ossia::audio_stretch_mode::RubberBandStandard:
31 case ossia::audio_stretch_mode::RubberBandPercussive:
32 preset |= preset_t::PercussiveOptions;
35 case ossia::audio_stretch_mode::RubberBandStandardHQ:
36 preset |= RubberBand::RubberBandStretcher::OptionEngineFiner;
37 preset |= RubberBand::RubberBandStretcher::OptionPitchHighConsistency;
40 case ossia::audio_stretch_mode::RubberBandPercussiveHQ:
41 preset |= preset_t::PercussiveOptions;
42 preset |= RubberBand::RubberBandStretcher::OptionEngineFiner;
43 preset |= RubberBand::RubberBandStretcher::OptionPitchHighConsistency;
53struct rubberband_stretcher
56 uint32_t opt, std::size_t channels, std::size_t sampleRate, int64_t pos)
57 : m_rubberBand{std::make_unique<RubberBand::RubberBandStretcher>(
58 sampleRate, channels, opt)}
59 , next_sample_to_read{pos}
65 rubberband_stretcher(
const rubberband_stretcher&) =
delete;
66 rubberband_stretcher& operator=(
const rubberband_stretcher&) =
delete;
67 rubberband_stretcher(rubberband_stretcher&&) =
default;
68 rubberband_stretcher& operator=(rubberband_stretcher&&) =
default;
70 std::unique_ptr<RubberBand::RubberBandStretcher> m_rubberBand;
71 int64_t next_sample_to_read = 0;
74 void transport(int64_t date)
76 m_rubberBand->reset();
77 next_sample_to_read = date;
82 run(T& audio_fetcher,
const ossia::token_request& t, ossia::exec_state_facade e,
83 double tempo_ratio,
const std::size_t chan,
const std::size_t len,
84 int64_t samples_to_read,
const int64_t samples_to_write,
85 const int64_t samples_offset,
const ossia::mutable_audio_span<double>& ap)
noexcept
87 const double abs_tempo_ratio = std::abs(tempo_ratio);
88 if(abs_tempo_ratio != m_rubberBand->getTimeRatio())
90 m_rubberBand->setTimeRatio(abs_tempo_ratio);
95 const int max_chan = std::max(chan, m_rubberBand->getChannelCount());
96 const int frames = std::max((int64_t)16, samples_to_read);
97 float**
const input = (
float**)alloca(
sizeof(
float*) * max_chan);
98 float**
const output = (
float**)alloca(
sizeof(
float*) * max_chan);
99 for(std::size_t i = 0; i < chan; i++)
101 input[i] = (
float*)alloca(
sizeof(
float) * frames);
102 output[i] = (
float*)alloca(
sizeof(
float) * samples_to_write);
104 for(std::size_t i = chan; i < m_rubberBand->getChannelCount(); i++)
106 input[i] = (
float*)alloca(
sizeof(
float) * frames);
107 std::fill_n(input[i], frames, 0.f);
108 output[i] = (
float*)alloca(
sizeof(
float) * samples_to_write);
113 while(m_rubberBand->available() < samples_to_write)
115 audio_fetcher.fetch_audio(next_sample_to_read, samples_to_read, input);
117 m_rubberBand->process(input, samples_to_read,
false);
119 next_sample_to_read += samples_to_read;
120 samples_to_read = 16;
123 m_rubberBand->retrieve(
124 output, std::min((
int)samples_to_write, m_rubberBand->available()));
126 for(std::size_t i = 0; i < chan; i++)
128 for(int64_t j = 0; j < samples_to_write; j++)
130 ap[i][j + samples_offset] = double(output[i][j]);
137 while(m_rubberBand->available() < samples_to_write)
139 audio_fetcher.fetch_audio_backward(next_sample_to_read, samples_to_read, input);
141 m_rubberBand->process(input, samples_to_read,
false);
143 next_sample_to_read -= samples_to_read;
144 samples_to_read = 16;
147 const int retrieved = m_rubberBand->retrieve(
148 output, std::min((
int)samples_to_write, m_rubberBand->available()));
150 for(std::size_t i = 0; i < chan; i++)
152 for(int64_t j = 0; j < samples_to_write; j++)
154 ap[i][j + samples_offset] = double(output[i][j]);
162#include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
166static constexpr uint32_t get_rubberband_preset(ossia::audio_stretch_mode mode)
170using rubberband_stretcher = raw_stretcher;