func (s *Source) Resume() {
	if s.isValid() && s.paused {
		pool.mutex.Lock()
		defer pool.mutex.Unlock()
		al.PlaySources(s.source)
		s.paused = false
	}
}
Resume resumes a paused source.
package openal
import (
	"time"
	"github.com/tanema/amore/audio/openal/al"
	"github.com/tanema/amore/audio/openal/decoding"
)
const (
	maxAttenuationDistance = 1000000.0  
	maxBuffers             = 8          
)
type Source struct {
	decoder      *decoding.Decoder
	source       al.Source
	isStatic     bool
	pitch        float32
	volume       float32
	looping      bool
	paused       bool
	staticBuffer al.Buffer
	offsetBytes  int32
}
func NewSource(filepath string, static bool) (*Source, error) {
	if pool == nil {
		createPool()
	}
	decoder, err := decoding.Decode(filepath)
	if err != nil {
		return nil, err
	}
	newSource := &Source{
		decoder:  decoder,
		isStatic: static,
		pitch:    1,
		volume:   1,
	}
	if static {
		newSource.staticBuffer = al.GenBuffers(1)[0]
		newSource.staticBuffer.BufferData(decoder.Format, decoder.GetData(), decoder.SampleRate)
	}
	return newSource, nil
}
func (s *Source) isValid() bool {
	return s.source != 0
}
func (s *Source) IsFinished() bool {
	if s.isStatic {
		return s.IsStopped()
	}
	return s.IsStopped() && !s.IsLooping() && s.decoder.IsFinished()
}
func (s *Source) update() bool {
	if !s.isValid() {
		return false
	}
	if s.isStatic {
		return !s.IsStopped()
	} else if s.IsLooping() || !s.IsFinished() {
		pool.mutex.Lock()
		defer pool.mutex.Unlock()
		for i := s.source.BuffersProcessed(); i > 0; i-- {
			curOffsetBytes := s.source.OffsetByte()
			buffer := s.source.UnqueueBuffer()
			newOffsetBytes := s.source.OffsetByte()
			s.offsetBytes += (curOffsetBytes - newOffsetBytes)
			if s.stream(buffer) > 0 {
				s.source.QueueBuffers(buffer)
			}
		}
		return true
	}
	return false
}
func (s *Source) reset() {
	if !s.isValid() {
		return
	}
	s.source.SetGain(s.volume)
	s.source.SetPitch(s.pitch)
	if s.isStatic {
		s.source.SetLooping(s.looping)
	}
}
func (s *Source) GetDuration() time.Duration {
	return s.decoder.Duration()
}
func (s *Source) GetPitch() float32 {
	if s.isValid() {
		return s.source.Pitch()
	}
	return s.pitch
}
func (s *Source) GetVolume() float32 {
	if s.isValid() {
		return s.source.Gain()
	}
	return s.volume
}
func (s *Source) GetState() string {
	switch s.source.State() {
	case al.Initial:
		return "initial"
	case al.Playing:
		return "playing"
	case al.Paused:
		return "paused"
	case al.Stopped:
		return "stopped"
	default:
		return "unknown"
	}
}
func (s *Source) IsLooping() bool {
	return s.looping
}
func (s *Source) IsPaused() bool {
	if s.isValid() {
		return s.GetState() == "paused"
	}
	return false
}
func (s *Source) IsPlaying() bool {
	if s.isValid() {
		return s.GetState() == "playing"
	}
	return false
}
func (s *Source) IsStatic() bool {
	return s.isStatic
}
func (s *Source) IsStopped() bool {
	if s.isValid() {
		return s.GetState() == "stopped"
	}
	return true
}
func (s *Source) SetLooping(loop bool) {
	s.looping = loop
	s.reset()
}
func (s *Source) SetPitch(p float32) {
	s.pitch = p
	s.reset()
}
func (s *Source) SetVolume(v float32) {
	s.volume = v
	s.reset()
}
func (s *Source) Play() bool {
	if s.IsPlaying() {
		return true
	}
	if s.IsPaused() {
		s.Resume()
		return true
	}
	if !pool.claim(s) || !s.isValid() {
		return false
	}
	pool.mutex.Lock()
	defer pool.mutex.Unlock()
	if s.isStatic {
		s.source.SetBuffer(s.staticBuffer)
	} else {
		buffers := []al.Buffer{}
		for i := 0; i < maxBuffers; i++ {
			buffer := al.GenBuffers(1)[0]
			if s.stream(buffer) > 0 {
				buffers = append(buffers, buffer)
			}
			if s.decoder.IsFinished() {
				break
			}
		}
		if len(buffers) > 0 {
			s.source.QueueBuffers(buffers...)
		}
	}
	s.reset()
	al.Error()
	al.PlaySources(s.source)
	return al.Error() == al.NoError
}
func (s *Source) stream(buffer al.Buffer) int {
	decoded := s.decoder.Decode()  
	if decoded > 0 {
		buffer.BufferData(s.decoder.Format, s.decoder.Buffer, s.decoder.SampleRate)
	}
	if s.decoder.IsFinished() && s.IsLooping() {
		s.Rewind()
	}
	return decoded
}
func (s *Source) Pause() {
	if s.isValid() {
		pool.mutex.Lock()
		defer pool.mutex.Unlock()
		al.PauseSources(s.source)
		s.paused = true
	}
}