Делаю HRTF (head-related transfer function) для своего звукового движка и все вроде бы получается весьма неплохо, но при смене спектров HRIR (head-related impulse response) для правого и левого уха при перемещении источника звука, слышны короткие глухие щелчки. Если HRIR остается тем же самым, то никаких щелчков нет. Алгоритм я использую относительно простой:
1) Берем базу HRIR отсюда
2) Получаем спектры HRIR через БПФ (быстрое преобразование Фурье)
3) Для каждого источника выполняем свертку сигнала от источника с HRIR в пространстве частот по этому методу
4) Получаем очень годное звучание и отличный объемный звук, но со щелчками при смене HRIR.
Как видно из графического представления алгоритма, для каждого нового отрезка сигнала часть сигнала после свертки с предыдущего "кадра" суммируется:
Как правильно поступать в таком случае? Возможно есть какой-то метод интерполяции и что-то подобное?
Похоже что вот это http://www02.smt.ufrj.br/~diniz/conf/confi117.pdf может помочь.
mr.DIMAS
Как видно из графического представления алгоритма, для каждого нового отрезка сигнала часть сигнала после свертки с предыдущего "кадра" суммируется:
Щелчки - это явно фазовый сдвиг складываемых кусков. (А сдвиг как раз и нужен.)
У меня похожее было, вылечил когда сделал "синхронизацию" по прохождению волны через ноль.
В общем интерполяция HRIR почти помогла, щелчки стали едва слышимы. Но думаю это просто косяк в реализации, буду дебажить.
mr.DIMAS
На той неделе делал реализацию hrtf у себя и столкнулся с той же проблемой щелчков при смене hrir. Идея со сферой и интерполяцией hrir по барицентрическим координатам крутая, но мне кажется, что ее можно улучшить(оптимизировать) если сферу рейкастить не тупо брутфорсом треугольников, а как-то иначе, например по вертикмльным срезам азимутов - по dir.y определяем срез азимутов и рейкастим треугольники внутри среза. Также можно учесть, что левая и правая полусфера зеркальны между собой. Еще, как вариант, можно сгенерировать сферу с регулярным шагом сетки, тогда поиск пересечения с треугольником вообще можно свести к О(1).
Проблема щелчков полностью не решается интерполированием предыдущего и текущего вектора до источника. У себя решил следующим образом: для каждого сегмента применяем 2 hrtf (от предыдущей и текущией позиции источника) и линейно интерполируем между результирующими дорожками. Псевдокод:
// prev, cur - предыдущее и текущее состояние вектора до источника в координатах слушателя sampleSphere(prev, lefthrtfPrev, righthrtfPrev ); for each segment { dir = lerp( prev, cur, (segmentNum+1)/segmentsCount).norm(); sampleSphere(dir, lefthrtf, righthrtf ); applyHrtf( segment, lefthrtfPrev, righthrtfPrev, resultSamplesPrev ); applyHrtf( segment, lefthrt, righthrtf, resultSamplesCur ); lefthrtfPrev = lefthrt; righthrtfPrev = righthrtf; for n 0..segmentLength { x = n/segmentLength; resultSamples[n].left = lerp( resultSamplesPrev[n].left, resultSamplesCur[n].left, x ); resultSamples[n].right = lerp( resultSamplesPrev[n].right, resultSamplesCur[n].right, x ); } }
0xc0de Если честно я не запаривался с оптимизацией рейкаста, все равно большую часть времени жрет преобразование Фурье. Хотя в последнее время rustfft стал нагибать FFTW и может вполне станется так что придется оптимизировать рейкаст. А вот с удалением щелчков идея хорошая, может у себя запилю как время будет. Кстати ты же используешь сферы отсюда https://github.com/mrDIMAS/hrir_sphere_builder ?
mr.DIMAS
> Кстати ты же используешь сферы отсюда https://github.com/m… phere_builder ?
Да, irc_1002_c.bin
Тема в архиве.