package audio import ( "git.gammaspectra.live/S.O.N.G/Kirika/vector" "sync/atomic" ) type int32Source struct { BitDepth int SampleRate int Channels int Blocks chan []int32 locked atomic.Bool } func newInt32Source(bitDepth, sampleRate, channels int) TypedSource[int32] { if bitDepth <= 0 || bitDepth > 32 { return nil } return &int32Source{ BitDepth: bitDepth, SampleRate: sampleRate, Channels: channels, Blocks: make(chan []int32), } } func (s *int32Source) Split(n int) []Source { return Split[int32](s, n) } func (s *int32Source) New() TypedSource[int32] { return newInt32Source(s.BitDepth, s.SampleRate, s.Channels) } func (s *int32Source) GetBlocks() chan []int32 { if s.Locked() { return nil } if !s.locked.Swap(true) { return s.Blocks } return nil } func (s *int32Source) Close() { close(s.Blocks) } func (s *int32Source) GetSampleRate() int { return s.SampleRate } func (s *int32Source) GetChannels() int { return s.Channels } func (s *int32Source) GetBitDepth() int { return s.BitDepth } func (s *int32Source) Locked() bool { return s.locked.Load() } func (s *int32Source) Unlock() { s.locked.Store(false) } func (s *int32Source) SwapBlocks(blocks chan []int32) chan []int32 { oldBlocks := s.Blocks s.Blocks = blocks return oldBlocks } func (s *int32Source) GetFormat() SourceFormat { return SourceInt32 } func (s *int32Source) ToInt16() TypedSource[int16] { if s.Locked() { return nil } source := newInt16Source(16, s.SampleRate, s.Channels) go func() { defer source.Close() for block := range s.GetBlocks() { source.IngestInt16(vector.Int32ToInt16(block, s.BitDepth), 16) } }() return source } func (s *int32Source) ToInt32(bitDepth int) TypedSource[int32] { if s.BitDepth == bitDepth { return s } source := newInt32Source(bitDepth, s.SampleRate, s.Channels) go func() { diff := s.BitDepth - bitDepth defer source.Close() if diff >= 0 { for block := range s.GetBlocks() { buf := make([]int32, len(block)) for i := range block { buf[i] = block[i] >> diff } source.IngestInt32(buf, bitDepth) } } else { diff = -diff for block := range s.GetBlocks() { buf := make([]int32, len(block)) for i := range block { buf[i] = block[i] << diff } source.IngestInt32(buf, bitDepth) } } }() return source } func (s *int32Source) ToFloat32() TypedSource[float32] { if s.Locked() { return nil } source := newFloat32Source(s.BitDepth, s.SampleRate, s.Channels) go func() { defer source.Close() for block := range s.GetBlocks() { source.IngestFloat32(vector.Int32ToFloat32(block, s.BitDepth)) } }() return source } func (s *int32Source) IngestFloat32(buf []float32) { s.Blocks <- vector.Float32ToInt32(buf, s.BitDepth) } func (s *int32Source) IngestInt8(buf []int8, bitDepth int) { block := make([]int32, len(buf)) for i := range buf { block[i] = int32(buf[i]) << (s.BitDepth - bitDepth) } s.Blocks <- block } func (s *int32Source) IngestInt16(buf []int16, bitDepth int) { block := make([]int32, len(buf)) for i := range buf { block[i] = int32(buf[i]) << (s.BitDepth - bitDepth) } s.Blocks <- block } func (s *int32Source) IngestInt24(buf []byte, bitDepth int) { s.Blocks <- vector.BytesToInt32(buf, bitDepth) } func (s *int32Source) IngestInt32(buf []int32, bitDepth int) { if bitDepth == s.BitDepth { s.Blocks <- buf } else { block := make([]int32, len(buf)) for i := range buf { block[i] = buf[i] << (s.BitDepth - bitDepth) } s.Blocks <- block } } func (s *int32Source) IngestNative(buf []int32, bitDepth int) { s.IngestInt32(buf, bitDepth) }