← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
audio_kernels.c
Go to the documentation of this file.
1/**
2 * @file audio_kernels.c
3 * @brief Numerically explicit audio frontend reference kernels.
4 */
5
6#include "ckernel_audio.h"
7#include "ck_threadpool.h"
8
9#include <math.h>
10#include <limits.h>
11#include <stddef.h>
12#include <stdlib.h>
13#include <string.h>
14#if defined(__AVX2__) && defined(__FMA__)
15#include <immintrin.h>
16#endif
17
18#define CK_AUDIO_PI_F 3.14159265358979323846f
19#define CK_AUDIO_PI_D 3.14159265358979323846264338327950288
20
21static int reflect_index(int index, int length)
22{
23 while (index < 0 || index >= length) {
24 if (index < 0) {
25 index = -index;
26 } else {
27 index = 2 * length - index - 2;
28 }
29 }
30 return index;
31}
32
33static uint16_t read_u16_le(const uint8_t *p)
34{
35 return (uint16_t)p[0] | ((uint16_t)p[1] << 8);
36}
37
38static uint32_t read_u32_le(const uint8_t *p)
39{
40 return (uint32_t)p[0] | ((uint32_t)p[1] << 8) |
41 ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
42}
43
45 const uint8_t *bytes,
46 size_t byte_count,
47 CKAudioWavInfo *info)
48{
49 if (bytes == NULL || info == NULL) {
50 return -1;
51 }
52 if (byte_count < 12 || memcmp(bytes, "RIFF", 4) != 0 ||
53 memcmp(bytes + 8, "WAVE", 4) != 0) {
54 return -2;
55 }
56 const size_t riff_end = (size_t)read_u32_le(bytes + 4) + 8u;
57 if (riff_end < 12 || riff_end > byte_count) {
58 return -3;
59 }
60 memset(info, 0, sizeof(*info));
61 int found_format = 0;
62 int found_data = 0;
63 size_t offset = 12;
64 while (offset + 8 <= riff_end) {
65 const uint8_t *chunk = bytes + offset;
66 const uint32_t chunk_bytes = read_u32_le(chunk + 4);
67 const size_t payload = offset + 8;
68 if ((size_t)chunk_bytes > riff_end - payload) {
69 return -3;
70 }
71 if (!found_format && memcmp(chunk, "fmt ", 4) == 0) {
72 if (chunk_bytes < 16) {
73 return -4;
74 }
75 info->format_tag = (int)read_u16_le(bytes + payload);
76 info->channels = (int)read_u16_le(bytes + payload + 2);
77 info->sample_rate = (int)read_u32_le(bytes + payload + 4);
78 info->bits_per_sample = (int)read_u16_le(bytes + payload + 14);
79 found_format = 1;
80 } else if (!found_data && memcmp(chunk, "data", 4) == 0) {
81 info->data_offset = payload;
82 info->data_bytes = chunk_bytes;
83 found_data = 1;
84 }
85 const size_t padded = (size_t)chunk_bytes + ((size_t)chunk_bytes & 1u);
86 if (padded > SIZE_MAX - payload) {
87 return -3;
88 }
89 offset = payload + padded;
90 }
91 if (!found_format || !found_data || info->format_tag != 1 ||
92 info->channels <= 0 || info->sample_rate <= 0 ||
93 info->bits_per_sample != 16) {
94 return -5;
95 }
96 const size_t bytes_per_frame = (size_t)info->channels * 2u;
97 if (bytes_per_frame == 0 || info->data_bytes % bytes_per_frame != 0 ||
98 info->data_bytes / bytes_per_frame > (size_t)INT_MAX) {
99 return -6;
100 }
101 info->frames = (int)(info->data_bytes / bytes_per_frame);
102 return info->frames > 0 ? 0 : -6;
103}
104
106 const uint8_t *bytes,
107 size_t byte_count,
108 const CKAudioWavInfo *info,
109 float *mono,
110 int mono_capacity)
111{
112 if (bytes == NULL || info == NULL || mono == NULL) {
113 return -1;
114 }
115 if (info->format_tag != 1 || info->bits_per_sample != 16 ||
116 info->channels <= 0 || info->frames <= 0 || mono_capacity < info->frames ||
117 info->data_offset > byte_count || info->data_bytes > byte_count - info->data_offset) {
118 return -2;
119 }
120 const uint8_t *pcm = bytes + info->data_offset;
121 const float scale = 1.0f / 32768.0f;
122 for (int frame = 0; frame < info->frames; ++frame) {
123 float sum = 0.0f;
124 for (int channel = 0; channel < info->channels; ++channel) {
125 const size_t index = ((size_t)frame * info->channels + channel) * 2u;
126 sum += (float)(int16_t)read_u16_le(pcm + index);
127 }
128 mono[frame] = (sum / (float)info->channels) * scale;
129 }
130 return info->frames;
131}
132
134 const uint8_t *bytes,
135 size_t byte_count,
136 float *mono,
137 int mono_capacity,
138 CKAudioWavInfo *info)
139{
141 bytes, byte_count, 0, mono, mono_capacity, info);
142}
143
145 const uint8_t *bytes,
146 size_t byte_count,
147 int start_frame,
148 float *mono,
149 int mono_capacity,
150 CKAudioWavInfo *info)
151{
152 const int status = audio_wav_parse_memory(bytes, byte_count, info);
153 if (status != 0) {
154 return status;
155 }
156 if (start_frame < 0 || start_frame >= info->frames || mono_capacity <= 0) {
157 return -7;
158 }
159 const int available = info->frames - start_frame;
160 const int decoded = available < mono_capacity ? available : mono_capacity;
161 const uint8_t *pcm = bytes + info->data_offset;
162 const float scale = 1.0f / 32768.0f;
163 for (int frame = 0; frame < decoded; ++frame) {
164 float sum = 0.0f;
165 const size_t source_frame = (size_t)start_frame + (size_t)frame;
166 for (int channel = 0; channel < info->channels; ++channel) {
167 const size_t index =
168 (source_frame * (size_t)info->channels + (size_t)channel) * 2u;
169 sum += (float)(int16_t)read_u16_le(pcm + index);
170 }
171 mono[frame] = (sum / (float)info->channels) * scale;
172 }
173 return decoded;
174}
175
177 const int16_t *interleaved,
178 int n_frames,
179 int n_channels,
180 float *mono)
181{
182 if (interleaved == NULL || mono == NULL) {
183 return -1;
184 }
185 if (n_frames <= 0 || n_channels <= 0) {
186 return -2;
187 }
188 const float scale = 1.0f / 32768.0f;
189 for (int frame = 0; frame < n_frames; ++frame) {
190 float sum = 0.0f;
191 for (int channel = 0; channel < n_channels; ++channel) {
192 sum += (float)interleaved[(size_t)frame * n_channels + channel];
193 }
194 mono[frame] = (sum / (float)n_channels) * scale;
195 }
196 return 0;
197}
198
200 int input_frames,
201 int input_rate,
202 int output_rate)
203{
204 if (input_frames <= 0 || input_rate <= 0 || output_rate <= 0) {
205 return -1;
206 }
207 return 1 + (int)(((long long)(input_frames - 1) * output_rate) / input_rate);
208}
209
211 const float *input,
212 int input_frames,
213 int input_rate,
214 float *output,
215 int output_frames,
216 int output_rate)
217{
218 if (input == NULL || output == NULL) {
219 return -1;
220 }
221 const int expected = audio_resampled_frame_count(input_frames, input_rate, output_rate);
222 if (expected <= 0 || output_frames != expected) {
223 return -2;
224 }
225 for (int frame = 0; frame < output_frames; ++frame) {
226 const long long numerator = (long long)frame * input_rate;
227 const int left = (int)(numerator / output_rate);
228 const int right = left + 1 < input_frames ? left + 1 : left;
229 const float fraction = (float)(numerator % output_rate) / (float)output_rate;
230 output[frame] = fmaf(input[right] - input[left], fraction, input[left]);
231 }
232 return 0;
233}
234
236 const float *input,
237 int input_frames,
238 int input_rate,
239 float *output,
240 int output_frames,
241 int output_rate,
242 int radius)
243{
244 if (input == NULL || output == NULL) {
245 return -1;
246 }
247 const int expected = audio_resampled_frame_count(input_frames, input_rate, output_rate);
248 if (expected <= 0 || output_frames != expected || radius < 2 || radius > 128) {
249 return -2;
250 }
251 const double ratio = (double)output_rate / (double)input_rate;
252 const double cutoff = ratio < 1.0 ? ratio : 1.0;
253 for (int frame = 0; frame < output_frames; ++frame) {
254 const double source = (double)frame * (double)input_rate / (double)output_rate;
255 const int center = (int)floor(source);
256 double weighted = 0.0;
257 double weight_sum = 0.0;
258 for (int tap = center - radius + 1; tap <= center + radius; ++tap) {
259 if (tap < 0 || tap >= input_frames) {
260 continue;
261 }
262 const double distance = source - (double)tap;
263 const double scaled = cutoff * distance;
264 const double sinc = fabs(scaled) < 1.0e-12 ? 1.0 :
265 sin(CK_AUDIO_PI_D * scaled) / (CK_AUDIO_PI_D * scaled);
266 const double window_x = distance / (double)radius;
267 if (fabs(window_x) >= 1.0) {
268 continue;
269 }
270 const double window = 0.5 * (1.0 + cos(CK_AUDIO_PI_D * window_x));
271 const double weight = cutoff * sinc * window;
272 weighted += (double)input[tap] * weight;
273 weight_sum += weight;
274 }
275 output[frame] = weight_sum != 0.0 ? (float)(weighted / weight_sum) : 0.0f;
276 }
277 return 0;
278}
279
281 const float *input,
282 int input_frames,
283 float *output,
284 int output_frames)
285{
286 if (input == NULL || output == NULL) {
287 return -1;
288 }
289 if (input_frames <= 0 || output_frames <= 0) {
290 return -2;
291 }
292 const int copied = input_frames < output_frames ? input_frames : output_frames;
293 memmove(output, input, (size_t)copied * sizeof(float));
294 if (copied < output_frames) {
295 memset(
296 output + copied,
297 0,
298 (size_t)(output_frames - copied) * sizeof(float));
299 }
300 return copied;
301}
302
304 const float *input,
305 float *output,
306 int frames,
307 float coefficient)
308{
309 if (input == NULL || output == NULL) {
310 return -1;
311 }
312 if (frames <= 0 || !isfinite(coefficient)) {
313 return -2;
314 }
315 if (input == output) {
316 for (int frame = frames - 1; frame > 0; --frame) {
317 output[frame] = input[frame] - coefficient * input[frame - 1];
318 }
319 } else {
320 output[0] = input[0];
321 for (int frame = 1; frame < frames; ++frame) {
322 output[frame] = input[frame] - coefficient * input[frame - 1];
323 }
324 }
325 return 0;
326}
327
329 const float *input,
330 float *output,
331 int channels,
332 int frames,
333 float epsilon)
334{
335 if (input == NULL || output == NULL) {
336 return -1;
337 }
338 if (channels <= 0 || frames <= 0 || !isfinite(epsilon) || epsilon < 0.0f) {
339 return -2;
340 }
341 const int denominator = frames > 1 ? frames - 1 : 1;
342 for (int channel = 0; channel < channels; ++channel) {
343 double sum = 0.0;
344 double sum_squared_difference = 0.0;
345 for (int frame = 0; frame < frames; ++frame) {
346 sum += (double)input[(size_t)frame * channels + channel];
347 }
348 const double mean = sum / (double)frames;
349 for (int frame = 0; frame < frames; ++frame) {
350 const double difference =
351 (double)input[(size_t)frame * channels + channel] - mean;
352 sum_squared_difference += difference * difference;
353 }
354 float standard_deviation = sqrtf(
355 (float)(sum_squared_difference / (double)denominator));
356 if (isnan(standard_deviation)) {
357 standard_deviation = 0.0f;
358 }
359 const float inverse_standard_deviation =
360 1.0f / (standard_deviation + epsilon);
361 for (int frame = 0; frame < frames; ++frame) {
362 const size_t index = (size_t)frame * channels + channel;
363 output[index] = (float)((double)input[index] - mean) *
364 inverse_standard_deviation;
365 }
366 }
367 return 0;
368}
369
371 int n_fft,
372 float *window,
373 float *cos_table,
374 float *sin_table)
375{
376 if (window == NULL || cos_table == NULL || sin_table == NULL) {
377 return -1;
378 }
379 if (n_fft <= 0 || (n_fft & 1) != 0) {
380 return -2;
381 }
382 const int bins = n_fft / 2 + 1;
383 for (int sample = 0; sample < n_fft; ++sample) {
384 window[sample] = 0.5f - 0.5f * cosf(
385 2.0f * CK_AUDIO_PI_F * (float)sample / (float)n_fft);
386 }
387 for (int bin = 0; bin < bins; ++bin) {
388 for (int sample = 0; sample < n_fft; ++sample) {
389 const float angle = -2.0f * CK_AUDIO_PI_F *
390 (float)(bin * sample) / (float)n_fft;
391 const size_t index = (size_t)bin * n_fft + sample;
392 cos_table[index] = cosf(angle);
393 sin_table[index] = sinf(angle);
394 }
395 }
396 return 0;
397}
398
399static double audio_hz_to_mel_slaney(double hz)
400{
401 if (hz < 1000.0) {
402 return hz / (200.0 / 3.0);
403 }
404 return 15.0 + log(hz / 1000.0) / (log(6.4) / 27.0);
405}
406
407static double audio_mel_to_hz_slaney(double mel)
408{
409 if (mel < 15.0) {
410 return (200.0 / 3.0) * mel;
411 }
412 return 1000.0 * exp((log(6.4) / 27.0) * (mel - 15.0));
413}
414
416 int sample_rate,
417 int n_fft,
418 int n_mels,
419 float *mel_filters)
420{
421 if (mel_filters == NULL) {
422 return -1;
423 }
424 if (sample_rate <= 0 || n_fft <= 0 || (n_fft & 1) != 0 || n_mels <= 0) {
425 return -2;
426 }
427 const int bins = n_fft / 2 + 1;
428 const double mel_min = audio_hz_to_mel_slaney(0.0);
429 const double mel_max = audio_hz_to_mel_slaney((double)sample_rate / 2.0);
430 for (int mel = 0; mel < n_mels; ++mel) {
431 const double left_mel =
432 mel_min + (mel_max - mel_min) * (double)mel / (double)(n_mels + 1);
433 const double center_mel =
434 mel_min + (mel_max - mel_min) * (double)(mel + 1) / (double)(n_mels + 1);
435 const double right_mel =
436 mel_min + (mel_max - mel_min) * (double)(mel + 2) / (double)(n_mels + 1);
437 const double left = audio_mel_to_hz_slaney(left_mel);
438 const double center = audio_mel_to_hz_slaney(center_mel);
439 const double right = audio_mel_to_hz_slaney(right_mel);
440 const double normalization = 2.0 / (right - left);
441 for (int bin = 0; bin < bins; ++bin) {
442 const double hz =
443 ((double)sample_rate / 2.0) * (double)bin / (double)(bins - 1);
444 const double lower = (hz - left) / (center - left);
445 const double upper = (right - hz) / (right - center);
446 const double triangle = fmax(0.0, fmin(lower, upper));
447 mel_filters[(size_t)mel * bins + bin] =
448 (float)(triangle * normalization);
449 }
450 }
451 return 0;
452}
453
455 const float *samples,
456 int n_samples,
457 const float *window,
458 const float *cos_table,
459 const float *sin_table,
460 int n_fft,
461 int hop_length,
462 float *power,
463 int n_frames)
464{
465 if (samples == NULL || window == NULL || cos_table == NULL ||
466 sin_table == NULL || power == NULL) {
467 return -1;
468 }
469 if (n_fft <= 0 || hop_length <= 0 || n_samples <= n_fft / 2 ||
470 (n_fft & 1) != 0 || n_frames <= 0) {
471 return -2;
472 }
473 if (n_frames != n_samples / hop_length) {
474 return -3;
475 }
476 const int bins = n_fft / 2 + 1;
477 const int center = n_fft / 2;
478 for (int frame = 0; frame < n_frames; ++frame) {
479 for (int bin = 0; bin < bins; ++bin) {
480 const float *cos_row = cos_table + (size_t)bin * n_fft;
481 const float *sin_row = sin_table + (size_t)bin * n_fft;
482 float real = 0.0f;
483 float imag = 0.0f;
484 for (int sample = 0; sample < n_fft; ++sample) {
485 const int source = reflect_index(
486 frame * hop_length + sample - center, n_samples);
487 const float value = samples[source] * window[sample];
488 real = fmaf(value, cos_row[sample], real);
489 imag = fmaf(value, sin_row[sample], imag);
490 }
491 power[(size_t)frame * bins + bin] =
492 fmaf(real, real, imag * imag);
493 }
494 }
495 return 0;
496}
497
499 const float *samples,
500 int n_samples,
501 const float *window,
502 int window_length,
503 const float *cos_table,
504 const float *sin_table,
505 int n_fft,
506 int hop_length,
507 int reflect_padding,
508 float *power,
509 int n_frames)
510{
511 if (samples == NULL || window == NULL || cos_table == NULL ||
512 sin_table == NULL || power == NULL) {
513 return -1;
514 }
515 if (n_samples <= 0 || window_length <= 0 || n_fft <= 0 ||
516 window_length > n_fft || (n_fft & 1) != 0 || hop_length <= 0 ||
517 n_frames <= 0 || (reflect_padding != 0 && reflect_padding != 1)) {
518 return -2;
519 }
520 if (n_frames != n_samples / hop_length + 1) {
521 return -3;
522 }
523
524 const int bins = n_fft / 2 + 1;
525 const int center = n_fft / 2;
526 const int window_start = (n_fft - window_length) / 2;
527 for (int frame = 0; frame < n_frames; ++frame) {
528 for (int bin = 0; bin < bins; ++bin) {
529 const float *cos_row = cos_table + (size_t)bin * n_fft;
530 const float *sin_row = sin_table + (size_t)bin * n_fft;
531 float real = 0.0f;
532 float imag = 0.0f;
533 for (int sample = 0; sample < window_length; ++sample) {
534 const int fft_sample = window_start + sample;
535 int source = frame * hop_length + fft_sample - center;
536 if (source < 0 || source >= n_samples) {
537 if (!reflect_padding) {
538 continue;
539 }
540 source = reflect_index(source, n_samples);
541 }
542 const float value = samples[source] * window[sample];
543 real = fmaf(value, cos_row[fft_sample], real);
544 imag = fmaf(value, sin_row[fft_sample], imag);
545 }
546 power[(size_t)frame * bins + bin] =
547 fmaf(real, real, imag * imag);
548 }
549 }
550 return 0;
551}
552
554 const float *power,
555 const float *mel_filters,
556 float *log_mel,
557 int frames,
558 int bins,
559 int channels,
560 float epsilon)
561{
562 if (power == NULL || mel_filters == NULL || log_mel == NULL) {
563 return -1;
564 }
565 if (frames <= 0 || bins <= 0 || channels <= 0 || epsilon <= 0.0f) {
566 return -2;
567 }
568 for (int frame = 0; frame < frames; ++frame) {
569 const float *spectrum = power + (size_t)frame * bins;
570 float *output = log_mel + (size_t)frame * channels;
571 for (int channel = 0; channel < channels; ++channel) {
572 const float *filter = mel_filters + (size_t)channel * bins;
573 float sum = 0.0f;
574 for (int bin = 0; bin < bins; ++bin) {
575 sum = fmaf(spectrum[bin], filter[bin], sum);
576 }
577 output[channel] = logf(sum + epsilon);
578 }
579 }
580 return 0;
581}
582
584 const float *samples,
585 int n_samples,
586 int frame,
587 const float *window,
588 const float *cos_table,
589 const float *sin_table,
590 float *power,
591 float *fft_scratch);
592
594 const float *samples,
595 int n_samples,
596 const float *window,
597 const float *cos_table,
598 const float *sin_table,
599 int hop_length,
600 float *power,
601 int n_frames,
602 float *fft_scratch)
603{
604 const int n_fft = CK_AUDIO_WHISPER_N_FFT;
605 if (samples == NULL || window == NULL || cos_table == NULL ||
606 sin_table == NULL || power == NULL || fft_scratch == NULL) {
607 return -1;
608 }
609 if (hop_length != CK_AUDIO_WHISPER_HOP_LENGTH ||
610 n_samples <= n_fft / 2 || n_frames <= 0 ||
611 n_frames != n_samples / hop_length) {
612 return -2;
613 }
614 for (int frame = 0; frame < n_frames; ++frame) {
616 samples,
617 n_samples,
618 frame,
619 window,
620 cos_table,
621 sin_table,
622 power + (size_t)frame * CK_AUDIO_WHISPER_POWER_BINS,
623 fft_scratch);
624 }
625 return 0;
626}
627
629 const float *samples,
630 int n_samples,
631 int frame,
632 const float *window,
633 const float *cos_table,
634 const float *sin_table,
635 float *power,
636 float *fft_scratch)
637{
638 const int radix = 20;
639 const int center = CK_AUDIO_WHISPER_N_FFT / 2;
640 float *stage_real = fft_scratch;
641 float *stage_imag = fft_scratch + CK_AUDIO_WHISPER_N_FFT;
642 for (int p = 0; p < radix; ++p) {
643 for (int k = 0; k < radix; ++k) {
644 float real = 0.0f;
645 float imag = 0.0f;
646 for (int q = 0; q < radix; ++q) {
647 const int sample = p + radix * q;
648 const int source = reflect_index(
649 frame * CK_AUDIO_WHISPER_HOP_LENGTH + sample - center,
650 n_samples);
651 const float value = samples[source] * window[sample];
652 const size_t twiddle =
653 (size_t)k * CK_AUDIO_WHISPER_N_FFT + radix * q;
654 real = fmaf(value, cos_table[twiddle], real);
655 imag = fmaf(value, sin_table[twiddle], imag);
656 }
657 stage_real[p * radix + k] = real;
658 stage_imag[p * radix + k] = imag;
659 }
660 }
661 for (int frequency = 0;
662 frequency < CK_AUDIO_WHISPER_POWER_BINS;
663 ++frequency) {
664 const int k = frequency % radix;
665 float real = 0.0f;
666 float imag = 0.0f;
667 for (int p = 0; p < radix; ++p) {
668 const float a = stage_real[p * radix + k];
669 const float b = stage_imag[p * radix + k];
670 const size_t twiddle =
671 (size_t)frequency * CK_AUDIO_WHISPER_N_FFT + p;
672 const float c = cos_table[twiddle];
673 const float s = sin_table[twiddle];
674 real = fmaf(a, c, fmaf(-b, s, real));
675 imag = fmaf(a, s, fmaf(b, c, imag));
676 }
677 power[frequency] = fmaf(real, real, imag * imag);
678 }
679}
680
682 const uint8_t *bytes,
683 size_t byte_count,
684 int start_frame,
685 int target_sample_rate,
686 const float *window,
687 const float *cos_table,
688 const float *sin_table,
689 const float *mel_filters,
690 int n_mels,
691 int output_frames,
692 float *log_mel)
693{
694 if (bytes == NULL || window == NULL || cos_table == NULL ||
695 sin_table == NULL || mel_filters == NULL || log_mel == NULL) {
696 return -1;
697 }
698 CKAudioWavInfo info;
699 if (audio_wav_parse_memory(bytes, byte_count, &info) != 0 ||
700 info.sample_rate != target_sample_rate ||
701 target_sample_rate != CK_AUDIO_WHISPER_SAMPLE_RATE ||
702 start_frame < 0 ||
703 start_frame % CK_AUDIO_WHISPER_HOP_LENGTH != 0 ||
704 n_mels <= 0 || output_frames <= 0) {
705 return -2;
706 }
707 float *samples = (float *)malloc((size_t)info.frames * sizeof(float));
708 if (samples == NULL) {
709 return -3;
710 }
711 const int decoded = audio_wav_decode_pcm16_mono_f32(
712 bytes, byte_count, &info, samples, info.frames);
713 if (decoded != info.frames) {
714 free(samples);
715 return -4;
716 }
717
718 memset(
719 log_mel,
720 0,
721 (size_t)n_mels * (size_t)output_frames * sizeof(float));
722 const int global_frames = info.frames / CK_AUDIO_WHISPER_HOP_LENGTH;
723 const int start_feature = start_frame / CK_AUDIO_WHISPER_HOP_LENGTH;
724 float maximum = -INFINITY;
725 float power[CK_AUDIO_WHISPER_POWER_BINS];
726 float fft_scratch[2 * CK_AUDIO_WHISPER_N_FFT];
727 for (int frame = 0; frame < global_frames; ++frame) {
729 samples,
730 info.frames,
731 frame,
732 window,
733 cos_table,
734 sin_table,
735 power,
736 fft_scratch);
737 for (int mel = 0; mel < n_mels; ++mel) {
738 const float *filter =
739 mel_filters + (size_t)mel * CK_AUDIO_WHISPER_POWER_BINS;
740 float sum = 0.0f;
741 for (int bin = 0; bin < CK_AUDIO_WHISPER_POWER_BINS; ++bin) {
742 sum = fmaf(filter[bin], power[bin], sum);
743 }
744 const float value = log10f(fmaxf(sum, 1.0e-10f));
745 maximum = fmaxf(maximum, value);
746 const int output_frame = frame - start_feature;
747 if (output_frame >= 0 && output_frame < output_frames) {
748 log_mel[(size_t)mel * output_frames + output_frame] = value;
749 }
750 }
751 }
752 free(samples);
753 if (!isfinite(maximum)) {
754 return -5;
755 }
756
757 const int available = global_frames - start_feature;
758 const int valid_frames =
759 available < output_frames ? (available > 0 ? available : 0) : output_frames;
760 const float floor = maximum - 8.0f;
761 for (int mel = 0; mel < n_mels; ++mel) {
762 float *output = log_mel + (size_t)mel * output_frames;
763 for (int frame = 0; frame < valid_frames; ++frame) {
764 output[frame] = (fmaxf(output[frame], floor) + 4.0f) / 4.0f;
765 }
766 }
767 return valid_frames;
768}
769
770typedef struct {
771 const float *input;
772 const float *weight;
773 const float *bias;
774 float *output;
775 int input_channels;
776 int output_channels;
777 int input_frames;
778 int kernel_size;
779 int stride;
780 int padding;
781 int output_frames;
782 int use_stride2_contiguous;
783} ck_audio_conv1d_f32_args_t;
784
785#if defined(__AVX2__) && defined(__FMA__)
786static inline __m256 ck_audio_load_stride2_8(const float *input)
787{
788 const __m256i select_even = _mm256_setr_epi32(0, 2, 4, 6, 0, 0, 0, 0);
789 const __m256 lo = _mm256_permutevar8x32_ps(
790 _mm256_loadu_ps(input), select_even);
791 const __m256 hi = _mm256_permutevar8x32_ps(
792 _mm256_loadu_ps(input + 8), select_even);
793 return _mm256_insertf128_ps(
794 _mm256_castps128_ps256(_mm256_castps256_ps128(lo)),
795 _mm256_castps256_ps128(hi), 1);
796}
797
798#endif
799
801 int ith,
802 int nth,
803 void *opaque)
804{
805 const ck_audio_conv1d_f32_args_t *args =
806 (const ck_audio_conv1d_f32_args_t *)opaque;
807 for (int out_channel = ith; out_channel < args->output_channels;
808 out_channel += nth) {
809 const float *weight_channel = args->weight +
810 (size_t)out_channel * args->input_channels * args->kernel_size;
811 float *output_channel = args->output +
812 (size_t)out_channel * args->output_frames;
813 int out_frame = 0;
814 const int interior_begin =
815 (args->padding + args->stride - 1) / args->stride;
816 for (; out_frame < interior_begin && out_frame < args->output_frames;
817 ++out_frame) {
818 float sum = args->bias != NULL ? args->bias[out_channel] : 0.0f;
819 for (int in_channel = 0; in_channel < args->input_channels;
820 ++in_channel) {
821 const float *input_channel = args->input +
822 (size_t)in_channel * args->input_frames;
823 const float *weight_row = weight_channel +
824 (size_t)in_channel * args->kernel_size;
825 for (int kernel = 0; kernel < args->kernel_size; ++kernel) {
826 const int in_frame =
827 out_frame * args->stride + kernel - args->padding;
828 if (in_frame >= 0 && in_frame < args->input_frames) {
829 sum = fmaf(input_channel[in_frame], weight_row[kernel], sum);
830 }
831 }
832 }
833 output_channel[out_frame] = sum;
834 }
835#if defined(__AVX2__) && defined(__FMA__)
836 for (; out_frame + 7 < args->output_frames &&
837 (out_frame + 7) * args->stride + args->kernel_size - 1 -
838 args->padding < args->input_frames;
839 out_frame += 8) {
840 __m256 sums = _mm256_set1_ps(
841 args->bias != NULL ? args->bias[out_channel] : 0.0f);
842 for (int in_channel = 0; in_channel < args->input_channels;
843 ++in_channel) {
844 const float *input_channel = args->input +
845 (size_t)in_channel * args->input_frames;
846 const float *weight_row = weight_channel +
847 (size_t)in_channel * args->kernel_size;
848 for (int kernel = 0; kernel < args->kernel_size; ++kernel) {
849 const int base =
850 out_frame * args->stride + kernel - args->padding;
851 __m256 samples;
852 if (args->stride == 1) {
853 samples = _mm256_loadu_ps(input_channel + base);
854 } else if (args->stride == 2 &&
855 args->use_stride2_contiguous &&
856 base + 15 < args->input_frames) {
857 samples = ck_audio_load_stride2_8(input_channel + base);
858 } else if (args->stride == 2) {
859 const __m256i indices = _mm256_setr_epi32(
860 base, base + 2, base + 4, base + 6,
861 base + 8, base + 10, base + 12, base + 14);
862 samples = _mm256_i32gather_ps(input_channel, indices, 4);
863 } else {
864 samples = _mm256_setr_ps(
865 input_channel[base],
866 input_channel[base + args->stride],
867 input_channel[base + 2 * args->stride],
868 input_channel[base + 3 * args->stride],
869 input_channel[base + 4 * args->stride],
870 input_channel[base + 5 * args->stride],
871 input_channel[base + 6 * args->stride],
872 input_channel[base + 7 * args->stride]);
873 }
874 sums = _mm256_fmadd_ps(
875 samples, _mm256_set1_ps(weight_row[kernel]), sums);
876 }
877 }
878 _mm256_storeu_ps(output_channel + out_frame, sums);
879 }
880#endif
881 for (; out_frame < args->output_frames; ++out_frame) {
882 float sum = args->bias != NULL ? args->bias[out_channel] : 0.0f;
883 for (int in_channel = 0; in_channel < args->input_channels;
884 ++in_channel) {
885 const float *input_channel = args->input +
886 (size_t)in_channel * args->input_frames;
887 const float *weight_row = weight_channel +
888 (size_t)in_channel * args->kernel_size;
889 for (int kernel = 0; kernel < args->kernel_size; ++kernel) {
890 const int in_frame =
891 out_frame * args->stride + kernel - args->padding;
892 if (in_frame >= 0 && in_frame < args->input_frames) {
893 sum = fmaf(input_channel[in_frame], weight_row[kernel], sum);
894 }
895 }
896 }
897 output_channel[out_frame] = sum;
898 }
899 }
900}
901
903 const float *input,
904 const float *weight,
905 const float *bias,
906 float *output,
907 int input_channels,
908 int output_channels,
909 int input_frames,
910 int kernel_size,
911 int stride,
912 int padding,
913 int output_frames)
914{
915 if (input == NULL || weight == NULL || output == NULL) {
916 return -1;
917 }
918 if (input_channels <= 0 || output_channels <= 0 || input_frames <= 0 ||
919 kernel_size <= 0 || stride <= 0 || padding < 0 || output_frames <= 0) {
920 return -2;
921 }
922 const int expected = (input_frames + 2 * padding - kernel_size) / stride + 1;
923 if (output_frames != expected) {
924 return -3;
925 }
926 const char *disable_stride2 =
927 getenv("CK_DISABLE_AUDIO_CONV_STRIDE2_CONTIGUOUS");
928 ck_audio_conv1d_f32_args_t args = {
929 .input = input,
930 .weight = weight,
931 .bias = bias,
932 .output = output,
933 .input_channels = input_channels,
934 .output_channels = output_channels,
935 .input_frames = input_frames,
936 .kernel_size = kernel_size,
937 .stride = stride,
938 .padding = padding,
939 .output_frames = output_frames,
940 .use_stride2_contiguous = !(
941 disable_stride2 && disable_stride2[0] &&
942 strcmp(disable_stride2, "0") != 0),
943 };
944 ck_threadpool_t *pool = ck_threadpool_global();
945 int active = pool ? ck_threadpool_n_threads(pool) : 1;
946 if (active > output_channels) active = output_channels;
947 if (pool != NULL && active > 1) {
949 pool, active, ck_audio_conv1d_channel_major_f32_work, &args);
950 } else {
952 }
953 return 0;
954}
955
956typedef struct {
957 const float *input;
958 const float *weight;
959 const float *bias;
960 float *output;
961 int input_width;
962 int input_height;
963 int input_channels;
964 int output_channels;
965 int kernel_width;
966 int kernel_height;
967 int stride_width;
968 int stride_height;
969 int padding_width;
970 int padding_height;
971 int groups;
972 int output_width;
973 int output_height;
974} ck_audio_conv2d_whc_f32_args_t;
975
977 int begin,
978 int end,
979 void *opaque)
980{
981 const ck_audio_conv2d_whc_f32_args_t *args =
982 (const ck_audio_conv2d_whc_f32_args_t *)opaque;
983 const int outputs_per_channel = args->output_width * args->output_height;
984 const int input_channels_per_group = args->input_channels / args->groups;
985 const int output_channels_per_group = args->output_channels / args->groups;
986 for (int index = begin; index < end; ++index) {
987 const int output_channel = index / outputs_per_channel;
988 const int spatial = index - output_channel * outputs_per_channel;
989 const int output_y = spatial / args->output_width;
990 const int output_x = spatial - output_y * args->output_width;
991 const int group = output_channel / output_channels_per_group;
992 const int input_channel_begin = group * input_channels_per_group;
993 float sum = args->bias != NULL ? args->bias[output_channel] : 0.0f;
994 for (int input_channel_offset = 0;
995 input_channel_offset < input_channels_per_group;
996 ++input_channel_offset) {
997 const int input_channel = input_channel_begin + input_channel_offset;
998 for (int kernel_y = 0; kernel_y < args->kernel_height; ++kernel_y) {
999 const int input_y = output_y * args->stride_height + kernel_y -
1000 args->padding_height;
1001 if (input_y < 0 || input_y >= args->input_height) {
1002 continue;
1003 }
1004 for (int kernel_x = 0; kernel_x < args->kernel_width; ++kernel_x) {
1005 const int input_x = output_x * args->stride_width + kernel_x -
1006 args->padding_width;
1007 if (input_x < 0 || input_x >= args->input_width) {
1008 continue;
1009 }
1010 const size_t input_index =
1011 ((size_t)input_channel * args->input_height + input_y) *
1012 args->input_width + input_x;
1013 const size_t weight_index =
1014 (((size_t)output_channel * input_channels_per_group +
1015 input_channel_offset) * args->kernel_height + kernel_y) *
1016 args->kernel_width + kernel_x;
1017 sum = fmaf(args->input[input_index], args->weight[weight_index], sum);
1018 }
1019 }
1020 }
1021 args->output[index] = sum;
1022 }
1023}
1024
1026 const float *input,
1027 const float *weight,
1028 const float *bias,
1029 float *output,
1030 int input_width,
1031 int input_height,
1032 int input_channels,
1033 int output_channels,
1034 int kernel_width,
1035 int kernel_height,
1036 int stride_width,
1037 int stride_height,
1038 int padding_width,
1039 int padding_height,
1040 int groups,
1041 int output_width,
1042 int output_height)
1043{
1044 if (input == NULL || weight == NULL || output == NULL) {
1045 return -1;
1046 }
1047 if (input_width <= 0 || input_height <= 0 || input_channels <= 0 ||
1048 output_channels <= 0 || kernel_width <= 0 || kernel_height <= 0 ||
1049 stride_width <= 0 || stride_height <= 0 || padding_width < 0 ||
1050 padding_height < 0 || groups <= 0 || output_width <= 0 ||
1051 output_height <= 0 || input_channels % groups != 0 ||
1052 output_channels % groups != 0) {
1053 return -2;
1054 }
1055 const int expected_width =
1056 (input_width + 2 * padding_width - kernel_width) / stride_width + 1;
1057 const int expected_height =
1058 (input_height + 2 * padding_height - kernel_height) / stride_height + 1;
1059 if (output_width != expected_width || output_height != expected_height) {
1060 return -3;
1061 }
1062 ck_audio_conv2d_whc_f32_args_t args = {
1063 .input = input,
1064 .weight = weight,
1065 .bias = bias,
1066 .output = output,
1067 .input_width = input_width,
1068 .input_height = input_height,
1069 .input_channels = input_channels,
1070 .output_channels = output_channels,
1071 .kernel_width = kernel_width,
1072 .kernel_height = kernel_height,
1073 .stride_width = stride_width,
1074 .stride_height = stride_height,
1075 .padding_width = padding_width,
1076 .padding_height = padding_height,
1077 .groups = groups,
1078 .output_width = output_width,
1079 .output_height = output_height,
1080 };
1081 const int output_elements = output_channels * output_height * output_width;
1082 ck_threadpool_t *pool = ck_threadpool_global();
1083 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1084 if (active > output_elements) {
1085 active = output_elements;
1086 }
1087 if (pool != NULL && active > 1) {
1088 const int grain = output_width > 0 ? output_width : 1;
1090 pool, active, 0, output_elements, grain,
1092 } else {
1093 ck_audio_conv2d_whc_grouped_f32_range(0, output_elements, &args);
1094 }
1095 return 0;
1096}
1097
1098typedef struct {
1099 const float *value;
1100 const float *gate;
1101 float *output;
1102} ck_audio_glu_split_f32_args_t;
1103
1104static void ck_audio_glu_split_f32_range(int begin, int end, void *opaque)
1105{
1106 const ck_audio_glu_split_f32_args_t *args =
1107 (const ck_audio_glu_split_f32_args_t *)opaque;
1108 for (int index = begin; index < end; ++index) {
1109 const float gate = args->gate[index];
1110 const float sigmoid = 1.0f / (1.0f + expf(-gate));
1111 args->output[index] = args->value[index] * sigmoid;
1112 }
1113}
1114
1116 const float *input,
1117 float *output,
1118 int channels,
1119 int frames)
1120{
1121 if (input == NULL || output == NULL) {
1122 return -1;
1123 }
1124 if (channels <= 0 || frames <= 0) {
1125 return -2;
1126 }
1127 const int elements = channels * frames;
1128 ck_audio_glu_split_f32_args_t args = {
1129 .value = input,
1130 .gate = input + elements,
1131 .output = output,
1132 };
1133 ck_threadpool_t *pool = ck_threadpool_global();
1134 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1135 if (active > elements) {
1136 active = elements;
1137 }
1138 if (pool != NULL && active > 1) {
1140 pool, active, 0, elements, 256,
1142 } else {
1143 ck_audio_glu_split_f32_range(0, elements, &args);
1144 }
1145 return 0;
1146}
1147
1148typedef struct {
1149 const float *raw_scores;
1150 float *scores;
1151 int query_frames;
1152 int raw_key_frames;
1153} ck_audio_relative_shift_f32_args_t;
1154
1156 int begin, int end, void *opaque)
1157{
1158 const ck_audio_relative_shift_f32_args_t *args =
1159 (const ck_audio_relative_shift_f32_args_t *)opaque;
1160 const int frames = args->query_frames;
1161 const int raw_frames = args->raw_key_frames;
1162 for (int row = begin; row < end; ++row) {
1163 const int query = row % frames;
1164 const float *raw = args->raw_scores + (size_t)row * raw_frames;
1165 float *output = args->scores + (size_t)row * frames;
1166 const int origin = frames - 1 - query;
1167 for (int key = 0; key < frames; ++key) {
1168 output[key] = raw[origin + key];
1169 }
1170 }
1171}
1172
1174 const float *raw_scores,
1175 float *scores,
1176 int heads,
1177 int query_frames)
1178{
1179 if (raw_scores == NULL || scores == NULL) {
1180 return -1;
1181 }
1182 if (heads <= 0 || query_frames <= 0) {
1183 return -2;
1184 }
1185 const int rows = heads * query_frames;
1186 ck_audio_relative_shift_f32_args_t args = {
1187 .raw_scores = raw_scores,
1188 .scores = scores,
1189 .query_frames = query_frames,
1190 .raw_key_frames = 2 * query_frames - 1,
1191 };
1192 ck_threadpool_t *pool = ck_threadpool_global();
1193 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1194 if (active > rows) {
1195 active = rows;
1196 }
1197 if (pool != NULL && active > 1) {
1199 pool, active, 0, rows, 1,
1201 } else {
1202 ck_audio_relative_shift_f32_range(0, rows, &args);
1203 }
1204 return 0;
1205}
1206
1208 const float *input,
1209 float *output,
1210 int channels,
1211 int frames)
1212{
1213 if (input == NULL || output == NULL) {
1214 return -1;
1215 }
1216 if (channels <= 0 || frames <= 0) {
1217 return -2;
1218 }
1219 for (int frame = 0; frame < frames; ++frame) {
1220 for (int channel = 0; channel < channels; ++channel) {
1221 output[(size_t)frame * channels + channel] =
1222 input[(size_t)channel * frames + frame];
1223 }
1224 }
1225 return 0;
1226}
1227
1229 const float *samples,
1230 int n_samples,
1231 float *power,
1232 int n_frames)
1233{
1234 if (samples == NULL || power == NULL) {
1235 return -1;
1236 }
1237 if (n_samples <= CK_AUDIO_WHISPER_N_FFT / 2 || n_frames <= 0) {
1238 return -2;
1239 }
1240 if (n_frames != n_samples / CK_AUDIO_WHISPER_HOP_LENGTH) {
1241 return -3;
1242 }
1243
1244 const int center = CK_AUDIO_WHISPER_N_FFT / 2;
1245 for (int frame = 0; frame < n_frames; ++frame) {
1246 for (int bin = 0; bin < CK_AUDIO_WHISPER_POWER_BINS; ++bin) {
1247 float real = 0.0f;
1248 float imag = 0.0f;
1249 for (int sample = 0; sample < CK_AUDIO_WHISPER_N_FFT; ++sample) {
1250 const int source = reflect_index(
1251 frame * CK_AUDIO_WHISPER_HOP_LENGTH + sample - center,
1252 n_samples);
1253 const float window = 0.5f - 0.5f * cosf(
1254 2.0f * CK_AUDIO_PI_F * (float)sample /
1255 (float)CK_AUDIO_WHISPER_N_FFT);
1256 const float value = samples[source] * window;
1257 const float angle = -2.0f * CK_AUDIO_PI_F *
1258 (float)(bin * sample) / (float)CK_AUDIO_WHISPER_N_FFT;
1259 real = fmaf(value, cosf(angle), real);
1260 imag = fmaf(value, sinf(angle), imag);
1261 }
1262 power[(size_t)frame * CK_AUDIO_WHISPER_POWER_BINS + bin] =
1263 fmaf(real, real, imag * imag);
1264 }
1265 }
1266 return 0;
1267}
1268
1270 const float *power,
1271 const float *mel_filters,
1272 int n_mels,
1273 int n_frames,
1274 float *log_mel)
1275{
1276 if (power == NULL || mel_filters == NULL || log_mel == NULL) {
1277 return -1;
1278 }
1279 if (n_mels <= 0 || n_frames <= 0) {
1280 return -2;
1281 }
1282
1283 float maximum = -INFINITY;
1284 for (int mel = 0; mel < n_mels; ++mel) {
1285 const float *filter = mel_filters + (size_t)mel * CK_AUDIO_WHISPER_POWER_BINS;
1286 float *output = log_mel + (size_t)mel * n_frames;
1287 for (int frame = 0; frame < n_frames; ++frame) {
1288 const float *spectrum = power + (size_t)frame * CK_AUDIO_WHISPER_POWER_BINS;
1289 float sum = 0.0f;
1290 for (int bin = 0; bin < CK_AUDIO_WHISPER_POWER_BINS; ++bin) {
1291 sum = fmaf(filter[bin], spectrum[bin], sum);
1292 }
1293 const float value = log10f(fmaxf(sum, 1.0e-10f));
1294 output[frame] = value;
1295 maximum = fmaxf(maximum, value);
1296 }
1297 }
1298
1299 const float floor = maximum - 8.0f;
1300 for (int mel = 0; mel < n_mels; ++mel) {
1301 float *output = log_mel + (size_t)mel * n_frames;
1302 for (int frame = 0; frame < n_frames; ++frame) {
1303 output[frame] = (fmaxf(output[frame], floor) + 4.0f) / 4.0f;
1304 }
1305 }
1306 return 0;
1307}
1308
1310 const float *samples,
1311 int n_samples,
1312 const float *mel_filters,
1313 int n_mels,
1314 float *power_scratch,
1315 float *log_mel,
1316 int n_frames)
1317{
1318 const int stft_status = audio_whisper_stft_power_reference_f32(
1319 samples, n_samples, power_scratch, n_frames);
1320 if (stft_status != 0) {
1321 return stft_status;
1322 }
1324 power_scratch, mel_filters, n_mels, n_frames, log_mel);
1325}
int audio_whisper_mel_filters_slaney_f32(int sample_rate, int n_fft, int n_mels, float *mel_filters)
int audio_whisper_log_mel_reference_f32(const float *samples, int n_samples, const float *mel_filters, int n_mels, float *power_scratch, float *log_mel, int n_frames)
int audio_stft_power_precomputed_f32(const float *samples, int n_samples, const float *window, const float *cos_table, const float *sin_table, int n_fft, int hop_length, float *power, int n_frames)
int audio_resample_linear_f32(const float *input, int input_frames, int input_rate, float *output, int output_frames, int output_rate)
int audio_wav_parse_memory(const uint8_t *bytes, size_t byte_count, CKAudioWavInfo *info)
int audio_conv2d_whc_grouped_f32(const float *input, const float *weight, const float *bias, float *output, int input_width, int input_height, int input_channels, int output_channels, int kernel_width, int kernel_height, int stride_width, int stride_height, int padding_width, int padding_height, int groups, int output_width, int output_height)
int audio_log_mel_time_major_f32(const float *power, const float *mel_filters, float *log_mel, int frames, int bins, int channels, float epsilon)
static void ck_audio_relative_shift_f32_range(int begin, int end, void *opaque)
int audio_wav_decode_pcm16_mono_f32(const uint8_t *bytes, size_t byte_count, const CKAudioWavInfo *info, float *mono, int mono_capacity)
int audio_whisper_log_mel_window_wav_pcm16_f32(const uint8_t *bytes, size_t byte_count, int start_frame, int target_sample_rate, const float *window, const float *cos_table, const float *sin_table, const float *mel_filters, int n_mels, int output_frames, float *log_mel)
static uint16_t read_u16_le(const uint8_t *p)
static int reflect_index(int index, int length)
int audio_preemphasis_f32(const float *input, float *output, int frames, float coefficient)
int audio_relative_shift_f32(const float *raw_scores, float *scores, int heads, int query_frames)
#define CK_AUDIO_PI_D
int audio_whisper_stft_power_reference_f32(const float *samples, int n_samples, float *power, int n_frames)
#define CK_AUDIO_PI_F
int audio_stft_power_centered_window_f32(const float *samples, int n_samples, const float *window, int window_length, const float *cos_table, const float *sin_table, int n_fft, int hop_length, int reflect_padding, float *power, int n_frames)
int audio_stft_precompute_tables_f32(int n_fft, float *window, float *cos_table, float *sin_table)
static void audio_stft_power_fft400_frame_f32(const float *samples, int n_samples, int frame, const float *window, const float *cos_table, const float *sin_table, float *power, float *fft_scratch)
static double audio_hz_to_mel_slaney(double hz)
int audio_glu_split_channel_major_f32(const float *input, float *output, int channels, int frames)
static void ck_audio_conv1d_channel_major_f32_work(int ith, int nth, void *opaque)
int audio_pcm_s16_to_mono_f32(const int16_t *interleaved, int n_frames, int n_channels, float *mono)
int audio_transpose_channel_to_token_f32(const float *input, float *output, int channels, int frames)
static double audio_mel_to_hz_slaney(double mel)
int audio_whisper_log_mel_from_power_reference_f32(const float *power, const float *mel_filters, int n_mels, int n_frames, float *log_mel)
int audio_feature_normalize_per_feature_f32(const float *input, float *output, int channels, int frames, float epsilon)
static uint32_t read_u32_le(const uint8_t *p)
int audio_pad_or_truncate_f32(const float *input, int input_frames, float *output, int output_frames)
int audio_conv1d_channel_major_f32(const float *input, const float *weight, const float *bias, float *output, int input_channels, int output_channels, int input_frames, int kernel_size, int stride, int padding, int output_frames)
int audio_resample_windowed_sinc_f32(const float *input, int input_frames, int input_rate, float *output, int output_frames, int output_rate, int radius)
int audio_wav_decode_memory_pcm16_mono_window_f32(const uint8_t *bytes, size_t byte_count, int start_frame, float *mono, int mono_capacity, CKAudioWavInfo *info)
int audio_stft_power_fft400_f32(const float *samples, int n_samples, const float *window, const float *cos_table, const float *sin_table, int hop_length, float *power, int n_frames, float *fft_scratch)
static void ck_audio_glu_split_f32_range(int begin, int end, void *opaque)
int audio_resampled_frame_count(int input_frames, int input_rate, int output_rate)
static void ck_audio_conv2d_whc_grouped_f32_range(int begin, int end, void *opaque)
int audio_wav_decode_memory_pcm16_mono_f32(const uint8_t *bytes, size_t byte_count, float *mono, int mono_capacity, CKAudioWavInfo *info)
Persistent pthread thread pool for CK-Engine inference.
void ck_threadpool_parallel_for_n(ck_threadpool_t *pool, int active_threads, int begin, int end, int grain_size, ck_range_fn_t fn, void *args)
void ck_threadpool_dispatch_n(ck_threadpool_t *pool, int active_threads, ck_work_fn_t fn, void *args)
ck_threadpool_t * ck_threadpool_global(void)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
#define CK_AUDIO_WHISPER_N_FFT
#define CK_AUDIO_WHISPER_HOP_LENGTH
#define CK_AUDIO_WHISPER_SAMPLE_RATE
#define CK_AUDIO_WHISPER_POWER_BINS
const char * left
Definition true_bpe.h:138
const char const char * right
Definition true_bpe.h:139
uint32_t end
Definition utf8.c:215