![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
WAV - TimeStreatch (сжатие звука по времени) ...
Wm.DIGGER © (2006-05-03 12:53:00)Господа, подскажите пожалуйста. Мне нужно реализовать алгоритм TimeStreatch - сжатие звука по времени ... т.е. допустим время звучания wav-файла 3 сек. мне нужно сделать чтобы оно было 2,5 сек. Эта функция есть почти во всех звуковых редакторах и в каждом используется свой алгоритм, но вот описания хотябы одного алгоритма я нигде не нашёл ...
Пошёл самым простым путём: решил рассчитать коэффициент (шаг) и просто выбросить семплы в соответствие с этим шагом ... т.е. скажем из 3 сек. сделать 2,5 при частоте 48000Гц 16 bit Mono ... после расчётов получил шаг = 4 ... т.е. отбрасываю каждый 4-тый семпл последовательности ...
ок - получаю новый wav-файл продолжительностью 2,5 сек ...
но вот голос (в файле был записан голос) :)))) голос становится "писклявым" :) т.е. искажается ...
я понимаю, что сделанное мной мягко говоря "тупо" :)
подскажите, как выполнить сжатие по времени и получить звук без искажений ... ?
Wm.DIGGER (2006-05-05 11:07:00) [21]а вы, уважаемый, хоть знаете что такое Информатика ... :)))) ?
причём здесь написание кода - это программирование к информатике как науке отношение имеет косвенное ...
а если не знаете, так и скажите ... а то умников я смотрю развилось ...
языком часать все гаразды, а что-то конкретное недождёшся ...
Jeer (2006-05-05 10:57:00) [22]Wm.DIGGER © (05.05.06 04:16) [15]
> не поленитесь, код напишите ...
Учись аспирант.
Интересно какую математику и информатику ты преподаешь ?
programania © (04.05.06 20:15) [14]
> Преобразовать в массив частот
> Сдвинуть их вниз на 10% от размера массива т.к. он равен
> размеру массива по времени
> Преобразовать назад
Это не то, это - pitch
Wm.DIGGER (2006-05-05 04:16:00) [23]ну, господа, ну программулю можно?
ну, вот - Преобразовать в массив частот ... а что сразу весь звуковой файл?
нет, а сколько лучше взять ... я же говорил ... там размер окна нужно. какой размер лучше брать? не поленитесь, код напишите ...
programania (2006-05-04 20:15:00) [24]>ancara © (04.05.06 10:31) [8]
>ну так попробуй вырезать кусками по 50 - 100 мс, что получится?
Получится много треска из-за сильных мгновенных перепадов амплитуды
Вырезать лучше в месте перехода через 0
а еще лучше искать минимальные участки
с самой одинаковой амплитудой и производной
т.е. наклоном на краях равномерно по всему звуку
и их вырезать или вставлять
тогда наверно будет незаметно
>Wm.DIGGER © (04.05.06 15:24) [11]
>я дам процедуру БПФ (FFT) ... можешь написать, как её применить конкретно к звуку ...
Преобразовать в массив частот
Сдвинуть их вниз на 10% от размера массива т.к. он равен размеру массива по времени
Преобразовать назад
Сжать амплитуды по времени на 10% как в [7]
Jeer (2006-05-04 17:36:00) [25]Завтра отвечу, но если ты сумеешь сделать новый MPEX - Штейнберг (Steinberg) возмет тебя на работу не глядя.
Wm.DIGGER (2006-05-04 15:32:00) [26]В зависимости от переданных параметров, может выполняться
как прямое, так и обратное преобразование.
Входные параметры:
nn - Число значений функции. Должно быть степенью
двойки. Алгоритм не проверяет правильность
переданного значения.
a - array [0 .. 2*nn-1] of Real
Значения функции. I-ому значению соответствуют
элементы a[2*I] (вещественная часть)
и a[2*I+1] (мнимая часть).
InverseFFT
- направление преобразования.
True, если обратное, False, если прямое.
Выходные параметры:
a - результат преобразования.
Wm.DIGGER (2006-05-04 15:24:00) [27]собственно могу даже упростить задачу ...
я дам процедуру БПФ (FFT) ... можешь написать, как её применить конкретно к звуку ... ? ну очень нужно ... плиззз!
type TDArray = array of Double;
procedure FastFourierTransform(var a : TDArray;
nn : Integer;
InverseFFT : Boolean);
var
ii : Integer;
jj : Integer;
n : Integer;
mmax : Integer;
m : Integer;
j : Integer;
istep : Integer;
i : Integer;
isign : Integer;
wtemp : Double;
wr : Double;
wpr : Double;
wpi : Double;
wi : Double;
theta : Double;
tempr : Double;
tempi : Double;
begin
if InverseFFT then
begin
isign := -1;
end
else
begin
isign := 1;
end;
n := 2*nn;
j := 1;
ii:=1;
while ii<=nn do
begin
i := 2*ii-1;
if j>i then
begin
tempr := a[j-1];
tempi := a[j];
a[j-1] := a[i-1];
a[j] := a[i];
a[i-1] := tempr;
a[i] := tempi;
end;
m := n div 2;
while (m>=2) and (j>m) do
begin
j := j-m;
m := m div 2;
end;
j := j+m;
Inc(ii);
end;
mmax := 2;
while n>mmax do
begin
istep := 2*mmax;
theta := 2*Pi/(isign*mmax);
wpr := -2.0*sqr(sin(0.5*theta));
wpi := sin(theta);
wr := 1.0;
wi := 0.0;
ii:=1;
while ii<=mmax div 2 do
begin
m := 2*ii-1;
jj:=0;
while jj<=(n-m) div istep do
begin
i := m+jj*istep;
j := i+mmax;
tempr := wr*a[j-1]-wi*a[j];
tempi := wr*a[j]+wi*a[j-1];
a[j-1] := a[i-1]-tempr;
a[j] := a[i]-tempi;
a[i-1] := a[i-1]+tempr;
a[i] := a[i]+tempi;
Inc(jj);
end;
wtemp := wr;
wr := wr*wpr-wi*wpi+wr;
wi := wi*wpr+wtemp*wpi+wi;
Inc(ii);
end;
mmax := istep;
end;
if InverseFFT then
begin
I:=1;
while I<=2*nn do
begin
a[I-1] := a[I-1]/nn;
Inc(I);
end;
end;
end;
Wm.DIGGER (2006-05-04 14:47:00) [28]Jeerэто хорошо ... но ты можешь привести пример реализации БПФ ... ? т.е. не самого БПФ, а как это использовать на практике для звука ... как выбрать размер окна хотябы? напиши, я думаю не только мне будет интересно ...
P.S. про тип звука я говорил, это речь - чистый голос ...
Jeer (2006-05-04 11:12:00) [29]Wm.DIGGER © (03.05.06 23:09) [6]
Надо точнее задавать вопросы и обрисовывать задачу, тогда яснее на что отвечать.
Если не оговорен тип звука, то обсуждение данного эффекта бессмысленно.
Очевидно, что композитный звук из чистых тонов сжать по времени без изменения тональности не удастся.
Cool Edit не меняет тональность в этом случае только для TimeStretch типа "Fast Talker", а для остальных типов - заметное изменение тона, что и понятно.
Все остальные типы композитного звука с широким спектром могут быть обработаны данным эффектом путем отделения нижних (фонемных) и верхних
(тебральных) частот.
Делать это, действительно, лучше с использованием FFT.
Алгоритм такой:
Применяется прямое FFT - получаем спектр фонограммы.
На уровне разделения 50-80 Гц выделяются нижний и верхний спектры фонограммы с небольшим наложением друг на друга.
Нижняя часть спектра транспонируется (растягивается) вверх по частоте в 1.0 - 2.0 раз (больше обычно не делается).
Спектры складываются и применяется обратное FFT для восстановления сигнала.
Вуаля.
ancara (2006-05-04 10:31:00) [30]ну так попробуй вырезать кусками по 50 - 100 мс, что получится?
Wm.DIGGER (2006-05-04 02:01:00) [31]вот код кидаю ... что у меня получается ...
звук сжимается по времени (идёт быстрее), но становиться высоким (если это голос, то писклявым ...) а в звуковых редакторах тоже сжимается, но остаётся нормальным по высоте звучания ...
чего делать?
uses MMSystem;
type
hWAVEHeader = record
idRiff:array[0..3] of Char;
RiffLen:LongInt;
idWave:array[0..3] of Char;
idFmt:array[0..3] of Char;
InfoLen:LongInt;
WaveType:SmallInt;
Channels:SmallInt;
Freq:LongInt;
BytesPerSec:LongInt;
Align:SmallInt;
Bits:SmallInt;
end;
hWAVEDATAHeader = record
idData:array[0..3] of Char;
DataLen:LongInt;
end;
procedure WAVETimeStretch(WAVEFileName:string; NewTime:Real);
var WF,SWF:TFileStream;
WAVEHeader:hWAVEHeader;
DATAHeader:hWAVEDATAHeader;
NBuf,SBuf:array[0..1023] of SmallInt;
BufSize,BStep,NTStep,SStep,SCount:Word;
NewDataLength:integer;
CurrentTime:Real;
begin
WF := TFileStream.Create(WAVEFileName,fmOpenReadWrite);
WF.Position := 0;
WF.ReadBuffer(WAVEHeader,SizeOF(WAVEHeader));
WF.ReadBuffer(DATAHeader,SizeOF(DATAHeader));
SWF := TFileStream.Create(WAVEFileName + '.new.wav',fmCreate);
SWF.WriteBuffer(WAVEHeader,SizeOF(WAVEHeader));
SWF.WriteBuffer(DATAHeader,SizeOF(DATAHeader));
NewDataLength := Round(NewTime * WAVEHeader.Align * WAVEHeader.Freq);
CurrentTime := (NewDataLength / WAVEHeader.Align) / WAVEHeader.Freq; //length in seconds
NTStep := Round((DATAHeader.DataLen / WAVEHeader.Align) / (DATAHeader.DataLen / WAVEHeader.Align - NewDataLength / WAVEHeader.Align));
while WF.Position < DATAHeader.DataLen do
begin
if (WF.Position + SizeOF(NBuf)) < DATAHeader.DataLen then BufSize := SizeOF(NBuf)
else BufSize := DATAHeader.DataLen - WF.Position;
WF.Read(NBuf,BufSize);
BStep := 0; SStep := 0; SCount := 1;
while BStep < 1024 do
begin
if SCount < NTStep then begin SBuf[SStep] := NBuf[BStep]; inc(SStep); inc(SCount); end
else SCount := 1;
inc(BStep);
end;
dec(SStep);
SWF.Write(SBuf,SStep * SizeOF(SmallInt));
end;
SWF.Position := 0;
WAVEHeader := SetWAVEHeader(WAVEHeader.Channels,WAVEHeader.Freq,WAVEHeader.Bits,CurrentTime);
DATAHeader := SetWAVEDATAHeader(WAVEHeader);
SWF.WriteBuffer(WAVEHeader,SizeOF(WAVEHeader));
SWF.WriteBuffer(DATAHeader,SizeOF(DATAHeader));
SWF.Free;
WF.Free;
end;
Wm.DIGGER (2006-05-03 23:09:00) [32]господа, TimeStretch ... есть в любом звуковом редакторе! ...
не нужно пытаться ответить на вопрос, если не знаете о чём речь ...
из часа 30 мин сделать никто не пытается ... как правило коррекция проводиться не более чем на 10% иначе даже самые передовые алгоритмы начинаю давать артефакты ...
ancaraда, именно "ускорение или замедление" звука без потери тональности ... меня интерисует замедление ...
там весь звук разбивается на участки определённой длинны ...
и проводится какой-то анализ ... после чего выводиться зависимоть ...
но вот что это за анализ и какая должна быть зависимость я и не знаю ...
мне посоветовали читать про ряды Фурье ...
но читать можно вечно ...
здесь бы алгоритм, а лучше его реализацию ...
ancara (2006-05-03 16:38:00) [33]А я, кажись, понял что он хочет. Ему нужно чтоб время сократилось а тональность сохранилась. В каком-то проигрывателе, вроде PowerDVD, (да и вообще во многих) можно регулировать скорость воспроизведения, можно установить, например, 2-х кратную. В этом случае, персонажи фильма реально начинают тараторить, т.е. говорить своими голосами, но быстрее.
Как реализовано там не знаю, но мне кажется вырезаются не отдельные сэмплы а их последовательности, т.е. куски аудиотрека такие... Может по 100 мс или меньше, надо экспериментально подбирать, ИМХО.
Jeer (2006-05-03 14:05:00) [34]Тогда непонятно, что хочешь ты.
Как ты себе представляешь - вся пестня звучит 1 час, ты хочешь чтобы звучала 30 мин. Скорость проигрывания должна увеличиться в два раза и
> Jeer © (03.05.06 13:06) [2]
Если тебе надо, чтобы длительность была меньше без частотных искажений, то просто отрезаешь "лишний" участок.
Wm.DIGGER (2006-05-03 13:24:00) [35]но Resampling это другая фанкция совсем ...
это пересчёт семплов из 48000 в 44100 скажем и т.п. ...
(может ошибаюсь, но вроде нет ...)
а пример можно в виде кода ...
вот скажем у нас просто массив: m:array[0..1023] of SmallInt;
в нём записано 1024 семпла (для 16 бит 1 сэмпл - 2 байта - SmallInt).
как сдалать то, что ты написал выше? :)
Jeer (2006-05-03 13:06:00) [36]А сжатие временной оси естественно приведет к повышению тона.
Jeer (2006-05-03 13:05:00) [37]Resampling.
Если в лоб, то делается интерполяция (линейная или более высоких порядков - обычно куба достаточно) между отсчетами исходного звука и выбирается ближайшая точка к узлу новой временной сетки.