OSSIA
Open Scenario System for Interactive Application
repitch_stretcher.hpp
1 #pragma once
2 #include <ossia/detail/config.hpp>
3 
4 #if defined(OSSIA_ENABLE_LIBSAMPLERATE)
5 #if __has_include(<samplerate.h>)
6 #include <ossia/dataflow/audio_port.hpp>
7 #include <ossia/dataflow/graph_node.hpp>
8 #include <ossia/dataflow/nodes/media.hpp>
9 #include <ossia/dataflow/token_request.hpp>
10 
11 #include <boost/circular_buffer.hpp>
12 
13 #include <samplerate.h>
14 
15 #include <cinttypes>
16 namespace ossia
17 {
18 struct repitch_stretcher
19 {
20  struct resample_channel
21  {
22  resample_channel(int buffersize) noexcept
23  : resampler{src_new(SRC_SINC_BEST_QUALITY, 1, nullptr)}
24  , data(10 * buffersize)
25  {
26  }
27  resample_channel(resample_channel&& other) noexcept
28  : resampler{other.resampler}
29  , data{std::move(other.data)}
30  {
31  other.resampler = nullptr;
32  }
33  resample_channel& operator=(resample_channel&& other) noexcept
34  {
35  resampler = other.resampler;
36  data = std::move(other.data);
37  other.resampler = nullptr;
38  return *this;
39  }
40 
41  resample_channel(const resample_channel&) = delete;
42  resample_channel& operator=(const resample_channel&) = delete;
43 
44  ~resample_channel()
45  {
46  if(resampler)
47  src_delete(resampler);
48  }
49 
50  std::vector<float> input_buffer;
51  SRC_STATE* resampler{};
52  boost::circular_buffer<float> data;
53  };
54 
55  repitch_stretcher(int channels, int bufferSize, int64_t pos)
56  : next_sample_to_read{pos}
57  {
58  repitchers.reserve(channels);
59  while(int(repitchers.size()) < channels)
60  {
61  repitchers.emplace_back(bufferSize);
62  }
63  }
64 
65  std::vector<float*> input_channels;
66  std::vector<float> output_buffer;
67  std::vector<resample_channel> repitchers;
68  int64_t next_sample_to_read{};
69 
70  void transport(int64_t date) { next_sample_to_read = date; }
71 
72  template <typename T>
73  void
74  run(T& audio_fetcher, const ossia::token_request& t, ossia::exec_state_facade e,
75  double tempo_ratio, const std::size_t chan, const int64_t len,
76  int64_t samples_to_read, const int64_t samples_to_write,
77  const int64_t samples_offset, const ossia::mutable_audio_span<double>& ap) noexcept
78  {
79  assert(chan > 0);
80 
81  input_channels.resize(chan);
82  for(std::size_t i = 0; i < chan; i++)
83  {
84  repitchers[i].input_buffer.resize(std::max((int64_t)16, samples_to_read));
85  input_channels[i] = repitchers[i].input_buffer.data();
86  }
87  output_buffer.resize(samples_to_write);
88  auto output = output_buffer.data();
89 
90  int64_t num_samples_available = repitchers[0].data.size();
91 
92  while(num_samples_available < samples_to_write)
93  {
94  audio_fetcher.fetch_audio(
95  next_sample_to_read, samples_to_read, input_channels.data());
96 
97  SRC_DATA data;
98  for(std::size_t i = 0; i < chan; ++i)
99  {
100  data.data_in = repitchers[i].input_buffer.data();
101  data.data_out = output;
102  data.input_frames = samples_to_read;
103  data.output_frames = samples_to_write - num_samples_available;
104  data.input_frames_used = 0;
105  data.output_frames_gen = 0;
106  data.src_ratio = tempo_ratio;
107  data.end_of_input = 0;
108 
109  // Resample
110  src_process(repitchers[i].resampler, &data);
111 
112  // Put output in circular buffer
113  /*
114  if(data.output_frames_gen == 0)
115  {
116  std::cerr << "we did not write anything new "
117  << data.input_frames << " "
118  << data.output_frames << " "
119  << data.input_frames_used << " "
120  << data.output_frames_gen << " "
121  << num_samples_written << std::endl;
122  }
123  */
124  for(int j = 0; j < data.output_frames_gen; j++)
125  repitchers[i].data.push_back(output[j]);
126  }
127  next_sample_to_read += data.input_frames_used;
128  samples_to_read = 16;
129  num_samples_available = repitchers[0].data.size();
130  }
131 
132  for(std::size_t i = 0; i < chan; ++i)
133  {
134  auto it = repitchers[i].data.begin();
135  for(int j = 0; j < samples_to_write; j++)
136  {
137  ap[i][j + samples_offset] = double(*it);
138  ++it;
139  }
140 
141  repitchers[i].data.erase_begin(samples_to_write);
142  }
143  }
144 };
145 }
146 
147 #else
148 
149 #include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
150 
151 namespace ossia
152 {
153 using repitch_stretcher = raw_stretcher;
154 }
155 #endif
156 
157 #else
158 
159 #include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
160 
161 namespace ossia
162 {
163 using repitch_stretcher = raw_stretcher;
164 }
165 #endif
Definition: git_info.h:7
constexpr OSSIA_INLINE auto max(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
max function tailored for values
Definition: math.hpp:96