func tryClose(w io.Writer) error { if w, ok := w.(io.Closer); ok { return w.Close() } return nil }
// unbuffered encode Signals as PCM data,in a Riff wave container. func encode(w io.Writer, sampleBytes uint8, sampleRate uint32, length x, ss ...Signal) (err error) { samplePeriod := X(1 / float32(sampleRate)) samples := uint32(length/samplePeriod) + 1 binary.Write(w, binary.LittleEndian, riffHeader{'R', 'I', 'F', 'F', samples*uint32(sampleBytes) + 36, 'W', 'A', 'V', 'E'}) binary.Write(w, binary.LittleEndian, chunkHeader{'f', 'm', 't', ' ', 16}) binary.Write(w, binary.LittleEndian, formatChunk{ Code: 1, Channels: uint16(len(ss)), SampleRate: sampleRate, ByteRate: sampleRate * uint32(sampleBytes) * uint32(len(ss)), SampleBytes: uint16(sampleBytes) * uint16(len(ss)), Bits: uint16(8 * sampleBytes), }) binary.Write(w, binary.LittleEndian, chunkHeader{'d', 'a', 't', 'a', samples * uint32(sampleBytes) * uint32(len(ss))}) readerForPCM8Bit := func(s Signal) io.Reader { r, w := io.Pipe() go func() { // try shortcuts first offset, ok := s.(Offset) if pcms, ok2 := offset.LimitedSignal.(PCM8bit); ok && ok2 && pcms.samplePeriod == samplePeriod && pcms.MaxX() >= length-offset.Offset { offsetSamples := int(offset.Offset / samplePeriod) if offsetSamples < 0 { w.Write(pcms.Data[-offsetSamples : -offsetSamples+int(samples)]) } else { for x, zeroSample := 0, []byte{0x80}; x < offsetSamples; x++ { w.Write(zeroSample) } w.Write(pcms.Data[:int(samples)-offsetSamples]) } w.Close() } else if pcm, ok := s.(PCM8bit); ok && pcm.samplePeriod == samplePeriod && pcm.MaxX() >= length { w.Write(pcm.Data[:samples]) w.Close() } else { defer func() { e := recover() if e != nil { w.CloseWithError(e.(error)) } else { w.Close() } }() for i, sample := uint32(0), make([]byte, 1); err == nil && i < samples; i++ { sample[0] = encodePCM8bit(s.property(x(i) * samplePeriod)) _, err = w.Write(sample) } } }() return r } readerForPCM16Bit := func(s Signal) io.Reader { r, w := io.Pipe() go func() { // try shortcuts first offset, ok := s.(Offset) if pcms, ok2 := offset.LimitedSignal.(PCM16bit); ok && ok2 && pcms.samplePeriod == samplePeriod && pcms.MaxX() >= length-offset.Offset { offsetSamples := int(offset.Offset / samplePeriod) if offsetSamples < 0 { w.Write(pcms.Data[-offsetSamples*2 : (int(samples)-offsetSamples)*2]) } else { for x, zeroSample := 0, []byte{0x00, 0x00}; x < offsetSamples; x++ { w.Write(zeroSample) } w.Write(pcms.Data[:(int(samples)-offsetSamples)*2]) } w.Close() } else if pcm, ok := s.(PCM16bit); ok && pcm.samplePeriod == samplePeriod && pcm.MaxX() >= length { w.Write(pcm.Data[:samples*2]) w.Close() } else { defer func() { e := recover() if e != nil { w.CloseWithError(e.(error)) } else { w.Close() } }() for i, sample := uint32(0), make([]byte, 2); err == nil && i < samples; i++ { sample[0], sample[1] = encodePCM16bit(s.property(x(i) * samplePeriod)) _, err = w.Write(sample) } } }() return r } readerForPCM24Bit := func(s Signal) io.Reader { r, w := io.Pipe() go func() { // try shortcuts first offset, ok := s.(Offset) if pcms, ok2 := offset.LimitedSignal.(PCM24bit); ok && ok2 && pcms.samplePeriod == samplePeriod && pcms.MaxX() >= length-offset.Offset { offsetSamples := int(offset.Offset / samplePeriod) if offsetSamples < 0 { w.Write(pcms.Data[-offsetSamples*3 : (int(samples)-offsetSamples)*3]) } else { for x, zeroSample := 0, []byte{0x00, 0x00, 0x00}; x < offsetSamples; x++ { w.Write(zeroSample) } w.Write(pcms.Data[:(int(samples)-offsetSamples)*3]) } w.Close() } else if pcm, ok := s.(PCM24bit); ok && pcm.samplePeriod == samplePeriod && pcm.MaxX() >= length { w.Write(pcm.Data[:samples*3]) w.Close() } else { defer func() { e := recover() if e != nil { w.CloseWithError(e.(error)) } else { w.Close() } }() for i, sample := uint32(0), make([]byte, 3); err == nil && i < samples; i++ { sample[0], sample[1], sample[2] = encodePCM24bit(s.property(x(i) * samplePeriod)) _, err = w.Write(sample) } } }() return r } readerForPCM32Bit := func(s Signal) io.Reader { r, w := io.Pipe() go func() { // try shortcuts first offset, ok := s.(Offset) if pcms, ok2 := offset.LimitedSignal.(PCM32bit); ok && ok2 && pcms.samplePeriod == samplePeriod && pcms.MaxX() >= length-offset.Offset { offsetSamples := int(offset.Offset / samplePeriod) if offsetSamples < 0 { w.Write(pcms.Data[-offsetSamples*4 : (int(samples)-offsetSamples)*4]) } else { for x, zeroSample := 0, []byte{0x00, 0x00, 0x00, 0x00}; x < offsetSamples; x++ { w.Write(zeroSample) } w.Write(pcms.Data[:(int(samples)-offsetSamples)*4]) } w.Close() } else if pcm, ok := s.(PCM32bit); ok && pcm.samplePeriod == samplePeriod && pcm.MaxX() >= length { w.Write(pcm.Data[:samples*4]) w.Close() } else { defer func() { e := recover() if e != nil { w.CloseWithError(e.(error)) } else { w.Close() } }() for i, sample := uint32(0), make([]byte, 4); err == nil && i < samples; i++ { sample[0], sample[1], sample[2], sample[3] = encodePCM32bit(s.property(x(i) * samplePeriod)) _, err = w.Write(sample) } } }() return r } readerForPCM48Bit := func(s Signal) io.Reader { r, w := io.Pipe() go func() { // try shortcuts first offset, ok := s.(Offset) if pcms, ok2 := offset.LimitedSignal.(PCM48bit); ok && ok2 && pcms.samplePeriod == samplePeriod && pcms.MaxX() >= length-offset.Offset { offsetSamples := int(offset.Offset / samplePeriod) if offsetSamples < 0 { w.Write(pcms.Data[-offsetSamples*6 : (int(samples)-offsetSamples)*6]) } else { for x, zeroSample := 0, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; x < offsetSamples; x++ { w.Write(zeroSample) } w.Write(pcms.Data[:(int(samples)-offsetSamples)*6]) } w.Close() } else if pcm, ok := s.(PCM48bit); ok && pcm.samplePeriod == samplePeriod && pcm.MaxX() >= length { w.Write(pcm.Data[:samples*6]) w.Close() } else { defer func() { e := recover() if e != nil { w.CloseWithError(e.(error)) } else { w.Close() } }() for i, sample := uint32(0), make([]byte, 6); err == nil && i < samples; i++ { sample[0], sample[1], sample[2], sample[3], sample[4], sample[5] = encodePCM48bit(s.property(x(i) * samplePeriod)) _, err = w.Write(sample) } } }() return r } readerForPCM64Bit := func(s Signal) io.Reader { r, w := io.Pipe() go func() { // try shortcuts first offset, ok := s.(Offset) if pcms, ok2 := offset.LimitedSignal.(PCM64bit); ok && ok2 && pcms.samplePeriod == samplePeriod && pcms.MaxX() >= length-offset.Offset { offsetSamples := int(offset.Offset / samplePeriod) if offsetSamples < 0 { w.Write(pcms.Data[-offsetSamples*8 : (int(samples)-offsetSamples)*8]) } else { for x, zeroSample := 0, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; x < offsetSamples; x++ { w.Write(zeroSample) } w.Write(pcms.Data[:(int(samples)-offsetSamples)*8]) } w.Close() } else if pcm, ok := s.(PCM64bit); ok && pcm.samplePeriod == samplePeriod && pcm.MaxX() >= length { w.Write(pcm.Data[:samples*8]) w.Close() } else { defer func() { e := recover() if e != nil { w.CloseWithError(e.(error)) } else { w.Close() } }() for i, sample := uint32(0), make([]byte, 8); err == nil && i < samples; i++ { sample[0], sample[1], sample[2], sample[3], sample[4], sample[5], sample[6], sample[7] = encodePCM64bit(s.property(x(i) * samplePeriod)) _, err = w.Write(sample) } } }() return r } readers := make([]io.Reader, len(ss)) switch sampleBytes { case 1: for i, _ := range readers { readers[i] = readerForPCM8Bit(ss[i]) } err = interleavedWrite(w, 1, readers...) case 2: for i, _ := range readers { readers[i] = readerForPCM16Bit(ss[i]) } err = interleavedWrite(w, 2, readers...) case 3: for i, _ := range readers { readers[i] = readerForPCM24Bit(ss[i]) } err = interleavedWrite(w, 3, readers...) case 4: for i, _ := range readers { readers[i] = readerForPCM32Bit(ss[i]) } err = interleavedWrite(w, 4, readers...) case 6: for i, _ := range readers { readers[i] = readerForPCM48Bit(ss[i]) } err = interleavedWrite(w, 6, readers...) case 8: for i, _ := range readers { readers[i] = readerForPCM64Bit(ss[i]) } err = interleavedWrite(w, 8, readers...) } return }