#include <stdint.h>
#include <stdio.h>
/**
* Ресемплинг 16000 -> 8000 Гц
* @param input - входной массив (размер 2n)
* @param output - выходной массив (размер n)
* @param n_out - количество выходных сэмплов (кратно 8)
*/
void resample_16to8_asm(const int16_t* input, int16_t* output, int n_out) {
const int16_t* in_ptr = input;
int16_t* out_ptr = output;
int iterations = n_out / 8;
if (iterations <= 0) return;
asm volatile (
"1: \n\t"
// 1. Загружаем 16 сэмплов (два 128-битных регистра)
"ld1 {v0.8h, v1.8h}, [%[in]], #32 \n\t"
// 2. Вариант А: Просто децимация (берем каждый второй)
// Пользуемся инструкцией UZP1 (Unzip), которая собирает четные элементы
"uzp1 v2.8h, v0.8h, v1.8h \n\t"
/*
Вариант Б: Децимация с усреднением (ФНЧ), чтобы не было алиасинга.
Если нужен этот вариант, расскомментируйте код ниже, а uzp1 удалите:
"uzp1 v2.8h, v0.8h, v1.8h \n\t" // Четные сэмплы
"uzp2 v3.8h, v0.8h, v1.8h \n\t" // Нечетные сэмплы
"srhadd v2.8h, v2.8h, v3.8h \n\t" // Среднее между соседями
*/
// 3. Сохраняем 8 сэмплов результата
"st1 {v2.8h}, [%[out]], #16 \n\t"
// 4. Цикл
"subs %w[count], %w[count], #1 \n\t"
"b.ne 1b \n\t"
: [in] "+r" (in_ptr), [out] "+r" (out_ptr), [count] "+r" (iterations)
:
: "v0", "v1", "v2", "v3", "cc", "memory"
);
}
int main() {
// Вход: 16 сэмплов (16кГц)
int16_t input[16] = {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85};
int16_t output[8];
resample_16to8_asm(input, output, 8);
printf("In (16kHz) -> Out (8kHz):\n");
for (int i = 0; i < 8; i++) {
printf("%d ", output[i]); // Ожидаем 10, 20, 30... (каждый второй)
}
printf("\n");
return 0;
}