• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mewkiz / flac / 6713408042

31 Oct 2023 11:04PM UTC coverage: 68.265% (+4.9%) from 63.409%
6713408042

push

github

mewmew
internal/bits: minor updates of TestUnary for consistency

Run `goimports -w` to sort imports and change order of
"expected xx, got xx" to match other test cases
(e.g. TestZigZag).

1680 of 2461 relevant lines covered (68.26%)

4364391.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.7
/encode_subframe.go
1
package flac
2

3
import (
4
        "fmt"
5

6
        "github.com/icza/bitio"
7
        "github.com/mewkiz/flac/frame"
8
        iobits "github.com/mewkiz/flac/internal/bits"
9
        "github.com/mewkiz/pkg/errutil"
10
)
11

12
// --- [ Subframe ] ------------------------------------------------------------
13

14
// encodeSubframe encodes the given subframe, writing to bw.
15
func encodeSubframe(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
75,229✔
16
        // Encode subframe header.
75,229✔
17
        if err := encodeSubframeHeader(bw, subframe.SubHeader); err != nil {
75,229✔
18
                return errutil.Err(err)
×
19
        }
×
20

21
        // Adjust bps of subframe for wasted bits-per-sample.
22
        bps -= subframe.Wasted
75,229✔
23

75,229✔
24
        // Right shift to account for wasted bits-per-sample.
75,229✔
25
        // TODO: figure out how to make this non-destructive (use defer to restore original samples?).
75,229✔
26
        if subframe.Wasted > 0 {
76,009✔
27
                for i, sample := range subframe.Samples {
414,334✔
28
                        subframe.Samples[i] = sample >> subframe.Wasted
413,554✔
29
                }
413,554✔
30
        }
31

32
        // Encode audio samples.
33
        switch subframe.Pred {
75,229✔
34
        case frame.PredConstant:
2,652✔
35
                if err := encodeConstantSamples(bw, hdr, subframe, bps); err != nil {
2,652✔
36
                        return errutil.Err(err)
×
37
                }
×
38
        case frame.PredVerbatim:
110✔
39
                if err := encodeVerbatimSamples(bw, hdr, subframe, bps); err != nil {
110✔
40
                        return errutil.Err(err)
×
41
                }
×
42
        case frame.PredFixed:
39,748✔
43
                if err := encodeFixedSamples(bw, hdr, subframe, bps); err != nil {
39,748✔
44
                        return errutil.Err(err)
×
45
                }
×
46
        case frame.PredFIR:
32,719✔
47
                if err := encodeFIRSamples(bw, hdr, subframe, bps); err != nil {
32,719✔
48
                        return errutil.Err(err)
×
49
                }
×
50
        default:
×
51
                return errutil.Newf("support for prediction method %v not yet implemented", subframe.Pred)
×
52
        }
53
        return nil
75,229✔
54
}
55

56
// --- [ Subframe header ] -----------------------------------------------------
57

58
// encodeSubframeHeader encodes the given subframe header, writing to bw.
59
func encodeSubframeHeader(bw *bitio.Writer, subHdr frame.SubHeader) error {
75,229✔
60
        // Zero bit padding, to prevent sync-fooling string of 1s.
75,229✔
61
        if err := bw.WriteBits(0x0, 1); err != nil {
75,229✔
62
                return errutil.Err(err)
×
63
        }
×
64

65
        // Subframe type:
66
        //     000000 : SUBFRAME_CONSTANT
67
        //     000001 : SUBFRAME_VERBATIM
68
        //     00001x : reserved
69
        //     0001xx : reserved
70
        //     001xxx : if(xxx <= 4) SUBFRAME_FIXED, xxx=order ; else reserved
71
        //     01xxxx : reserved
72
        //     1xxxxx : SUBFRAME_LPC, xxxxx=order-1
73
        var bits uint64
75,229✔
74
        switch subHdr.Pred {
75,229✔
75
        case frame.PredConstant:
2,652✔
76
                // 000000 : SUBFRAME_CONSTANT
2,652✔
77
                bits = 0x00
2,652✔
78
        case frame.PredVerbatim:
110✔
79
                // 000001 : SUBFRAME_VERBATIM
110✔
80
                bits = 0x01
110✔
81
        case frame.PredFixed:
39,748✔
82
                // 001xxx : if(xxx <= 4) SUBFRAME_FIXED, xxx=order ; else reserved
39,748✔
83
                bits = 0x08 | uint64(subHdr.Order)
39,748✔
84
        case frame.PredFIR:
32,719✔
85
                // 1xxxxx : SUBFRAME_LPC, xxxxx=order-1
32,719✔
86
                bits = 0x20 | uint64(subHdr.Order-1)
32,719✔
87
        }
88
        if err := bw.WriteBits(bits, 6); err != nil {
75,229✔
89
                return errutil.Err(err)
×
90
        }
×
91

92
        // <1+k> 'Wasted bits-per-sample' flag:
93
        //
94
        //     0 : no wasted bits-per-sample in source subblock, k=0
95
        //     1 : k wasted bits-per-sample in source subblock, k-1 follows, unary coded; e.g. k=3 => 001 follows, k=7 => 0000001 follows.
96
        hasWastedBits := subHdr.Wasted > 0
75,229✔
97
        if err := bw.WriteBool(hasWastedBits); err != nil {
75,229✔
98
                return errutil.Err(err)
×
99
        }
×
100
        if hasWastedBits {
76,009✔
101
                if err := iobits.WriteUnary(bw, uint64(subHdr.Wasted-1)); err != nil {
780✔
102
                        return errutil.Err(err)
×
103
                }
×
104
        }
105
        return nil
75,229✔
106
}
107

