Интерполяция высоты тона с использованием numpy

У меня есть массив numpy, содержащий 88200 элементов, представляющих 2-секундный образец звука, сэмплированный с частотой дискретизации 44,1 кГц. Предполагается, что высота семпла составляет 130,8 Гц. Я могу интерполировать аудиоданные и растянуть их на 4-секундный образец, который уменьшит высоту звука вдвое, или сжать его до 1-секундного образца, который удвоит высоту звука.

Я хочу реализовать скольжение высоты тона (портаменто). То есть какая-то интерполяция, чтобы высота тона начиналась с 130,8 Гц и плавно скользила до 261,6 Гц, когда сэмпл заканчивается.

Как я могу сделать это, используя Python и numpy? Я думаю, что смогу реализовать это с помощью функций linspace и interp, но я не могу заставить его работать правильно.


person Björn Lindqvist    schedule 30.01.2020    source источник
comment
Чтобы скользить по высоте, интерполяция будет происходить в изменяющихся точках массива. Вероятно, вам лучше написать свою собственную функцию, чтобы вы могли легко переключаться между линейной, сплайновой и лагранжевой интерполяцией. Если у вас есть аудио buffer, которое вы замедляете, и вы запрашиваете индексы 0, 0.5, 1, 1.4, для индексов 0.5 и 1.4 нет прямого линейного интервала, вам нужно будет принимать его в каждом конкретном случае.   -  person fdcpp    schedule 30.01.2020
comment
Можно ли использовать библиотеки без numpy? Не то чтобы невозможно придерживаться numpy, но сделать это хорошо нетривиально.   -  person Lukasz Tracewski    schedule 01.02.2020
comment
Я действительно решил свою проблему, используя numpy! Скоро напишу ответ. Если вы или кто-то еще можете улучшить его, я хотел бы это увидеть!   -  person Björn Lindqvist    schedule 01.02.2020


Ответы (1)


Вот код numpy, который я использовал:

def slide_sample(arr, v1):
    x_old = np.linspace(0, arr.size, arr.size)
    v0 = 1
    ratio = 2 / (v0 + v1)
    vels = np.linspace(v0, v1, int(arr.size * ratio))
    x_new = np.append([0], np.cumsum(vels))
    return np.interp(x_new, x_old, arr)

arr — это образец массива для скольжения, а v1 — относительный шаг для скольжения. Таким образом, slide_sample(arr, 2) будет скользить в два раза выше, а slide_sample(arr, 0.5) - в два раза выше.

person Björn Lindqvist    schedule 05.02.2020