2#include <ossia/audio/audio_parameter.hpp>
3#include <ossia/audio/drwav_handle.hpp>
4#include <ossia/dataflow/audio_stretch_mode.hpp>
5#include <ossia/dataflow/graph_node.hpp>
6#include <ossia/dataflow/nodes/media.hpp>
7#include <ossia/dataflow/nodes/sound.hpp>
8#include <ossia/dataflow/port.hpp>
9#include <ossia/detail/pod_vector.hpp>
16class sound_mmap final :
public ossia::sound_node
19 sound_mmap() { m_outlets.push_back(&audio_out); }
21 ~sound_mmap() =
default;
23 std::string label() const noexcept
override {
return "sound_mmap"; }
25 void set_start(std::size_t v) { start = v; }
27 void set_upmix(std::size_t v) { upmix = v; }
29 void set_sound(drwav_handle hdl)
32 m_handle = std::move(hdl);
35 switch(m_handle.translatedFormatTag())
37 case DR_WAVE_FORMAT_PCM: {
38 switch(m_handle.bitsPerSample())
41 m_converter = read_u8;
44 m_converter = read_s16;
47 m_converter = read_s24;
50 m_converter = read_s32;
55 case DR_WAVE_FORMAT_IEEE_FLOAT: {
56 switch(m_handle.bitsPerSample())
59 m_converter = read_f32;
62 m_converter = read_f64;
68 m_converter =
nullptr;
74 void transport(time_value date)
override
76 m_resampler.transport(to_sample(date, m_handle.sampleRate()));
80 int64_t start, int64_t samples_to_write,
double** audio_array_base)
noexcept
82 const int channels = this->channels();
83 const int file_duration = this->duration();
85 m_resampleBuffer.resize(channels);
86 for(
auto& buf : m_resampleBuffer)
87 buf.resize(samples_to_write);
89 float** audio_array = (
float**)alloca(
sizeof(
float*) * channels);
90 for(
int i = 0; i < channels; i++)
92 m_resampleBuffer[i].resize(samples_to_write);
93 audio_array[i] = m_resampleBuffer[i].data();
96 ossia::mutable_audio_span<float> source(channels);
99 if(samples_to_write * channels > 10000)
101 m_safetyBuffer.resize(samples_to_write * channels);
102 frame_data = m_safetyBuffer.data();
108 frame_data = (
double*)alloca(
sizeof(
double) * samples_to_write * channels);
113 for(
int k = 0; k < samples_to_write; k++)
116 int pos = this->m_start_offset_samples
117 + ((start + k) % this->m_loop_duration_samples);
118 if(pos >= file_duration)
120 for(
int i = 0; i < channels; i++)
121 audio_array[i][k] = 0;
125 const bool ok = this->m_handle.seek_to_pcm_frame(pos);
128 for(
int i = 0; i < channels; i++)
129 audio_array[i][k] = 0;
134 const auto count = this->m_handle.read_pcm_frames(
max, frame_data);
137 for(
int i = 0; i < channels; i++)
138 source[i] = tcb::span(audio_array[i] + k, count);
139 m_converter(source, frame_data, count);
143 for(
int i = 0; i < channels; i++)
144 audio_array[i][k] = 0;
150 for(
int i = 0; i < channels; i++)
152 source[i] = tcb::span(audio_array[i], samples_to_write);
155 bool ok = start + m_start_offset_samples < file_duration;
157 ok = ok && this->m_handle.seek_to_pcm_frame(start + m_start_offset_samples);
161 const auto count = this->m_handle.read_pcm_frames(samples_to_write, frame_data);
162 m_converter(source, frame_data, count);
163 for(
int i = 0; i < channels; i++)
164 for(
int k = count; k < samples_to_write; k++)
165 audio_array[i][k] = 0;
169 for(
int i = 0; i < channels; i++)
170 for(
int k = 0; k < samples_to_write; k++)
171 audio_array[i][k] = 0;
176 for(
int i = 0; i < channels; i++)
177 std::copy_n(audio_array[i], samples_to_write, audio_array_base[i]);
180 void fetch_audio(int64_t start, int64_t samples_to_write,
float** audio_array)
noexcept
182 const int channels = this->channels();
183 const int file_duration = this->duration();
185 ossia::mutable_audio_span<float> source(channels);
187 double* frame_data{};
188 if(samples_to_write * channels > 10000)
190 m_safetyBuffer.resize(samples_to_write * channels);
191 frame_data = m_safetyBuffer.data();
197 frame_data = (
double*)alloca(
sizeof(
double) * samples_to_write * channels);
202 for(
int k = 0; k < samples_to_write; k++)
205 int pos = this->m_start_offset_samples
206 + ((start + k) % this->m_loop_duration_samples);
207 if(pos >= file_duration)
209 for(
int i = 0; i < channels; i++)
210 audio_array[i][k] = 0;
214 const bool ok = this->m_handle.seek_to_pcm_frame(pos);
217 for(
int i = 0; i < channels; i++)
218 audio_array[i][k] = 0;
223 const auto count = this->m_handle.read_pcm_frames(
max, frame_data);
226 for(
int i = 0; i < channels; i++)
227 source[i] = tcb::span(audio_array[i] + k, count);
228 m_converter(source, frame_data, count);
232 for(
int i = 0; i < channels; i++)
233 audio_array[i][k] = 0;
239 for(
int i = 0; i < channels; i++)
241 source[i] = tcb::span(audio_array[i], samples_to_write);
244 const bool ok = this->m_handle.seek_to_pcm_frame(start + m_start_offset_samples);
247 for(
int i = 0; i < channels; i++)
248 for(
int k = 0; k < samples_to_write; k++)
249 audio_array[i][k] = 0;
253 const auto count = this->m_handle.read_pcm_frames(samples_to_write, frame_data);
254 m_converter(source, frame_data, count);
255 for(
int i = 0; i < channels; i++)
256 for(
int k = count; k < samples_to_write; k++)
257 audio_array[i][k] = 0;
261 void run(
const ossia::token_request& t, ossia::exec_state_facade e)
noexcept override
263 if(!m_handle || !m_converter)
270 const auto channels = m_handle.channels();
271 const auto len = m_handle.totalPCMFrameCount();
273 ossia::audio_port& ap = *audio_out;
274 ap.set_channels(std::max((std::size_t)upmix, (std::size_t)channels));
276 const auto [samples_to_read, samples_to_write]
277 = snd::sample_info(e.bufferSize(), e.modelToSamples(), t);
278 if(samples_to_write <= 0)
281 assert(samples_to_write > 0);
283 const auto samples_offset = t.physical_start(e.modelToSamples());
286 if(t.prev_date < m_prev_date)
291 if(t.prev_date != 0_tv)
293 transport(t.prev_date);
303 transport(t.prev_date);
307 for(std::size_t chan = 0; chan < channels; chan++)
309 ap.channel(chan).resize(e.bufferSize());
312 double stretch_ratio = update_stretch(t, e);
316 *
this, t, e, stretch_ratio, channels, len, samples_to_read, samples_to_write,
319 for(std::size_t chan = 0; chan < channels; chan++)
323 t.start_discontinuous, t.end_discontinuous, ap.channel(chan), samples_offset,
327 ossia::snd::perform_upmix(this->upmix, channels, ap);
328 ossia::snd::perform_start_offset(this->start, ap);
330 m_prev_date = t.date;
338 [[nodiscard]] std::size_t channels()
const
340 return m_handle ? m_handle.channels() : 0;
342 [[nodiscard]] std::size_t duration()
const
344 return m_handle ? m_handle.totalPCMFrameCount() : 0;
348 drwav_handle m_handle{};
350 ossia::audio_outlet audio_out;
356 = void (*)(ossia::mutable_audio_span<float>& ap,
void* data, int64_t samples);
357 read_fn_t m_converter{};
358 std::vector<double> m_safetyBuffer;
359 std::vector<std::vector<float>> m_resampleBuffer;
OSSIA_INLINE constexpr 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
The time_value class.
Definition ossia/editor/scenario/time_value.hpp:30