使用SoX合成可变长度多音调音频,同时避免剪辑

时间:2016-07-09 10:15:25

标签: php audio sox

我将在前言中说我在音频处理和综合方面是一个新手,如果我做出一些愚蠢的假设或误解核心概念,请纠正我。

我正在尝试使用SoX将数字数据数组转换为单个音频文件。到目前为止,我有两种“工作”方法会产生一些非常可怕的结果,并且两者都有严重的局限性。

我在64位WIN 8.1盒子上通过PHP使用SoX。

方法1 输出单个音调然后连接

$toneLinks=array();
for($i=0;$i<count($sourceData);$i++){
  $filename='tones\\'.$dataTitle.'_'.$i.'.au';
  $soxCommand=$soxFolder.'sox -n '.$filename.' synth .5 sin '.($sourceData[$i]).' vol 0.5 ';
  shell_exec($soxCommand);
  $toneLinks[]=$filename;
}
$chunks=array_chunk($toneLinks,100);
$chunkFiles=array();
for($ch=0;$ch<count($chunks);$ch++){
  $name='tones\\'.$dataTitle.'_chunk_'.$ch.'.au';
  $soxCommand=$soxFolder.'sox ';
  for($i=0;$i<count($chunks[$ch]);$i++){
      $soxCommand.=' '.$chunks[$ch][$i]; 
  }
  $soxCommand.=' '.$name;
  $result=shell_exec($soxCommand);
  $chunkFiles[]=$name;
}
$soxCommand=$soxFolder.'sox ';
for($i=0;$i<count($chunkFiles);$i++){
  $soxCommand.=' '.$chunkFiles[$i]; 
}
$soxCommand.=' '.$dataTitle.'.au';
shell_exec($soxCommand);

限制:

  • 慢,需要多次单独执行
  • 混音似乎是有限的,即尝试加入100或200个文件将产生包含一些但不是所有音调的文件。尝试加入1000个文件将失败,没有输出。人们可能会连接几个文件,然后连接这些连接的文件,但这会加剧第一个限制。当创建多个&lt; = 100色调中间文件的最终混合时,看起来混合在组件完成渲染之前被处理,产生空的最终混合。
  • 放弃了“混合”,并且能够使用更新的方法1成功连接任意数量的音调,因为这种方法显示了最大的承诺,我会继续尝试和更新,因为最终限制已取得进展。
  • 虽然不是很关键,但最终输出没有“流动”,听起来就像是这样,很多单独的音调粘在一起。

方法2 在单个命令中生成“和弦”

$soxCommand=$soxFolder.'sox -n '.$dataTitle.'.au synth ';
for($i=1;$i<count($sourceData);$i++){
    $soxCommand.='.25 sin '.($sourceData[$i]).' ';  
}
$soxCommand.='delay ';
for($i=1;$i<count($sourceData);$i++){
    $soxCommand.=($i*.2).' ';   
}
$soxCommand.='remix - fade 0 '.(count($sourceData)*.2+.5).' .1 norm -1';
shell_exec($soxCommand);

限制:

  • 尝试创造超过300个音调的“和弦”,遇到一个 与上一个方法类似的问题,但是连接较小 使用此方法的文件听起来很奇怪,因为有混合色调 在连接处有可听断点的组件。人们可以重叠文件,但这仍然不理想。
  • 虽然音符与此方法重叠会产生“流动”音频 它也引入了剪辑,可能是由于两个层次结构 音量为1的音调。我无法按照方法1
  • 计算出如何指定音量

理想的答案将解决以下问题:

  • 合成多个音调并将它们组合成一个单一的内聚 一块“音乐”
  • 使用不确定长度的源数据集
  • 避免在最终输出中剪裁

1 个答案:

答案 0 :(得分:0)

经过一些实验,我已经找到了满足我要求的方法。我确信可以使用管道来提高过程效率,但是这种方法已经在不到一分钟的时间内对大约所需大小(~2,000)的数据集产生了所需的结果。

//Generate individual tones
$tones=array();
for($i=0;$i<count($sourceData)-1;$i++){
    $name='tones\\'.$dataTitle.'_'.$i.'.au';
    $soxCommand=$soxFolder.'sox -n '.$name.' synth 0.2 sin '.($sourceData[$i]).' fade q 0.05 0 ';
    shell_exec($soxCommand);
    $tones[]=$name;
}
//Break into manageable chunks to avoid exec character limit
$chunks=array_chunk($tones,100);
$chunkFiles=array();
for($ch=0;$ch<count($chunks);$ch++){
    $name='tones\\'.$dataTitle.'_chunk_'.$ch.'.au';
    $soxCommand=$soxFolder.'sox ';
    for($i=0;$i<count($chunks[$ch]);$i++){
        $soxCommand.=' '.$chunks[$ch][$i]; 
    }
    $soxCommand.=' '.$name.' splice 0.2';
    shell_exec($soxCommand);
    $chunkFiles[]=$name;
}
//Render chunks into final track
$soxCommand=$soxFolder.'sox ';
for($i=0;$i<count($chunkFiles);$i++){
    $soxCommand.=' '.$chunkFiles[$i]; 
}
$soxCommand.=' '.$dataTitle.'.au splice 20';
shell_exec($soxCommand);
//Clean component files
for($i=0;$i<count($tones);$i++){
    unlink($tones[$i]); 
}
for($i=0;$i<count($chunkFiles);$i++){
    unlink($chunkFiles[$i]); 
}

消除SoX命令的消歧

生成音调:&#34; sox -n [outfile] synth 0.2 [frequency] fade q 0.05 0&#34;

此命令产生0.2秒的音调,在音轨自然结束前0.05秒,四分之一正弦淡入0.05秒,四分之一正弦淡出。

组合音调/组块:&#34; sox [tone1] [tone2] [音调...] [outfile]拼接0.2&#34;

这里的秘诀就是拼接,它将自动尝试消除由哑连接引起的点击。最后一个命令只是将音调infiles替换为chunk infiles,并将拼接点从0.2秒增加到20秒。