Files
go-mxl-player/internal/output/audio.go
T
2026-08-28 21:53:27 +03:00

66 lines
1.5 KiB
Go

package output
import (
"errors"
"mxl-player/internal/playback"
)
var (
ErrInvalidAudioFrame = errors.New("invalid audio frame")
ErrAudioPayloadTooSmall = errors.New("audio channel payload is too small")
)
func InterleaveF32(frame playback.AudioFrame) ([]byte, error) {
if frame.Channels == 0 ||
frame.SampleCount == 0 ||
frame.SampleRateNumerator <= 0 ||
frame.SampleRateDenominator <= 0 {
return nil, ErrInvalidAudioFrame
}
if uint64(len(frame.Samples)) != frame.Channels {
return nil, ErrInvalidAudioFrame
}
if frame.SampleCount > ^uint64(0)/4 {
return nil, ErrInvalidAudioFrame
}
bytesPerChannel := frame.SampleCount * 4
if frame.Channels > ^uint64(0)/bytesPerChannel {
return nil, ErrInvalidAudioFrame
}
totalBytes := frame.Channels * bytesPerChannel
maxInt := uint64(^uint(0) >> 1)
if totalBytes > maxInt {
return nil, ErrInvalidAudioFrame
}
for _, samples := range frame.Samples {
if bytesPerChannel > uint64(len(samples)) {
return nil, ErrAudioPayloadTooSmall
}
}
result := make([]byte, int(totalBytes))
for sample := uint64(0); sample < frame.SampleCount; sample++ {
for channel := uint64(0); channel < frame.Channels; channel++ {
sourceOffset := sample * 4
destinationOffset := (sample*frame.Channels + channel) * 4
sourceStart := int(sourceOffset)
destinationStart := int(destinationOffset)
copy(
result[destinationStart:destinationStart+4],
frame.Samples[channel][sourceStart:sourceStart+4],
)
}
}
return result, nil
}