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>
19static constexpr auto get_samplerate_preset(ossia::audio_stretch_mode mode)
21 int qmode = SRC_SINC_BEST_QUALITY;
22 if(mode == audio_stretch_mode::RepitchMediumQ)
23 qmode = SRC_SINC_FASTEST;
24 if(mode == audio_stretch_mode::RepitchFastestQ)
29struct repitch_stretcher
31 struct resample_channel
33 explicit resample_channel(
int preset,
int buffersize) noexcept
34 : resampler{src_new(preset, 1,
nullptr)}
35 , data(10 * buffersize)
38 resample_channel(resample_channel&& other) noexcept
39 : resampler{other.resampler}
40 , data{std::move(other.data)}
42 other.resampler =
nullptr;
44 resample_channel& operator=(resample_channel&& other)
noexcept
46 resampler = other.resampler;
47 data = std::move(other.data);
48 other.resampler =
nullptr;
52 resample_channel(
const resample_channel&) =
delete;
53 resample_channel& operator=(
const resample_channel&) =
delete;
58 src_delete(resampler);
61 std::vector<float> input_buffer;
62 SRC_STATE* resampler{};
63 boost::circular_buffer<float> data;
66 repitch_stretcher(
int preset,
int channels,
int bufferSize, int64_t pos)
67 : next_sample_to_read{pos}
70 repitchers.reserve(channels);
71 while(
int(repitchers.size()) < channels)
73 repitchers.emplace_back(preset, bufferSize);
77 std::vector<float*> input_channels;
78 std::vector<float> output_buffer;
79 std::vector<resample_channel> repitchers;
80 int64_t next_sample_to_read{};
83 void transport(int64_t date) { next_sample_to_read = date; }
87 run(T& audio_fetcher,
const ossia::token_request& t, ossia::exec_state_facade e,
88 double tempo_ratio,
const std::size_t chan,
const int64_t len,
89 int64_t samples_to_read,
const int64_t samples_to_write,
90 const int64_t samples_offset,
const ossia::mutable_audio_span<double>& ap)
noexcept
94 input_channels.resize(chan);
95 for(std::size_t i = 0; i < chan; i++)
97 repitchers[i].input_buffer.resize(std::max((int64_t)16, samples_to_read));
98 input_channels[i] = repitchers[i].input_buffer.data();
100 output_buffer.resize(samples_to_write);
101 auto output = output_buffer.data();
103 int64_t num_samples_available = repitchers[0].data.size();
105 while(num_samples_available < samples_to_write)
107 audio_fetcher.fetch_audio(
108 next_sample_to_read, samples_to_read, input_channels.data());
111 for(std::size_t i = 0; i < chan; ++i)
113 data.data_in = repitchers[i].input_buffer.data();
114 data.data_out = output;
115 data.input_frames = samples_to_read;
116 data.output_frames = samples_to_write - num_samples_available;
117 data.input_frames_used = 0;
118 data.output_frames_gen = 0;
119 data.src_ratio = tempo_ratio;
120 data.end_of_input = 0;
123 src_process(repitchers[i].resampler, &data);
137 for(
int j = 0; j < data.output_frames_gen; j++)
138 repitchers[i].data.push_back(output[j]);
140 next_sample_to_read += data.input_frames_used;
141 samples_to_read = 16;
142 num_samples_available = repitchers[0].data.size();
145 for(std::size_t i = 0; i < chan; ++i)
147 auto it = repitchers[i].data.begin();
148 for(
int j = 0; j < samples_to_write; j++)
150 ap[i][j + samples_offset] = double(*it);
154 repitchers[i].data.erase_begin(samples_to_write);
162#include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
166static constexpr int get_samplerate_preset(ossia::audio_stretch_mode mode)
170using repitch_stretcher = raw_stretcher;
176#include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
180static constexpr int get_samplerate_preset(ossia::audio_stretch_mode mode)
184using repitch_stretcher = raw_stretcher;