soundtouch变速主要采用WSOLA算法来进行变速。

http://www.surina.net/soundtouch/

https://blog.csdn.net/suhetao/article/details/5863477

The principle of WSOLA refer to following figure:

There are three important parameter: SequenceMs, overlapMs, seekWindowMs.

These parameters affect to the time-stretch algorithm as follows:

    • DEFAULT_SEQUENCE_MS: This is the default length of a single processing sequence in milliseconds which determines the how the original sound is chopped in the time-stretch algorithm. Larger values mean fewer sequences are used in processing. In principle a larger value sounds better when slowing down the tempo, but worse when increasing the tempo and vice versa.

      By default, this setting value is calculated automatically according to tempo value.

    • DEFAULT_SEEKWINDOW_MS: The seeking window default length in milliseconds is for the algorithm that seeks the best possible overlapping location. This determines from how wide a sample "window" the algorithm can use to find an optimal mixing location when the sound sequences are to be linked back together.

      The bigger this window setting is, the higher the possibility to find a better mixing position becomes, but at the same time large values may cause a "drifting" sound artifact because neighboring sequences can be chosen at more uneven intervals. If there's a disturbing artifact that sounds as if a constant frequency was drifting around, try reducing this setting.

      By default, this setting value is calculated automatically according to tempo value.

    • DEFAULT_OVERLAP_MS: Overlap length in milliseconds. When the sound sequences are mixed back together to form again a continuous sound stream, this parameter defines how much the ends of the consecutive sequences will overlap with each other.

      This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting by a large amount, you might wish to try a smaller value on this.

function out = check_limits(in, min, max)

if in < min

  out = min;

else if in > max

  out = max;

else

  out = in;

end

end

function [seekWindowLength, seekLength, overlapLength] = calcSeqParams(fs, tempo)

overlapMs = 8;

autoseq_tempo_low = 0.5;

autoseq_tempo_top = 2.0;

autoseq_at_min = 90;

autoseq_at_max = 40;

autoseq_k =(autoseq_at_max - autoseq_at_min) / (autoseq_temp_top - auto_temp_low);

autoseq_c = autoseq_at_min -autoseq_k * autoseq_temp_low;

autoseek_at_min = 20;

autoseek_at_max = 15;

autoseek_k =(autoseek_at_max - autoseek_at_min) / (autoseq_temp_top - auto_temp_low);

autoseek_c = autoseek_at_min -autoseek_k * autoseq_temp_low;

%calc sequenceMs

seq = autoseq_c + autoseq_k * tempo;

seq = check_limits(seq, autoseq_at_max, autoseq_at_min);

sequenceMs = round(seq);

seek= autoseek_c + autoseek_k * tempo;

seek= check_limits(seek, autoseek_at_max, autoseek_at_min);

seekMs = round(seek)

seekWindowLength = sequenceMs * fs / 1000;

seekLength = seekMs * fs /1000;

overlapLength = overlapMs * fs / 1000;

overlapLength  = overlapLength - mod(overlapLength, 8);

end

function corr = calcCrossCorr(mixingSeg, compareSeg)

len = length(compareSeg(:,1));

corr = 0;

norm = 0;

for i = 1: 1 : len

  corr = corr + mixingSeg(i) * compareSeg(i);

  norm = norm + mixingSeg(i) * mixingSeg(i);

end

corr = corr / sqrt(norm);

end

function offset = seekBestOverlapPosition(seekWindow, compareSeg, overlapLength, seekLength)

bestCorr = calcCrossCorr(seekWindow(1:overlapLength, 1), compareSeg);

offset = 1;

for i = 2 : 1 : seekLength

  corr = calcCrossCorr(seekWindow(i:i + overlapLength, 1), compareSeg);

  if corr > bestCorr

    bestCorr = corr;

    offset = i;

  end

end

end

function output = overlap(rampUp, rampDown)

len=length(rampDown);

for i = 1:1:len

  output(i,1) = rampUp(i) * i / len + rampDown(i) * (len - i) / len;

end

end

function [output, outpos, lastCompare, inpos] = processSamples(input, inputLen, expectOutputLen, compareSeg, overlapLength, seekLength, seekWindowLength, tempo, isBeginning)

nominalSkip = tempo * (seekWindowLength - overlapLength);

sampleReq  = max(round(nominalSkip) + overlapLength, seekWindow);

inpos = 1;

outpos = 1;

offset = 0;

skipFract = 0;

