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 }