Skip to content

Commit

Permalink
flac: add escaped parition encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
mewmew committed Oct 31, 2023
1 parent 8b7bbe0 commit 3d4bcfd
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 8 deletions.
9 changes: 3 additions & 6 deletions enc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ func TestEncode(t *testing.T) {
"testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac",
"testdata/flac-test-files/subset/14 - wasted bits.flac",
"testdata/flac-test-files/subset/15 - only verbatim subframes.flac",
// TODO: implement encoding of escaped partitions
//"testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac",
"testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac",
"testdata/flac-test-files/subset/17 - all fixed orders.flac",
"testdata/flac-test-files/subset/18 - precision search.flac",
"testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac",
Expand All @@ -73,8 +72,7 @@ func TestEncode(t *testing.T) {
"testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac",
"testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac",
"testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac",
// TODO: implement encoding of escaped partitions.
//"testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac",
"testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac",
"testdata/flac-test-files/subset/33 - samplerate 192kHz.flac",
// TODO: fix diff.
//"testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac",
Expand Down Expand Up @@ -108,8 +106,7 @@ func TestEncode(t *testing.T) {
"testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac",
"testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac",
"testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac",
// TODO: implement encoding of escaped partitions.
//"testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac",
"testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac",
}
for _, path := range paths {
t.Run(path, func(t *testing.T) {
Expand Down
23 changes: 21 additions & 2 deletions encode_subframe.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,27 @@ func encodeRicePart(bw *bitio.Writer, subframe *frame.Subframe, paramSize uint,
}

if paramSize == 4 && param == 0xF || paramSize == 5 && param == 0x1F {
// TODO: implement encoding of escaped partitions.
panic("TODO: implement encoding of escaped partitions.")
// 1111 or 11111: Escape code, meaning the partition is in unencoded
// binary form using n bits per sample; n follows as a 5-bit number.
if err := bw.WriteBits(uint64(partition.EscapedBitsPerSample), 5); err != nil {
return errutil.Err(err)
}
for j := 0; j < nsamples; j++ {
// ref: https://datatracker.ietf.org/doc/draft-ietf-cellar-flac/
//
// From section 9.2.7.1. Escaped partition:
//
// The residual samples themselves are stored signed two's
// complement. For example, when a partition is escaped and each
// residual sample is stored with 3 bits, the number -1 is
// represented as 0b111.
residual := residuals[curResidualIndex]
curResidualIndex++
if err := bw.WriteBits(uint64(residual), uint8(partition.EscapedBitsPerSample)); err != nil {
return errutil.Err(err)
}
}
continue
}

// Encode the Rice residuals of the partition.
Expand Down
3 changes: 3 additions & 0 deletions frame/subframe.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ type RiceSubframe struct {
type RicePartition struct {
// Rice parameter.
Param uint
// Residual sample size in bits-per-sample used by escaped partitions.
EscapedBitsPerSample uint
}

// parseHeader reads and parses the header of a subframe.
Expand Down Expand Up @@ -455,6 +457,7 @@ func (subframe *Subframe) decodeRicePart(br *bits.Reader, paramSize uint) error
return unexpected(err)
}
n := uint(x)
partition.EscapedBitsPerSample = n
for j := 0; j < nsamples; j++ {
sample, err := br.Read(n)
if err != nil {
Expand Down

0 comments on commit 3d4bcfd

Please sign in to comment.