#define DAC_FS 68000 //[Hz] желаемая частота квантования ЦАП (<=реальной)
#define DAC_DIV (TimerAPBCLK(nTIM_dac, H) / DAC_FS)
#define DAC_FS_REAL divCeil(TimerAPBCLK(nTIM_dac, H), DAC_DIV) //[Hz] реальная частота квантования ЦАП (>=DAC_FS) [Hz]
#define DS_FACTOR 3 //показатель макс.даунсэмплинга
#define DS_MAX ((1 << DS_FACTOR) - 1) //макс.даунсэмплинг (макс.возможное отношение частоты сэмплирования mp3-потока к DAC_FS_REAL)
static u32 rsmplX; //текущая фаза ресэмплинга; целая часть - старшие DS_FACTOR бит
static u32 rsmplFix; //отношение частоты сэмплирования mp3 к частоте DAC_FS_REAL; целая часть - старшие DS_FACTOR бит
static u32 rsmplVar; //произведение rsmplFix и переменного коэфф.ресэмплинга, вычисляемого от уровня заполненности inbuf.ring; формат аналогичен rsmplFix
static u16 rsmplBSiz; //кол-во пар (левый/правый) сэмплов в rsmplBuf
static void ReSmpl()
{
CPU_SR_ALLOCATE();
uint i0, i1, n, n1 = rsmplBSiz;
//n1 - число сэмплов во вх.буфере
s16 *psr = &rsmplBuf[0]; //указатель поток вх.сэмплов (сэмплы хранятся парами 16-битных значений для левого/правого канала)
while (1) {
i1 = sbufW; //индекс записи в кольцевой буфер вых.сэмплов
if ((int)(n = (i0 = sbufE) - i1 - 1) < 0) {
n = ncell(smplBuf.data) - i1;
if (!i0) n--;
}
//здесь n - число сэмплов ЦАП, которое можно записать в вых.буфер
if (!n) { //нет места для записи в smplBuf.data
if (afaza == AFAZA_BREAK) return;
ENTR_CRT_SECTION();
if (afaza == AFAZA_PREBUF) {
i0 = ibufR;
if ((int)(n = ibufW - i0) < 0) n += sizeof(inbuf.ring);
if (n >= prebufPorog || aoutOn == OTYP_MEM) {
afaza = AFAZA_PLAY;
EXIT_CRT_SECTION();
TaskChangePrio(PRIO_TASK_AOUT_LOW, PRIO_TASK_AOUT_HIGH);
} else EXIT_CRT_SECTION();
} else EXIT_CRT_SECTION();
MboxPend(mboxOut, ms2tkt(20));
continue;
}
u32 *psw = &smplBuf.data[i1]; //указатель на формируемый поток вых.сэмплов
u32 c, c0, c1, ca = rsmplX;
do { //здесь собственно - сам цикл ресэмплинга входных отсчётов в выходные
n1 -= c = (ca += rsmplVar) >> 32 - DS_FACTOR;
psr += c * 2;
ca -= c << 32 - DS_FACTOR;
c = ca >> 16 - DS_FACTOR;
c0 = (psr[2] * (s32)c + psr[0] * (s32)(B16 - c) >> 16) * mp3Volume; //здесь собственно вычисление очередного вых. сэмпла для левого канала (а может правого?

c1 = (psr[3] * (s32)c + psr[1] * (s32)(B16 - c) >> 16) * mp3Volume; //здесь для другого канала
*psw++ = (c0 + B23 >> 8 & 0xFFF0) | (c1 + B23 >> 12 << 20); //объединяем и преобразуем в формат 2-канального ЦАП STM32F429
} while (--n && n1 > DS_MAX);
rsmplX = ca;
i1 = psw - &smplBuf.data[0];
if (i1 >= ncell(smplBuf.data)) i1 = 0;
sbufW = i1;
if (n1 <= DS_MAX) break;
}
rsmplBSiz = n1;
memmove(&rsmplBuf[0], psr, n1 + 1 << 2);
}
DAC_FS - можно задать любым какое нравится и поддерживает ЦАП, но желательно близким к частоте вх.потока и если ниже частоты вх.потока, то не более чем в DS_MAX раз;
rsmplFix - у меня вычисляется для каждого вх. MP3-фрейма - из него берётся samplerate этого фрейма и получаем значение фиксированного коэфф. ресэмплинга для данного MP3-фрейма;
rsmplVar - вычисляется непрерывно - это произведение rsmplFix на коэфф. заполненности основного кольцевого буфера mp3-потока; за счёт этого выполняется согласование скоростей вх.потока (определяемого генератором передатчика) и вых. потока (определяемого тактовой ЦАП); зависимость коэфф. заполненности кольц.буфера - нелинейная.
Более правильный/точный метод это задействовать таймер TIM2, но руки пока не еще дошли - надо кое-какие нюансы самого ASRC допилить

.
Использую простой ФНЧ первого порядка. Его основная задача уменьшить джиттер, поскольку плавают измерения (получается 216048+-100 тактов, надо переходить на аппаратный замер таймером).
Имхо - у SOF-фреймов от хоста тоже может быть джиттер. Так что аппаратным или не аппаратным таймером мерять - всё равно значения будут дёргаться - так как погрешность возникает не у Вас. Всё равно придётся усреднять или ФНЧ.
Алгоритм очень простой - соедините отсчеты линиями, теперь у Вас есть значения сигнала в произвольной точки времени (что собственно для ASRC и нужно)

"Возня" с более сложными алгоритмами фактически сводится к более точной интерполяции сигнала между отсчетами.
Кода нет, я этот вариант только покрутил в Матлабе и отказался, т.к. при моих соотношениях частоты дискретизации и сигнала (12кГц:3.5кГц) он дает очень много искажений.
Приведённый мной код должен нормально работать при соотношениях вх./вых. частот сэмплирования (коэфф.ресэмплинга) в диапазоне менее: 0.5<K<2.
Он конечно будет работать и за пределами этого диапазона, но тогда часть сэмплов будет просто выкидываться (не учитываться в вых.сигнале). Чтобы убрать этот недостаток надо по идее поток вх.сэмплов предварительно прогнать через ФНЧ (а для случая K<=0.5 - предварительно добавить сэмплов в поток так, чтобы стало K>0.5 и потом прогнать через ФНЧ). Но я уже не стал этим заморачиваться, так как и такое качество меня уже устроило