108
// --- [ Constant samples ] ----------------------------------------------------
109

110
// encodeConstantSamples stores the given constant sample, writing to bw.
111
func encodeConstantSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
2,652✔
112
        samples := subframe.Samples
2,652✔
113
        sample := samples[0]
2,652✔
114
        for _, s := range samples[1:] {
10,705,356✔
115
                if sample != s {
10,702,704✔
116
                        return errutil.Newf("constant sample mismatch; expected %v, got %v", sample, s)
×
117
                }
×
118
        }
119
        // Unencoded constant value of the subblock, n = frame's bits-per-sample.
120
        if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
2,652✔
121
                return errutil.Err(err)
×
122
        }
×
123
        return nil
2,652✔
124
}
125

126
// --- [ Verbatim samples ] ----------------------------------------------------
127

128
// encodeVerbatimSamples stores the given samples verbatim (uncompressed),
129
// writing to bw.
130
func encodeVerbatimSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
110✔
131
        // Unencoded subblock; n = frame's bits-per-sample, i = frame's blocksize.
110✔
132
        samples := subframe.Samples
110✔
133
        if int(hdr.BlockSize) != len(samples) {
110✔
134
                return errutil.Newf("block size and sample count mismatch; expected %d, got %d", hdr.BlockSize, len(samples))
×
135
        }
×
136
        for _, sample := range samples {
440,620✔
137
                if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
440,510✔
138
                        return errutil.Err(err)
×
139
                }
×
140
        }
141
        return nil
110✔
142
}
143

144
// --- [ Fixed samples ] -------------------------------------------------------
145

146
// encodeFixedSamples stores the given samples using linear prediction coding
147
// with a fixed set of predefined polynomial coefficients, writing to bw.
148
func encodeFixedSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
39,748✔
149
        // Encode unencoded warm-up samples.
39,748✔
150
        samples := subframe.Samples
39,748✔
151
        for i := 0; i < subframe.Order; i++ {
135,693✔
152
                sample := samples[i]
95,945✔
153
                if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
95,945✔
154
                        return errutil.Err(err)
×
155
                }
×
156
        }
157

158
        // Compute residuals (signal errors of the prediction) between audio
159
        // samples and LPC predicted audio samples.
160
        const shift = 0
39,748✔
161
        residuals, err := getLPCResiduals(subframe, frame.FixedCoeffs[subframe.Order], shift)
39,748✔
162
        if err != nil {
39,748✔
163
                return errutil.Err(err)
×
164
        }
×
165

166
        // Encode subframe residuals.
167
        if err := encodeResiduals(bw, subframe, residuals); err != nil {
39,748✔
168
                return errutil.Err(err)
×
169
        }
×
170
        return nil
39,748✔
171
}
172

173
// --- [ FIR samples ] -------------------------------------------------------
174

175
// encodeFIRSamples stores the given samples using linear prediction coding
176
// with a custom set of predefined polynomial coefficients, writing to bw.
177
func encodeFIRSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
32,719✔
178
        // Encode unencoded warm-up samples.
32,719✔
179
        samples := subframe.Samples
32,719✔
180
        for i := 0; i < subframe.Order; i++ {
219,175✔
181
                sample := samples[i]
186,456✔
182
                if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
186,456✔
183
                        return errutil.Err(err)
×
184
                }
×
185
        }
186

187
        // 4 bits: (coefficients' precision in bits) - 1.
188
        if err := bw.WriteBits(uint64(subframe.CoeffPrec-1), 4); err != nil {
32,719✔
189
                return errutil.Err(err)
×
190
        }
×
191

192
        // 5 bits: predictor coefficient shift needed in bits.
