Types/Wave/set_Samples.ps1

param(
[float[]]
$Samples
)

$BitsPerSample = 
    if ($this.BitsPerSample) { $this.BitsPerSample } 
    else { 8 }

$audioFormat = 
    if ($this.AudioFormat) { $this.AudioFormat } 
    else { 1 }

$GetBytes = [BitConverter]::GetBytes
$sampleNumber = 0
$progress = [Ordered]@{
    Id = Get-Random
    Status = "Encoding"
    Activity = " "
}

$This.Data = @(
    foreach ($sample in $samples) {
        #region Encode Sample

        # We _could_ encapsulate the encoding off into it's own procedure.

        # However, callstacks have overhead.

        # Inline code will be quicker.
        # (hence duplicating it across multiple files)
        
        $sampleNumber++
        if (-not ($sampleNumber % 1kb)) {
            $progress.Status = "$sampleNumber / $($Samples.Length)"
            $progress.PercentComplete = ($sampleNumber * 100 / $samples.Length)
            Write-Progress @progress
        }

        # If we are using 32-bit floating point audio
        if ($BitsPerSample -eq 32 -and $audioFormat -eq 3) {
            # we are basically done.
            # No clamping required. # Just cast to float,
            $GetBytes.Invoke([float]$sample) # get the bytes,
            continue # and continue
        }

        # If we are dealing with whole number audio formats,
        # We've got to clamp it down to an amplitude between -1 and 1.

        # Unfortunately, `Clamp` is not part of older .NET framework versions
        # So we will clamp the old-fashioned way, with an `if`
        if ($sample -gt 1) { $sample = 1 }
        elseif ($sample -lt -1) { $sample = -1 }

        # If there are 8 bits per sample
        if ($BitsPerSample -eq 8) {        
            # round each sample into bytes, with 127 as the zero point.
            [byte][Math]::Floor(
                127 + $sample * 127
            )
        }

        # If there are 16 bits per sample
        elseif ($BitsPerSample -eq 16) {
            # we just need to scale an `[int16]`
            # Hardcode `[int16]::MaxValue` for speed
            $GetBytes.Invoke([int16]($sample * 32767))
        }

        # If there are 32 bits per sample
        elseif ($BitsPerSample -eq 32) {
            # we can just scale to an `[int32]`.
            # Hardcode `[int32]::MaxValue` for speed
            $GetBytes.Invoke([int32]($sample * 2147483647))
        }
        #endregion Encode Sample
    }

    $progress.Remove('PercentComplete')
    $progress.Completed = $true
    Write-Progress @progress
)

return