Example #1
0
func AddSource(in snd.Sound) error {
	switch in.Channels() {
	case 1:
		hwa.format = al.FormatMono16
	case 2:
		hwa.format = al.FormatStereo16
	default:
		return fmt.Errorf("snd/al: can't handle input with channels(%v)", in.Channels())
	}
	hwa.in = in
	hwa.out = make([]byte, in.BufferLen()*2)

	s := al.GenSources(1)
	if code := al.Error(); code != 0 {
		return fmt.Errorf("snd/al: generate source failed [err=%v]", code)
	}
	hwa.source = s[0]
	hwa.buf.src = s[0]

	log.Println("snd/al: software latency", SoftLatency())

	hwa.inputs = snd.GetInputs(in)

	return nil
}
Example #2
0
// NewPlayer returns a new Player.
// It initializes the underlying audio devices and the related resources.
// If zero values are provided for format and sample rate values, the player
// determines them from the source's WAV header.
// An error is returned if the format and sample rate can't be determined.
func NewPlayer(src ReadSeekCloser, format Format, samplesPerSecond int64) (*Player, error) {
	if err := al.OpenDevice(); err != nil {
		return nil, err
	}
	if err := createContext(); err != nil {
		return nil, err
	}
	s := al.GenSources(1)
	if code := al.Error(); code != 0 {
		return nil, fmt.Errorf("audio: cannot generate an audio source [err=%x]", code)
	}
	p := &Player{
		t:      &track{format: format, src: src, samplesPerSecond: samplesPerSecond},
		source: s[0],
	}
	if err := p.discoverHeader(); err != nil {
		return nil, err
	}
	if p.t.format == 0 {
		return nil, errors.New("audio: cannot determine the format")
	}
	if p.t.samplesPerSecond == 0 {
		return nil, errors.New("audio: cannot determine the sample rate")
	}
	return p, nil
}
Example #3
0
func NewPlayer(sampleRate, channelNum, bytesPerSample int) (*Player, error) {
	var p *Player
	if err := al.OpenDevice(); err != nil {
		return nil, fmt.Errorf("driver: OpenAL initialization failed: %v", err)
	}
	s := al.GenSources(1)
	if e := al.Error(); e != 0 {
		return nil, fmt.Errorf("driver: al.GenSources error: %d", e)
	}
	p = &Player{
		alSource:   s[0],
		alBuffers:  []al.Buffer{},
		sampleRate: sampleRate,
		alFormat:   alFormat(channelNum, bytesPerSample),
	}
	runtime.SetFinalizer(p, (*Player).Close)

	bs := al.GenBuffers(maxBufferNum)
	const bufferSize = 1024
	emptyBytes := make([]byte, bufferSize)
	for _, b := range bs {
		// Note that the third argument of only the first buffer is used.
		b.BufferData(p.alFormat, emptyBytes, int32(p.sampleRate))
		p.alSource.QueueBuffers(b)
	}
	al.PlaySources(p.alSource)
	return p, nil
}
Example #4
0
func (p *Player) Close() error {
	if err := al.Error(); err != 0 {
		return fmt.Errorf("driver: error before closing: %d", err)
	}
	if p.isClosed {
		return nil
	}
	var bs []al.Buffer
	al.RewindSources(p.alSource)
	al.StopSources(p.alSource)
	if n := p.alSource.BuffersQueued(); 0 < n {
		bs = make([]al.Buffer, n)
		p.alSource.UnqueueBuffers(bs...)
		p.alBuffers = append(p.alBuffers, bs...)
	}
	p.isClosed = true
	if err := al.Error(); err != 0 {
		return fmt.Errorf("driver: error after closing: %d", err)
	}
	runtime.SetFinalizer(p, nil)
	return nil
}
Example #5
0
func NewContext(oscillator model.Oscillator) *Context {
	if err := al.OpenDevice(); err != nil {
		log.Fatal(err)
	}
	s := al.GenSources(1)
	if code := al.Error(); code != 0 {
		log.Fatalln("openal error:", code)
	}
	return &Context{
		source:     s[0],
		queue:      []al.Buffer{},
		oscillator: oscillator,
	}
}
Example #6
0
// Get returns a slice of buffers of length b.size ready to receive data and be queued.
// If b.src reports processing at-least as many buffers as b.size, buffers up to b.size
// will be unqueued for reuse. Otherwise, new buffers will be generated.
//
// If the length of b.bufs has grown to be greater than maxbufs, a nil slice is returned.
func (b *Buffer) Get() (bufs []al.Buffer) {
	if proc := int(b.src.BuffersProcessed()); proc >= b.size {
		// advance by size, BuffersProcessed will report that many less next time.
		bufs = b.bufs[b.idx : b.idx+b.size]
		b.src.UnqueueBuffers(bufs)
		if code := al.Error(); code != 0 {
			log.Printf("snd/al: unqueue buffers failed [err=%v]\n", code)
		}
		b.idx = (b.idx + b.size) % len(b.bufs)
	} else if len(b.bufs) >= maxbufs {
		// likely programmer error, something has gone horribly wrong.
		log.Printf("snd/al: get buffers failed, maxbufs reached [len=%v]\n", len(b.bufs))
		return nil
	} else {
		// make more buffers to fill data regardless of what openal says about processed.
		bufs = al.GenBuffers(b.size)
		if code := al.Error(); code != 0 {
			log.Printf("snd/al: generate buffers failed [err=%v]\n", code)
		}
		b.bufs = append(b.bufs, bufs...)
	}
	return bufs
}
Example #7
0
func (p *Player) Proceed(data []byte) error {
	if err := al.Error(); err != 0 {
		return fmt.Errorf("driver: before proceed: %d", err)
	}
	processedNum := p.alSource.BuffersProcessed()
	if 0 < processedNum {
		bufs := make([]al.Buffer, processedNum)
		p.alSource.UnqueueBuffers(bufs...)
		if err := al.Error(); err != 0 {
			return fmt.Errorf("driver: Unqueue in process: %d", err)
		}
		p.alBuffers = append(p.alBuffers, bufs...)
	}

	if len(p.alBuffers) == 0 {
		// This can happen (#207)
		return nil
	}
	buf := p.alBuffers[0]
	p.alBuffers = p.alBuffers[1:]
	buf.BufferData(p.alFormat, data, int32(p.sampleRate))
	p.alSource.QueueBuffers(buf)
	if err := al.Error(); err != 0 {
		return fmt.Errorf("driver: Queue in process: %d", err)
	}

	if p.alSource.State() == al.Stopped || p.alSource.State() == al.Initial {
		al.RewindSources(p.alSource)
		al.PlaySources(p.alSource)
		if err := al.Error(); err != 0 {
			return fmt.Errorf("driver: PlaySource in process: %d", err)
		}
	}

	return nil
}
Example #8
0
func NewContext(oscilator Oscilator) *Context {
	if err := al.OpenDevice(); err != nil {
		log.Fatal(err)
	}
	s := al.GenSources(1)
	if code := al.Error(); code != 0 {
		log.Fatalln("openal error:", code)
	}
	//s[0].SetGain(s[0].MaxGain())
	//s[0].SetPosition(al.ListenerPosition())
	return &Context{
		source:    s[0],
		queue:     []al.Buffer{},
		oscilator: oscilator,
	}
}
Example #9
0
// lastErr returns the last error or nil if the last operation
// has been succesful.
func lastErr() error {
	if code := al.Error(); code != 0 {
		return fmt.Errorf("audio: openal failed with %x", code)
	}
	return nil
}
Example #10
0
func Tick() {
	start := time.Now()

	if code := al.DeviceError(); code != 0 {
		log.Printf("snd/al: unknown device error [err=%v]\n", code)
	}
	if code := al.Error(); code != 0 {
		log.Printf("snd/al: unknown error [err=%v]\n", code)
	}

	bufs := hwa.buf.Get()

	for _, buf := range bufs {
		hwa.tc++

		// TODO the general idea here is that GetInputs is rather cheap to call, even with the
		// current first-draft implementation, so it could only return inputs that are actually
		// turned on. This would introduce software latency determined by snd.DefaultBufferLen
		// as turning an input back on would not get picked up until the next iteration.
		// if !realtime {
		// hwa.inputs = snd.GetInputs(hwa.in)
		// }

		dp.Dispatch(hwa.tc, hwa.inputs...)

		for i, x := range hwa.in.Samples() {
			// clip
			if x > 1 {
				x = 1
			} else if x < -1 {
				x = -1
			}
			n := int16(math.MaxInt16 * x)
			hwa.out[2*i] = byte(n)
			hwa.out[2*i+1] = byte(n >> 8)
		}

		buf.BufferData(hwa.format, hwa.out, int32(hwa.in.SampleRate()))
		if code := al.Error(); code != 0 {
			log.Printf("snd/al: buffer data failed [err=%v]\n", code)
		}
	}

	if len(bufs) != 0 {
		hwa.source.QueueBuffers(bufs)
	}
	if code := al.Error(); code != 0 {
		log.Printf("snd/al: queue buffer failed [err=%v]\n", code)
	}

	switch hwa.source.State() {
	case al.Initial:
		al.PlaySources(hwa.source)
	case al.Playing:
	case al.Paused:
	case al.Stopped:
		hwa.underruns++
		al.PlaySources(hwa.source)
	}

	hwa.tdur += time.Now().Sub(start)
}