193
        if err := bw.WriteBits(uint64(subframe.CoeffShift), 5); err != nil {
32,719✔
194
                return errutil.Err(err)
×
195
        }
×
196

197
        // Encode coefficients.
198
        for _, coeff := range subframe.Coeffs {
219,175✔
199
                // (prec) bits: Predictor coefficient.
186,456✔
200
                if err := bw.WriteBits(uint64(coeff), uint8(subframe.CoeffPrec)); err != nil {
186,456✔
201
                        return errutil.Err(err)
×
202
                }
×
203
        }
204

205
        // Compute residuals (signal errors of the prediction) between audio
206
        // samples and LPC predicted audio samples.
207
        residuals, err := getLPCResiduals(subframe, subframe.Coeffs, subframe.CoeffShift)
32,719✔
208
        if err != nil {
32,719✔
209
                return errutil.Err(err)
×
210
        }
×
211

212
        // Encode subframe residuals.
213
        if err := encodeResiduals(bw, subframe, residuals); err != nil {
32,719✔
214
                return errutil.Err(err)
×
215
        }
×
216
        return nil
32,719✔
217
}
218

219
// encodeResiduals encodes the residuals (prediction method error signals) of the
220
// subframe.
221
//
222
// ref: https://www.xiph.org/flac/format.html#residual
223
func encodeResiduals(bw *bitio.Writer, subframe *frame.Subframe, residuals []int32) error {
72,467✔
224
        // 2 bits: Residual coding method.
72,467✔
225
        if err := bw.WriteBits(uint64(subframe.ResidualCodingMethod), 2); err != nil {
72,467✔
226
                return errutil.Err(err)
×
227
        }
×
228
        // The 2 bits are used to specify the residual coding method as follows:
229
        //    00: Rice coding with a 4-bit Rice parameter.
230
        //    01: Rice coding with a 5-bit Rice parameter.
231
        //    10: reserved.
232
        //    11: reserved.
233
        switch subframe.ResidualCodingMethod {
72,467✔
234
        case frame.ResidualCodingMethodRice1:
70,193✔
235
                return encodeRicePart(bw, subframe, 4, residuals)
70,193✔
236
        case frame.ResidualCodingMethodRice2:
2,274✔
237
                return encodeRicePart(bw, subframe, 5, residuals)
2,274✔
238
        default:
×
239
                return fmt.Errorf("encodeResiduals: reserved residual coding method bit pattern (%02b)", uint8(subframe.ResidualCodingMethod))
×
240
        }
241
}
242

243
// encodeRicePart encodes a Rice partition of residuals from the subframe, using
244
// a Rice parameter of the specified size in bits.
245
//
246
// ref: https://www.xiph.org/flac/format.html#partitioned_rice
247
// ref: https://www.xiph.org/flac/format.html#partitioned_rice2
248
func encodeRicePart(bw *bitio.Writer, subframe *frame.Subframe, paramSize uint, residuals []int32) error {
72,467✔
249
        // 4 bits: Partition order.
72,467✔
250
        riceSubframe := subframe.RiceSubframe
72,467✔
251
        if err := bw.WriteBits(uint64(riceSubframe.PartOrder), 4); err != nil {
72,467✔
252
                return errutil.Err(err)
×
253
        }
×
254

255
        // Parse Rice partitions; in total 2^partOrder partitions.
256
        //
257
        // ref: https://www.xiph.org/flac/format.html#rice_partition
258
        // ref: https://www.xiph.org/flac/format.html#rice2_partition
259
        partOrder := riceSubframe.PartOrder
72,467✔
260
        nparts := 1 << partOrder
72,467✔
261
        curResidualIndex := 0
72,467✔
262
        for i := range riceSubframe.Partitions {
383,276✔
263
                partition := &riceSubframe.Partitions[i]
310,809✔
264
                // (4 or 5) bits: Rice parameter.
310,809✔
265
                param := partition.Param
310,809✔
266
                if err := bw.WriteBits(uint64(param), uint8(paramSize)); err != nil {
310,809✔
267
                        return errutil.Err(err)
×
268
                }
×
269

270
                // Determine the number of Rice encoded samples in the partition.
271
                var nsamples int
310,809✔
272
                if partOrder == 0 {
372,572✔
273
                        nsamples = subframe.NSamples - subframe.Order
61,763✔
274
                } else if i != 0 {
549,151✔
275
                        nsamples = subframe.NSamples / nparts
238,342✔
276
                } else {
249,046✔
277
                        nsamples = subframe.NSamples/nparts - subframe.Order
10,704✔
278
                }
10,704✔
279

280
                if paramSize == 4 && param == 0xF || paramSize == 5 && param == 0x1F {
313,514✔
281
                        // 1111 or 11111: Escape code, meaning the partition is in unencoded
2,705✔
282
                        // binary form using n bits per sample; n follows as a 5-bit number.
2,705✔
283
                        if err := bw.WriteBits(uint64(partition.EscapedBitsPerSample), 5); err != nil {
2,705✔
284
                                return errutil.Err(err)
×
285
                        }
×
286
                        for j := 0; j < nsamples; j++ {
56,693✔
287
                                // ref: https://datatracker.ietf.org/doc/draft-ietf-cellar-flac/
53,988✔
288
                                //
53,988✔
289
                                // From section 9.2.7.1.  Escaped partition:
53,988✔
290
                                //
53,988✔
291
                                // The residual samples themselves are stored signed two's
53,988✔
292
                                // complement.  For example, when a partition is escaped and each
53,988✔
293
                                // residual sample is stored with 3 bits, the number -1 is
53,988✔
294
                                // represented as 0b111.
53,988✔
295
                                residual := residuals[curResidualIndex]
53,988✔
296
                                curResidualIndex++
53,988✔
297
                                if err := bw.WriteBits(uint64(residual), uint8(partition.EscapedBitsPerSample)); err != nil {
53,988✔
298
                                        return errutil.Err(err)
×
299
                                }
×
300
                        }
301
                        continue
2,705✔
302
                }
303

304
                // Encode the Rice residuals of the partition.
305
                for j := 0; j < nsamples; j++ {
63,675,548✔
306
                        residual := residuals[curResidualIndex]
63,367,444✔
307
                        curResidualIndex++
63,367,444✔
308
                        if err := encodeRiceResidual(bw, param, residual); err != nil {
63,367,444✔
309
                                return errutil.Err(err)
×
310
                        }
×
311
                }
312
        }
313

314
        return nil
72,467✔
315
}
316

