When running the code below with one of the two weave procs there are every now and then little spikes on the resulting wave form. These are single samples where the value is off. The non weave trace function does not have this problem. In the sound these can be heard as "crackle".
The image shows spectrograms of the resulting signals, top left is clean and without weave, top right is with weave and shows spikes in the spectrogram. The two lower images show detail on sample level.
import std/[math, sequtils]
import easywave #https://github.com/johnnovak/easywave
import weave
proc initWriteWave(filename: string, bitdepth:int, sampleRate:int, channels: int): RiffWriter =
let wf = WaveFormat(
sampleFormat: sfPCM,
bitsPerSample: bitdepth,
sampleRate: samplerate.int,
numChannels: channels
)
var rw = createRiffFile(filename, FourCC_WAVE, littleEndian)
rw.writeFormatChunk(wf)
rw.beginChunk(FourCC_WAVE_data)
return rw
proc lerp*(t, minin, maxin, minout, maxout: float):float {.inline.}=
((t - minin) / (maxin - minin)) * (maxout - minout) + minout
func normalize(sampleseq:var seq[float], bitdepth: int, headroom: float = 1.0) =
var
(minval, maxval) = minmax(sampleseq)
let halfbitdepth = (pow(2.0, bitdepth.float) / 2.0) - 1.0
if minval.abs > maxval.abs :
maxval = abs minval
else:
minval = - maxval
for i in 0..<sampleseq.len:
sampleseq[i] = lerp(sampleseq[i], minval, maxval, -halfbitdepth, halfbitdepth) * pow(10.0, -headroom/20)
proc traceWeave(freqbands:seq[float], duration: float, samplerate:int):seq[float] {.inline.}=
let numframes = (duration * samplerate.float).int
var sampleseq = newSeq[float](numframes)
let buf = cast[ptr UncheckedArray[float]](sampleseq[0].addr)
init(Weave)
parallelFor tick in 0..<numframes:
captures: {buf, freqbands, samplerate}
parallelFor i in 0..<freqbands.len:
captures: {tick, buf, freqbands, samplerate}
buf[tick] = buf[tick] + (sin(tick.float * TAU.float * (freqbands[i] / samplerate.float))).float
exit(Weave)
return sampleseq
proc traceWeaveStaged(freqbands:seq[float], duration: float, samplerate:int):seq[float] {.inline.}=
let numframes = (duration * samplerate.float).int
var sampleseq = newSeq[float](numframes)
let buf = cast[ptr UncheckedArray[float]](sampleseq[0].addr)
init(Weave)
parallelFor tick in 0..<numframes:
captures: {buf, freqbands, samplerate}
parallelForStaged i in 0..<freqbands.len:
captures: {tick, buf, freqbands, samplerate}
awaitable: iLoop
prologue:
var sigSum:float = 0.0
loop:
sigSum += (sin(tick.float * TAU.float * (freqbands[i] / samplerate.float))).float
epilogue:
buf[tick] = sigsum
exit(Weave)
return sampleseq
proc trace(freqbands:seq[float], duration: float, samplerate:int):seq[float] {.inline.}=
let numframes = (duration * samplerate.float).int
var sampleseq = newSeq[float](numframes)
for tick in 0..<numframes:
for i in 0..<freqbands.len:
sampleseq[tick] = sampleseq[tick] + (sin(tick.float * TAU.float * (freqbands[i] / samplerate.float))).float
return sampleseq
when isMainModule:
var
outbuf: seq[uint16]
let
path = "audiosample.wav"
bitdepth = 16
samplerate = 44100
duration = 2.0
channels = 1
rw = initWriteWave(path, bitdepth, samplerate, channels)
freqbands = @[200.0,300.0,500.0]
var samples = traceWeave(freqbands, duration, samplerate)
#var samples = traceWeaveStaged(freqbands, duration, samplerate)
#var samples = trace(freqbands, duration, samplerate)
samples.normalize(bitdepth, 3.0)
for i16 in 0..<samples.len:
outbuf.add(toBiggestInt(samples[i16]).uint16)
rw.write(outbuf, 0, outbuf.len)
rw.close()
When running the code below with one of the two
weave
procs there are every now and then little spikes on the resulting wave form. These are single samples where the value is off. The non weavetrace
function does not have this problem. In the sound these can be heard as "crackle".The image shows spectrograms of the resulting signals, top left is clean and without weave, top right is with weave and shows spikes in the spectrogram. The two lower images show detail on sample level.