2#include <ossia/detail/config.hpp>
4#if defined(OSSIA_ENABLE_LIBSAMPLERATE)
5#if __has_include(<samplerate.h>)
6#include <ossia/dataflow/audio_port.hpp>
7#include <ossia/dataflow/audio_stretch_mode.hpp>
8#include <ossia/dataflow/graph_node.hpp>
9#include <ossia/dataflow/nodes/media.hpp>
10#include <ossia/dataflow/token_request.hpp>
12#include <boost/circular_buffer.hpp>
14#include <samplerate.h>
21static constexpr auto get_samplerate_preset(ossia::audio_stretch_mode mode)
23 int qmode = SRC_SINC_BEST_QUALITY;
24 if(mode == audio_stretch_mode::RepitchMediumQ)
25 qmode = SRC_SINC_FASTEST;
26 if(mode == audio_stretch_mode::RepitchFastestQ)
31struct repitch_stretcher
33 struct resample_channel
35 explicit resample_channel(
int preset,
int buffersize) noexcept
36 : resampler{src_new(preset, 1,
nullptr)}
37 , data(10 * buffersize)
40 resample_channel(resample_channel&& other) noexcept
41 : resampler{other.resampler}
42 , data{std::move(other.data)}
44 other.resampler =
nullptr;
46 resample_channel& operator=(resample_channel&& other)
noexcept
48 resampler = other.resampler;
49 data = std::move(other.data);
50 other.resampler =
nullptr;
54 resample_channel(
const resample_channel&) =
delete;
55 resample_channel& operator=(
const resample_channel&) =
delete;
60 src_delete(resampler);
63 std::vector<float> input_buffer;
64 SRC_STATE* resampler{};
65 boost::circular_buffer<float> data;
68 repitch_stretcher(
int preset,
int channels,
int bufferSize, int64_t pos)
69 : next_sample_to_read{pos}
72 repitchers.reserve(channels);
73 while(
int(repitchers.size()) < channels)
75 repitchers.emplace_back(preset, bufferSize);
79 std::vector<float*> input_channels;
80 std::vector<float> output_buffer;
81 std::vector<resample_channel> repitchers;
82 int64_t next_sample_to_read{};
86 [[nodiscard]]
static constexpr int64_t start_delay() noexcept {
return 0; }
88 void transport(int64_t date) { next_sample_to_read = date; }
92 run(T& audio_fetcher,
const ossia::token_request& t, ossia::exec_state_facade e,
93 double tempo_ratio,
double rate_ratio,
const std::size_t chan,
const int64_t len,
94 int64_t samples_to_read,
const int64_t samples_to_write,
95 const int64_t samples_offset,
const ossia::mutable_audio_span<double>& ap)
noexcept
102 const double src_ratio
103 = std::clamp(std::abs(rate_ratio * tempo_ratio), 1. / 256., 70.);
105 input_channels.resize(chan);
106 for(std::size_t i = 0; i < chan; i++)
108 repitchers[i].input_buffer.resize(std::max((int64_t)16, samples_to_read));
109 input_channels[i] = repitchers[i].input_buffer.data();
111 output_buffer.resize(samples_to_write);
112 auto output = output_buffer.data();
114 int64_t num_samples_available = repitchers[0].data.size();
118 while(num_samples_available < samples_to_write)
120 audio_fetcher.fetch_audio(
121 next_sample_to_read, samples_to_read, input_channels.data());
124 for(std::size_t i = 0; i < chan; ++i)
126 data.data_in = repitchers[i].input_buffer.data();
127 data.data_out = output;
128 data.input_frames = samples_to_read;
129 data.output_frames = samples_to_write - num_samples_available;
130 data.input_frames_used = 0;
131 data.output_frames_gen = 0;
132 data.src_ratio = src_ratio;
133 data.end_of_input = 0;
136 src_process(repitchers[i].resampler, &data);
138 for(
int j = 0; j < data.output_frames_gen; j++)
139 repitchers[i].data.push_back(output[j]);
141 next_sample_to_read += data.input_frames_used;
142 samples_to_read = 16;
143 num_samples_available = repitchers[0].data.size();
146 if(data.input_frames_used == 0 && data.output_frames_gen == 0)
151 = std::min<int64_t>(samples_to_write, repitchers[0].data.size());
152 for(std::size_t i = 0; i < chan; ++i)
154 auto it = repitchers[i].data.begin();
155 for(int64_t j = 0; j < got; j++)
157 ap[i][j + samples_offset] = double(*it);
160 for(int64_t j = got; j < samples_to_write; j++)
161 ap[i][j + samples_offset] = 0.;
163 repitchers[i].data.erase_begin(got);
169 while(num_samples_available < samples_to_write)
171 audio_fetcher.fetch_audio_backward(
172 next_sample_to_read, samples_to_read, input_channels.data());
175 for(std::size_t i = 0; i < chan; ++i)
177 data.data_in = repitchers[i].input_buffer.data();
178 data.data_out = output;
179 data.input_frames = samples_to_read;
180 data.output_frames = samples_to_write - num_samples_available;
181 data.input_frames_used = 0;
182 data.output_frames_gen = 0;
183 data.src_ratio = src_ratio;
184 data.end_of_input = 0;
186 src_process(repitchers[i].resampler, &data);
188 for(
int j = 0; j < data.output_frames_gen; j++)
189 repitchers[i].data.push_back(output[j]);
191 next_sample_to_read -= data.input_frames_used;
192 samples_to_read = 16;
193 num_samples_available = repitchers[0].data.size();
196 if(data.input_frames_used == 0 && data.output_frames_gen == 0)
201 = std::min<int64_t>(samples_to_write, repitchers[0].data.size());
202 for(std::size_t i = 0; i < chan; ++i)
204 auto it = repitchers[i].data.begin();
205 for(int64_t j = 0; j < got; j++)
207 ap[i][j + samples_offset] = double(*it);
210 for(int64_t j = got; j < samples_to_write; j++)
211 ap[i][j + samples_offset] = 0.;
213 repitchers[i].data.erase_begin(got);
222#include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
226static constexpr int get_samplerate_preset(ossia::audio_stretch_mode mode)
230using repitch_stretcher = raw_stretcher;
236#include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
240static constexpr int get_samplerate_preset(ossia::audio_stretch_mode mode)
244using repitch_stretcher = raw_stretcher;