|
1
|
1 #include "foobar2000-sdk-pch.h"
|
|
|
2 #include "mem_block_container.h"
|
|
|
3 #include "audio_chunk.h"
|
|
|
4
|
|
|
5 void audio_chunk::allocate(size_t size, bool bQuicker) {
|
|
|
6 if (bQuicker) {
|
|
|
7 const size_t before = this->get_data_size();
|
|
|
8 const size_t allow_waste = pfc::max_t<size_t>(size, 4096);
|
|
|
9 const size_t upper = (size + allow_waste > size) ? size + allow_waste : SIZE_MAX;
|
|
|
10 if (before >= size && before <= upper) return;
|
|
|
11 }
|
|
|
12 this->set_data_size(size);
|
|
|
13 }
|
|
|
14
|
|
|
15 void audio_chunk::set_data(const audio_sample* src, size_t samples, spec_t const & spec, bool bQuicker) {
|
|
|
16 t_size size = samples * spec.chanCount;
|
|
|
17 allocate(size, bQuicker);
|
|
|
18 if (src)
|
|
|
19 pfc::memcpy_t(get_data(), src, size);
|
|
|
20 else
|
|
|
21 pfc::memset_t(get_data(), (audio_sample)0, size);
|
|
|
22 set_sample_count(samples);
|
|
|
23 set_spec(spec);
|
|
|
24 }
|
|
|
25
|
|
|
26 void audio_chunk::set_data(const audio_sample* src, size_t samples, unsigned nch, unsigned srate, unsigned channel_config)
|
|
|
27 {
|
|
|
28 set_data(src, samples, makeSpec(srate, nch, channel_config));
|
|
|
29 }
|
|
|
30
|
|
|
31 void audio_chunk::set_data(const audio_sample* src, size_t samples, unsigned nch, unsigned srate) {
|
|
|
32
|
|
|
33 set_data(src, samples, makeSpec(srate, nch));
|
|
|
34 }
|
|
|
35
|
|
|
36 inline bool check_exclusive(unsigned val, unsigned mask)
|
|
|
37 {
|
|
|
38 return (val&mask)!=0 && (val&mask)!=mask;
|
|
|
39 }
|
|
|
40
|
|
|
41 static void _import8u(uint8_t const * in, audio_sample * out, size_t count) {
|
|
|
42 for(size_t walk = 0; walk < count; ++walk) {
|
|
|
43 uint32_t i = *(in++);
|
|
|
44 i -= 0x80; // to signed
|
|
|
45 *(out++) = (audio_sample) (int32_t) i / (float) 0x80;
|
|
|
46 }
|
|
|
47 }
|
|
|
48
|
|
|
49 static void _import8s(uint8_t const * in, audio_sample * out, size_t count) {
|
|
|
50 for(size_t walk = 0; walk < count; ++walk) {
|
|
|
51 int32_t i = (int8_t) *(in++);
|
|
|
52 *(out++) = (audio_sample) i / (float) 0x80;
|
|
|
53 }
|
|
|
54 }
|
|
|
55
|
|
|
56 static audio_sample _import24s(uint32_t i) {
|
|
|
57 i ^= 0x800000; // to unsigned
|
|
|
58 i -= 0x800000; // and back to signed / fill MSBs proper
|
|
|
59 return (audio_sample) (int32_t) i / (audio_sample) 0x800000;
|
|
|
60 }
|
|
|
61
|
|
|
62 static void _import24(const void * in_, audio_sample * out, size_t count) {
|
|
|
63 const uint8_t * in = (const uint8_t*) in_;
|
|
|
64 #if 1
|
|
|
65 while(count > 0 && !pfc::is_ptr_aligned_t<4>(in)) {
|
|
|
66 uint32_t i = *(in++);
|
|
|
67 i |= (uint32_t) *(in++) << 8;
|
|
|
68 i |= (uint32_t) *(in++) << 16;
|
|
|
69 *(out++) = _import24s(i);
|
|
|
70 --count;
|
|
|
71 }
|
|
|
72 {
|
|
|
73 for(size_t loop = count >> 2; loop; --loop) {
|
|
|
74 uint32_t i1 = * (uint32_t*) in; in += 4;
|
|
|
75 uint32_t i2 = * (uint32_t*) in; in += 4;
|
|
|
76 uint32_t i3 = * (uint32_t*) in; in += 4;
|
|
|
77 *out++ = _import24s( i1 & 0xFFFFFF );
|
|
|
78 *out++ = _import24s( (i1 >> 24) | ((i2 & 0xFFFF) << 8) );
|
|
|
79 *out++ = _import24s( (i2 >> 16) | ((i3 & 0xFF) << 16) );
|
|
|
80 *out++ = _import24s( i3 >> 8 );
|
|
|
81 }
|
|
|
82 count &= 3;
|
|
|
83 }
|
|
|
84 for( ; count ; --count) {
|
|
|
85 uint32_t i = *(in++);
|
|
|
86 i |= (uint32_t) *(in++) << 8;
|
|
|
87 i |= (uint32_t) *(in++) << 16;
|
|
|
88 *(out++) = _import24s(i);
|
|
|
89 }
|
|
|
90 #else
|
|
|
91 if (count > 0) {
|
|
|
92 int32_t i = *(in++);
|
|
|
93 i |= (int32_t) *(in++) << 8;
|
|
|
94 i |= (int32_t) (int8_t) *in << 16;
|
|
|
95 *out++ = (audio_sample) i / (audio_sample) 0x800000;
|
|
|
96 --count;
|
|
|
97
|
|
|
98 // Now we have in ptr at offset_of_next - 1 and we can read as int32 then discard the LSBs
|
|
|
99 for(;count;--count) {
|
|
|
100 int32_t i = *( int32_t*) in; in += 3;
|
|
|
101 *out++ = (audio_sample) (i >> 8) / (audio_sample) 0x800000;
|
|
|
102 }
|
|
|
103 }
|
|
|
104 #endif
|
|
|
105 }
|
|
|
106
|
|
|
107 template<bool byteSwap, bool isSigned> static void _import16any(const void * in, audio_sample * out, size_t count) {
|
|
|
108 uint16_t const * inPtr = (uint16_t const*) in;
|
|
|
109 const audio_sample factor = 1.0f / (audio_sample) 0x8000;
|
|
|
110 for(size_t walk = 0; walk < count; ++walk) {
|
|
|
111 uint16_t v = *inPtr++;
|
|
|
112 if (byteSwap) v = pfc::byteswap_t(v);
|
|
|
113 if (!isSigned) v ^= 0x8000; // to signed
|
|
|
114 *out++ = (audio_sample) (int16_t) v * factor;
|
|
|
115 }
|
|
|
116 }
|
|
|
117
|
|
|
118 template<bool byteSwap, bool isSigned> static void _import32any(const void * in, audio_sample * out, size_t count) {
|
|
|
119 uint32_t const * inPtr = (uint32_t const*) in;
|
|
|
120 const audio_sample factor = 1.0f / (audio_sample) 0x80000000ul;
|
|
|
121 for(size_t walk = 0; walk < count; ++walk) {
|
|
|
122 uint32_t v = *inPtr++;
|
|
|
123 if (byteSwap) v = pfc::byteswap_t(v);
|
|
|
124 if (!isSigned) v ^= 0x80000000u; // to signed
|
|
|
125 *out++ = (audio_sample) (int32_t) v * factor;
|
|
|
126 }
|
|
|
127 }
|
|
|
128
|
|
|
129 template<bool byteSwap, bool isSigned> static void _import24any(const void * in, audio_sample * out, size_t count) {
|
|
|
130 uint8_t const * inPtr = (uint8_t const*) in;
|
|
|
131 const audio_sample factor = 1.0f / (audio_sample) 0x800000;
|
|
|
132 for(size_t walk = 0; walk < count; ++walk) {
|
|
|
133 uint32_t v;
|
|
|
134 if (byteSwap) v = (uint32_t) inPtr[2] | ( (uint32_t) inPtr[1] << 8 ) | ( (uint32_t) inPtr[0] << 16 );
|
|
|
135 else v = (uint32_t) inPtr[0] | ( (uint32_t) inPtr[1] << 8 ) | ( (uint32_t) inPtr[2] << 16 );
|
|
|
136 inPtr += 3;
|
|
|
137 if (isSigned) v ^= 0x800000; // to unsigned
|
|
|
138 v -= 0x800000; // then subtract to get proper MSBs
|
|
|
139 *out++ = (audio_sample) (int32_t) v * factor;
|
|
|
140 }
|
|
|
141 }
|
|
|
142
|
|
|
143 void audio_chunk::set_data_fixedpoint_ex(const void * source,t_size size,unsigned srate,unsigned nch,unsigned bps,unsigned flags,unsigned p_channel_config)
|
|
|
144 {
|
|
|
145 PFC_ASSERT( check_exclusive(flags,FLAG_SIGNED|FLAG_UNSIGNED) );
|
|
|
146 PFC_ASSERT( check_exclusive(flags,FLAG_LITTLE_ENDIAN|FLAG_BIG_ENDIAN) );
|
|
|
147
|
|
|
148 bool byteSwap = !!(flags & FLAG_BIG_ENDIAN);
|
|
|
149 if (pfc::byte_order_is_big_endian) byteSwap = !byteSwap;
|
|
|
150
|
|
|
151 t_size count = size / (bps/8);
|
|
|
152 set_data_size(count);
|
|
|
153 audio_sample * buffer = get_data();
|
|
|
154 bool isSigned = !!(flags & FLAG_SIGNED);
|
|
|
155
|
|
|
156 switch(bps)
|
|
|
157 {
|
|
|
158 case 8:
|
|
|
159 // byte order irrelevant
|
|
|
160 if (isSigned) _import8s( (const uint8_t*) source , buffer, count);
|
|
|
161 else _import8u( (const uint8_t*) source , buffer, count);
|
|
|
162 break;
|
|
|
163 case 16:
|
|
|
164 if (byteSwap) {
|
|
|
165 if (isSigned) {
|
|
|
166 _import16any<true, true>( source, buffer, count );
|
|
|
167 } else {
|
|
|
168 _import16any<true, false>( source, buffer, count );
|
|
|
169 }
|
|
|
170 } else {
|
|
|
171 if (isSigned) {
|
|
|
172 //_import16any<false, true>( source, buffer, count );
|
|
|
173 audio_math::convert_from_int16((const int16_t*)source,count,buffer,1.0);
|
|
|
174 } else {
|
|
|
175 _import16any<false, false>( source, buffer, count);
|
|
|
176 }
|
|
|
177 }
|
|
|
178 break;
|
|
|
179 case 24:
|
|
|
180 if (byteSwap) {
|
|
|
181 if (isSigned) {
|
|
|
182 _import24any<true, true>( source, buffer, count );
|
|
|
183 } else {
|
|
|
184 _import24any<true, false>( source, buffer, count );
|
|
|
185 }
|
|
|
186 } else {
|
|
|
187 if (isSigned) {
|
|
|
188 //_import24any<false, true>( source, buffer, count);
|
|
|
189 _import24( source, buffer, count);
|
|
|
190 } else {
|
|
|
191 _import24any<false, false>( source, buffer, count);
|
|
|
192 }
|
|
|
193 }
|
|
|
194 break;
|
|
|
195 case 32:
|
|
|
196 if (byteSwap) {
|
|
|
197 if (isSigned) {
|
|
|
198 _import32any<true, true>( source, buffer, count );
|
|
|
199 } else {
|
|
|
200 _import32any<true, false>( source, buffer, count );
|
|
|
201 }
|
|
|
202 } else {
|
|
|
203 if (isSigned) {
|
|
|
204 audio_math::convert_from_int32((const int32_t*)source,count,buffer,1.0);
|
|
|
205 } else {
|
|
|
206 _import32any<false, false>( source, buffer, count);
|
|
|
207 }
|
|
|
208 }
|
|
|
209 break;
|
|
|
210 default:
|
|
|
211 //unknown size, cant convert
|
|
|
212 pfc::memset_t(buffer,(audio_sample)0,count);
|
|
|
213 break;
|
|
|
214 }
|
|
|
215 set_sample_count(count/nch);
|
|
|
216 set_srate(srate);
|
|
|
217 set_channels(nch,p_channel_config);
|
|
|
218 }
|
|
|
219
|
|
|
220 void audio_chunk::set_data_fixedpoint_ms(const void * ptr, size_t bytes, unsigned sampleRate, unsigned channels, unsigned bps, unsigned channelConfig) {
|
|
|
221 //set_data_fixedpoint_ex(ptr,bytes,sampleRate,channels,bps,(bps==8 ? FLAG_UNSIGNED : FLAG_SIGNED) | flags_autoendian(), channelConfig);
|
|
|
222 PFC_ASSERT( bps != 0 );
|
|
|
223 size_t count = bytes / (bps/8);
|
|
|
224 this->set_data_size( count );
|
|
|
225 audio_sample * buffer = this->get_data();
|
|
|
226 switch(bps) {
|
|
|
227 case 8:
|
|
|
228 _import8u((const uint8_t*)ptr, buffer, count);
|
|
|
229 break;
|
|
|
230 case 16:
|
|
|
231 audio_math::convert_from_int16((const int16_t*) ptr, count, buffer, 1.0);
|
|
|
232 break;
|
|
|
233 case 24:
|
|
|
234 _import24( ptr, buffer, count);
|
|
|
235 break;
|
|
|
236 case 32:
|
|
|
237 audio_math::convert_from_int32((const int32_t*) ptr, count, buffer, 1.0);
|
|
|
238 break;
|
|
|
239 default:
|
|
|
240 PFC_ASSERT(!"Unknown bit depth!");
|
|
|
241 memset(buffer, 0, sizeof(audio_sample) * count);
|
|
|
242 break;
|
|
|
243 }
|
|
|
244 set_sample_count(count/channels);
|
|
|
245 set_srate(sampleRate);
|
|
|
246 set_channels(channels,channelConfig);
|
|
|
247 }
|
|
|
248
|
|
|
249 void audio_chunk::set_data_fixedpoint_signed(const void * ptr,t_size bytes,unsigned sampleRate,unsigned channels,unsigned bps,unsigned channelConfig) {
|
|
|
250 PFC_ASSERT( bps != 0 );
|
|
|
251 size_t count = bytes / (bps/8);
|
|
|
252 this->set_data_size( count );
|
|
|
253 audio_sample * buffer = this->get_data();
|
|
|
254 switch(bps) {
|
|
|
255 case 8:
|
|
|
256 _import8s((const uint8_t*)ptr, buffer, count);
|
|
|
257 break;
|
|
|
258 case 16:
|
|
|
259 audio_math::convert_from_int16((const int16_t*) ptr, count, buffer, 1.0);
|
|
|
260 break;
|
|
|
261 case 24:
|
|
|
262 _import24( ptr, buffer, count);
|
|
|
263 break;
|
|
|
264 case 32:
|
|
|
265 audio_math::convert_from_int32((const int32_t*) ptr, count, buffer, 1.0);
|
|
|
266 break;
|
|
|
267 default:
|
|
|
268 PFC_ASSERT(!"Unknown bit depth!");
|
|
|
269 memset(buffer, 0, sizeof(audio_sample) * count);
|
|
|
270 break;
|
|
|
271 }
|
|
|
272 set_sample_count(count/channels);
|
|
|
273 set_srate(sampleRate);
|
|
|
274 set_channels(channels,channelConfig);
|
|
|
275 }
|
|
|
276
|
|
|
277 void audio_chunk::set_data_int16(const int16_t * src,t_size samples,unsigned nch,unsigned srate,unsigned channel_config) {
|
|
|
278 const size_t count = samples * nch;
|
|
|
279 this->set_data_size( count );
|
|
|
280 audio_sample * buffer = this->get_data();
|
|
|
281 audio_math::convert_from_int16(src, count, buffer, 1.0);
|
|
|
282 set_sample_count(samples);
|
|
|
283 set_srate(srate);
|
|
|
284 set_channels(nch,channel_config);
|
|
|
285 }
|
|
|
286
|
|
|
287 template<class t_float>
|
|
|
288 static void process_float_multi(audio_sample * p_out,const t_float * p_in,const t_size p_count)
|
|
|
289 {
|
|
|
290 audio_math::convert(p_in, p_out, p_count);
|
|
|
291 }
|
|
|
292
|
|
|
293 template<class t_float>
|
|
|
294 static void process_float_multi_swap(audio_sample * p_out,const t_float * p_in,const t_size p_count)
|
|
|
295 {
|
|
|
296 for(size_t n=0;n<p_count;n++) {
|
|
|
297 p_out[n] = (audio_sample) pfc::byteswap_t(p_in[n]);
|
|
|
298 }
|
|
|
299 }
|
|
|
300
|
|
|
301 void audio_chunk::set_data_32(const float* src, size_t samples, spec_t const& spec) {
|
|
|
302 #if audio_sample_size == 32
|
|
|
303 set_data(src, samples, spec);
|
|
|
304 #else
|
|
|
305 t_size size = samples * spec.chanCount;
|
|
|
306 set_data_size(size);
|
|
|
307 if (src)
|
|
|
308 audio_math::convert(src, get_data(), size);
|
|
|
309 else
|
|
|
310 pfc::memset_t(get_data(), (audio_sample)0, size);
|
|
|
311 set_sample_count(samples);
|
|
|
312 set_spec(spec);
|
|
|
313 #endif
|
|
|
314 }
|
|
|
315 void audio_chunk::set_data_32(const float* src, size_t samples, unsigned nch, unsigned srate) {
|
|
|
316 set_data_32(src, samples, makeSpec(srate, nch) );
|
|
|
317 }
|
|
|
318
|
|
|
319 void audio_chunk::set_data_floatingpoint_ex(const void * ptr,t_size size,unsigned srate,unsigned nch,unsigned bps,unsigned flags,unsigned p_channel_config)
|
|
|
320 {
|
|
|
321 PFC_ASSERT(is_supported_floatingpoint(bps));
|
|
|
322 PFC_ASSERT( check_exclusive(flags,FLAG_LITTLE_ENDIAN|FLAG_BIG_ENDIAN) );
|
|
|
323 PFC_ASSERT( ! (flags & (FLAG_SIGNED|FLAG_UNSIGNED) ) );
|
|
|
324
|
|
|
325 bool use_swap = pfc::byte_order_is_big_endian ? !!(flags & FLAG_LITTLE_ENDIAN) : !!(flags & FLAG_BIG_ENDIAN);
|
|
|
326
|
|
|
327 const t_size count = size / (bps/8);
|
|
|
328 set_data_size(count);
|
|
|
329 audio_sample * out = get_data();
|
|
|
330
|
|
|
331 if (bps == 32)
|
|
|
332 {
|
|
|
333 if (use_swap)
|
|
|
334 process_float_multi_swap(out,reinterpret_cast<const float*>(ptr),count);
|
|
|
335 else
|
|
|
336 process_float_multi(out,reinterpret_cast<const float*>(ptr),count);
|
|
|
337 }
|
|
|
338 else if (bps == 64)
|
|
|
339 {
|
|
|
340 if (use_swap)
|
|
|
341 process_float_multi_swap(out,reinterpret_cast<const double*>(ptr),count);
|
|
|
342 else
|
|
|
343 process_float_multi(out,reinterpret_cast<const double*>(ptr),count);
|
|
|
344 } else if (bps == 16) {
|
|
|
345 const uint16_t * in = reinterpret_cast<const uint16_t*>(ptr);
|
|
|
346 if (use_swap) {
|
|
|
347 for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat16(pfc::byteswap_t(in[walk]));
|
|
|
348 } else {
|
|
|
349 for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat16(in[walk]);
|
|
|
350 }
|
|
|
351 } else if (bps == 24) {
|
|
|
352 const uint8_t * in = reinterpret_cast<const uint8_t*>(ptr);
|
|
|
353 if (use_swap) {
|
|
|
354 for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat24ptrbs(&in[walk*3]);
|
|
|
355 } else {
|
|
|
356 for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat24ptr(&in[walk*3]);
|
|
|
357 }
|
|
|
358 } else pfc::throw_exception_with_message< exception_io_data >("invalid bit depth");
|
|
|
359
|
|
|
360 set_sample_count(count/nch);
|
|
|
361 set_srate(srate);
|
|
|
362 set_channels(nch,p_channel_config);
|
|
|
363 }
|
|
|
364
|
|
|
365 pfc::string8 audio_chunk::formatChunkSpec() const {
|
|
|
366 pfc::string8 msg;
|
|
|
367 msg << get_sample_rate() << " Hz, " << get_channels() << ":0x" << pfc::format_hex(get_channel_config(), 2) << " channels, " << get_sample_count() << " samples";
|
|
|
368 return msg;
|
|
|
369 }
|
|
|
370
|
|
|
371 void audio_chunk::debugChunkSpec() const {
|
|
|
372 FB2K_DebugLog() << "Chunk: " << this->formatChunkSpec();
|
|
|
373 }
|
|
|
374
|
|
|
375 #if PFC_DEBUG
|
|
|
376 void audio_chunk::assert_valid(const char * ctx) const {
|
|
|
377 if (!is_valid()) {
|
|
|
378 FB2K_DebugLog() << "audio_chunk::assert_valid failure in " << ctx;
|
|
|
379 debugChunkSpec();
|
|
|
380 uBugCheck();
|
|
|
381 }
|
|
|
382 }
|
|
|
383 #endif
|
|
|
384 bool audio_chunk::is_valid() const
|
|
|
385 {
|
|
|
386 unsigned nch = get_channels();
|
|
|
387 if (nch == 0 || nch > 32) return false;
|
|
|
388 if (!g_is_valid_sample_rate(get_srate())) return false;
|
|
|
389 t_size samples = get_sample_count();
|
|
|
390 if (samples==0 || samples >= 0x80000000ul / (sizeof(audio_sample) * nch) ) return false;
|
|
|
391 t_size size = get_data_size();
|
|
|
392 if (samples * nch > size) return false;
|
|
|
393 if (!get_data()) return false;
|
|
|
394 return true;
|
|
|
395 }
|
|
|
396
|
|
|
397 bool audio_chunk::is_spec_valid() const {
|
|
|
398 return this->get_spec().is_valid();
|
|
|
399 }
|
|
|
400
|
|
|
401 void audio_chunk::pad_with_silence_ex(t_size samples,unsigned hint_nch,unsigned hint_srate) {
|
|
|
402 if (is_empty())
|
|
|
403 {
|
|
|
404 if (hint_srate && hint_nch) {
|
|
|
405 return set_data(0,samples,hint_nch,hint_srate);
|
|
|
406 } else throw exception_io_data();
|
|
|
407 }
|
|
|
408 else
|
|
|
409 {
|
|
|
410 if (hint_srate && hint_srate != get_srate()) samples = MulDiv_Size(samples,get_srate(),hint_srate);
|
|
|
411 if (samples > get_sample_count())
|
|
|
412 {
|
|
|
413 t_size old_size = get_sample_count() * get_channels();
|
|
|
414 t_size new_size = samples * get_channels();
|
|
|
415 set_data_size(new_size);
|
|
|
416 pfc::memset_t(get_data() + old_size,(audio_sample)0,new_size - old_size);
|
|
|
417 set_sample_count(samples);
|
|
|
418 }
|
|
|
419 }
|
|
|
420 }
|
|
|
421
|
|
|
422 void audio_chunk::pad_with_silence(t_size samples) {
|
|
|
423 if (samples > get_sample_count())
|
|
|
424 {
|
|
|
425 t_size old_size = get_sample_count() * get_channels();
|
|
|
426 t_size new_size = pfc::multiply_guarded(samples,(size_t)get_channels());
|
|
|
427 set_data_size(new_size);
|
|
|
428 pfc::memset_t(get_data() + old_size,(audio_sample)0,new_size - old_size);
|
|
|
429 set_sample_count(samples);
|
|
|
430 }
|
|
|
431 }
|
|
|
432
|
|
|
433 void audio_chunk::set_silence(t_size samples) {
|
|
|
434 t_size items = samples * get_channels();
|
|
|
435 set_data_size(items);
|
|
|
436 pfc::memset_null_t(get_data(), items);
|
|
|
437 set_sample_count(samples);
|
|
|
438 }
|
|
|
439
|
|
|
440 void audio_chunk::set_silence_seconds( double seconds ) {
|
|
|
441 set_silence( (size_t) audio_math::time_to_samples( seconds, this->get_sample_rate() ) );
|
|
|
442 }
|
|
|
443
|
|
|
444 void audio_chunk::insert_silence_fromstart(t_size samples) {
|
|
|
445 t_size old_size = get_sample_count() * get_channels();
|
|
|
446 t_size delta = samples * get_channels();
|
|
|
447 t_size new_size = old_size + delta;
|
|
|
448 set_data_size(new_size);
|
|
|
449 audio_sample * ptr = get_data();
|
|
|
450 pfc::memmove_t(ptr+delta,ptr,old_size);
|
|
|
451 pfc::memset_t(ptr,(audio_sample)0,delta);
|
|
|
452 set_sample_count(get_sample_count() + samples);
|
|
|
453 }
|
|
|
454
|
|
|
455 bool audio_chunk::process_skip(double & skipDuration) {
|
|
|
456 t_uint64 skipSamples = audio_math::time_to_samples(skipDuration, get_sample_rate());
|
|
|
457 if (skipSamples == 0) {skipDuration = 0; return true;}
|
|
|
458 const t_size mySamples = get_sample_count();
|
|
|
459 if (skipSamples < mySamples) {
|
|
|
460 skip_first_samples((t_size)skipSamples);
|
|
|
461 skipDuration = 0;
|
|
|
462 return true;
|
|
|
463 }
|
|
|
464 if (skipSamples == mySamples) {
|
|
|
465 skipDuration = 0;
|
|
|
466 return false;
|
|
|
467 }
|
|
|
468 skipDuration -= audio_math::samples_to_time(mySamples, get_sample_rate());
|
|
|
469 return false;
|
|
|
470 }
|
|
|
471
|
|
|
472 t_size audio_chunk::skip_first_samples(t_size samples_delta)
|
|
|
473 {
|
|
|
474 t_size samples_old = get_sample_count();
|
|
|
475 if (samples_delta >= samples_old)
|
|
|
476 {
|
|
|
477 set_sample_count(0);
|
|
|
478 set_data_size(0);
|
|
|
479 return samples_old;
|
|
|
480 }
|
|
|
481 else
|
|
|
482 {
|
|
|
483 t_size samples_new = samples_old - samples_delta;
|
|
|
484 unsigned nch = get_channels();
|
|
|
485 audio_sample * ptr = get_data();
|
|
|
486 pfc::memmove_t(ptr,ptr+nch*samples_delta,nch*samples_new);
|
|
|
487 set_sample_count(samples_new);
|
|
|
488 set_data_size(nch*samples_new);
|
|
|
489 return samples_delta;
|
|
|
490 }
|
|
|
491 }
|
|
|
492
|
|
|
493 audio_sample audio_chunk::get_peak(audio_sample p_peak) const {
|
|
|
494 return pfc::max_t(p_peak, get_peak());
|
|
|
495 }
|
|
|
496
|
|
|
497 audio_sample audio_chunk::get_peak() const {
|
|
|
498 return audio_math::calculate_peak(get_data(),get_sample_count() * get_channels());
|
|
|
499 }
|
|
|
500
|
|
|
501 void audio_chunk::scale(audio_sample p_value)
|
|
|
502 {
|
|
|
503 audio_sample * ptr = get_data();
|
|
|
504 audio_math::scale(ptr,get_sample_count() * get_channels(),ptr,p_value);
|
|
|
505 }
|
|
|
506
|
|
|
507
|
|
|
508 namespace {
|
|
|
509
|
|
|
510 struct sampleToIntDesc {
|
|
|
511 unsigned bps, bpsValid;
|
|
|
512 bool useUpperBits;
|
|
|
513 audio_sample scale;
|
|
|
514 };
|
|
|
515 template<typename int_t> class sampleToInt {
|
|
|
516 public:
|
|
|
517 sampleToInt(sampleToIntDesc const & d) {
|
|
|
518 clipLo = - ( (int_t) 1 << (d.bpsValid-1));
|
|
|
519 clipHi = ( (int_t) 1 << (d.bpsValid-1)) - 1;
|
|
|
520 scale = (float) ( (int64_t) 1 << (d.bpsValid - 1) ) * d.scale;
|
|
|
521 if (d.useUpperBits) {
|
|
|
522 shift = (int8_t)( d.bps - d.bpsValid );
|
|
|
523 } else {
|
|
|
524 shift = 0;
|
|
|
525 }
|
|
|
526 }
|
|
|
527 inline int_t operator() (audio_sample s) const {
|
|
|
528 int_t v;
|
|
|
529 if constexpr (sizeof(int_t) > 4) v = (int_t) audio_math::rint64( s * scale );
|
|
|
530 else v = (int_t)audio_math::rint32( s * scale );
|
|
|
531 return pfc::clip_t<int_t>( v, clipLo, clipHi) << shift;
|
|
|
532 }
|
|
|
533 private:
|
|
|
534 int_t clipLo, clipHi;
|
|
|
535 int8_t shift;
|
|
|
536 audio_sample scale;
|
|
|
537 };
|
|
|
538 }
|
|
|
539 static void render_24bit(const audio_sample * in, t_size inLen, void * out, sampleToIntDesc const & d) {
|
|
|
540 t_uint8 * outWalk = reinterpret_cast<t_uint8*>(out);
|
|
|
541 sampleToInt<int32_t> gen(d);
|
|
|
542 for(t_size walk = 0; walk < inLen; ++walk) {
|
|
|
543 int32_t v = gen(in[walk]);
|
|
|
544 *(outWalk ++) = (t_uint8) (v & 0xFF);
|
|
|
545 *(outWalk ++) = (t_uint8) ((v >> 8) & 0xFF);
|
|
|
546 *(outWalk ++) = (t_uint8) ((v >> 16) & 0xFF);
|
|
|
547 }
|
|
|
548 }
|
|
|
549 static void render_8bit(const audio_sample * in, t_size inLen, void * out, sampleToIntDesc const & d) {
|
|
|
550 sampleToInt<int32_t> gen(d);
|
|
|
551 t_int8 * outWalk = reinterpret_cast<t_int8*>(out);
|
|
|
552 for(t_size walk = 0; walk < inLen; ++walk) {
|
|
|
553 *outWalk++ = (t_int8)gen(in[walk]);
|
|
|
554 }
|
|
|
555 }
|
|
|
556 static void render_16bit(const audio_sample * in, t_size inLen, void * out, sampleToIntDesc const & d) {
|
|
|
557 sampleToInt<int32_t> gen(d);
|
|
|
558 int16_t * outWalk = reinterpret_cast<int16_t*>(out);
|
|
|
559 for(t_size walk = 0; walk < inLen; ++walk) {
|
|
|
560 *outWalk++ = (int16_t)gen(in[walk]);
|
|
|
561 }
|
|
|
562 }
|
|
|
563
|
|
|
564 template<typename internal_t>
|
|
|
565 static void render_32bit_(const audio_sample * in, t_size inLen, void * out, sampleToIntDesc const & d) {
|
|
|
566 sampleToInt<internal_t> gen(d); // must use int64 for clipping
|
|
|
567 int32_t * outWalk = reinterpret_cast<int32_t*>(out);
|
|
|
568 for(t_size walk = 0; walk < inLen; ++walk) {
|
|
|
569 *outWalk++ = (int32_t)gen(in[walk]);
|
|
|
570 }
|
|
|
571 }
|
|
|
572
|
|
|
573 bool audio_chunk::g_toFixedPoint(const audio_sample * in, void * out, size_t count, uint32_t bps, uint32_t bpsValid, bool useUpperBits, audio_sample scale) {
|
|
|
574 const sampleToIntDesc d = {bps, bpsValid, useUpperBits, scale};
|
|
|
575 if (bps == 0) {
|
|
|
576 PFC_ASSERT(!"How did we get here?");
|
|
|
577 return false;
|
|
|
578 } else if (bps <= 8) {
|
|
|
579 render_8bit(in, count, out, d);
|
|
|
580 } else if (bps <= 16) {
|
|
|
581 render_16bit(in, count, out, d);
|
|
|
582 } else if (bps <= 24) {
|
|
|
583 render_24bit(in, count, out, d);
|
|
|
584 } else if (bps <= 32) {
|
|
|
585 if (bpsValid <= 28) { // for speed
|
|
|
586 render_32bit_<int32_t>(in, count, out, d);
|
|
|
587 } else {
|
|
|
588 render_32bit_<int64_t>(in, count, out, d);
|
|
|
589 }
|
|
|
590 } else {
|
|
|
591 PFC_ASSERT(!"How did we get here?");
|
|
|
592 return false;
|
|
|
593 }
|
|
|
594
|
|
|
595 return true;
|
|
|
596 }
|
|
|
597
|
|
|
598 bool audio_chunk::toFixedPoint(class mem_block_container & out, uint32_t bps, uint32_t bpsValid, bool useUpperBits, audio_sample scale) const {
|
|
|
599 bps = (bps + 7) & ~7;
|
|
|
600 if (bps < bpsValid) return false;
|
|
|
601 const size_t count = get_sample_count() * get_channel_count();
|
|
|
602 out.set_size( count * (bps/8) );
|
|
|
603 return g_toFixedPoint(get_data(), out.get_ptr(), count, bps, bpsValid, useUpperBits, scale);
|
|
|
604 }
|
|
|
605
|
|
|
606 bool audio_chunk::to_raw_data(mem_block_container & out, t_uint32 bps, bool useUpperBits, audio_sample scale) const {
|
|
|
607 uint32_t bpsValid = bps;
|
|
|
608 bps = (bps + 7) & ~7;
|
|
|
609 const size_t count = get_sample_count() * get_channel_count();
|
|
|
610 out.set_size( count * (bps/8) );
|
|
|
611 void * outPtr = out.get_ptr();
|
|
|
612 audio_sample const * inPtr = get_data();
|
|
|
613 if (bps == 32) {
|
|
|
614 float * f = (float*) outPtr;
|
|
|
615 audio_math::convert(inPtr, f, count, scale);
|
|
|
616 return true;
|
|
|
617 } else {
|
|
|
618 return g_toFixedPoint(inPtr, outPtr, count, bps, bpsValid, useUpperBits, scale);
|
|
|
619 }
|
|
|
620 }
|
|
|
621
|
|
|
622 audio_chunk::spec_t audio_chunk::makeSpec(uint32_t rate, uint32_t channels) {
|
|
|
623 return makeSpec( rate, channels, g_guess_channel_config(channels) );
|
|
|
624 }
|
|
|
625
|
|
|
626 audio_chunk::spec_t audio_chunk::makeSpec(uint32_t rate, uint32_t channels, uint32_t mask) {
|
|
|
627 PFC_ASSERT(mask == 0 || pfc::countBits32(mask) == channels);
|
|
|
628 spec_t spec = {};
|
|
|
629 spec.sampleRate = rate; spec.chanCount = channels; spec.chanMask = mask;
|
|
|
630 return spec;
|
|
|
631 }
|
|
|
632
|
|
|
633 bool audio_chunk::spec_t::equals( const spec_t & v1, const spec_t & v2 ) {
|
|
|
634 return v1.sampleRate == v2.sampleRate && v1.chanCount == v2.chanCount && v1.chanMask == v2.chanMask;
|
|
|
635 }
|
|
|
636
|
|
|
637 pfc::string8 audio_chunk::spec_t::toString(const char * delim) const {
|
|
|
638 pfc::string_formatter temp;
|
|
|
639 if ( sampleRate > 0 ) temp << sampleRate << "Hz";
|
|
|
640 if (chanCount > 0) {
|
|
|
641 if ( temp.length() > 0 ) temp << delim;
|
|
|
642 temp << chanCount << "ch";
|
|
|
643 }
|
|
|
644
|
|
|
645 if ( chanMask != audio_chunk::channel_config_mono && chanMask != audio_chunk::channel_config_stereo ) {
|
|
|
646 pfc::string8 strMask;
|
|
|
647 audio_chunk::g_formatChannelMaskDesc( chanMask, strMask );
|
|
|
648 if ( temp.length() > 0) temp << delim;
|
|
|
649 temp << strMask;
|
|
|
650 }
|
|
|
651 return temp;
|
|
|
652 }
|
|
|
653
|
|
|
654 audio_chunk::spec_t audio_chunk::get_spec() const {
|
|
|
655 spec_t spec = {};
|
|
|
656 spec.sampleRate = this->get_sample_rate();
|
|
|
657 spec.chanCount = this->get_channel_count();
|
|
|
658 spec.chanMask = this->get_channel_config();
|
|
|
659 return spec;
|
|
|
660 }
|
|
|
661 void audio_chunk::set_spec(const spec_t & spec) {
|
|
|
662 set_sample_rate(spec.sampleRate);
|
|
|
663 set_channels( spec.chanCount, spec.chanMask );
|
|
|
664 }
|
|
|
665
|
|
|
666 bool audio_chunk::spec_t::is_valid() const {
|
|
|
667 if (this->chanCount==0 || this->chanCount>256) return false;
|
|
|
668 if (!audio_chunk::g_is_valid_sample_rate(this->sampleRate)) return false;
|
|
|
669 return true;
|
|
|
670 }
|
|
|
671
|
|
|
672 #ifdef _WIN32
|
|
|
673
|
|
|
674 WAVEFORMATEX audio_chunk::spec_t::toWFX() const {
|
|
|
675 const uint32_t sampleWidth = sizeof(audio_sample);
|
|
|
676
|
|
|
677 WAVEFORMATEX wfx = {};
|
|
|
678 wfx.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
|
|
679 wfx.nChannels = (WORD) chanCount;
|
|
|
680 wfx.nSamplesPerSec = sampleRate;
|
|
|
681 wfx.nAvgBytesPerSec = sampleRate * chanCount * sampleWidth;
|
|
|
682 wfx.nBlockAlign = (WORD)( chanCount * sampleWidth );
|
|
|
683 wfx.wBitsPerSample = sampleWidth * 8;
|
|
|
684 return wfx;
|
|
|
685 }
|
|
|
686
|
|
|
687 WAVEFORMATEXTENSIBLE audio_chunk::spec_t::toWFXEX() const {
|
|
|
688 const uint32_t sampleWidth = sizeof(audio_sample);
|
|
|
689 const bool isFloat = true;
|
|
|
690
|
|
|
691 WAVEFORMATEXTENSIBLE wfxe;
|
|
|
692 wfxe.Format = toWFX();
|
|
|
693 wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
|
|
694 wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfxe.Format);
|
|
|
695 wfxe.Samples.wValidBitsPerSample = sampleWidth * 8;
|
|
|
696 wfxe.dwChannelMask = audio_chunk::g_channel_config_to_wfx(this->chanMask);
|
|
|
697 wfxe.SubFormat = isFloat ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
|
|
|
698
|
|
|
699 return wfxe;
|
|
|
700 }
|
|
|
701
|
|
|
702 WAVEFORMATEX audio_chunk::spec_t::toWFXWithBPS(uint32_t bps) const {
|
|
|
703 const uint32_t sampleWidth = (bps+7)/8;
|
|
|
704
|
|
|
705 WAVEFORMATEX wfx = {};
|
|
|
706 wfx.wFormatTag = WAVE_FORMAT_PCM;
|
|
|
707 wfx.nChannels = (WORD)chanCount;
|
|
|
708 wfx.nSamplesPerSec = sampleRate;
|
|
|
709 wfx.nAvgBytesPerSec = sampleRate * chanCount * sampleWidth;
|
|
|
710 wfx.nBlockAlign = (WORD)( chanCount * sampleWidth );
|
|
|
711 wfx.wBitsPerSample = (WORD)( sampleWidth * 8 );
|
|
|
712 return wfx;
|
|
|
713 }
|
|
|
714
|
|
|
715 WAVEFORMATEXTENSIBLE audio_chunk::spec_t::toWFXEXWithBPS(uint32_t bps) const {
|
|
|
716 const uint32_t sampleWidth = (bps + 7) / 8;
|
|
|
717 const bool isFloat = false;
|
|
|
718
|
|
|
719 WAVEFORMATEXTENSIBLE wfxe;
|
|
|
720 wfxe.Format = toWFXWithBPS(bps);
|
|
|
721 wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
|
|
722 wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfxe.Format);
|
|
|
723 wfxe.Samples.wValidBitsPerSample = (WORD)( sampleWidth * 8 );
|
|
|
724 wfxe.dwChannelMask = audio_chunk::g_channel_config_to_wfx(this->chanMask);
|
|
|
725 wfxe.SubFormat = isFloat ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
|
|
|
726
|
|
|
727 return wfxe;
|
|
|
728 }
|
|
|
729 #endif // _WIN32
|
|
|
730
|
|
|
731 void audio_chunk::append(const audio_chunk& other) {
|
|
|
732 if (other.get_spec() != this->get_spec()) {
|
|
|
733 throw pfc::exception_invalid_params();
|
|
|
734 }
|
|
|
735
|
|
|
736 this->grow_data_size(get_used_size() + other.get_used_size());
|
|
|
737 audio_sample* p = this->get_data() + get_used_size();
|
|
|
738 memcpy(p, other.get_data(), other.get_used_size() * sizeof(audio_sample));
|
|
|
739 set_sample_count(get_sample_count() + other.get_sample_count());
|
|
|
740 }
|