From 46e9cd6b14c0757a5b9abb9c731b25d6fea3cbd7 Mon Sep 17 00:00:00 2001 From: mewmew Date: Sun, 27 May 2018 15:09:56 +0200 Subject: [PATCH] frame: simplify parseHeader by refactoring Fixes lint issue reported by gocyclo: frame/frame.go:212:1: cyclomatic complexity 52 of func `(*Frame).parseHeader` is high (> 30) (gocyclo) func (frame *Frame) parseHeader() error { ^ Updates #25. --- frame/frame.go | 167 ++++++++++++++++++++++++++++------------------ frame/subframe.go | 12 ++-- 2 files changed, 107 insertions(+), 72 deletions(-) diff --git a/frame/frame.go b/frame/frame.go index 653320a..f9f34b1 100644 --- a/frame/frame.go +++ b/frame/frame.go @@ -121,7 +121,7 @@ func (frame *Frame) Parse() error { } // Parse subframe. - frame.Subframes[channel], err = frame.parseSubframe(bps) + frame.Subframes[channel], err = frame.parseSubframe(frame.br, bps) if err != nil { return err } @@ -215,9 +215,11 @@ func (frame *Frame) parseHeader() error { h := crc8.NewATM() hr := io.TeeReader(frame.hr, h) - // 14 bits: sync-code (11111111111110) + // Create bit reader. br := bits.NewReader(hr) frame.br = br + + // 14 bits: sync-code (11111111111110) x, err := br.Read(14) if err != nil { // This is the only place an audio frame may return io.EOF, which signals @@ -260,38 +262,65 @@ func (frame *Frame) parseHeader() error { return unexpected(err) } - // 4 bits: Channels. - // - // The 4 bits are used to specify the channels as follows: - // 0000: (1 channel) mono. - // 0001: (2 channels) left, right. - // 0010: (3 channels) left, right, center. - // 0011: (4 channels) left, right, left surround, right surround. - // 0100: (5 channels) left, right, center, left surround, right surround. - // 0101: (6 channels) left, right, center, LFE, left surround, right surround. - // 0110: (7 channels) left, right, center, LFE, center surround, side left, side right. - // 0111: (8 channels) left, right, center, LFE, left surround, right surround, side left, side right. - // 1000: (2 channels) left, side; using inter-channel decorrelation. - // 1001: (2 channels) side, right; using inter-channel decorrelation. - // 1010: (2 channels) mid, side; using inter-channel decorrelation. - // 1011: reserved. - // 1100: reserved. - // 1101: reserved. - // 1111: reserved. - x, err = br.Read(4) - if err != nil { - return unexpected(err) + // Parse channels. + if err := frame.parseChannels(br); err != nil { + return err } - if x >= 0xB { - return fmt.Errorf("frame.Frame.parseHeader: reserved channels bit pattern (%04b)", x) - } - frame.Channels = Channels(x) - // 3 bits: BitsPerSample. - x, err = br.Read(3) + // Parse bits per sample. + if err := frame.parseBitsPerSample(br); err != nil { + return err + } + + // 1 bit: reserved. + x, err = br.Read(1) if err != nil { return unexpected(err) } + if x != 0 { + return errors.New("frame.Frame.parseHeader: non-zero reserved value") + } + + // if (fixed block size) + // 1-6 bytes: UTF-8 encoded frame number. + // else + // 1-7 bytes: UTF-8 encoded sample number. + frame.Num, err = decodeUTF8Int(hr) + if err != nil { + return unexpected(err) + } + + // Parse block size. + if err := frame.parseBlockSize(br, blockSize); err != nil { + return err + } + + // Parse sample rate. + if err := frame.parseSampleRate(br, sampleRate); err != nil { + return err + } + + // 1 byte: CRC-8 checksum. + var want uint8 + if err = binary.Read(frame.hr, binary.BigEndian, &want); err != nil { + return unexpected(err) + } + got := h.Sum8() + if want != got { + return fmt.Errorf("frame.Frame.parseHeader: CRC-8 checksum mismatch; expected %v, got %v", want, got) + } + + return nil +} + +// parseBitsPerSample parses the bits per sample of the header. +func (frame *Frame) parseBitsPerSample(br *bits.Reader) error { + // 3 bits: BitsPerSample. + x, err := br.Read(3) + if err != nil { + return unexpected(err) + } + // The 3 bits are used to specify the sample size as follows: // 000: unknown sample size; get from StreamInfo. // 001: 8 bits-per-sample. @@ -328,27 +357,42 @@ func (frame *Frame) parseHeader() error { // 111: reserved. return fmt.Errorf("frame.Frame.parseHeader: reserved sample size bit pattern (%03b)", x) } + return nil +} - // 1 bit: reserved. - x, err = br.Read(1) - if err != nil { - return unexpected(err) - } - if x != 0 { - return errors.New("frame.Frame.parseHeader: non-zero reserved value") - } - - // if (fixed block size) - // 1-6 bytes: UTF-8 encoded frame number. - // else - // 1-7 bytes: UTF-8 encoded sample number. - frame.Num, err = decodeUTF8Int(hr) - if err != nil { - return unexpected(err) - } - - // Parse block size. +// parseChannels parses the channels of the header. +func (frame *Frame) parseChannels(br *bits.Reader) error { + // 4 bits: Channels. // + // The 4 bits are used to specify the channels as follows: + // 0000: (1 channel) mono. + // 0001: (2 channels) left, right. + // 0010: (3 channels) left, right, center. + // 0011: (4 channels) left, right, left surround, right surround. + // 0100: (5 channels) left, right, center, left surround, right surround. + // 0101: (6 channels) left, right, center, LFE, left surround, right surround. + // 0110: (7 channels) left, right, center, LFE, center surround, side left, side right. + // 0111: (8 channels) left, right, center, LFE, left surround, right surround, side left, side right. + // 1000: (2 channels) left, side; using inter-channel decorrelation. + // 1001: (2 channels) side, right; using inter-channel decorrelation. + // 1010: (2 channels) mid, side; using inter-channel decorrelation. + // 1011: reserved. + // 1100: reserved. + // 1101: reserved. + // 1111: reserved. + x, err := br.Read(4) + if err != nil { + return unexpected(err) + } + if x >= 0xB { + return fmt.Errorf("frame.Frame.parseHeader: reserved channels bit pattern (%04b)", x) + } + frame.Channels = Channels(x) + return nil +} + +// parseBlockSize parses the block size of the header. +func (frame *Frame) parseBlockSize(br *bits.Reader, blockSize uint64) error { // The 4 bits of n are used to specify the block size as follows: // 0000: reserved. // 0001: 192 samples. @@ -371,14 +415,14 @@ func (frame *Frame) parseHeader() error { frame.BlockSize = 576 * (1 << (n - 2)) case n == 0x6: // 0110: get 8 bit (block size)-1 from the end of the header. - x, err = br.Read(8) + x, err := br.Read(8) if err != nil { return unexpected(err) } frame.BlockSize = uint16(x + 1) case n == 0x7: // 0111: get 16 bit (block size)-1 from the end of the header. - x, err = br.Read(16) + x, err := br.Read(16) if err != nil { return unexpected(err) } @@ -387,9 +431,11 @@ func (frame *Frame) parseHeader() error { // 1000-1111: 256 * 2^(n-8) samples. frame.BlockSize = 256 * (1 << (n - 8)) } + return nil +} - // Parse sample rate. - // +// parseSampleRate parses the sample rate of the header. +func (frame *Frame) parseSampleRate(br *bits.Reader, sampleRate uint64) error { // The 4 bits are used to specify the sample rate as follows: // 0000: unknown sample rate; get from StreamInfo. // 0001: 88.2 kHz. @@ -449,7 +495,7 @@ func (frame *Frame) parseHeader() error { frame.SampleRate = 96000 case 0xC: // 1100: get 8 bit sample rate (in kHz) from the end of the header. - x, err = br.Read(8) + x, err := br.Read(8) if err != nil { return unexpected(err) } @@ -458,14 +504,14 @@ func (frame *Frame) parseHeader() error { log.Printf("frame.Frame.parseHeader: The flac library test cases do not yet include any audio files with sample rate %d. If possible please consider contributing this audio sample to improve the reliability of the test cases.", frame.SampleRate) case 0xD: // 1101: get 16 bit sample rate (in Hz) from the end of the header. - x, err = br.Read(16) + x, err := br.Read(16) if err != nil { return unexpected(err) } frame.SampleRate = uint32(x) case 0xE: // 1110: get 16 bit sample rate (in daHz) from the end of the header. - x, err = br.Read(16) + x, err := br.Read(16) if err != nil { return unexpected(err) } @@ -476,17 +522,6 @@ func (frame *Frame) parseHeader() error { // 1111: invalid. return errors.New("frame.Frame.parseHeader: invalid sample rate bit pattern (1111)") } - - // 1 byte: CRC-8 checksum. - var want uint8 - if err = binary.Read(frame.hr, binary.BigEndian, &want); err != nil { - return unexpected(err) - } - got := h.Sum8() - if got != want { - return fmt.Errorf("frame.Frame.parseHeader: CRC-8 checksum mismatch; expected %v, got %v", want, got) - } - return nil } diff --git a/frame/subframe.go b/frame/subframe.go index d8bd0c2..53d672f 100644 --- a/frame/subframe.go +++ b/frame/subframe.go @@ -28,10 +28,10 @@ type Subframe struct { // parseSubframe reads and parses the header, and the audio samples of a // subframe. -func (frame *Frame) parseSubframe(bps uint) (subframe *Subframe, err error) { +func (frame *Frame) parseSubframe(br *bits.Reader, bps uint) (subframe *Subframe, err error) { // Parse subframe header. subframe = new(Subframe) - if err = subframe.parseHeader(frame.br); err != nil { + if err = subframe.parseHeader(br); err != nil { return subframe, err } // Adjust bps of subframe for wasted bits-per-sample. @@ -42,13 +42,13 @@ func (frame *Frame) parseSubframe(bps uint) (subframe *Subframe, err error) { subframe.Samples = make([]int32, 0, subframe.NSamples) switch subframe.Pred { case PredConstant: - err = subframe.decodeConstant(frame.br, bps) + err = subframe.decodeConstant(br, bps) case PredVerbatim: - err = subframe.decodeVerbatim(frame.br, bps) + err = subframe.decodeVerbatim(br, bps) case PredFixed: - err = subframe.decodeFixed(frame.br, bps) + err = subframe.decodeFixed(br, bps) case PredFIR: - err = subframe.decodeFIR(frame.br, bps) + err = subframe.decodeFIR(br, bps) } // Left shift to accout for wasted bits-per-sample.