예제 #1
0
파일: player.go 프로젝트: rubyist/tdrum
func main() {
	flag.Parse()

	sequencer := NewSequencer()

	for _, file := range flag.Args() {
		pattern, err := drum.DecodeFile(file)
		if err != nil {
			log.Fatal(err)
		}
		if err := sequencer.Add(pattern); err != nil {
			log.Fatal(err)
		}
		log.Print(pattern.String())
	}

	portaudio.Initialize()
	defer portaudio.Terminate()
	stream, err := portaudio.OpenDefaultStream(0, 2, 44100, 0, func(o []int32) {
		sequencer.Read(o)
	})
	if err != nil {
		log.Fatal(err)
	}
	defer stream.Close()
	stream.Start()
	defer stream.Stop()

	sequencer.Start()

	for {
		time.Sleep(time.Second)
	}
}
예제 #2
0
파일: main.go 프로젝트: rakyll/sigourney
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", socketHandler)
	go func() {
		if err := http.ListenAndServe(*listenAddr, nil); err != nil {
			log.Println(err)
		}
	}()

	os.Stdout.Write([]byte("Press enter to stop...\n"))
	os.Stdin.Read([]byte{0})
}
예제 #3
0
func main() {
	portaudio.Initialize()
	defer portaudio.Terminate()
	hs, err := portaudio.HostApis()
	chk(err)
	err = tmpl.Execute(os.Stdout, hs)
	chk(err)
}
예제 #4
0
func main() {
	sampleRate := 44100
	blockSize := 205 * sampleRate / 8000
	window := blockSize / 4
	dt := dtmf.NewStandard(sampleRate, blockSize)
	lastKey := -1
	keyCount := 0
	samples := make([]float32, blockSize)

	if err := portaudio.Initialize(); err != nil {
		log.Fatalf("Initialize: %+v", err)
	}
	defer func() {
		if err := portaudio.Terminate(); err != nil {
			log.Fatalf("Terminate: %+v", err)
		}
	}()
	inputBuf := make([]float32, window)
	stream, err := portaudio.OpenDefaultStream(1, 0, float64(sampleRate), len(inputBuf), inputBuf)
	if err != nil {
		log.Fatalf("OpenDefaultStream: %+v", err)
	}
	defer stream.Close()
	if err := stream.Start(); err != nil {
		log.Fatalf("Start: %+v", err)
	}
	defer stream.Stop()

	fmt.Printf("%+v\n", stream.Info())

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, os.Kill)
	for {
		if err := stream.Read(); err != nil {
			log.Fatalf("Read: %+v", err)
		}

		copy(samples, samples[window:])
		copy(samples[len(samples)-len(inputBuf):], inputBuf)

		if k, t := dt.Feed(samples); k == lastKey && t > 0.0 {
			keyCount++
			if keyCount == 10 {
				fmt.Printf("%c", dtmf.Keypad[k])
			}
		} else {
			lastKey = k
			keyCount = 0
		}

		select {
		case <-sig:
			fmt.Println()
			return
		default:
		}
	}
}
예제 #5
0
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())
}
예제 #6
0
파일: echo.go 프로젝트: krak3n/portaudio-go
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())
}
예제 #7
0
// Play will play the given pattern.
// It will generate different sounds for each instrument
// every time it is called. For simplification, those sounds
// are just sine waves.
func (p *Pattern) Play(playingTime time.Duration) error {
	// Initialize portaudio
	portaudio.Initialize()
	defer portaudio.Terminate()

	stream, err := portaudio.OpenDefaultStream(0, 1, sampleRate, 0, processAudio)
	if err != nil {
		return errors.New("could not open default stream")
	}
	defer stream.Close()

	// Create random tone map
	toneMap = make(map[byte]*tone)
	rand.Seed(time.Now().Unix())
	for i := range p.instruments {
		var err error
		toneMap[i], err = newTone(rand.Float64()*600+300, sampleRate)
		if err != nil {
			return fmt.Errorf("could not create tone for instrument %v", i)
		}
	}

	stream.Start()
	defer stream.Stop()

	// Signal for stopping
	timeOut := time.After(playingTime)

	timePerStep := time.Duration(60/p.header.BPM*1000) * time.Millisecond
	ticker := time.NewTicker(timePerStep)
	currentStep := 0

	// Play!
	for _ = range ticker.C {
		for i, instrument := range p.instruments {
			if instrument.Pattern[currentStep] == 0 {
				toneMap[i].playing = false
			} else {
				toneMap[i].playing = true
			}
		}

		currentStep++
		if currentStep > 15 {
			currentStep = 0
		}

		select {
		case <-timeOut:
			ticker.Stop()
			return nil
		default:
		}
	}

	return nil
}
예제 #8
0
파일: port.go 프로젝트: rossipedia/mog
func (p *port) Dispose() {
	portInitCount--
	if portInitCount == 0 {
		portaudio.Terminate()
	}
	if p.st != nil {
		_ = p.st.Stop() // ignore error
		p.st.Close()
	}
}
예제 #9
0
func sineLogon() {
	portaudio.Initialize()
	defer portaudio.Terminate()
	s := newStereoSine(132, 198/2, sampleRate)
	defer s.Close()
	chk(s.Start())

	doADSR(s, 0.4, 0.1, 0.1)
	doADSR(s, 0.1, 0.8, 0.9)

	// wait for buffer to drain
	time.Sleep(500 * time.Millisecond)
	chk(s.Stop())
}
예제 #10
0
파일: sine.go 프로젝트: sideb0ard/Craxx
func sineMain(ch *amqp.Channel) {

	go sniffy()
	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name, // queue name
		"",     // routing key
		"bpm",  // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	portaudio.Initialize()
	defer portaudio.Terminate()
	//s := newStereoSine(256, 320, sampleRate)
	s := newStereoSine(220, 220, sampleRate)
	defer s.Close()
	chk(s.Start())
	defer s.Stop()

	for m := range msgs {
		var bm BpmMsg
		err := json.Unmarshal(m.Body, &bm)
		if err != nil {
			fmt.Println("blah", err)
		}
		bpm = bm.Bpm
	}
}
예제 #11
0
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())
}
예제 #12
0
func main() {
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, usage)
		flag.PrintDefaults()
		os.Exit(2)
	}
	flag.Parse()
	if flag.NArg() != 1 {
		flag.Usage()
	}
	p, err := drum.DecodeFile(flag.Arg(0))
	if err != nil {
		log.Fatalf("cannot decode splice file: %v", err)
	}
	if *showInfo {
		fmt.Print(p)
		return
	}
	patches, err := readPatches(p, *sampleDir)
	if err != nil {
		log.Fatalf("cannot read sample patches: %v", err)
	}
	drumMod, err := drummachine.New(p, patches)
	if err != nil {
		log.Fatalf("cannot make new drum machine: %v", err)
	}

	portaudio.Initialize()
	defer portaudio.Terminate()

	portmidi.Initialize()
	defer portmidi.Terminate()

	e := audio.NewEngine()
	e.Input("in", drumMod)
	if err := e.Start(); err != nil {
		panic(err)
	}
	select {}
}
예제 #13
0
파일: run.go 프로젝트: tiancode/nes
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)
}
예제 #14
0
// Play an AIFF file using PortAudio
// Base on example code from: https://code.google.com/p/portaudio-go/source/browse/portaudio/examples/play.go
func PlayAIFF(p string, sig chan int) error {

	f, err := os.Open(p)
	if err != nil {
		return err
	}
	defer f.Close()

	id, data, err := readChunk(f)
	if err != nil {
		return err
	}
	if id.String() != "FORM" {
		return ErrBadFileFormat
	}
	_, err = data.Read(id[:])
	if err != nil {
		return err
	}
	if id.String() != "AIFF" {
		return ErrBadFileFormat
	}

	var c commonChunk
	var audio io.Reader
	for {
		id, chunk, err := readChunk(data)
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		switch id.String() {
		case "COMM":
			err = binary.Read(chunk, binary.BigEndian, &c)
			if err != nil {
				return err
			}
		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)
	if err != nil {
		return err
	}
	defer stream.Close()

	err = stream.Start()
	if err != nil {
		return err
	}

	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
		}
		if err != nil {
			return err
		}

		err = stream.Write()
		if err != nil {
			return err
		}

		select {
		case <-sig:
			return nil
		default:
		}
	}

	return nil
}
예제 #15
0
파일: tdrum.go 프로젝트: rubyist/tdrum
func main() {
	if len(os.Args) != 2 {
		fmt.Println("usage: tdrum file.splice")
		os.Exit(1)
	}

	pattern, err := drum.DecodeFile(os.Args[1])
	if err != nil {
		fmt.Printf("error: %s\n", err)
		os.Exit(1)
	}

	sequencer = NewSequencer()
	if err := sequencer.Add(pattern); err != nil {
		fmt.Printf("error: %s\n", err)
		os.Exit(1)
	}

	portaudio.Initialize()
	defer portaudio.Terminate()
	stream, err := portaudio.OpenDefaultStream(0, 2, 44100, 0, func(o []int32) {
		sequencer.Read(o)
	})
	if err != nil {
		log.Fatal(err)
	}
	defer stream.Close()
	stream.Start()
	defer stream.Stop()

	if err := termbox.Init(); err != nil {
		panic(err)
	}
	defer termbox.Close()
	termbox.SetOutputMode(termbox.Output256)

	eq := make(chan termbox.Event)
	go func() {
		for {
			eq <- termbox.PollEvent()
		}
	}()

	draw(pattern)
loop:
	for {
		select {
		case ev := <-eq:
			if ev.Type == termbox.EventKey && ev.Key == termbox.KeyEsc {
				break loop
			}
			if ev.Type == termbox.EventKey && ev.Key == termbox.KeySpace {
				if sequencer.Running {
					sequencer.Reset()
				} else {
					sequencer.Start()
				}
			}
		default:
			draw(pattern)
			time.Sleep(time.Millisecond * 2)
		}
	}
}
예제 #16
0
파일: main.go 프로젝트: sideb0ard/CMDSine
func main() {
	flag.Parse()
	//cmds := []string{"ls", "exit", "jobbie"}

	PS2 := ansi.Color("#CMDSine> ", "magenta")

	signalChan := make(chan SoundGen)

	tickChan := make(chan int)
	go ticker(tickChan)
	// go fib(tickerChan)

	portaudio.Initialize()
	defer portaudio.Terminate()

	m := newMixer()
	go m.mix(signalChan)

	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	// Check GOMAXPROCS
	max_procs := runtime.GOMAXPROCS(-1)
	num_procs_to_set := runtime.NumCPU()
	if max_procs != num_procs_to_set {
		runtime.GOMAXPROCS(num_procs_to_set)
	}

	// non-interactive - running Prime loop
	if *pflag == true {
		forevs := make(chan bool)
		go primez(signalChan, tickChan)
		<-forevs
	}

	shellReader := bufio.NewReader(os.Stdin)
	for {
		// SETUP && LOOP
		fmt.Printf(PS2)
		input, err := shellReader.ReadString('\n')
		if err != nil {
			if err.Error() == "EOF" {
				myexit()
			} else {
				fmt.Println("Got an err for ye: ", err)
			}
		}
		input = strings.TrimSpace(input)

		// ALL DA REGEX FROM HERE ON OUT..

		// SET OFF PRIME TRACK
		prx, _ := regexp.MatchString("^prime$", input)
		if prx {
			go primez(signalChan, tickChan)
		}

		// SET BPM
		bpmre := regexp.MustCompile("^bpm +([0-9]+)$")
		br := bpmre.FindStringSubmatch(input)
		if len(br) == 2 {
			bpmval, err := strconv.ParseFloat(br[1], 64)
			if err != nil {
				fmt.Println("Choked on your Beats Per Minute, mate..")
				continue
			}
			bpm = bpmval
			tickLength = 60000 / bpm / 60
			loopLength = tickLength * 16
		}

		// CREATE SINE w/ FREQ
		re := regexp.MustCompile("^sine +([0-9]+)$")
		sf := re.FindStringSubmatch(input)
		if len(sf) == 2 {
			freq, err := strconv.ParseFloat(sf[1], 64)
			if err != nil {
				fmt.Println("Choked on your sine freq, mate..")
				continue
			}
			newSine(signalChan, freq)
		}

		// SET SINE ATTRIB
		// ssx := regexp.MustCompile("^set sine ([0-9]) ([a-z]+) ([0-9\\.]+)$")
		// ssxf := ssx.FindStringSubmatch(input)
		// if len(ssxf) == 4 {
		// 	sineNum, err := strconv.Atoi(ssxf[1])
		// 	if err != nil {
		// 		fmt.Println(err)
		// 		continue
		// 	}
		// 	attrib := ssxf[2]
		// 	val, err := strconv.ParseFloat(ssxf[3], 64)
		// 	if err != nil {
		// 		fmt.Println(err)
		// 		continue
		// 	}
		// 	if sineNum < len(m.signals) {
		// 		m.signals[sineNum].set(attrib, val)
		// 	}
		// }

		// CREATE FREQMOD
		fmx := regexp.MustCompile("^fm +([0-9]+) +([0-9]+)$")
		fmxr := fmx.FindStringSubmatch(input)
		// if len(fmxr) == 2 {
		if len(fmxr) > 1 {
			fmt.Println("New FM!")
			car, err := strconv.ParseFloat(fmxr[1], 64)
			if err != nil {
				fmt.Println("Choked on your carrier freq, mate..")
				continue
			}
			mod, err := strconv.ParseFloat(fmxr[2], 64)
			if err != nil {
				fmt.Println("Choked on your modulator freq, mate..")
				continue
			}
			newFM(signalChan, car, mod)
		}

		// PROCESS LIST
		psx, _ := regexp.MatchString("^ps$", input)
		if psx {
			fmt.Printf("///CMDSine:: bpm: %.0f \\\\\\\n", bpm)
			m.listChans()
			fmt.Println()
		}
	}
}
예제 #17
0
파일: audio.go 프로젝트: XQYCHJ/termloop
// Stop shuts down PortAudio
func (a *Audio) Stop() {
	portaudio.Terminate()
}
예제 #18
0
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())
}
예제 #19
0
// Play attempts to play the specified pattern for 'n' seconds on the
// default audio output device on the current system. An error is
// returned if the audio could not be played correctly.
func Play(pt *Pattern, n int) error {
	// Validate that all tracks present in our pattern have sound files loaded.
	for _, tr := range pt.Tracks {
		_, ok := tracks[strings.ToLower(tr.Name)+".wav"]
		if !ok {
			return fmt.Errorf("track %s could not be found, required to play pattern", tr.Name)
		}
	}

	// Let's do some math first. At a tempo of 120 (bpm), we play 2 beats per second.
	// That means each beat takes 0.5 seconds. A beat is comprised of a quarter note,
	// which in turn is comprised of 4 steps. This means, each step takes 0.125 seconds.
	// The time taken by a step is what we are interested in, as that is what we will
	// use to schedule the playing of sounds.
	beatTime := 1.0 / (pt.Tempo / 60.0)
	stepTime := beatTime / 4.0

	// Initialize a list that represents our play queue. This is a list of
	// sounds that are queued up for playback.
	var queue = list.New()

	// We need to keep track of how many steps have been played so far.
	// This is always a value between 0 and 15 (since our tracks have a fixed
	// 16 steps). We also track the last time a step was played, so we know
	// when we can schedule the next.
	lastStep := 0
	lastStepPlayed := time.Duration(0)

	// Initialize portaudio.
	err := portaudio.Initialize()
	if err != nil {
		return err
	}
	defer portaudio.Terminate()

	// Let's open a stream up and configure our callback.
	stream, err := portaudio.OpenDefaultStream(0, numChannels, sampleRate, framesPerBuffer, func(output buffer, info portaudio.StreamCallbackTimeInfo) {
		// If sufficient time has passed since we last played a step, queue up the next.
		if info.OutputBufferDacTime-lastStepPlayed >= time.Duration(stepTime*float32(time.Second)) {
			for _, tr := range pt.Tracks {
				// Is this track scheduled to be played at this step?
				if tr.Steps[lastStep] == 0x1 {
					queue.PushBack(&queueItem{tracks[strings.ToLower(tr.Name)+".wav"], 0})
				}
			}

			lastStepPlayed = info.OutputBufferDacTime

			lastStep++
			if lastStep > 15 {
				lastStep = 0
			}
		}

		// Multiplex all queued sounds and play them.
		multiplexSounds(output, queue)
	})
	if err != nil {
		return err
	}

	// Let's play some drums!
	err = stream.Start()
	if err != nil {
		return err
	}

	// For 'n' seconds....
	time.Sleep(time.Duration(n) * time.Second)

	// Stop and cleanup.
	err = stream.Stop()
	if err != nil {
		return err
	}
	err = stream.Close()
	if err != nil {
		return err
	}

	return nil
}
예제 #20
0
파일: play.go 프로젝트: krak3n/portaudio-go
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:
		}
	}
}