OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
sound_utils.hpp
1#pragma once
2#include <ossia/dataflow/nodes/media.hpp>
4
5#include <algorithm>
6
7namespace ossia
8{
9
10// Reverse audio samples in-place for backward playback
11template <typename T>
12static void reverse_audio_buffer(T** audio_array, std::size_t channels, int64_t samples) noexcept
13{
14 for(std::size_t i = 0; i < channels; i++)
15 {
16 std::reverse(audio_array[i], audio_array[i] + samples);
17 }
18}
19
20// Read audio from buffer going backwards (for reverse playback)
21// 'start' is the position we're reading FROM (going towards 0)
22// Returns samples in forward order (caller should reverse if needed for stretchers)
23template <typename T>
24static void read_audio_from_buffer_backward(
25 const audio_span<float>& data, const int64_t start, const int64_t samples_to_write,
26 const int64_t start_offset, const int64_t loop_duration, const bool loops,
27 T** const audio_array) noexcept
28{
29 const auto channels = data.size();
30 if(channels == 0)
31 return;
32 const int64_t file_duration = data[0].size();
33
34 if(loops && loop_duration > 0)
35 {
36 // Looping backward: when we hit 0, we wrap to loop_duration
37 for(std::size_t i = 0; i < channels; i++)
38 {
39 auto& src = data[i];
40 T* dst = audio_array[i];
41
42 for(int64_t k = 0; k < samples_to_write; k++)
43 {
44 // Going backwards: start - k, with wrapping
45 int64_t raw_pos = start - k;
46
47 // Wrap around using modulo (handle negative values)
48 int64_t wrapped_pos = ((raw_pos % loop_duration) + loop_duration) % loop_duration;
49 int64_t pos = start_offset + wrapped_pos;
50
51 if(pos >= 0 && pos < file_duration)
52 dst[k] = src[pos];
53 else
54 dst[k] = 0;
55 }
56 }
57 }
58 else
59 {
60 // No looping: just read backwards, zero-fill if we go past the beginning
61 for(std::size_t i = 0; i < channels; i++)
62 {
63 const auto& src = data[i];
64 T* dst = audio_array[i];
65
66 for(int64_t k = 0; k < samples_to_write; k++)
67 {
68 int64_t pos = start_offset + start - k;
69
70 if(pos >= 0 && pos < file_duration)
71 dst[k] = src[pos];
72 else
73 dst[k] = 0;
74 }
75 }
76 }
77}
78
79template <typename T>
80static void read_audio_from_buffer(
81 const audio_span<float>& data, const int64_t start, const int64_t samples_to_write,
82 const int64_t start_offset, const int64_t loop_duration, const bool loops,
83 T** const audio_array) noexcept
84{
85 const auto channels = data.size();
86 if(channels == 0)
87 return;
88 const int64_t file_duration = data[0].size();
89
90 if(loops)
91 {
92 // Case where we won't loop around at all in that buffer
93 if(start + samples_to_write < loop_duration)
94 {
95 const int64_t read_start = start_offset + start;
96
97 // Absolute best case where we can just copy directly the whole buffer
98 if(read_start + samples_to_write < file_duration)
99 {
100 for(std::size_t i = 0; i < channels; i++)
101 {
102 auto& src = data[i];
103 T* dst = audio_array[i];
104
105 for(int64_t k = 0; k < samples_to_write; k++)
106 {
107 dst[k] = src[read_start + k];
108 }
109 }
110 }
111 else
112 {
113 // Here we must check for the end of file
114 for(std::size_t i = 0; i < channels; i++)
115 {
116 auto& src = data[i];
117 T* dst = audio_array[i];
118
119 for(int64_t k = 0; k < samples_to_write; k++)
120 {
121 int64_t pos = read_start + k;
122 if(pos < file_duration)
123 dst[k] = src[pos];
124 else
125 dst[k] = 0;
126 }
127 }
128 }
129 }
130 else
131 {
132 // Here we may loop within that buffer
133 for(std::size_t i = 0; i < channels; i++)
134 {
135 auto& src = data[i];
136 T* dst = audio_array[i];
137
138 for(int64_t k = 0; k < samples_to_write; k++)
139 {
140 int64_t pos = start_offset + ((start + k) % loop_duration);
141 if(pos < file_duration)
142 dst[k] = src[pos];
143 else
144 dst[k] = 0;
145 }
146 }
147 }
148 }
149 else
150 {
151 for(std::size_t i = 0; i < channels; i++)
152 {
153 const auto& src = data[i];
154 T* dst = audio_array[i];
155
156 if(file_duration >= start + samples_to_write + start_offset)
157 {
158 // Absolute best case where we can copy the whole buffer
159 for(int64_t k = 0, pos = start + start_offset; k < samples_to_write; k++, pos++)
160 {
161 dst[k] = src[pos];
162 }
163 }
164 else
165 {
166 // This buffer will have the end of the file
167 const int64_t max = ossia::clamp(
168 file_duration - (start + start_offset), (int64_t)0, samples_to_write);
169 for(int64_t k = 0, pos = start + start_offset; k < max; k++, pos++)
170 {
171 dst[k] = src[pos];
172 }
173 for(int k = max; k < samples_to_write; k++)
174 {
175 dst[k] = 0;
176 }
177 }
178 }
179 }
180}
181}
Definition git_info.h:7
OSSIA_INLINE constexpr T clamp(T d, const T min, const T max) noexcept
clamp Returns the value bounded by a min and a max
Definition math.hpp:154
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