Example #1
0
func newEcho(delay time.Duration) *echo {
	h, err := portaudio.DefaultHostApi()
	chk(err)
	p := portaudio.LowLatencyParameters(h.DefaultInputDevice, h.DefaultOutputDevice)
	p.Input.Channels = 1
	p.Output.Channels = 1
	e := &echo{buffer: make([]float32, int(p.SampleRate*delay.Seconds()))}
	e.Stream, err = portaudio.OpenStream(p, e.processAudio)
	chk(err)
	return e
}
Example #2
0
// Get a channel to read convenient data snippets from a device.
//  returns
//	<-chan TMSnippet	for caller to get audio samples
//	chan<- bool		for caller to send on when wanting to gracefully shutdown the audio stream and associated chans (true and false are treated the same here)
//	<-chan error		for the data-sending goroutine to report any errors
//	error			nil unless the stream can't be opened
// Note that this function doesn't (yet) automatically close if errors happen. It is currently the caller's responsibility to check if the error can be ignored and if not, to send something to the chan<- bool.
func MakeInputChannel(device Device) (<-chan *TMSnippet, chan<- bool, <-chan error, error) {
	streamParams := pa.LowLatencyParameters(device.paDeviceInfo, nil)
	streamParams.FramesPerBuffer = 64 // Number taken from portaudio-go/portaudio/examples/record.go line 70
	fmt.Printf("Stream parameters: %v\n", streamParams)
	buffer := make([]float32, streamParams.FramesPerBuffer)
	stream, err := pa.OpenStream(streamParams, buffer)
	if err != nil {
		return nil, nil, nil, err
	}
	tmschan := make(chan *TMSnippet, 10)
	closechan := make(chan bool)
	errchan := make(chan error)
	go func() {
		if err := stream.Start(); err != nil {
			errchan <- err
		}
		defer func() {
			err := stream.Close()
			if err != nil {
				errchan <- err
			}
			close(closechan)
			close(errchan)
		}()
		for {
			err := stream.Read()
			if err != nil {
				errchan <- err
				break
			}
			tms := new(TMSnippet)
			tms.SampleHz = streamParams.SampleRate
			tms.Samples = make([]float32, len(buffer))
			copy(tms.Samples, buffer)
			tmschan <- tms
		}
		/*
			for {
				if _, end := <-closechan; end {
					break
				}
				var tms TMSnippet
				tms.SampleHz = streamParams.SampleRate
				if framesAvailable, err := stream.AvailableToRead(); err == nil {
					if framesAvailable <= 0 {
						errchan <- errors.New("No frames available.")
						continue
					}
					// TODO: per TODO below, see if len(buffer) is more appropriate than framesAvailable
					tms.Samples = make([]float32, framesAvailable)
					// TODO: see if this gets stream.AvailableToRead()'s "maximum number of frames that can be read from the stream without blocking or busy waiting" described in portaudio.h or if it gets len(buffer) frames per method comment
					err = stream.Read()
					if err != nil {
						errchan <- err
					} else {
						n := copy(tms.Samples, buffer)
						if n != framesAvailable {
							errchan <- errors.New("Didn't get expected number of frames.")
						}
						tmschan <- &tms
					}
				} else {
					errchan <- err
				}
			}
		*/
	}()
	return tmschan, closechan, errchan, nil
}