有声读物播放器如何在不使用更多内存的情况下快速加快/减慢播放速度?

信息处理 声音的 算法 即时的 时域 索拉
2022-02-08 15:14:40

Android 上的许多有声读物播放器应用程序都有一个阅读速度滑块,可让我们选择阅读速度,例如0.5x 0.75x 1.00x 1.25x 1.50x这是没有音高变化的时间拉伸。

我对如何使用算法来做到这一点有一些想法PSOLA,但他们需要额外的内存,相当于原始音频文件的内存。

前任。

Original audio file -> PSOLA -> Modified audio file

但是当我们尝试改变阅读速度时,这些 Andorid 应用程序似乎并没有使用双倍的内存。他们如何in place如此迅速地延长/缩短时间?


编辑。我找到了这个YouTube 工程博客,它把我带到了sonic图书馆,这反过来又把我带到了PICOLA算法的描述。

我不明白图像中的算法。谁能解释一下?那些三角形是什么意思?他们如何决定这些AB要点?

PICOLA的时间尺度扩展程序 在此处输入图像描述

1个回答

哇,回答这个问题的差距很长,也许如果我有爱因斯坦的大脑,我可以理解图像,这不是我的情况哈哈。

我很久以前就接触过这个算法,我记得这让我很惊讶,几乎没有人在网上谈论 Morita Naotaka 的算法,我试图搜索他的原始论文但我在网上找不到,我想那个是日文的,我不知道...

因此,我从引用森田直孝的专利数量中了解到它,当我看到 2000 年左右使用相同代码的许多专利时,我冻结了。

据我所知,该算法源自TDHSTDHS,具有 TDHS 的优势,仅使用周期大小缓冲区即可完成工作。相信我,它和 TDHS 一样容易编码。

所以走吧,看看雅马哈专利号,US8085953这基本上是PICOLA森田直孝的……

这是该专利中的一张图片,可以更好地理解它是如何压缩的:

在此处输入图像描述

看起来像一个使用三角形窗口的 TDHS,但看看它是如何切割的wave A,并且wave B在精确的 Period size( Lp) 中,然后它们是 crossfaded A + B此图像似乎是使用 rate = 0.6factor(alpha) 进行的压缩, L可以使用以下方法确定:

L=round(Lpα1)

在这里它是如何扩展的:

在此处输入图像描述

现在L可以使用以下方法确定:

L=round(Lpα1α)

前段时间我在TDHS 这里展示了一个基本的压缩代码,现在让我们尝试一个更复杂和完整的例子来扩展(它会变慢),所以基于这个图像/方程,这里是我的PICOLA算法:

alpha=0.5;

f=735;
Fs=44100;
signal= 0.9*sin(2*pi*f/Fs*(1:44100)); signal = signal';

period= 60; % is it (Fs/F)

[signal,Fs]=audioread('ederwander.wav');
   
nsamples = length(signal);
out=zeros(1,floor(nsamples/alpha));
inptr=1;
outptr=1;


minF = 50;
maxF = 900;
     
minP = floor(Fs/maxF);
maxP = floor(Fs/minF);


winsize = 1024;

while ( inptr+winsize <= nsamples )

    
    %chunk used to find the period, its need be >= MaxP
    windowedSignal=signal(inptr:inptr+winsize);

    %Basic Autocorrelation to find the period
    Maximum=-Inf(1);
    for P =minP:maxP
        ac = sum(windowedSignal(1:(winsize)-P) .* windowedSignal(P:(winsize -1)));
        if ac > Maximum
            period=P;
            Maximum=ac;
        end
    end

    period = period-1;

    %split all how shown in the patent picture 
    waveA = signal(inptr:inptr+period-1);
    waveB = signal(inptr+period:(inptr+period*2-1));
    CrossfadeAB = (waveA .* linspace(0,1,period)') + (waveB .* (1-linspace(0,1,period))');
    L = round(period*alpha/(1-alpha));
    waveB_T0 = signal(inptr+period:inptr+L);
    out(outptr:outptr+period-1)=waveA;
    out(outptr+period:outptr+period*2-1)=CrossfadeAB';
    out(outptr+period*2:outptr+period+L)=waveB_T0';

    %increment input and output pointers
    inptr = inptr + L;
    outptr = outptr + L + period;
    

end


%not best choice, just append the end to match the out size, this will click, maybe need crossfade here
if outptr < nsamples/alpha

    fim=floor(nsamples/alpha)-outptr;
    out(outptr:floor(nsamples/alpha))=signal(nsamples-fim:nsamples);

end

plot(out);
sound(out,Fs);

我认为 PICOLA 的标准算法只会得到很好的结果0.5<=alpha<=2

再一次,它可以被认为是一种概念证明,以展示它是如何完成的!