使用 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);
限制:
- 慢,需要多次单独执行
混合似乎是有限的,即尝试加入 100 或 200 个文件将产生一个包含一些但不是全部音调的文件。尝试加入 1000 个文件将失败且没有输出。人们大概可以连接几个文件,然后连接这些连接的文件,但这会加剧第一个限制。当创建多个 <= 100 色调中间文件的最终混合时,似乎在组件完成渲染之前处理混合,产生空的最终混合。
- 已放弃 "mixing" 并能够使用更新后的方法 1 成功连接任意数量的音调,因为此方法显示出最有希望的我将继续试验并随着最终限制取得进展而更新。
- 虽然不重要,但最终输出没有 "flow",听起来就像是很多单独的音调粘在一起。
方法 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);
限制:
- 尝试用超过 300 种音调创造 "chords"
与最后一种方法类似的问题,但是连接更小
使用这种方法的文件听起来很奇怪,因为
在连接处有可听中断的组件。可以重叠文件,但这仍然不理想。
- 虽然使用此方法的音符重叠会产生 "flowing" 音频
它还引入了裁剪,大概是由于两个的分层
音量为 1 的音调。我无法按照方法 1
确定如何指定音量
理想的答案将解决以下问题:
- 合成多个音调并将它们组合成一个单一的内聚音调
一片"music"
- 使用不确定长度的源数据集
- 避免在最终输出中剪裁
经过更多的实验,我确定了一种满足我要求的方法。我确信可以利用管道来提高流程的效率,但是这种方法已经在不到一分钟的时间内对所需的近似大小 (~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。
首先我会说我在音频处理和合成方面完全是个新手,如果我做出了一些愚蠢的假设或误解了核心概念,请纠正我。
我正在尝试使用 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);
限制:
- 慢,需要多次单独执行
混合似乎是有限的,即尝试加入 100 或 200 个文件将产生一个包含一些但不是全部音调的文件。尝试加入 1000 个文件将失败且没有输出。人们大概可以连接几个文件,然后连接这些连接的文件,但这会加剧第一个限制。当创建多个 <= 100 色调中间文件的最终混合时,似乎在组件完成渲染之前处理混合,产生空的最终混合。- 已放弃 "mixing" 并能够使用更新后的方法 1 成功连接任意数量的音调,因为此方法显示出最有希望的我将继续试验并随着最终限制取得进展而更新。
- 虽然不重要,但最终输出没有 "flow",听起来就像是很多单独的音调粘在一起。
方法 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);
限制:
- 尝试用超过 300 种音调创造 "chords" 与最后一种方法类似的问题,但是连接更小 使用这种方法的文件听起来很奇怪,因为 在连接处有可听中断的组件。可以重叠文件,但这仍然不理想。
- 虽然使用此方法的音符重叠会产生 "flowing" 音频 它还引入了裁剪,大概是由于两个的分层 音量为 1 的音调。我无法按照方法 1 确定如何指定音量
理想的答案将解决以下问题:
- 合成多个音调并将它们组合成一个单一的内聚音调 一片"music"
- 使用不确定长度的源数据集
- 避免在最终输出中剪裁
经过更多的实验,我确定了一种满足我要求的方法。我确信可以利用管道来提高流程的效率,但是这种方法已经在不到一分钟的时间内对所需的近似大小 (~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。