How to set a specific number of samples at the start and end of a file to 0 in the batch process?

I needed to correct this:

I wanted to set this to 0.

However, I couldn’t find any way to zero those samples in WaveLab 11 Pro. Because of that, I had to change my workflow and manually reset all markers, which is very time consuming.

And since I wanted to replace the existing samples rather than add silence, the Silence plug‑in was of no use to me in this case.

I also noticed a bug in the Silence plug in: it only accepts whole numbers — decimal values can be entered but are ignored. Moreover, the much needed option to enter a sample count is missing as well.

The same input issue occurs with the Trimmer as well — and sample‑level granularity is needed there too.

This is in WaveLab 11 Pro.

Yes, I do have the fades, but the option ‘set all to zero’ is not available there. And since the settings only offer millisecond resolution, this wasn’t a solution either.

You could achieve the result through this batch processor plugin.

However, this may not be available in WaveLab 11 or any of the preceding versions — unless I’m overlooking something.

Thank you kindly for your reply.

This is available in WaveLab 11.

Ah, I’ve found it. But I don’t want to add any additional samples — I want to hard‑set the first and last 82 samples to zero.

Back to your original post: just press the backspace key.

Wonderful — I’ve learned something new. Thank you !!
Backspace resets the selected area to zero.

I needed to automate the process, as I don’t want to repeat it manually for every segment that I later split into separate files.

My solution is as follows: I use a PowerShell (.NET) script that converts the yellow markers into CD markers. Within this script, I adjusted the marker positions so that no mathematically generated artefacts remain in the files. In RX, I set the markers and apply the fades in and out (the markers are embedded in the files at that stage). I then switch to WaveLab, where I’ve configured it so that markers are not stored inside the audio files themselves, but instead in separate text files. After naming them, I process these text files and convert them into a CD‑marker file using this script.

A batch process for resetting them to zero would be quite useful — otherwise I’ll have to implement one myself (in case I decide not to reposition the CD‑marker cutting positions).

Unfortunately, while testing something related to the Lo‑Fi topic, WaveLab briefly displayed the green start‑up window and then failed to launch. I had to rename the old settings folder to get WaveLab 11 to start properly again. I’m now trying to locate the configuration option for “markers stored only in a separate file”. The markers in the text file are extremely important to me.

I recall reading that marker handling in version 12 had “deteriorated” somewhat compared with version 11. Has this still not been addressed, or am I mistaken? (For me, that would have been the highest priority.) It will certainly be interesting to see what WaveLab 13 brings. Counting … 3,2,1 … NAMM … NAMM …

Regarding Dolby Atmos — is Lo‑Fi actually a topic in that context, or have I misunderstood something? Cubase, Nuendo… they all seem to start at 20 Hz if one is lucky — or do they not?

A PowerShell-script on Windows for the zeroing.

I’m sharing it as-is, with no guarantees. If you find a better approach, I’d love to read about it. (I use the PowerShell ISE.)

