Exemple #1
0
// 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
}