Não tenho certeza se essa solução ajudará alguém, já que as circunstâncias são tão específicas, mas postarei de qualquer maneira, apenas por precaução.
Eu não acredito que exista um utilitário de linha de comando na Internet que possa definir pontos de loop de onda, então acabei escrevendo uma função em Node.js para fazer isso.
module.exports = function()
{
this.SetLoop = function(inputPath, outputPath, start, end)
{
// load input wave
var waveData = require('fs').readFileSync(inputPath);
// get sample rate of wave file
var sampleRateIndex;
for(var i = 0; i < waveData.length-4; i++)
{
if (waveData.toString('utf8', i, i + 4) === 'fmt ') // look for fmt chunk - which contains sample rate among other things - per wave format specification
{
sampleRateIndex = i + 4 + 4 + 2 + 2; // sample rate is 12 bytes after start of 'fmt ' chunk id
break;
}
}
if (sampleRateIndex === undefined)
return;
var sampleRate = waveData.readUInt32LE(sampleRateIndex);
// convert seconds to samples
start = Math.floor(sampleRate*start);
end = Math.floor(sampleRate*end);
// find index (byte offset) of smpl chunk if it exists
var smplIndex;
for(var i = waveData.length-4-1; i >= 0; i--) // start search from end of file going backward, since the smpl chunk is typically written after the actual waveform data
{
if (waveData.toString('utf8', i, i + 4) === 'smpl')
{
smplIndex = i; // start of smpl chunk id
break;
}
}
// if the smpl chunk already exists, remove it
if (smplIndex !== undefined)
{
var smplChunkSize = waveData.readUInt32LE(smplIndex + 4) + 8; // smpl chunk size is specified 4 bytes after start of smpl chunk id. add 8 bytes to include size of smpl chunk header itself
waveData = Buffer.concat( [ waveData.slice(0, smplIndex) , waveData.slice(smplIndex + smplChunkSize) ] ); // splice smpl chunk from wave file data
}
// make new buffer to replace smpl chunk
var smplChunk = Buffer.alloc(68); // the default smpl chunk written here is 60 bytes long. add 8 bytes to include size of smpl chunk header itself
// all bytes other than the ones specified below default to 0 and represent default values for the smpl chunk properties
smplChunk.write('smpl', 0, 4);
smplChunk.writeUInt32LE(60, 4); // the default smpl chunk written here is 60 bytes long
smplChunk.writeUInt32LE(60, 20); // middle C is MIDI note 60, therefore make MIDI unity note 60
smplChunk.writeUInt32LE(1, 36); // write at byte offset 36 that there is one loop cue info in the file
smplChunk.writeUInt32LE(start, 52); // write loop start point at byte offset 52
smplChunk.writeUInt32LE(end, 56); // write loop end point at byte offset 56
// append new smpl chunk to wave file
waveData = Buffer.concat( [ waveData, smplChunk ] );
// change wave file main header data to increase the file size to include smpl chunk (loop points)
var fileSizeIndex;
for(var i = 0; i < waveData.length-4; i++)
{
if (waveData.toString('utf8', i, i + 4) === 'RIFF') // look for RIFF chunk (should always be at the very beginning of file)
{
fileSizeIndex = i + 4; // file size is 4 bytes after start of RIFF chunk id
break;
}
}
if (fileSizeIndex === undefined)
return;
var fileSize = waveData.length-8; // get final length of wave file, minus 8 bytes to not include the RIFF chunk header itself
waveData.writeUInt32LE(fileSize, fileSizeIndex); // write new file length
// write new wave file
require('fs').writeFileSync(outputPath, waveData);
}
}
Para usar a função:
- Instalar o Node.js
- Salve a função acima no arquivo de texto e renomeie para tools.js
- Abra a janela de linha de comando do Node.js
-
require('C:/path/to/where/you/saved/tools.js')();
-
process.chdir('C:/path/to/wave/files');
-
SetLoop('input.wav','output.wav',1,2) // set loop start at 1.0 sec and loop end at 2.0 sec
Observe que esse código substitui completamente o fragmento smpl do arquivo e, como tal, descarta quaisquer pontos de sinalização / loop existentes no arquivo.