<commit_before>package wav

import (
	"io"
	"time"

	"github.com/pkg/errors"
)

type ReadSeekCloser interface {
	io.Reader
	io.Seeker
	io.Closer
}

type Streamer struct {
	rsc ReadSeekCloser
	h   header
	pos int32
	err error
}

func NewStreamer(rsc ReadSeekCloser) (s *Streamer, err error) {
	var (
		d    Streamer
		herr error
	)
	d.rsc = rsc
	defer func() { // hacky way to always close rsc if an error occured
		if err != nil {
			d.rsc.Close()
		}
	}()
	d.h, herr = readHeader(rsc)
	if herr != nil {
		return nil, errors.Wrap(herr, "wav")
	}
	if d.h.formatType != 1 {
		return nil, errors.New("wav: unsupported format type")
	}
	if d.h.numChans <= 0 {
		return nil, errors.New("wav: invalid number of channels (less than 1)")
	}
	if d.h.bitsPerSample != 8 && d.h.bitsPerSample != 16 {
		return nil, errors.New("wav: unsupported number of bits per sample, 8 or 16 are supported")
	}
	return &d, nil
}

func (s *Streamer) Err() error {
	return s.err
}

func (s *Streamer) Duration() time.Duration {
	numBytes := time.Duration(s.h.dataSize)
	perFrame := time.Duration(s.h.bytesPerFrame)
	sampRate := time.Duration(s.h.sampleRate)
	return numBytes / perFrame * time.Second / sampRate
}

func (s *Streamer) Position() time.Duration {
	frameIndex := time.Duration(s.pos / int32(s.h.bytesPerFrame))
	frameTime := time.Second / time.Duration(s.h.sampleRate)
	return frameIndex * frameTime
}

func (s *Streamer) Seek(d time.Duration) {
	if d < 0 || s.Duration() < d {
		panic("wav: seek duration out of range")
	}
	frame := int32(d / (time.Second / time.Duration(s.h.sampleRate)))
	pos := frame * int32(s.h.bytesPerFrame)
	_, err := s.rsc.Seek(int64(pos), io.SeekStart)
	if err != nil {
		s.err = err
		return
	}
	s.pos = pos
}
<commit_msg>audio: wav: fix seeking to include the header<commit_after>package wav

import (
	"io"
	"time"

	"github.com/pkg/errors"
)

type ReadSeekCloser interface {
	io.Reader
	io.Seeker
	io.Closer
}

type Streamer struct {
	rsc ReadSeekCloser
	h   header
	pos int32
	err error
}

func NewStreamer(rsc ReadSeekCloser) (s *Streamer, err error) {
	var (
		d    Streamer
		herr error
	)
	d.rsc = rsc
	defer func() { // hacky way to always close rsc if an error occured
		if err != nil {
			d.rsc.Close()
		}
	}()
	d.h, herr = readHeader(rsc)
	if herr != nil {
		return nil, errors.Wrap(herr, "wav")
	}
	if d.h.formatType != 1 {
		return nil, errors.New("wav: unsupported format type")
	}
	if d.h.numChans <= 0 {
		return nil, errors.New("wav: invalid number of channels (less than 1)")
	}
	if d.h.bitsPerSample != 8 && d.h.bitsPerSample != 16 {
		return nil, errors.New("wav: unsupported number of bits per sample, 8 or 16 are supported")
	}
	return &d, nil
}

func (s *Streamer) Err() error {
	return s.err
}

func (s *Streamer) Duration() time.Duration {
	numBytes := time.Duration(s.h.dataSize)
	perFrame := time.Duration(s.h.bytesPerFrame)
	sampRate := time.Duration(s.h.sampleRate)
	return numBytes / perFrame * time.Second / sampRate
}

func (s *Streamer) Position() time.Duration {
	frameIndex := time.Duration(s.pos / int32(s.h.bytesPerFrame))
	frameTime := time.Second / time.Duration(s.h.sampleRate)
	return frameIndex * frameTime
}

func (s *Streamer) Seek(d time.Duration) {
	if d < 0 || s.Duration() < d {
		panic("wav: seek duration out of range")
	}
	frame := int32(d / (time.Second / time.Duration(s.h.sampleRate)))
	pos := frame * int32(s.h.bytesPerFrame)
	_, err := s.rsc.Seek(int64(pos)+44, io.SeekStart) // 44 is the size of the header
	if err != nil {
		s.err = err
		return
	}
	s.pos = pos
}

{'fraction_non_alphanumeric': 0.14108001130901895, 'fraction_numerical': 0.012439920836867402, 'mean_word_length': 3.4335839598997495, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1738576', 'n_tokens_mistral': 1454, 'n_tokens_neox': 1384, 'n_words': 370}