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

Synthesise variable length multi tonal audio with SoX while avoiding clipping

首先我会说我在音频处理和合成方面完全是个新手,如果我做出了一些愚蠢的假设或误解了核心概念,请纠正我。

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

我在 64 位 WIN 8.1 机器上通过 PHP 使用 SoX。

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

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

限制:

方法 2 在单个命令中生成 "chord"

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

限制:

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

经过更多的实验,我确定了一种满足我要求的方法。我确信可以利用管道来提高流程的效率,但是这种方法已经在不到一分钟的时间内对所需的近似大小 (~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 命令的消歧

生成音调: "sox -n [outfile] synth 0.2 [frequency] fade q 0.05 0"

此命令生成一个 0.2 秒的音调,四分之一正弦波淡入 0.05 秒,四分之一正弦波在曲目自然结束前 0.05 秒淡出。

合并 tones/chunks: "sox [tone1] [tone2] [tone...] [outfile] splice 0.2"

其中的秘诀是拼接,它会自动尝试消除由哑连接引起的点击。最后的命令只是用块 infiles 替换音调 infiles,并将拼接点从 0.2sec 增加到 20sec。