OSSIA
Open Scenario System for Interactive Application
rubberband_stretcher.hpp
1 #pragma once
2 #include <ossia/detail/config.hpp>
3 
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>
10 
11 #if __has_include(<RubberBandStretcher.h>)
12 #include <RubberBandStretcher.h>
13 #elif __has_include(<rubberband/RubberBandStretcher.h>)
14 #include <rubberband/RubberBandStretcher.h>
15 #endif
16 
17 namespace ossia
18 {
19 static constexpr auto get_rubberband_preset(ossia::audio_stretch_mode mode)
20 {
21  using opt_t = RubberBand::RubberBandStretcher::Option;
22  using preset_t = RubberBand::RubberBandStretcher::PresetOption;
23  uint32_t preset = opt_t::OptionProcessRealTime | opt_t::OptionThreadingNever;
24  switch(mode)
25  {
26  case ossia::audio_stretch_mode::RubberBandStandard:
27  break;
28 
29  case ossia::audio_stretch_mode::RubberBandPercussive:
30  preset |= preset_t::PercussiveOptions;
31  break;
32 
33  case ossia::audio_stretch_mode::RubberBandStandardHQ:
34  preset |= RubberBand::RubberBandStretcher::OptionEngineFiner;
35  preset |= RubberBand::RubberBandStretcher::OptionPitchHighConsistency;
36  break;
37 
38  case ossia::audio_stretch_mode::RubberBandPercussiveHQ:
39  preset |= preset_t::PercussiveOptions;
40  preset |= RubberBand::RubberBandStretcher::OptionEngineFiner;
41  preset |= RubberBand::RubberBandStretcher::OptionPitchHighConsistency;
42  break;
43 
44  default:
45  break;
46  }
47 
48  return preset;
49 }
50 
51 struct rubberband_stretcher
52 {
53  rubberband_stretcher(
54  uint32_t opt, std::size_t channels, std::size_t sampleRate, int64_t pos)
55  : m_rubberBand{std::make_unique<RubberBand::RubberBandStretcher>(
56  sampleRate, channels, opt)}
57  , next_sample_to_read{pos}
58  , options{opt}
59 
60  {
61  }
62 
63  rubberband_stretcher(const rubberband_stretcher&) = delete;
64  rubberband_stretcher& operator=(const rubberband_stretcher&) = delete;
65  rubberband_stretcher(rubberband_stretcher&&) = default;
66  rubberband_stretcher& operator=(rubberband_stretcher&&) = default;
67 
68  std::unique_ptr<RubberBand::RubberBandStretcher> m_rubberBand;
69  int64_t next_sample_to_read = 0;
70  uint32_t options{};
71 
72  void transport(int64_t date)
73  {
74  m_rubberBand->reset();
75  next_sample_to_read = date;
76  }
77 
78  template <typename T>
79  void
80  run(T& audio_fetcher, const ossia::token_request& t, ossia::exec_state_facade e,
81  double tempo_ratio, const std::size_t chan, const std::size_t len,
82  int64_t samples_to_read, const int64_t samples_to_write,
83  const int64_t samples_offset, const ossia::mutable_audio_span<double>& ap) noexcept
84  {
85  if(tempo_ratio != m_rubberBand->getTimeRatio())
86  {
87  m_rubberBand->setTimeRatio(tempo_ratio);
88  }
89 
90  if(t.forward())
91  {
92  // TODO : if T::sample_type == float we could leverage it directly as
93  // input
94  float** const input = (float**)alloca(sizeof(float*) * chan);
95  float** const output = (float**)alloca(sizeof(float*) * chan);
96  for(std::size_t i = 0; i < chan; i++)
97  {
98  input[i]
99  = (float*)alloca(sizeof(float) * std::max((int64_t)16, samples_to_read));
100  output[i] = (float*)alloca(sizeof(float) * samples_to_write);
101  }
102 
103  while(m_rubberBand->available() < samples_to_write)
104  {
105  audio_fetcher.fetch_audio(next_sample_to_read, samples_to_read, input);
106 
107  m_rubberBand->process(input, samples_to_read, false);
108 
109  next_sample_to_read += samples_to_read;
110  samples_to_read = 16;
111  }
112 
113  m_rubberBand->retrieve(
114  output, std::min((int)samples_to_write, m_rubberBand->available()));
115 
116  for(std::size_t i = 0; i < chan; i++)
117  {
118  for(int64_t j = 0; j < samples_to_write; j++)
119  {
120  ap[i][j + samples_offset] = double(output[i][j]);
121  }
122  }
123  }
124  else
125  {
126  // TODO
127  }
128  }
129 };
130 }
131 #else
132 #include <ossia/dataflow/nodes/timestretch/raw_stretcher.hpp>
133 
134 namespace ossia
135 {
136 using rubberband_stretcher = raw_stretcher;
137 }
138 #endif
Definition: git_info.h:7
constexpr OSSIA_INLINE auto min(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
min function tailored for values
Definition: math.hpp:125
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