while inputLen - inpos >= sampleReq

  if isBeginning == 0

    offset = seekBestOverlapPosition(input(inpos : inpos + overlapLength + seekLength - 1, 1), compareSeg, overlapLength, seekLength);

    output(outpos:outpos + overlapLength - 1, 1) = overlap(input(inpos + offset : inpos + offset + overlapLength - 1, 1), compareseg);

    ouputpos = outpos + overlapLength;

    offset = offset  + overlapLength;

  else

    isBeginning = 0;

    skip = round(tempo * overlapLength);

    skipFract = skipFract - skip;

  end

  temp = (seekWindowLength - 2 * overlapLength);

  if outpos + tmep < expectOutputLen

    output(outpos : outpos + temp - 1, 1) = input (inpos + offset : inpos + offset + temp - 1, 1);

    outpos = outpos + temp;

  else   

    output(outpos : expectOutputLen, 1) = input (inpos + offset : inpos + offset + expectOutputLen- outpos, 1);

    outpos = expectOutputLen;

    beak;

  end

  compareSeg = input (inpos + offset + temp: inpos + offset + temp +overlapLength - 1, 1);

  skipFract = skipFract + nominalSkip;

  ovlSkip = floor(skipFract);

  skipFract = skipFract - ovlSkip;

  inpos = inpos  + ovlSkip;

end

lastCompare = compareSeg;

end

function output = changeTempo(input, fs, tempo)

inputLen = length(input(:,1));

outputLen = round(inputLen / tempo);

output = zeros(outputLen, 1);

[seekWindowLength, seekLength, overlapLength] = calcSeqParams(fs, tempo);

isBeginning = 1;

compareBuf = zeros(overlapLength, 1);

expectOutLen = outputLen;

[output, outpos, compareBuf, inpos] = processSamples(input, inputLen, expectOutLen, compareBuf, overlapLength, seekLength, seekWindowLength, tempo, isBeginning);

remainningSamples = inputLen - inpos;

%append zeros to the remainning data

remainningLen = remainningSamples + 200 * 128;

remainningInput = zeros(remainningLen, 1);

remainningInput(1:remainningSamples, 1) = input(inpos:inpos + remainningSamples - 1, 1);

if outputLen > outpos

  expectOutLen = outputLen - outpos + 1;

  isBeginning = 0;

  [tempOutput, tempOutpos, compareBuf, inpos] = processSamples(remainingInput, remainingInputLen, expectOutLen, compareBuf, overlapLength, seekLength, seekWindowLength, tempo, isBeginning);

  output(outpos:outputLen, 1) = tempOutput(1: tempOutpos);

end

end

main.m:

clc;

clear all;

[input fs] = wavread('test.wav');

tempo = 2;

output = changeTempo(input, fs, tempo);

wavwrite(output, fs, 'output.wav');

最新文章

  1. 指令的Link函数和Scope
  2. android-eclipse-phonegap 2..9以下(包含2.9)的项目配置
  3. Java多态性理解
  4. linux杂谈
  5. openstack4j
  6. ASP.NET- 执行SQL超时的解决方案
  7. partial与sorted
  8. 异步和同步http请求超时机制
  9. System.getProperty参数大全
  10. $Django cbv源码分析 djangorestframework框架之APIView源码分析
  11. AndroidStudio制作个人资料界面模块以及SQLite数据库的使用
  12. LeetCode-714.Best Time to Buy and Sell Stock with Transaction Fee
  13. cnBlogs博客推荐
  14. addClass+siblings+removeClass用意:
  15. ArrayList和Vector性能对比
  16. Sed替换文本中的指定内容
  17. ubuntu 下安装nodejs以及pm2
  18. C# WinForm开发DataGridView 使用
  19. HDOJ2084数塔问题
  20. bzoj4506: [Usaco2016 Jan]Fort Moo(暴力)

热门文章

  1. css flex弹性布局学习总结
  2. Network Emulator for Windows Toolkit(模拟弱网络环境的软件)
  3. 战“疫”背后的AI身影丨曼孚科技
  4. 数据结构(集合)学习之Collection和Iterator
  5. java Graphics2D绘制文字 本地正常服务器乱码问题
  6. Keras高层API之Metrics
  7. 第1节-认识Jemeter
  8. Educational Codeforces Round 46 (Rated for Div. 2) D
  9. HTTP代理服务器搭建
  10. GYCTF 盲注【regexp注入+时间盲注】