Подскажите, пожалуйста, как можно изменить
высоту тона звука, записанного в виде .wav
файла.
Я смог придумать два способа, но они не работают.
1. Пропускать/Добавлять отсчеты — проблемы
с качеством звука и его длиной.
2. При помощи преобразования Фурье преобразовать в сумму
гармонических колебаний, изменить частоты этих колебаний и
сделать обратное преобразования Фурье.
Например, если было колебание A*sin(wt), а относительное изменение
тона равно r, то после сдвига тона получится A*sin((w + r*w)t).
Когда я так сделал, то в результате у звука возник сильный шум.
Здравствуйте, Khalal, Вы писали:
K> Подскажите, пожалуйста, как можно изменить K>высоту тона звука, записанного в виде .wav K>файла. K> Я смог придумать два способа, но они не работают.
А для каких целей, если чтобы просто , для слуха,
можно использовать IDirectSoundBuffer. Там есть метод
SetFrеquense();
Использовал один раз для иммитации звука моторной лодки.
Здравствуйте, PavZ, Вы писали:
PZ>А для каких целей, если чтобы просто , для слуха, PZ>можно использовать IDirectSoundBuffer. Там есть метод PZ>SetFrеquense(); PZ>Использовал один раз для иммитации звука моторной лодки.
Нет, IDirectSoundBuffer я думаю тут не подойет.
Сдвиг высоты тона звука мне нужен для синтеза звучания инструментов из DownLoadableSound (DLS) файла. Причем программа должна работать как под Windows,
так и под Unix. Звуковая карта не должна использоваться.
K>1. Пропускать/Добавлять отсчеты — проблемы K>с качеством звука и его длиной.
Проблема с длинной мне кажется неизбежна, по той причине что увеличивается/уменьшается период
а wav как правило с одной и той же частотой дискретизации будет занимать места ~t.
А пропуск/добавление как реализовано ?
Я бы сделал так ( не знаю что из этого получиться реально ).
Изначально имеем набор значений амплитут от времени T причем T=t*n, где n — целое число , t — константа зависящая от частоты дискретизации = 1/f.
Соотв. общее время звучания будет = t*Nmax. Nmax — количество амплитуд в файле.
затем изменяем время t и расставляем амплитуды по новой шкале где T = t'*n.
Получаем общее время звучания = t'*Nmax
Теперь на эту шкалу накладываем старую (c t), как правило у нас не будет точных попаданий в новую шкалу ( c t').
Т.е. получается что конечное Nmaxres = (t'*Nmax)/t.
Вот пробегаем по всем n от 0 до Nmaxres-1.
Имеем время Tres = t*n, для каждого времени нужно заново расчитать амплитуду. для этого берем из новой шкалы
два ближайших значения для времени ...т.е. находим n' такое чтобы t'*n'<Tres<t'*(n'+1). для этих двух точек мы
имеем амплитуду An и An+1 ...соотв. нужно для Tres запомнить амплитуду Ares=((A(n'+1)-A(n'))/t')*(Tres-t'*n')
PZ>А пропуск/добавление как реализовано ?
Если надо сдвинуть тон звука на целое число октав то надо изменить скорость
его воспроизведения в соответствующее число раз.(2^(число октав))
Например для сдвига на октаву вверх скорость надо удвоить,
каждую пару отсчетов заменить средним арифметическим.
Для сдвига на октаву вниз скорость надо уменьшить в два раза,
соответственно, надо каждый отсчет повторить два раза.
Для сдвига на нецелое число октав по-видимому понадобится
аппроксимировать отсчеты многочленом и затем уже пропускать/добавлять их.
Но как можно решить проблему с длиной я не смог придумать.
PZ>Имеем время Tres = t*n, для каждого времени нужно заново расчитать амплитуду. для этого берем из новой шкалы PZ>два ближайших значения для времени ...т.е. находим n' такое чтобы t'*n'<Tres<t'*(n'+1). для этих двух точек мы PZ>имеем амплитуду An и An+1 ...соотв. нужно для Tres запомнить амплитуду Ares=((A(n'+1)-A(n'))/t')*(Tres-t'*n')
Спасибо за этот способ!
Вроде бы он позволяет решить проблему с длиной.
Только последняя формула, как я понимаю, это линейное приближение ?
Тогда она не совсем верна.
Вывод этой формулы:
x — n'*t y — A(n')
--------------- = ---------------
(n'+1)*t — n'*t A(n'+1) — A(n')
Подставляя x = Tres,получаем
Tres — n'*t
Ares = y = A(n')+ ------------- * ( A(n'+1) — A(n') )
t'
PZ>>Имеем время Tres = t*n, для каждого времени нужно заново расчитать амплитуду. для этого берем из новой шкалы PZ>>два ближайших значения для времени ...т.е. находим n' такое чтобы t'*n'<Tres<t'*(n'+1). для этих двух точек мы PZ>>имеем амплитуду An и An+1 ...соотв. нужно для Tres запомнить амплитуду Ares=((A(n'+1)-A(n'))/t')*(Tres-t'*n') K>Спасибо за этот способ! K>Вроде бы он позволяет решить проблему с длиной. K>Только последняя формула, как я понимаю, это линейное приближение ? K>Тогда она не совсем верна.
K>Вывод этой формулы:
K> x — n'*t y — A(n') K>--------------- = --------------- K>(n'+1)*t — n'*t A(n'+1) — A(n')
K>Подставляя x = Tres,получаем K> Tres — n'*t K>Ares = y = A(n')+ ------------- * ( A(n'+1) — A(n') ) K> t'
Ну да, ошибочка вышла, у меня Ares это получилось изменение амплитуды, нужно конечно добавить A(n')
Нет, этот алгоритм не совсем подходит.
Наложение не получается.
Например, если был сигнал
__|--|__|--|__|--|
то после сдвига тона на октаву вверх получится
_|-|_|-|_|-|
Так как звук, тон которого надо сдвинуть не такой простой, то удлинить его нельзя.