2
$\begingroup$

Many audiobook player apps on Android have a reading speed slider which lets us choose the reading speed e.g. 0.5x 0.75x 1.00x 1.25x 1.50x. This is time-stretching without pitch shifting.

I have some idea about how this could be done using PSOLA algorithm(s), but they would need extra memory equivalent to the memory of original audio file.

ex.

Original audio file -> PSOLA -> Modified audio file

But these Andorid apps don't seem to use double the memory when we try to change reading speed. How do they do an in place time stretching/shortening so quickly?


edit. I found this YouTube engineering blog, which led me to sonic library, which in turn led me to a description of PICOLA algorithm.

I don't understand the algorithm from the images though. Could anyone please explain? What do those triangles mean? How do they decide these A and B points?

Time scale expansion procedure of the PICOLA enter image description here

$\endgroup$
  • $\begingroup$ I can try write about picola, but for while you can read about TDHS here $\endgroup$ – ederwander Jan 8 '19 at 0:58
  • $\begingroup$ @ederwander could you please post your answer. will be much appreciated $\endgroup$ – xxx374562 Mar 26 '19 at 5:48
  • $\begingroup$ I finally had time to write about it $\endgroup$ – ederwander Aug 23 at 19:09
0
$\begingroup$

WOW long gap to answer this question, maybe if I have a Einstein brain I can understand the image, what is not my case lol.

I haved touched in this algorithm in a long time ago, and I remember that was a surprised for me that almost no one around the Web talks about the Algorithm from Morita Naotaka, I tryed seach his original paper but I cant found online, I think that it is in Japanese, well I dont know ...

So I learned about it looking at among number of patents that make references to the Morita Naotaka, and I freeze when I see a lot of patents around 2000 years that use the same code.

As far as I know this algorithm was derived from TDHS, has advantages about TDHS, this does the job using just Period size Buffer. And believe me it's as easy to code as TDHS.

So lets go, take a look at the Yamaha Patent number US8085953 this is basicly the PICOLA from Morita Naotaka...

Here one image from this Patent that is infinity better to understand how this works to compress :

enter image description here

Looks like one TDHS using a triangular window, but take a look how it are cutting wave A and wave B in the exact Period size(Lp), then they are crossfaded A + B. this image seems to be an compression using rate = 0.6 factor(alpha), L can be determined using:

$$ \begin{align} L & = \operatorname{round}\left(\frac{L_p}{\alpha-1}\right) \end{align} $$

And here how its works to expansion:

enter image description here

Now L can be determined using:

$$ \begin{align} L & = \operatorname{round}\left(L_p\frac{\alpha}{1-\alpha}\right) \end{align} $$

Time ago I show a basic code to compress based in TDHS here, now lets try a litle bit more complex and complete example to expand (it will slowdown), so based in this images/equations, here my PICOLA Algorithm:

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);

I think that standard algorithm of PICOLA just get nice results to 0.5<=alpha<=2

And one more time it's can be considered a proof of concept to show how its can be done!

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.