comparison foosdk/sdk/foobar2000/SDK/audio_chunk.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
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 }