func main() { var m Meter m.Initialize() defer portaudio.Terminate() var FLAGS_list = false flag.BoolVar(&FLAGS_list, "l", false, "List all devices") flag.Parse() if FLAGS_list { m.LogDevices() return } s := m.OpenStream() defer s.Close() select { // Wait forever. } if err := s.Stop(); err != nil { fmt.Printf("portaudio.Stream.Stop failed: ", err) return } }
func (spotify *Spotify) finishInitialisation(webApiAuth bool, pa *portAudio) error { if webApiAuth { if spotify.client = webapi.Auth(); spotify.client != nil { if privateUser, err := spotify.client.CurrentUser(); err == nil { if privateUser.ID != spotify.session.LoginUsername() { return errors.New("Username doesn't match with web-api authorization") } } else { spotify.client = nil } } } // init audio could happen after initPlaylist but this logs to output therefore // the screen isn't built properly portaudio.Initialize() go pa.player() defer portaudio.Terminate() if err := spotify.initPlaylist(); err != nil { return err } spotify.waitForEvents() return nil }
func main() { flag.Parse() portaudio.Initialize() defer portaudio.Terminate() portmidi.Initialize() defer portmidi.Terminate() if *doDemo { if err := demo(); err != nil { log.Println(err) } return } http.Handle("/", http.FileServer(http.Dir("static"))) http.HandleFunc("/socket", socket.Handler) l, err := net.Listen("tcp", *listenAddr) if err != nil { log.Fatal(err) } go http.Serve(l, nil) u := fmt.Sprintf("http://%v/", *listenAddr) if !*doBrowser || !openBrowser(u) { fmt.Printf("Open your web browser to %v\n\n", u) } fmt.Println("Press enter to quit...") os.Stdin.Read([]byte{0}) }
func main() { w := &window{voices: map[int]*sineVoice{}} p := audio.Params{SampleRate: 96000} audio.Init(w, p) portaudio.Initialize() defer portaudio.Terminate() s, err := portaudio.OpenDefaultStream(0, 1, p.SampleRate, 64, w.processAudio) if err != nil { fmt.Println(err) return } if err := s.Start(); err != nil { fmt.Println(err) return } defer s.Stop() if err := gui.Run(func() { gui.NewWindow(w, "beep", func(win *gui.Window) { w.Window = win gui.SetKeyFocus(w) }) }); err != nil { fmt.Println(err) } }
func main() { portaudio.Initialize() defer portaudio.Terminate() hs, err := portaudio.HostApis() chk(err) err = tmpl.Execute(os.Stdout, hs) chk(err) }
func (a *app) OnTerm() { if a.pastream != nil { a.pastream.Stop() a.pastream.Close() chk(portaudio.Terminate()) } a.r.Close() }
func main() { portaudio.Initialize() defer portaudio.Terminate() s := newStereoSine(256, 320, sampleRate) defer s.Close() chk(s.Start()) time.Sleep(2 * time.Second) chk(s.Stop()) }
func main() { portaudio.Initialize() defer portaudio.Terminate() e := newEcho(time.Second / 3) defer e.Close() chk(e.Start()) time.Sleep(4 * time.Second) chk(e.Stop()) }
// Slightly modified exact copy of the portaudio example func record(f *os.File, timer <-chan time.Time) { // form chunk _, _ = f.WriteString("FORM") binary.Write(f, binary.BigEndian, int32(0)) _, _ = f.WriteString("AIFF") // common chunk _, _ = f.WriteString("COMM") binary.Write(f, binary.BigEndian, int32(18)) binary.Write(f, binary.BigEndian, int16(1)) binary.Write(f, binary.BigEndian, int32(0)) binary.Write(f, binary.BigEndian, int16(32)) _, _ = f.Write([]byte{0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0}) //80-bit sample rate 44100 // sound chunk _, _ = f.WriteString("SSND") binary.Write(f, binary.BigEndian, int32(0)) binary.Write(f, binary.BigEndian, int32(0)) binary.Write(f, binary.BigEndian, int32(0)) nSamples := 0 defer func() { // fill in missing sizes totalBytes := 4 + 8 + 18 + 8 + 8 + 4*nSamples _, _ = f.Seek(4, 0) binary.Write(f, binary.BigEndian, int32(totalBytes)) _, _ = f.Seek(22, 0) binary.Write(f, binary.BigEndian, int32(nSamples)) _, _ = f.Seek(42, 0) binary.Write(f, binary.BigEndian, int32(4*nSamples+8)) f.Close() }() portaudio.Initialize() defer portaudio.Terminate() in := make([]int32, 64) stream, _ := portaudio.OpenDefaultStream(1, 0, 44100, len(in), in) defer stream.Close() stream.Start() defer stream.Stop() for { stream.Read() binary.Write(f, binary.BigEndian, in) nSamples += len(in) select { case <-timer: return default: } } }
func (spotify *Spotify) finishInitialisation(pa *portAudio) error { // init audio could happen after initPlaylist but this logs to output therefore // the screen isn't built properly portaudio.Initialize() go pa.player() defer portaudio.Terminate() if err := spotify.initPlaylist(); err != nil { return err } spotify.waitForEvents() return nil }
func main() { portaudio.Initialize() defer portaudio.Terminate() h, err := portaudio.DefaultHostApi() chk(err) stream, err := portaudio.OpenStream(portaudio.HighLatencyParameters(nil, h.DefaultOutputDevice), func(out []int32) { for i := range out { out[i] = int32(rand.Uint32()) } }) chk(err) defer stream.Close() chk(stream.Start()) time.Sleep(time.Second) chk(stream.Stop()) }
func main() { flag.Parse() if *random { *seed = time.Now().UnixNano() fmt.Println("seed =", *seed) } if *seed != math.MinInt64 { *random = true } rand.Seed(*seed) portaudio.Initialize() defer portaudio.Terminate() p := audio.Params{SampleRate: 48000} m := audio.MultiVoice{} audio.Init(&m, p) // for _, x := range [][2]float64{{1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {3, 2}, {4, 3}, {5, 4}, {7, 4}, {6, 5}, {7, 5}, {8, 5}, {9, 5}} { for xy := 1; xy <= 60; xy++ { for x := 2; x <= int(math.Sqrt(float64(xy))); x++ { if y := xy / x; x*y == xy && relPrime(x, y) { x, y, xy := float64(x), float64(y), float64(xy) c := math.Exp(-xy * math.Log2(y/x) / 12) f := y / x phase := 0.0 if *random { phase = rand.Float64() } m.Add(newSineBeat(.5*c, 128*f, 1/xy, phase, .1/f)) } } } s, err := portaudio.OpenDefaultStream(0, 1, p.SampleRate, 512, func(out []float32) { for i := range out { out[i] = float32(audio.Saturate(m.Sing())) } }) if err != nil { panic(err) } s.Start() fmt.Println("Press Enter to stop.") fmt.Scanln() s.Stop() }
func init() { portaudio.Initialize() go func() { defer os.Exit(0) sig := make(chan os.Signal, 1) signal.Notify(sig) if <-sig == syscall.SIGQUIT { buf := make([]byte, 1<<10) for runtime.Stack(buf, true) == len(buf) { buf = make([]byte, 2*len(buf)) } fmt.Fprintln(os.Stderr, string(buf)) } for _, c := range playControls { c.Stop() <-c.Done } portaudio.Terminate() }() }
func (self *Server) Start() error { portaudio.Initialize() defer portaudio.Terminate() var err error if err = self.startAudio(); err != nil { return err } if err = self.startSerial(); err != nil { return err } if err = self.startHttp(); err != nil { return err } return nil }
func Run(paths []string) { // initialize audio portaudio.Initialize() defer portaudio.Terminate() audio := NewAudio() if err := audio.Start(); err != nil { log.Fatalln(err) } defer audio.Stop() // initialize glfw if err := glfw.Init(); err != nil { log.Fatalln(err) } defer glfw.Terminate() // create window glfw.WindowHint(glfw.ContextVersionMajor, 2) glfw.WindowHint(glfw.ContextVersionMinor, 1) window, err := glfw.CreateWindow(width*scale, height*scale, title, nil, nil) if err != nil { log.Fatalln(err) } window.MakeContextCurrent() // initialize gl if err := gl.Init(); err != nil { log.Fatalln(err) } gl.Enable(gl.TEXTURE_2D) // run director director := NewDirector(window, audio) director.Start(paths) }
func main() { if len(os.Args) < 2 { fmt.Println("missing required argument: output file name") return } fmt.Println("Recording. Press Ctrl-C to stop.") sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, os.Kill) fileName := os.Args[1] if !strings.HasSuffix(fileName, ".aiff") { fileName += ".aiff" } f, err := os.Create(fileName) chk(err) // form chunk _, err = f.WriteString("FORM") chk(err) chk(binary.Write(f, binary.BigEndian, int32(0))) //total bytes _, err = f.WriteString("AIFF") chk(err) // common chunk _, err = f.WriteString("COMM") chk(err) chk(binary.Write(f, binary.BigEndian, int32(18))) //size chk(binary.Write(f, binary.BigEndian, int16(1))) //channels chk(binary.Write(f, binary.BigEndian, int32(0))) //number of samples chk(binary.Write(f, binary.BigEndian, int16(32))) //bits per sample _, err = f.Write([]byte{0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0}) //80-bit sample rate 44100 chk(err) // sound chunk _, err = f.WriteString("SSND") chk(err) chk(binary.Write(f, binary.BigEndian, int32(0))) //size chk(binary.Write(f, binary.BigEndian, int32(0))) //offset chk(binary.Write(f, binary.BigEndian, int32(0))) //block nSamples := 0 defer func() { // fill in missing sizes totalBytes := 4 + 8 + 18 + 8 + 8 + 4*nSamples _, err = f.Seek(4, 0) chk(err) chk(binary.Write(f, binary.BigEndian, int32(totalBytes))) _, err = f.Seek(22, 0) chk(err) chk(binary.Write(f, binary.BigEndian, int32(nSamples))) _, err = f.Seek(42, 0) chk(err) chk(binary.Write(f, binary.BigEndian, int32(4*nSamples+8))) chk(f.Close()) }() portaudio.Initialize() defer portaudio.Terminate() in := make([]int32, 64) stream, err := portaudio.OpenDefaultStream(1, 0, 44100, len(in), in) chk(err) defer stream.Close() chk(stream.Start()) for { chk(stream.Read()) chk(binary.Write(f, binary.BigEndian, in)) nSamples += len(in) select { case <-sig: return default: } } chk(stream.Stop()) }
func main() { if len(os.Args) < 2 { fmt.Println("missing required argument: input file name") return } fmt.Println("Playing. Press Ctrl-C to stop.") sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, os.Kill) fileName := os.Args[1] f, err := os.Open(fileName) chk(err) defer f.Close() id, data, err := readChunk(f) chk(err) if id.String() != "FORM" { fmt.Println("bad file format") return } _, err = data.Read(id[:]) chk(err) if id.String() != "AIFF" { fmt.Println("bad file format") return } var c commonChunk var audio io.Reader for { id, chunk, err := readChunk(data) if err == io.EOF { break } chk(err) switch id.String() { case "COMM": chk(binary.Read(chunk, binary.BigEndian, &c)) case "SSND": chunk.Seek(8, 1) //ignore offset and block audio = chunk default: fmt.Printf("ignoring unknown chunk '%s'\n", id) } } //assume 44100 sample rate, mono, 32 bit portaudio.Initialize() defer portaudio.Terminate() out := make([]int32, 8192) stream, err := portaudio.OpenDefaultStream(0, 1, 44100, len(out), &out) chk(err) defer stream.Close() chk(stream.Start()) defer stream.Stop() for remaining := int(c.NumSamples); remaining > 0; remaining -= len(out) { if len(out) > remaining { out = out[:remaining] } err := binary.Read(audio, binary.BigEndian, out) if err == io.EOF { break } chk(err) chk(stream.Write()) select { case <-sig: return default: } } }
func main() { if len(os.Args) < 2 { fmt.Println("Usage:", os.Args[0], "hostname:port [buffer-duration]") os.Exit(1) return } portaudio.Initialize() defer portaudio.Terminate() addr := os.Args[1] bufferStr := "100ms" if len(os.Args) > 2 { bufferStr = os.Args[2] } bufferLen, err := time.ParseDuration(bufferStr) if err != nil { fmt.Printf("Invalid buffer length: %v\n", err) return } conn, err := net.Dial("tcp", addr) if err != nil { fmt.Println("Error connecting to server:", err) return } defer conn.Close() buf := make([]byte, 8) _, err = io.ReadFull(conn, buf) if err != nil { fmt.Println("Error reading headers:", err) return } if buf[0] != 'R' { fmt.Printf("Invalid header start: %x\n", buf[0]) return } else if buf[1] == 0 { fmt.Println("Server is full") return } else if buf[1] != 1 { fmt.Printf("Unsupported protocol version: %d\n", buf[1]) return } flags := buf[2] if flags&rawstreamer.EncodingLittleEndian != 0 { Endianness = binary.LittleEndian } else if flags&rawstreamer.EncodingBigEndian != 0 { Endianness = binary.BigEndian } else { fmt.Println("Encoding endianness not specified!") return } encoding := flags & rawstreamer.EncodingMask numBytes := int(buf[3]) bits := numBytes * 8 if numBytes < 1 || numBytes > 4 { fmt.Printf("Unsupported number of bits: %d\n", bits) return } if encoding == rawstreamer.EncodingFloatingPoint { numBytes = 4 bits = 32 } sampleRate := Endianness.Uint32(buf[4:]) fmt.Printf("Streaming info: %dHz, ", sampleRate) fmt.Printf("%dbit %s, ", bits, rawstreamer.EncodingString[encoding]) fmt.Printf("%s, %v buffer\n", Endianness.String(), bufferLen) bufferSize := sampleRate / 50 // 20ms buffer size Buffers = []chan float32{ make(chan float32, getChannelBufferSize(bufferLen, bufferSize, sampleRate)), make(chan float32, getChannelBufferSize(bufferLen, bufferSize, sampleRate)), } Buffering = int32(getChannelBufferSize(bufferLen, bufferSize, sampleRate)) LastLeft = 0 LastRight = 0 printStatus() Stream, err = portaudio.OpenDefaultStream(0, 2, float64(sampleRate), int(bufferSize), processAudio) defer Stream.Close() err = Stream.Start() if err != nil { fmt.Println("Failed to start stream:", err) return } defer func() { Stream.Stop() close(Buffers[0]) close(Buffers[1]) }() buf = make([]byte, int(bufferSize)*numBytes*2) align := 8 % (numBytes * 2) if align > 0 { // Read in the extra padding _, err = io.ReadFull(conn, buf[:(numBytes*2)-align]) if err != nil { fmt.Println("Error reading headers:", err) return } } var lastData time.Time remainder := 0 for { n := 0 conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) n, err = io.ReadAtLeast(conn, buf[remainder:], numBytes*2-remainder) if err != nil { fmt.Println("Error reading stream:", err) return } n += remainder remainder = n % (numBytes * 2) for i := 0; i < (n - remainder); i += numBytes * 2 { BufferingSync.Lock() left := rawstreamer.ReadFloat32(buf[i:i+numBytes], flags, Endianness) right := rawstreamer.ReadFloat32(buf[i+numBytes:i+numBytes*2], flags, Endianness) if left != 0 || right != 0 { lastData = time.Now() Buffers[0] <- left Buffers[1] <- right } else if time.Since(lastData) < 1*time.Minute { Buffers[0] <- left Buffers[1] <- right } if atomic.LoadInt32(&Buffering) > 0 && time.Since(lastData) < 1*time.Minute { atomic.AddInt32(&Buffering, -1) } BufferingSync.Unlock() } copy(buf, buf[n-remainder:n]) } }
// Init starts the audio system, loads sound assets, and starts the sound loop. func Init() error { if err := portaudio.Initialize(); err != nil { return err } log.Printf("PortAudio version: %d %s", portaudio.Version(), portaudio.VersionText()) var err error makeBuffer := func(name string) []int16 { if err != nil { return nil } var r io.Reader if r, err = asset.Reader(name); err != nil { return nil } var w *wav if w, err = decodeWAV(r); err != nil { return nil } log.Printf("%s: %+v", name, w) buf := make([]int16, len(w.data)/2) for i := 0; i < len(buf); i++ { buf[i] = int16(w.data[i*2]) buf[i] += int16(w.data[i*2+1]) << 8 } return buf } var soundBuffers [][]int16 for _, a := range soundAssets { soundBuffers = append(soundBuffers, makeBuffer(a)) } if err != nil { return err } soundQueue := make(chan Sound, soundQueueSize) Play = func(s Sound) { soundQueue <- s } done := make(chan bool) Terminate = func() { done <- true <-done close(done) logFatalIfErr("portaudio.Terminate", portaudio.Terminate()) } go func() { const ( numInputChannels = 0 /* zero input - no recording */ numOutputChannels = 2 /* stereo output */ sampleRate = 44100 /* samples per second */ intervalMs = 100 framesPerBuffer = sampleRate / 1000.0 * intervalMs /* len(buf) == numChannels * framesPerBuffer */ outputBufferSize = numOutputChannels * framesPerBuffer ) // Temporary buffers to read and write the next audio batch. tmpIn := make([]int16, outputBufferSize) tmpOut := make([]int16, outputBufferSize) // outputRingBuffer is a buffer that the PortAudio callback will read data from, // and that we will periodically wake up to write new data to. outputRingBuffer := newRingBuffer(outputBufferSize * 10) // process is the callback that PortAudio will call when it needs audio data. process := func(out []int16) { outputRingBuffer.pop(tmpIn) for i := 0; i < len(out); i++ { out[i] = tmpIn[i] } } stream, err := portaudio.OpenDefaultStream(numInputChannels, numOutputChannels, sampleRate, framesPerBuffer, process) logFatalIfErr("portaudio.OpenDefaultStream", err) defer func() { logFatalIfErr("stream.Close", stream.Close()) }() logFatalIfErr("stream.Start()", stream.Start()) defer func() { // stream.Stop blocks until all samples have been played. logFatalIfErr("stream.Stop", stream.Stop()) done <- true }() var active [][]int16 quit := false loop: for { select { case <-time.After(intervalMs * time.Millisecond): // Play whatever sounds are in the queue at the time. n := len(soundQueue) for i := 0; i < n; i++ { active = append(active, soundBuffers[<-soundQueue]) } // Fill temporary buffer with any active sounds buffers. for i := 0; i < len(tmpOut); i++ { // Combine active signals together. var v int16 for j := 0; j < len(active); j++ { // Remove any buffers if they have no more samples. if len(active[j]) == 0 { active = append(active[:j], active[j+1:]...) j-- continue } v += active[j][0] active[j] = active[j][1:] } tmpOut[i] = v } outputRingBuffer.push(tmpOut...) // Only quit waking until there are no more streams to play. if quit && len(active) == 0 { break loop } case <-done: close(soundQueue) // Prevent any new sounds from being scheduled. quit = true } } }() return nil }
func Run() { chk(LoadUgen("./inst/spread.so", "spread")) chk(LoadUgen("./inst/reverb.so", "reverb")) chk(LoadUgen("./inst/lead2.so", "midi")) chk(LoadUgen("./inst/lead.so", "lead")) chk(LoadUgen("./inst/bass.so", "bass")) chk(LoadUgen("./inst/snare.so", "snare")) chk(LoadUgen("./inst/lopass.so", "lopass")) shouldRecord := flag.Bool("record", false, "whether to record") addr := flag.String("addr", "localhost:8080", "http service address") flag.Parse() portaudio.Initialize() defer portaudio.Terminate() if *shouldRecord { var err error f, err = os.Create("/tmp/recording.f32") // # to play: // $ play -x -r 44100 -c 1 /tmp/recording.f32 // # to convert to wav: // $ sox -x -r 44100 -c 1 /tmp/recording.f32 recording.wav chk(err) } s, err := openStream(processAudio) fmt.Println("%+v\n", s.Info()) chk(err) defer s.Close() if true { service.Initialize(*addr, cmdHandle) } if true { client, err := coremidi.NewClient("midi client") chk(err) port, err := coremidi.NewInputPort(client, "test", func(source coremidi.Source, event []byte) { handleMidiEvent(event, bleeps) }) chk(err) sources, err := coremidi.AllSources() chk(err) for _, source := range sources { // func(source coremidi.Source) { fmt.Printf("Listening to midi source %s [%s]\n", source.Name(), source.Manufacturer()) port.Connect(source) // }(source) } } filterOn("reverb", 80.0, []*float64{getBus(0)}) filterOn("lopass", 90.0, []*float64{getBus(0), &resFreq, &Q}) filterOn("spread", 100.0, []*float64{getBus(0), getBus(1)}) go func() { for { fmt.Printf("inner loop taking avg ~%f samples\n", inner.Seconds()*sampleRate/float64(innerCount)) inner = 0 innerCount = 0 time.Sleep(1 * time.Second) } }() chk(s.Start()) select {} defer chk(s.Stop()) }
func Play(x audio.Voice) { var v int var v2 *audio.Params var v3 interface{} var v4 *portaudio.Stream var v5 *portaudio.Stream var v6 chan struct{} var v7 chan struct{} var v8 interface{} var v9 float64 var v10 float64 var v11 int var v12 audio.Voice var v13 int v12 = x v8 = x portaudio.Initialize() //;0 defer portaudio.Terminate() //0; var v14 int x2 := make(chan struct{}, v14) v6 = x2 v7 = x2 const x3 = 96000 v9 = x3 v10 = x3 const x4 = 64 v13 = x4 v = x4 x5 := &audio.Params{SampleRate: v10, BufferSize: v13} v2 = x5 v2.Set(v8) //;1 const x6 = 1 v11 = x6 x7 := func(in [][]float32, out [][]float32) { var v15 []float32 var v16 [][]float32 var v17 bool var v18 audio.Audio v16 = out x8, done := v12.Sing() v18 = x8 v17 = done var v19 int x9 := &v16[v19] v15 = *x9 for k := range v18 { var v20 = &v18[k] var v21 int var v22 float64 var v23 float32 v21 = k v22 = *v20 x10 := (float32)(v22) v23 = x10 v15[v21] = v23 } if v17 { var v24 struct{} select { case v7 <- v24: default: } } } v3 = x7 var v25 int x11, _ := portaudio.OpenDefaultStream(v25, v11, v9, v, v3) //0; v4 = x11 v5 = x11 v4.Start() //1;2 <-v6 //2;3 v5.Stop() //3; }
//Creates a new engine and populates it with the core functions func LoadAudio(e *Engine) *Engine { e = add(e, "portaudio.init", NewCode("portaudio.init", 0, func(e *Engine, c *Thingy) *Engine { portaudio.Initialize() return e })) e = add(e, "portaudio.terminate", NewCode("portaudio.terminate", 0, func(e *Engine, c *Thingy) *Engine { defer portaudio.Terminate() return e })) e = add(e, "portaudio.setData", NewCode("setData", 3, func(ne *Engine, c *Thingy) *Engine { var posString, buffWrap, valString *Thingy posString, ne.dataStack = popStack(ne.dataStack) valString, ne.dataStack = popStack(ne.dataStack) buffWrap, ne.dataStack = popStack(ne.dataStack) var pos, _ = strconv.ParseInt(posString.getSource(), 10, 32) var val, _ = strconv.ParseFloat(valString.getSource(), 32) out := buffWrap._structVal.([][]float32) out[0][pos] = float32(val) return ne })) e = add(e, "portaudio.start", NewCode("portaudio.start", -1, func(e *Engine, c *Thingy) *Engine { //AudioCallbackState = e.RunString("CLEARSTACK", "setup audio callback") AudioCallbackState = e stream, err := portaudio.OpenDefaultStream(0, 2, sampleRate, 0, processAudio) chk(err) stream.Start() chk(err) e.dataStack = pushStack(e.dataStack, NewWrapper(stream)) chk(err) return e })) e = add(e, "portaudio.HostApis", NewCode("portaudio.HostApis", 0, func(e *Engine, c *Thingy) *Engine { var tmpl = template.Must(template.New("").Parse( `[ {{range .}} H[ Name [ {{.Name}} ] {{if .DefaultInputDevice}}DefaultInput [ {{.DefaultInputDevice.Name}} ] {{end}} {{if .DefaultOutputDevice}}DefaultOutput [ {{.DefaultOutputDevice.Name}} ] {{end}} Devices [ {{range .Devices}} H[ Name [ {{.Name}} ] MaxInputChannels [ {{.MaxInputChannels}} ] MaxOutputChannels [ {{.MaxOutputChannels}} ] DefaultLowInputLatency [ {{.DefaultLowInputLatency}} ] DefaultLowOutputLatency [ {{.DefaultLowOutputLatency}} ] DefaultHighInputLatency [ {{.DefaultHighInputLatency}} ] DefaultHighOutputLatency [ {{.DefaultHighOutputLatency}} ] DefaultSampleRate [ {{.DefaultSampleRate}} ] ]H {{end}} ] ]H {{end}} ]`, )) var b bytes.Buffer hs, err := portaudio.HostApis() chk(err) err = tmpl.Execute(&b, hs) chk(err) s := b.String() fmt.Println(s) return e })) return e }