🎉 live server seems to be working now
This commit is contained in:
83
third_party/sendspin-go/pkg/audio/resample.go
vendored
Normal file
83
third_party/sendspin-go/pkg/audio/resample.go
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
// ABOUTME: Linear resampler for converting between audio sample rates
|
||||
// ABOUTME: Uses linear interpolation to convert interleaved audio samples
|
||||
package audio
|
||||
|
||||
// Resampler performs linear interpolation to convert between sample rates
|
||||
type Resampler struct {
|
||||
inputRate int
|
||||
outputRate int
|
||||
channels int
|
||||
ratio float64
|
||||
position float64
|
||||
lastSample []int32 // one sample per channel
|
||||
}
|
||||
|
||||
func NewResampler(inputRate, outputRate, channels int) *Resampler {
|
||||
return &Resampler{
|
||||
inputRate: inputRate,
|
||||
outputRate: outputRate,
|
||||
channels: channels,
|
||||
ratio: float64(inputRate) / float64(outputRate),
|
||||
position: 0.0,
|
||||
lastSample: make([]int32, channels),
|
||||
}
|
||||
}
|
||||
|
||||
// Resample converts input samples to output sample rate using linear interpolation.
|
||||
// input and output are interleaved; returns the number of output samples written.
|
||||
func (r *Resampler) Resample(input []int32, output []int32) int {
|
||||
if len(input) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
inputFrames := len(input) / r.channels
|
||||
outputFrames := len(output) / r.channels
|
||||
|
||||
outIdx := 0
|
||||
|
||||
for outIdx < outputFrames {
|
||||
inputPos := r.position
|
||||
inputIdx := int(inputPos)
|
||||
|
||||
if inputIdx >= inputFrames-1 {
|
||||
break
|
||||
}
|
||||
|
||||
frac := inputPos - float64(inputIdx)
|
||||
|
||||
for ch := 0; ch < r.channels; ch++ {
|
||||
sample1 := input[inputIdx*r.channels+ch]
|
||||
sample2 := input[(inputIdx+1)*r.channels+ch]
|
||||
|
||||
interpolated := float64(sample1)*(1.0-frac) + float64(sample2)*frac
|
||||
output[outIdx*r.channels+ch] = int32(interpolated)
|
||||
}
|
||||
|
||||
outIdx++
|
||||
r.position += r.ratio
|
||||
}
|
||||
|
||||
// Reset position for next chunk, keeping fractional part
|
||||
r.position -= float64(int(r.position))
|
||||
|
||||
return outIdx * r.channels
|
||||
}
|
||||
|
||||
func (r *Resampler) Reset() {
|
||||
r.position = 0.0
|
||||
for i := range r.lastSample {
|
||||
r.lastSample[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Resampler) OutputSamplesNeeded(inputSamples int) int {
|
||||
inputFrames := inputSamples / r.channels
|
||||
outputFrames := int(float64(inputFrames) / r.ratio)
|
||||
return outputFrames * r.channels
|
||||
}
|
||||
|
||||
func (r *Resampler) InputSamplesNeeded(outputSamples int) int {
|
||||
outputFrames := outputSamples / r.channels
|
||||
inputFrames := int(float64(outputFrames) * r.ratio)
|
||||
return inputFrames * r.channels
|
||||
}
|
||||
Reference in New Issue
Block a user