Skip to content

set_Samples

James Brundage edited this page Oct 23, 2026 · 1 revision

set_Samples

Sets Wave Samples

Sets the samples in the Wave.

This changes the wave.

Parameters

Samples

The new samples

required type position pipeline wildcard aliases
false Double[] 1 false false
View Source
<#
.SYNOPSIS
    Sets Wave Samples
.DESCRIPTION
    Sets the samples in the Wave.

    This changes the wave.
#>
param(
# The new samples
[double[]]
$Samples
)

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

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

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

[byte[]]$CurrentData = $this.Data

# Classic "looking glass" problem
# We can avoid writing samples twice faster than re-encoding
# _if_ decoding takes us less time than just encoding over it.

# So first check for our cached property of samples
# and then see if the current data block is less than a megabyte
# If either of these is true, use the current samples.
if ($this.'#Samples'.Length -or 
    $CurrentData.Length -lt 512kb
) {
    [double[]]$CurrentSamples = $this.Samples
} else {
    # Otherwise, set the current samples to null
    # (which effectively avoids the logic to skip samples)
    [double[]]$CurrentSamples = $null
}

[int]$BlockSize = $BitsPerSample / 8

[byte[]]$NewData = @(
    foreach ($sample in $samples) {
        #region Encode Sample

        if ($sampleNumber -and -not ($sampleNumber % 32kb)) {
            $progress.Status = "$sampleNumber / $($Samples.Length)"
            $progress.PercentComplete = ($sampleNumber * 100 / $samples.Length)
            Write-Progress @progress
        }

        # If we already have samples
        if ($sampleNumber -lt $CurrentSamples.Length -and (
            # and this sample did not change
            ($CurrentSamples[$sampleNumber] -eq $sample)
        )) {
            # we can skip encoding and just output the original bytes.
            $CurrentData[
                ($sampleNumber * $BlockSize)..(
                    (($sampleNumber + 1) * $BlockSize) - 1
                )
            ]
            # advance our sample number
            $sampleNumber++
            continue # and continue.
        }
    
        
        $sampleNumber++
        

        # If we are using 32-bit floating point audio
        if ($BitsPerSample -eq 32 -and $audioFormat -eq 3) {
            # we are basically done.
            <#
            
            No clamping required.
            
            Well, not technically speaking.
            
            [float] has a max value of `3.402823E+38`.
            
            Attempting to play volume at this level will likely be limited physically,
            and would likely damage speakers and eardrums far before this volume could be achieved.
            
            #> 
            
            # So we will just cast to float, 
            [BitConverter]::GetBytes([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
            [BitConverter]::GetBytes([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
            [BitConverter]::GetBytes([int32]($sample * 2147483647))
        }
        #endregion Encode Sample
    }   
)

$progress.Remove('PercentComplete')
$progress.Completed = $true
Write-Progress @progress
# Set our new data
$This.Data = $newData
# This will invalidate our samples, 
# so cache the sample data we just passed.
$this | 
    Add-Member NoteProperty '#Samples' $samples -Force

return $this

Clone this wiki locally