317
// encodeRiceResidual encodes a Rice residual (error signal).
318
func encodeRiceResidual(bw *bitio.Writer, k uint, residual int32) error {
63,367,444✔
319
        // ZigZag encode.
63,367,444✔
320
        folded := iobits.EncodeZigZag(residual)
63,367,444✔
321

63,367,444✔
322
        // unfold into low- and high.
63,367,444✔
323
        lowMask := ^uint32(0) >> (32 - k) // lower k bits.
63,367,444✔
324
        highMask := ^uint32(0) << k       // upper bits.
63,367,444✔
325
        high := (folded & highMask) >> k
63,367,444✔
326
        low := folded & lowMask
63,367,444✔
327

63,367,444✔
328
        // Write unary encoded most significant bits.
63,367,444✔
329
        if err := iobits.WriteUnary(bw, uint64(high)); err != nil {
63,367,444✔
330
                return errutil.Err(err)
×
331
        }
×
332

333
        // Write binary encoded least significant bits.
334
        if err := bw.WriteBits(uint64(low), uint8(k)); err != nil {
63,367,444✔
335
                return errutil.Err(err)
×
336
        }
×
337
        return nil
63,367,444✔
338
}
339

340
// getLPCResiduals returns the residuals (signal errors of the prediction)
341
// between the given audio samples and the LPC predicted audio samples, using
342
// the coefficients of a given polynomial, and a couple (order of polynomial;
343
// i.e. len(coeffs)) of unencoded warm-up samples.
344
func getLPCResiduals(subframe *frame.Subframe, coeffs []int32, shift int32) ([]int32, error) {
72,467✔
345
        if len(coeffs) != subframe.Order {
72,467✔
346
                return nil, fmt.Errorf("getLPCResiduals: prediction order (%d) differs from number of coefficients (%d)", subframe.Order, len(coeffs))
×
347
        }
×
348
        if shift < 0 {
72,467✔
349
                return nil, fmt.Errorf("getLPCResiduals: invalid negative shift")
×
350
        }
×
351
        if subframe.NSamples != len(subframe.Samples) {
72,467✔
352
                return nil, fmt.Errorf("getLPCResiduals: subframe sample count mismatch; expected %d, got %d", subframe.NSamples, len(subframe.Samples))
×
353
        }
×
354
        var residuals []int32
72,467✔
355
        for i := subframe.Order; i < subframe.NSamples; i++ {
63,493,899✔
356
                var sample int64
63,421,432✔
357
                for j, c := range coeffs {
593,998,493✔
358
                        sample += int64(c) * int64(subframe.Samples[i-j-1])
530,577,061✔
359
                }
530,577,061✔
360
                residual := subframe.Samples[i] - int32(sample>>uint(shift))
63,421,432✔
361
                residuals = append(residuals, residual)
63,421,432✔
362
        }
363
        return residuals, nil
72,467✔
364
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc