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

我正在尝试使用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个文件将失败,并且没有任何输出。一个人可能会串联几个文件,然后串联那些串联的文件,但这会加剧第一个限制。当创建多个
  • 放弃了“混合”功能,并且能够使用更新的方法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
  • 指定音量

    理想的答案将解决以下问题:
  • 合成多个音调并将它们组合为单个内聚
    一块“音乐”
  • 使用不确定长度的源数据集
  • 避免剪切最终输出中的
  • 最佳答案

    经过更多的实验,我确定了可以满足我的要求的方法。我敢肯定,可以利用管道来提高过程效率,但是这种方法在一分钟内就可以在所需大小(〜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 [输出文件]合成器0.2 [频率]淡入q 0.05 0”

    此命令会在音轨自然结束之前生成0.2秒的音调,并带有0.05秒的四分之一正弦渐弱和0.05秒的四分之一正弦渐弱。

    组合音调/块:“sox [tone1] [tone2] [tone ...] [outfile]拼接0.2”

    其中的秘诀在于接头,它将自动尝试消除由哑级联所引起的咔嗒声。最后的命令只是将音调infile替换为块infile,并将接合点从0.2sec增加到20sec。

    10-06 12:56