2018-08-18 18:18:12 +00:00
package flac
import (
"encoding/binary"
"io"
2022-07-16 22:07:10 +00:00
"git.gammaspectra.live/S.O.N.G/flacgo/frame"
"git.gammaspectra.live/S.O.N.G/flacgo/internal/hashutil/crc16"
"git.gammaspectra.live/S.O.N.G/flacgo/internal/hashutil/crc8"
"git.gammaspectra.live/S.O.N.G/flacgo/internal/utf8"
2018-08-18 18:18:12 +00:00
"github.com/icza/bitio"
"github.com/mewkiz/pkg/errutil"
)
// --- [ Frame ] ---------------------------------------------------------------
// WriteFrame encodes the given audio frame to the output stream. The Num field
// of the frame header is automatically calculated by the encoder.
func ( enc * Encoder ) WriteFrame ( f * frame . Frame ) error {
// Sanity checks.
nchannels := int ( enc . Info . NChannels )
if nchannels != len ( f . Subframes ) {
return errutil . Newf ( "subframe and channel count mismatch; expected %d, got %d" , nchannels , len ( f . Subframes ) )
}
nsamplesPerChannel := f . Subframes [ 0 ] . NSamples
if ! ( 16 <= nsamplesPerChannel && nsamplesPerChannel <= 65535 ) {
return errutil . Newf ( "invalid number of samples per channel; expected >= 16 && <= 65535, got %d" , nsamplesPerChannel )
}
for i , subframe := range f . Subframes {
if nsamplesPerChannel != len ( subframe . Samples ) {
return errutil . Newf ( "invalid number of samples in channel %d; expected %d, got %d" , i , nsamplesPerChannel , len ( subframe . Samples ) )
}
}
if nchannels != f . Channels . Count ( ) {
return errutil . Newf ( "channel count mismatch; expected %d, got %d" , nchannels , f . Channels . Count ( ) )
}
// Create a new CRC-16 hash writer which adds the data from all write
// operations to a running hash.
h := crc16 . NewIBM ( )
hw := io . MultiWriter ( h , enc . w )
// Encode frame header.
f . Num = enc . curNum
if f . HasFixedBlockSize {
enc . curNum ++
} else {
enc . curNum += uint64 ( nsamplesPerChannel )
}
enc . nsamples += uint64 ( nsamplesPerChannel )
blockSize := uint16 ( nsamplesPerChannel )
if enc . blockSizeMin == 0 || blockSize < enc . blockSizeMin {
enc . blockSizeMin = blockSize
}
if enc . blockSizeMax == 0 || blockSize > enc . blockSizeMax {
enc . blockSizeMax = blockSize
}
// TODO: track number of bytes written to hw, to update values of
// frameSizeMin and frameSizeMax.
// Add unencoded audio samples to running MD5 hash.
f . Hash ( enc . md5sum )
if err := enc . encodeFrameHeader ( hw , f . Header ) ; err != nil {
return errutil . Err ( err )
}
// Encode subframes.
bw := bitio . NewWriter ( hw )
for _ , subframe := range f . Subframes {
if err := encodeSubframe ( bw , f . Header , subframe ) ; err != nil {
return errutil . Err ( err )
}
}
// Zero-padding to byte alignment.
// Flush pending writes to subframe.
if _ , err := bw . Align ( ) ; err != nil {
return errutil . Err ( err )
}
// CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with 0) of
// everything before the crc, back to and including the frame header sync
// code.
crc := h . Sum16 ( )
if err := binary . Write ( enc . w , binary . BigEndian , crc ) ; err != nil {
return errutil . Err ( err )
}
return nil
}
// --- [ Frame header ] --------------------------------------------------------
// encodeFrameHeader encodes the given frame header, writing to w.
func ( enc * Encoder ) encodeFrameHeader ( w io . Writer , hdr frame . Header ) error {
// Create a new CRC-8 hash writer which adds the data from all write
// operations to a running hash.
h := crc8 . NewATM ( )
hw := io . MultiWriter ( h , w )
bw := bitio . NewWriter ( hw )
enc . c = bw
// Sync code: 11111111111110
if err := bw . WriteBits ( 0x3FFE , 14 ) ; err != nil {
return errutil . Err ( err )
}
// Reserved: 0
if err := bw . WriteBits ( 0x0 , 1 ) ; err != nil {
return errutil . Err ( err )
}
// Blocking strategy:
// 0 : fixed-blocksize stream; frame header encodes the frame number
// 1 : variable-blocksize stream; frame header encodes the sample number
if err := bw . WriteBool ( ! hdr . HasFixedBlockSize ) ; err != nil {
return errutil . Err ( err )
}
// Encode block size.
nblockSizeSuffixBits , err := encodeFrameHeaderBlockSize ( bw , hdr . BlockSize )
if err != nil {
return errutil . Err ( err )
}
// Encode sample rate.
sampleRateSuffixBits , nsampleRateSuffixBits , err := encodeFrameHeaderSampleRate ( bw , hdr . SampleRate )
if err != nil {
return errutil . Err ( err )
}
// Encode channels assignment.
if err := encodeFrameHeaderChannels ( bw , hdr . Channels ) ; err != nil {
return errutil . Err ( err )
}
// Encode bits-per-sample.
if err := encodeFrameHeaderBitsPerSample ( bw , hdr . BitsPerSample ) ; err != nil {
return errutil . Err ( err )
}
// Reserved: 0
if err := bw . WriteBits ( 0x0 , 1 ) ; err != nil {
return errutil . Err ( err )
}
// if (variable blocksize)
// <8-56>:"UTF-8" coded sample number (decoded number is 36 bits)
// else
// <8-48>:"UTF-8" coded frame number (decoded number is 31 bits)
if err := utf8 . Encode ( bw , hdr . Num ) ; err != nil {
return errutil . Err ( err )
}
// Write block size after the frame header (used for uncommon block sizes).
if nblockSizeSuffixBits > 0 {
// 0110 : get 8 bit (blocksize-1) from end of header
// 0111 : get 16 bit (blocksize-1) from end of header
if err := bw . WriteBits ( uint64 ( hdr . BlockSize - 1 ) , nblockSizeSuffixBits ) ; err != nil {
return errutil . Err ( err )
}
}
// Write sample rate after the frame header (used for uncommon sample rates).
if nsampleRateSuffixBits > 0 {
if err := bw . WriteBits ( sampleRateSuffixBits , nsampleRateSuffixBits ) ; err != nil {
return errutil . Err ( err )
}
}
// Flush pending writes to frame header.
if _ , err := bw . Align ( ) ; err != nil {
return errutil . Err ( err )
}
// CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) of
// everything before the crc, including the sync code.
crc := h . Sum8 ( )
if err := binary . Write ( w , binary . BigEndian , crc ) ; err != nil {
return errutil . Err ( err )
}
return nil
}
// ~~~ [ Block size ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// encodeFrameHeaderBlockSize encodes the block size of the frame header,
// writing to bw. It returns the number of bits used to store block size after
// the frame header.
2019-12-20 20:26:19 +00:00
func encodeFrameHeaderBlockSize ( bw * bitio . Writer , blockSize uint16 ) ( nblockSizeSuffixBits byte , err error ) {
2018-08-18 18:18:12 +00:00
// Block size in inter-channel samples:
// 0000 : reserved
// 0001 : 192 samples
// 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608
// 0110 : get 8 bit (blocksize-1) from end of header
// 0111 : get 16 bit (blocksize-1) from end of header
// 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768
var bits uint64
switch blockSize {
case 192 :
// 0001
bits = 0x1
2022-07-26 14:09:59 +00:00
// 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608
case 576 :
bits = 0x2
case 1152 :
bits = 0x3
case 2304 :
bits = 0x4
case 4608 :
bits = 0x5
// 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768
case 256 :
bits = 0x8
case 512 :
bits = 0x9
case 1024 :
bits = 0xa
case 2048 :
bits = 0xb
case 4096 :
bits = 0xc
case 8192 :
bits = 0xd
case 16384 :
bits = 0xe
case 32768 :
bits = 0xf
2018-08-18 18:18:12 +00:00
default :
if blockSize <= 256 {
// 0110 : get 8 bit (blocksize-1) from end of header
bits = 0x6
nblockSizeSuffixBits = 8
} else {
// 0111 : get 16 bit (blocksize-1) from end of header
bits = 0x7
nblockSizeSuffixBits = 16
}
}
if err := bw . WriteBits ( bits , 4 ) ; err != nil {
return 0 , errutil . Err ( err )
}
return nblockSizeSuffixBits , nil
}
// ~~~ [ Sample rate ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// encodeFrameHeaderSampleRate encodes the sample rate of the frame header,
// writing to bw. It returns the bits and the number of bits used to store
// sample rate after the frame header.
2019-12-20 20:26:19 +00:00
func encodeFrameHeaderSampleRate ( bw * bitio . Writer , sampleRate uint32 ) ( sampleRateSuffixBits uint64 , nsampleRateSuffixBits byte , err error ) {
2018-08-18 18:18:12 +00:00
// Sample rate:
// 0000 : get from STREAMINFO metadata block
// 0001 : 88.2kHz
// 0010 : 176.4kHz
// 0011 : 192kHz
// 0100 : 8kHz
// 0101 : 16kHz
// 0110 : 22.05kHz
// 0111 : 24kHz
// 1000 : 32kHz
// 1001 : 44.1kHz
// 1010 : 48kHz
// 1011 : 96kHz
// 1100 : get 8 bit sample rate (in kHz) from end of header
// 1101 : get 16 bit sample rate (in Hz) from end of header
// 1110 : get 16 bit sample rate (in tens of Hz) from end of header
// 1111 : invalid, to prevent sync-fooling string of 1s
var bits uint64
switch sampleRate {
case 0 :
// 0000 : get from STREAMINFO metadata block
bits = 0
case 88200 :
// 0001 : 88.2kHz
bits = 0x1
case 176400 :
// 0010 : 176.4kHz
bits = 0x2
case 192000 :
// 0011 : 192kHz
bits = 0x3
case 8000 :
// 0100 : 8kHz
bits = 0x4
case 16000 :
// 0101 : 16kHz
bits = 0x5
case 22050 :
// 0110 : 22.05kHz
bits = 0x6
case 24000 :
// 0111 : 24kHz
bits = 0x7
case 32000 :
// 1000 : 32kHz
bits = 0x8
case 44100 :
// 1001 : 44.1kHz
bits = 0x9
case 48000 :
// 1010 : 48kHz
bits = 0xA
case 96000 :
// 1011 : 96kHz
bits = 0xB
default :
switch {
case sampleRate <= 255000 && sampleRate % 1000 == 0 :
// 1100 : get 8 bit sample rate (in kHz) from end of header
bits = 0xC
sampleRateSuffixBits = uint64 ( sampleRate / 1000 )
nsampleRateSuffixBits = 8
case sampleRate <= 65535 :
// 1101 : get 16 bit sample rate (in Hz) from end of header
bits = 0xD
sampleRateSuffixBits = uint64 ( sampleRate )
nsampleRateSuffixBits = 16
case sampleRate <= 655350 && sampleRate % 10 == 0 :
// 1110 : get 16 bit sample rate (in tens of Hz) from end of header
bits = 0xE
sampleRateSuffixBits = uint64 ( sampleRate / 10 )
nsampleRateSuffixBits = 16
default :
return 0 , 0 , errutil . Newf ( "unable to encode sample rate %v" , sampleRate )
}
}
if err := bw . WriteBits ( bits , 4 ) ; err != nil {
return 0 , 0 , errutil . Err ( err )
}
return sampleRateSuffixBits , nsampleRateSuffixBits , nil
}
// ~~~ [ Channels assignment ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// encodeFrameHeaderChannels encodes the channels assignment of the frame
// header, writing to bw.
2019-12-20 20:26:19 +00:00
func encodeFrameHeaderChannels ( bw * bitio . Writer , channels frame . Channels ) error {
2018-08-18 18:18:12 +00:00
// Channel assignment.
// 0000-0111 : (number of independent channels)-1. Where defined, the channel order follows SMPTE/ITU-R recommendations. The assignments are as follows:
// 1 channel: mono
// 2 channels: left, right
// 3 channels: left, right, center
// 4 channels: front left, front right, back left, back right
// 5 channels: front left, front right, front center, back/surround left, back/surround right
// 6 channels: front left, front right, front center, LFE, back/surround left, back/surround right
// 7 channels: front left, front right, front center, LFE, back center, side left, side right
// 8 channels: front left, front right, front center, LFE, back left, back right, side left, side right
// 1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel
// 1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel
// 1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel
// 1011-1111 : reserved
var bits uint64
switch channels {
case frame . ChannelsMono , frame . ChannelsLR , frame . ChannelsLRC , frame . ChannelsLRLsRs , frame . ChannelsLRCLsRs , frame . ChannelsLRCLfeLsRs , frame . ChannelsLRCLfeCsSlSr , frame . ChannelsLRCLfeLsRsSlSr :
// 1 channel: mono.
// 2 channels: left, right.
// 3 channels: left, right, center.
// 4 channels: left, right, left surround, right surround.
// 5 channels: left, right, center, left surround, right surround.
// 6 channels: left, right, center, LFE, left surround, right surround.
// 7 channels: left, right, center, LFE, center surround, side left, side right.
// 8 channels: left, right, center, LFE, left surround, right surround, side left, side right.
bits = uint64 ( channels . Count ( ) - 1 )
case frame . ChannelsLeftSide :
// 2 channels: left, side; using inter-channel decorrelation.
// 1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel
bits = 0x8
case frame . ChannelsSideRight :
// 2 channels: side, right; using inter-channel decorrelation.
// 1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel
bits = 0x9
case frame . ChannelsMidSide :
// 2 channels: mid, side; using inter-channel decorrelation.
// 1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel
bits = 0xA
default :
return errutil . Newf ( "support for channel assignment %v not yet implemented" , channels )
}
if err := bw . WriteBits ( bits , 4 ) ; err != nil {
return errutil . Err ( err )
}
return nil
}
// ~~~ [ Bits-per-sample ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// encodeFrameHeaderBitsPerSample encodes the bits-per-sample of the frame
// header, writing to bw.
2019-12-20 20:26:19 +00:00
func encodeFrameHeaderBitsPerSample ( bw * bitio . Writer , bps uint8 ) error {
2018-08-18 18:18:12 +00:00
// Sample size in bits:
// 000 : get from STREAMINFO metadata block
// 001 : 8 bits per sample
// 010 : 12 bits per sample
// 011 : reserved
// 100 : 16 bits per sample
// 101 : 20 bits per sample
// 110 : 24 bits per sample
// 111 : reserved
var bits uint64
switch bps {
case 0 :
// 000 : get from STREAMINFO metadata block
bits = 0x0
case 8 :
// 001 : 8 bits per sample
bits = 0x1
case 12 :
// 010 : 12 bits per sample
bits = 0x2
case 16 :
// 100 : 16 bits per sample
bits = 0x4
case 20 :
// 101 : 20 bits per sample
bits = 0x5
case 24 :
// 110 : 24 bits per sample
bits = 0x6
default :
return errutil . Newf ( "support for sample size %v not yet implemented" , bps )
}
if err := bw . WriteBits ( bits , 3 ) ; err != nil {
return errutil . Err ( err )
}
return nil
}