// InitializeSound Initializes sound func InitializeSound(numKeys int) { var i float64 data = []byte{} for i = 0; i < 100000; i = i + 8 { data = append(data, byte(128+127*math.Sin(i))) } err := al.OpenDevice() if err != nil { fmt.Println(err) } sources = al.GenSources(numKeys) buffers = al.GenBuffers(numKeys) secSources = al.GenSources(numKeys) secBuffers = al.GenBuffers(numKeys) for j := 0; j < numKeys; j++ { buffers[j].BufferData(al.FormatMono8, data, int32(100*(numKeys-j))) secBuffers[j].BufferData(al.FormatMono8, data, 2*int32(100*(numKeys-j))) sources[j].QueueBuffers(buffers[j : j+1]...) secSources[j].QueueBuffers(buffers[j : j+1]...) } }
func (c *Context) Play() { c.Lock() defer c.Unlock() n := c.source.BuffersProcessed() if n > 0 { rm, split := c.queue[:n], c.queue[n:] c.queue = split c.source.UnqueueBuffers(rm...) al.DeleteBuffers(rm...) } for len(c.queue) < QUEUE { b := al.GenBuffers(1) buf := make([]byte, NS*CZ) for n := 0; n < NS*CZ; n += CZ { v := int16(float32(32767) * c.oscilator()) binary.LittleEndian.PutUint16(buf[n:n+2], uint16(v)) } b[0].BufferData(Fmt, buf, SampleRate) c.source.QueueBuffers(b...) c.queue = append(c.queue, b...) } if c.source.State() != al.Playing { al.PlaySources(c.source) } }
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 }
// newPianoKey creates a PianoKey with color and sound. func newPianoKey(glctx gl.Context, keyColor util.RGBColor, note util.KeyNote) *PianoKey { key := new(PianoKey) key.keyColor = keyColor // Create buffer key.glBuf = glctx.CreateBuffer() glctx.BindBuffer(gl.ARRAY_BUFFER, key.glBuf) // Generate sound _ = al.OpenDevice() key.soundBuffers = al.GenBuffers(1) key.soundSources = al.GenSources(1) key.soundBuffers[0].BufferData(al.FormatStereo8, audio.GenSound(note), audio.SampleRate) key.soundSources[0].QueueBuffers(key.soundBuffers) return key }
func (p *Player) prepare(offset int64, force bool) error { p.mu.Lock() if !force && p.prep { p.mu.Unlock() return nil } p.mu.Unlock() if p.t.hasHeader { offset += headerSize } if _, err := p.t.src.Seek(offset, 0); err != nil { return err } var bufs []al.Buffer // TODO(jbd): Limit the number of buffers in use, unqueue and reuse // the existing buffers as buffers are processed. buf := make([]byte, 128*1024) size := offset for { n, err := p.t.src.Read(buf) if n > 0 { size += int64(n) b := al.GenBuffers(1) b[0].BufferData(formatCodes[p.t.format], buf[:n], int32(p.t.samplesPerSecond)) bufs = append(bufs, b[0]) } if err == io.EOF { break } if err != nil { return err } } p.mu.Lock() if len(p.bufs) > 0 { p.source.UnqueueBuffers(p.bufs...) al.DeleteBuffers(p.bufs...) } p.sizeBytes = size p.bufs = bufs p.prep = true if len(bufs) > 0 { p.source.QueueBuffers(bufs...) } p.mu.Unlock() return nil }
// NewPianoKey returns a key for our piano. func NewPianoKey(pos mgl32.Vec3, lightColor mgl32.Vec3, white bool, freq float32) PianoKey { var color mgl32.Vec4 var keySize float32 if white { color = mgl32.Vec4{0.98, 0.97, 0.94} keySize = 2 } else { color = mgl32.Vec4{0.1, 0.1, 0.1, 1.0} keySize = 1 } pk := PianoKey{Pos: pos, Angle: 0, Color: color, Frequency: freq, Finger: -1, white: white, LightColor: lightColor} pk.BBox[0] = pos.Sub(mgl32.Vec3{0.5, 0.6, keySize}) pk.BBox[1] = pos.Add(mgl32.Vec3{0.5, 0.6, keySize}) pk.source = al.GenSources(1)[0] pk.source.SetGain(1.0) pk.source.SetPosition(al.Vector{pos.X(), pos.Y(), pos.Z()}) pk.source.SetVelocity(al.Vector{}) pk.buffers = al.GenBuffers(3) var samples [1024 * 16]int16 sampleRate := 44100 amplitude := float32(0.8 * 0x7FFF) for i := 0; i < len(samples); i++ { val := f32.Sin((2.0 * math.Pi * freq) / float32(sampleRate) * float32(i)) samples[i] = int16(amplitude * val) } buf := &bytes.Buffer{} binary.Write(buf, binary.LittleEndian, &samples) pk.buffers[0].BufferData(al.FormatMono16, buf.Bytes(), 44100) f, _ := os.Create("audio.raw") binary.Write(f, binary.LittleEndian, &samples) f.Close() return pk }
// 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 }
func (p *Player) prepare(background bool, offset int64, force bool) error { p.mu.Lock() if !force && p.prep { p.mu.Unlock() return nil } p.mu.Unlock() if p.t.hasHeader { offset += headerSize } if _, err := p.t.src.Seek(offset, 0); err != nil { return err } var bufs []al.Buffer // TODO(jbd): Limit the number of buffers in use, unqueue and reuse // the existing buffers as buffers are processed. buf := make([]byte, 128*1024) size := offset for { n, err := p.t.src.Read(buf) if n > 0 { size += int64(n) b := al.GenBuffers(1) if !background && p.t.format == Stereo16 { inputBuffer := bytes.NewBuffer(buf) outputBuffer := new(bytes.Buffer) var left, right int16 // TODO: this might not be the best way to convert Stereo16 to Mono16, but it's something for converted := 0; converted < n; converted += 4 { binary.Read(inputBuffer, binary.LittleEndian, &left) binary.Read(inputBuffer, binary.LittleEndian, &right) binary.Write(outputBuffer, binary.LittleEndian, int16((int32(left)+int32(right))/2)) } b[0].BufferData(formatCodes[Mono16], outputBuffer.Bytes(), int32(p.t.samplesPerSecond/2)) } else { b[0].BufferData(formatCodes[p.t.format], buf[:n], int32(p.t.samplesPerSecond)) } bufs = append(bufs, b[0]) } if err == io.EOF { break } if err != nil { return err } } p.mu.Lock() if len(p.bufs) > 0 { p.source.UnqueueBuffers(p.bufs...) al.DeleteBuffers(p.bufs...) } p.sizeBytes = size p.bufs = bufs p.prep = true if len(bufs) > 0 { p.source.QueueBuffers(bufs...) } p.mu.Unlock() return nil }