Сдвиг высоты тона звука
От: Khalal  
Дата: 10.07.03 21:24
Оценка:
Подскажите, пожалуйста, как можно изменить
высоту тона звука, записанного в виде .wav
файла.
Я смог придумать два способа, но они не работают.

1. Пропускать/Добавлять отсчеты — проблемы
с качеством звука и его длиной.
2. При помощи преобразования Фурье преобразовать в сумму
гармонических колебаний, изменить частоты этих колебаний и
сделать обратное преобразования Фурье.
Например, если было колебание A*sin(wt), а относительное изменение
тона равно r, то после сдвига тона получится A*sin((w + r*w)t).
Когда я так сделал, то в результате у звука возник сильный шум.
Re: Сдвиг высоты тона звука
От: PavZ  
Дата: 11.07.03 08:42
Оценка:
Здравствуйте, Khalal, Вы писали:

K> Подскажите, пожалуйста, как можно изменить

K>высоту тона звука, записанного в виде .wav
K>файла.
K> Я смог придумать два способа, но они не работают.

А для каких целей, если чтобы просто , для слуха,
можно использовать IDirectSoundBuffer. Там есть метод
SetFrеquense();
Использовал один раз для иммитации звука моторной лодки.
Re[2]: Сдвиг высоты тона звука
От: Khalal  
Дата: 11.07.03 09:37
Оценка:
Здравствуйте, PavZ, Вы писали:

PZ>А для каких целей, если чтобы просто , для слуха,

PZ>можно использовать IDirectSoundBuffer. Там есть метод
PZ>SetFrеquense();
PZ>Использовал один раз для иммитации звука моторной лодки.
Нет, IDirectSoundBuffer я думаю тут не подойет.
Сдвиг высоты тона звука мне нужен для синтеза звучания инструментов из DownLoadableSound (DLS) файла. Причем программа должна работать как под Windows,
так и под Unix. Звуковая карта не должна использоваться.
Re: Сдвиг высоты тона звука
От: PavZ  
Дата: 11.07.03 10:10
Оценка:
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')
Re[2]: Сдвиг высоты тона звука
От: Khalal  
Дата: 11.07.03 12:20
Оценка:
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'
Re[3]: Сдвиг высоты тона звука
От: PavZ  
Дата: 11.07.03 12:28
Оценка:
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')
Re[3]: Сдвиг высоты тона звука
От: Khalal  
Дата: 11.07.03 12:30
Оценка:
формула немного съехала, и пару штрихов пропустил.
K>Вывод этой формулы:

x — n'*t'
--------------- =
(n'+1)*t' — n'*t'

y — A(n')
=---------------
A(n'+1) — A(n')



Подставляя x = Tres,получаем
Ares = y = A(n')+

Tres — n'*t'
------------- * ( A(n'+1) — A(n') )
t'
Re[4]: Сдвиг высоты тона звука
От: PavZ  
Дата: 11.07.03 15:06
Оценка:
Ну как работает ?
Cильно звук подпортился ?
Re[5]: Сдвиг высоты тона звука
От: Khalal  
Дата: 11.07.03 15:58
Оценка:
PZ>Ну как работает ?
PZ>Cильно звук подпортился ?

Нет, этот алгоритм не совсем подходит.
Наложение не получается.

Например, если был сигнал
__|--|__|--|__|--|
то после сдвига тона на октаву вверх получится
_|-|_|-|_|-|
Так как звук, тон которого надо сдвинуть не такой простой, то удлинить его нельзя.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.