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>
20static constexpr auto get_samplerate_preset(ossia::audio_stretch_mode mode)
22 int qmode = SRC_SINC_BEST_QUALITY;
23 if(mode == audio_stretch_mode::RepitchMediumQ)
24 qmode = SRC_SINC_FASTEST;
25 if(mode == audio_stretch_mode::RepitchFastestQ)
30struct repitch_stretcher
32 struct resample_channel
34 explicit resample_channel(
int preset,
int buffersize) noexcept
35 : resampler{src_new(preset, 1,
nullptr)}
36 , data(10 * buffersize)
39 resample_channel(resample_channel&& other) noexcept
40 : resampler{other.resampler}
41 , data{std::move(other.data)}
43 other.resampler =
nullptr;
45 resample_channel& operator=(resample_channel&& other)
noexcept
47 resampler = other.resampler;
48 data = std::move(other.data);
49 other.resampler =
nullptr;
53 resample_channel(
const resample_channel&) =
delete;
54 resample_channel& operator=(
const resample_channel&) =
delete;
59 src_delete(resampler);
62 std::vector<float> input_buffer;
63 SRC_STATE* resampler{};
64 boost::circular_buffer<float> data;
67 repitch_stretcher(
int preset,
int channels,
int bufferSize, int64_t pos)
68 : next_sample_to_read{pos}
71 repitchers.reserve(channels);
72 while(
int(repitchers.size()) < channels)
74 repitchers.emplace_back(preset, bufferSize);
78 std::vector<float*> input_channels;
79 std::vector<float> output_buffer;
80 std::vector<resample_channel> repitchers;
81 int64_t next_sample_to_read{};
84 void transport(int64_t date) { next_sample_to_read = date; }
88 run(T& audio_fetcher,
const ossia::token_request& t, ossia::exec_state_facade e,
89 double tempo_ratio,
const std::size_t chan,
const int64_t len,
90 int64_t samples_to_read,
const int64_t samples_to_write,
91 const int64_t samples_offset,
const ossia::mutable_audio_span<double>& ap)
noexcept
95 input_channels.resize(chan);
96 for(std::size_t i = 0; i < chan; i++)
98 repitchers[i].input_buffer.resize(std::max((int64_t)16, samples_to_read));
99 input_channels[i] = repitchers[i].input_buffer.data();
101 output_buffer.resize(samples_to_write);
102 auto output = output_buffer.data();
104 int64_t num_samples_available = repitchers[0].data.size();
108 while(num_samples_available < samples_to_write)
110 audio_fetcher.fetch_audio(
111 next_sample_to_read, samples_to_read, input_channels.data());
114 for(std::size_t i = 0; i < chan; ++i)
116 data.data_in = repitchers[i].input_buffer.data();
117 data.data_out = output;
118 data.input_frames = samples_to_read;
119 data.output_frames = samples_to_write - num_samples_available;
120 data.input_frames_used = 0;
121 data.output_frames_gen = 0;
122 data.src_ratio = std::min(70., tempo_ratio);
123 data.end_of_input = 0;
126 src_process(repitchers[i].resampler, &data);
128 for(
int j = 0; j < data.output_frames_gen; j++)
129 repitchers[i].data.push_back(output[j]);
131 next_sample_to_read += data.input_frames_used;
132 samples_to_read = 16;
133 num_samples_available = repitchers[0].data.size();
136 for(std::size_t i = 0; i < chan; ++i)
138 auto it = repitchers[i].data.begin();
139 for(
int j = 0; j < samples_to_write; j++)
141 ap[i][j + samples_offset] = double(*it);
145 repitchers[i].data.erase_begin(samples_to_write);
151 while(num_samples_available < samples_to_write)
153 audio_fetcher.fetch_audio_backward(
154 next_sample_to_read, samples_to_read, input_channels.data());
157 for(std::size_t i = 0; i < chan; ++i)
159 data.data_in = repitchers[i].input_buffer.data();
160 data.data_out = output;
161 data.input_frames = samples_to_read;
162 data.output_frames = samples_to_write - num_samples_available;
163 data.input_frames_used = 0;
164 data.output_frames_gen = 0;
165 data.src_ratio = std::min(70., std::abs(tempo_ratio));
166 data.end_of_input = 0;
168 src_process(repitchers[i].resampler, &data);
170 for(
int j = 0; j < data.output_frames_gen; j++)
171 repitchers[i].data.push_back(output[j]);
173 next_sample_to_read -= data.input_frames_used;
174 samples_to_read = 16;
175 num_samples_available = repitchers[0].data.size();
178 for(std::size_t i = 0; i < chan; ++i)
180 auto it = repitchers[i].data.begin();
181 for(
int j = 0; j < samples_to_write; j++)
183 ap[i][j + samples_offset] = double(*it);
187 repitchers[i].data.erase_begin(samples_to_write);
196#include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
200static constexpr int get_samplerate_preset(ossia::audio_stretch_mode mode)
204using repitch_stretcher = raw_stretcher;
210#include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
214static constexpr int get_samplerate_preset(ossia::audio_stretch_mode mode)
218using repitch_stretcher = raw_stretcher;