<#
    WAV Sample Zeroing Tool (PowerShell + Embedded C#)
    --------------------------------------------------
    This script processes WAV audio files and zeros out a specified number 
    of samples at the beginning and end of the audio data.

    Features:
    - Supports PCM 16‑bit, 24‑bit, 32‑bit, and IEEE Float 32‑bit WAV files
    - Automatically detects number of channels (mono, stereo, etc.)
    - Automatically detects bit depth and calculates frame size
    - Uses a dynamically generated C# class name to avoid Add-Type collisions
    - Safely loads the generated type from the dynamic assembly
    - Accepts "samples per channel" as input (not frames)

    Notes:
    - A "frame" = one sample for each channel at a given time.
      Example: Stereo = 2 samples per frame (L + R).
    - Zeroing frames ensures both channels stay aligned.

    Date: 2026-01-23
    Language: English
#>

# ---------------------------------------------------------
# Generate a unique class name to avoid Add-Type conflicts
# ---------------------------------------------------------
$unique = [Guid]::NewGuid().ToString("N")
$classname = "WavTools_$unique"

# ---------------------------------------------------------
# Embed C# code that performs the WAV processing
# ---------------------------------------------------------
Add-Type -TypeDefinition @"
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

public static class $classname
{
    // Helper class to store WAV chunk metadata
    public class ChunkInfo
    {
        public string Id;
        public long Offset;
        public long Size;
    }

    // Main processing function
    public static void ZeroSamplesToNewFile(string inputPath, string outputPath, int samplesStart, int samplesEnd)
    {
        if (!File.Exists(inputPath))
            throw new FileNotFoundException("Input file not found.", inputPath);

        if (samplesStart < 0 || samplesEnd < 0)
            throw new ArgumentException("Sample values must be >= 0.");

        byte[] riffHeader = new byte[12];

        using (FileStream fsIn = new FileStream(inputPath, FileMode.Open, FileAccess.Read))
        using (BinaryReader br = new BinaryReader(fsIn))
        {
            // ---------------------------------------------------------
            // Validate RIFF/WAVE header
            // ---------------------------------------------------------
            if (fsIn.Read(riffHeader, 0, 12) != 12)
                throw new InvalidDataException("File too short for RIFF header.");

            if (Encoding.ASCII.GetString(riffHeader, 0, 4) != "RIFF")
                throw new InvalidDataException("Not a RIFF file.");

            if (Encoding.ASCII.GetString(riffHeader, 8, 4) != "WAVE")
                throw new InvalidDataException("Not a WAVE file.");

            // ---------------------------------------------------------
            // Read all chunks (fmt, data, etc.)
            // ---------------------------------------------------------
            List<ChunkInfo> chunks = new List<ChunkInfo>();

            while (fsIn.Position + 8 <= fsIn.Length)
            {
                byte[] idBytes = br.ReadBytes(4);
                byte[] sizeBytes = br.ReadBytes(4);
                if (idBytes.Length < 4 || sizeBytes.Length < 4)
                    break;

                string id = Encoding.ASCII.GetString(idBytes);
                int size = BitConverter.ToInt32(sizeBytes, 0);
                long chunkStart = fsIn.Position;

                chunks.Add(new ChunkInfo
                {
                    Id = id,
                    Offset = chunkStart,
                    Size = size
                });

                long nextPos = chunkStart + size;
                if (nextPos > fsIn.Length)
                    break;

                fsIn.Seek(size, SeekOrigin.Current);
            }

            // ---------------------------------------------------------
            // Locate fmt chunk
            // ---------------------------------------------------------
            ChunkInfo fmtChunk = chunks.Find(c => c.Id == "fmt ");
            if (fmtChunk == null)
                throw new InvalidDataException("fmt chunk not found.");

            fsIn.Seek(fmtChunk.Offset, SeekOrigin.Begin);
            byte[] fmtData = br.ReadBytes((int)fmtChunk.Size);

            ushort audioFormat = BitConverter.ToUInt16(fmtData, 0);
            ushort numChannels = BitConverter.ToUInt16(fmtData, 2);
            uint sampleRate = BitConverter.ToUInt32(fmtData, 4);
            ushort blockAlign = BitConverter.ToUInt16(fmtData, 12);
            ushort bitsPerSample = BitConverter.ToUInt16(fmtData, 14);

            int bytesPerSample = bitsPerSample / 8;
            int bytesPerFrame = bytesPerSample * numChannels;

            // ---------------------------------------------------------
            // Convert "samples per channel" → "frames"
            // (1 frame = all channels at a given time)
            // ---------------------------------------------------------
            int framesStart = samplesStart;
            int framesEnd   = samplesEnd;

            // ---------------------------------------------------------
            // Locate data chunk
            // ---------------------------------------------------------
            ChunkInfo dataChunk = chunks.Find(c => c.Id == "data");
            if (dataChunk == null)
                throw new InvalidDataException("data chunk not found.");

            long dataStart = dataChunk.Offset;
            long dataSize = dataChunk.Size;

            long bytesStart = (long)framesStart * bytesPerFrame;
            long bytesEnd   = (long)framesEnd   * bytesPerFrame;

            if (dataSize < bytesStart + bytesEnd)
                throw new InvalidDataException("Audio data too short for requested zeroing.");

            // ---------------------------------------------------------
            // Create output file
            // ---------------------------------------------------------
            using (FileStream fsOut = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
            using (BinaryWriter bwOut = new BinaryWriter(fsOut))
            {
                fsIn.Seek(0, SeekOrigin.Begin);
                byte[] buffer = new byte[8192];

                // Copy everything before the data chunk
                long copyUntil = dataStart - 8; // minus header size
                long remaining = copyUntil;

                while (remaining > 0)
                {
                    int toRead = (int)Math.Min(buffer.Length, remaining);
                    int read = fsIn.Read(buffer, 0, toRead);
                    if (read == 0) break;
                    bwOut.Write(buffer, 0, read);
                    remaining -= read;
                }

                // Copy data chunk header
                fsIn.Seek(dataStart - 8, SeekOrigin.Begin);
                bwOut.Write(br.ReadBytes(8));

                // ---------------------------------------------------------
                // Write zeroed frames at the beginning
                // ---------------------------------------------------------
                byte[] zeroFrame = new byte[bytesPerFrame];
                for (int i = 0; i < framesStart; i++)
                    bwOut.Write(zeroFrame);

                // ---------------------------------------------------------
                // Copy middle section (untouched audio)
                // ---------------------------------------------------------
                long middleStart = dataStart + bytesStart;
                long middleEnd   = dataStart + dataSize - bytesEnd;
                long middleLength = middleEnd - middleStart;

                fsIn.Seek(middleStart, SeekOrigin.Begin);
                remaining = middleLength;

                while (remaining > 0)
                {
                    int toRead = (int)Math.Min(buffer.Length, remaining);
                    int read = fsIn.Read(buffer, 0, toRead);
                    if (read == 0) break;
                    bwOut.Write(buffer, 0, read);
                    remaining -= read;
                }

                // ---------------------------------------------------------
                // Write zeroed frames at the end
                // ---------------------------------------------------------
                for (int i = 0; i < framesEnd; i++)
                    bwOut.Write(zeroFrame);

                // ---------------------------------------------------------
                // Copy any chunks after the data chunk
                // ---------------------------------------------------------
                long afterData = dataStart + dataSize;
                fsIn.Seek(afterData, SeekOrigin.Begin);

                while (fsIn.Position < fsIn.Length)
                {
                    int read = fsIn.Read(buffer, 0, buffer.Length);
                    if (read == 0) break;
                    bwOut.Write(buffer, 0, read);
                }
            }
        }
    }
}
"@

# ---------------------------------------------------------
# PowerShell section: Process all WAV files in a folder
# ---------------------------------------------------------

$folder = 'I:\xxx'
$outputFolder = Join-Path $folder 'Output'

if (-not (Test-Path $outputFolder)) {
    New-Item -ItemType Directory -Path $outputFolder | Out-Null
}

# User input: number of samples per channel to zero
$samplesStart = 80
$samplesEnd   = 100

$files = Get-ChildItem -Path $folder -Filter *.wav

foreach ($f in $files) {
    $out = Join-Path $outputFolder ($f.BaseName + '_mod.wav')
    Write-Host "Processing: $out"

    try {
        # ---------------------------------------------------------
        # Locate the dynamically generated assembly containing the class
        # ---------------------------------------------------------
        $asm = [AppDomain]::CurrentDomain.GetAssemblies() |
               Where-Object { $_.GetTypes().Name -contains $classname }

        if (-not $asm) {
            throw "Could not locate assembly for type $classname."
        }

        # Retrieve the type from the assembly
        $type = $asm.GetType($classname)

        if (-not $type) {
            throw "Could not load type $classname."
        }

        # Call the static C# method
        $type::ZeroSamplesToNewFile($f.FullName, $out, $samplesStart, $samplesEnd)

        Write-Host "  ✔ Success"
    }
    catch {
        Write-Host "  ✖ Error: $($_.Exception.Message)"
    }
}

Write-Host ""
Write-Host "Done."
Write-Host "Output files are located in:"
Write-Host "  $outputFolder"