Batch define pontos de loop WAV (ou qualquer dado de bloco de arquivos)

1

O formato de arquivo wave suporta um pedaço de dados chamado "smpl", que é reconhecido pela maioria dos plug-ins de DAW e da maioria dos samplers como o Kontakt. O pedaço de dados permite que você especifique uma posição inicial de loop e uma posição final de loop para o arquivo wave.

link link

Como eu pude obter / definir as propriedades desses dados em vários arquivos? Idealmente, eu gostaria de fazer algo assim:

utility.exe input.wav output.wav --loopstart 44100 --loopend 88200

Onde é necessário input.wav como entrada e output.wav com pontos de loop inicial e final inseridos em 1 segundo e 2 segundos em (assumindo áudio de 44,1 kHz) respectivamente.

Eu já sei sobre o SoX, libsndfile e coisas do tipo, mas eles infelizmente não têm essa funcionalidade. Existe outra maneira de conseguir isso?

    
por V. Rubinetti 10.02.2017 / 08:12

1 resposta

2

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:

  1. Instalar o Node.js
  2. Salve a função acima no arquivo de texto e renomeie para tools.js
  3. Abra a janela de linha de comando do Node.js
  4. require('C:/path/to/where/you/saved/tools.js')();
  5. process.chdir('C:/path/to/wave/files');
  6. 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.

    
por 10.02.2017 / 14:22