diff --git a/cmd/wav2flac/main.go b/cmd/wav2flac/main.go index 8832e48..6743311 100644 --- a/cmd/wav2flac/main.go +++ b/cmd/wav2flac/main.go @@ -100,23 +100,14 @@ func wav2flac(wavPath string, force bool) error { } subframes := make([]*frame.Subframe, nchannels) - subHdr := frame.SubHeader{ - // Specifies the prediction method used to encode the audio sample of the - // subframe. - Pred: frame.PredVerbatim, - // Prediction order used by fixed and FIR linear prediction decoding. - Order: 0, - // Wasted bits-per-sample. - Wasted: 0, - } for i := range subframes { subframe := &frame.Subframe{ - SubHeader: subHdr, - Samples: make([]int32, nsamplesPerChannel), + Samples: make([]int32, nsamplesPerChannel), } subframes[i] = subframe } - for j := 0; !dec.EOF(); j++ { + for frameNum := 0; !dec.EOF(); frameNum++ { + fmt.Println("frame number:", frameNum) // Decode WAV samples. n, err := dec.PCMBuffer(buf) if err != nil { @@ -126,6 +117,16 @@ func wav2flac(wavPath string, force bool) error { break } for _, subframe := range subframes { + subHdr := frame.SubHeader{ + // Specifies the prediction method used to encode the audio sample of the + // subframe. + Pred: frame.PredVerbatim, + // Prediction order used by fixed and FIR linear prediction decoding. + Order: 0, + // Wasted bits-per-sample. + Wasted: 0, + } + subframe.SubHeader = subHdr subframe.NSamples = n / nchannels subframe.Samples = subframe.Samples[:subframe.NSamples] } @@ -133,7 +134,21 @@ func wav2flac(wavPath string, force bool) error { subframe := subframes[i%nchannels] subframe.Samples[i/nchannels] = int32(sample) } - fmt.Println("j:", j) + // Check if the subframe may be encoded as constant; when all samples are + // the same. + for _, subframe := range subframes { + sample := subframe.Samples[0] + constant := true + for _, s := range subframe.Samples[1:] { + if sample != s { + constant = false + } + } + if constant { + fmt.Println("constant method") + subframe.SubHeader.Pred = frame.PredConstant + } + } // Encode FLAC frame. channels, err := getChannels(nchannels) diff --git a/encode_subframe.go b/encode_subframe.go index 60d1434..360e28e 100644 --- a/encode_subframe.go +++ b/encode_subframe.go @@ -18,20 +18,20 @@ func encodeSubframe(bw bitio.Writer, hdr frame.Header, subframe *frame.Subframe) // Encode audio samples. switch subframe.Pred { - //case frame.PredConstant: - // if err := encodeConstantSamples(bw, samples); err != nil { - // return errutil.Err(err) - // } + case frame.PredConstant: + if err := encodeConstantSamples(bw, hdr.BitsPerSample, subframe.Samples); err != nil { + return errutil.Err(err) + } case frame.PredVerbatim: if err := encodeVerbatimSamples(bw, hdr, subframe.Samples); err != nil { return errutil.Err(err) } //case frame.PredFixed: - // if err := encodeFixedSamples(bw, samples, subframe.Order); err != nil { + // if err := encodeFixedSamples(bw, hdr, subframe.Samples, subframe.Order); err != nil { // return errutil.Err(err) // } //case frame.PredFIR: - // if err := encodeFIRSamples(bw, samples, subframe.Order); err != nil { + // if err := encodeFIRSamples(bw, hdr, subframe.Samples, subframe.Order); err != nil { // return errutil.Err(err) // } default: @@ -92,6 +92,23 @@ func encodeSubframeHeader(bw bitio.Writer, hdr frame.SubHeader) error { return nil } +// --- [ Constant samples ] ---------------------------------------------------- + +// encodeConstantSamples stores the given constant sample, writing to bw. +func encodeConstantSamples(bw bitio.Writer, bps byte, samples []int32) error { + sample := samples[0] + for _, s := range samples[1:] { + if sample != s { + return errutil.Newf("constant sample mismatch; expected %v, got %v", sample, s) + } + } + // Unencoded constant value of the subblock, n = frame's bits-per-sample. + if err := bw.WriteBits(uint64(sample), bps); err != nil { + return errutil.Err(err) + } + return nil +} + // --- [ Verbatim samples ] ---------------------------------------------------- // encodeVerbatimSamples stores the given samples verbatim (uncompressed),