player.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build !wasm
  5. package audio
  6. // #include <stdlib.h>
  7. import "C"
  8. import (
  9. "github.com/g3n/engine/audio/al"
  10. "github.com/g3n/engine/core"
  11. "github.com/g3n/engine/gls"
  12. "github.com/g3n/engine/math32"
  13. "io"
  14. "time"
  15. "unsafe"
  16. )
  17. const (
  18. playerBufferCount = 2
  19. playerBufferSize = 32 * 1024
  20. )
  21. // Player is a 3D (spatial) audio file player
  22. // It embeds a core.Node so it can be inserted as a child in any other 3D object.
  23. type Player struct {
  24. core.Node // Embedded node
  25. af *AudioFile // Pointer to media audio file
  26. buffers []uint32 // OpenAL buffer names
  27. source uint32 // OpenAL source name
  28. nextBuf int // Index of next buffer to fill
  29. pdata unsafe.Pointer // Pointer to C allocated storage
  30. disposed bool // Disposed flag
  31. gchan chan (string) // Channel for informing of goroutine end
  32. }
  33. // NewPlayer creates and returns a pointer to a new audio player object
  34. // which will play the audio encoded in the specified file.
  35. // Currently it supports wave and Ogg Vorbis formats.
  36. func NewPlayer(filename string) (*Player, error) {
  37. // Try to open audio file
  38. af, err := NewAudioFile(filename)
  39. if err != nil {
  40. return nil, err
  41. }
  42. // Creates player
  43. p := new(Player)
  44. p.Node.Init(p)
  45. p.af = af
  46. // Generate buffers names
  47. p.buffers = al.GenBuffers(playerBufferCount)
  48. // Generate source name
  49. p.source = al.GenSource()
  50. // Allocates C memory buffer
  51. p.pdata = C.malloc(playerBufferSize)
  52. // Initialize channel for communication with internal goroutine
  53. p.gchan = make(chan string, 1)
  54. return p, nil
  55. }
  56. // Dispose disposes of this player resources
  57. func (p *Player) Dispose() {
  58. p.Stop()
  59. // Close file
  60. p.af.Close()
  61. // Release OpenAL resources
  62. al.DeleteSource(p.source)
  63. al.DeleteBuffers(p.buffers)
  64. // Release C memory
  65. C.free(p.pdata)
  66. p.pdata = nil
  67. p.disposed = true
  68. }
  69. // State returns the current state of this player
  70. func (p *Player) State() int {
  71. return int(al.GetSourcei(p.source, al.SourceState))
  72. }
  73. // Play starts playing this player
  74. func (p *Player) Play() error {
  75. state := p.State()
  76. // Already playing, nothing to do
  77. if state == al.Playing {
  78. return nil
  79. }
  80. // If paused, goroutine should be running, just starts playing
  81. if state == al.Paused {
  82. al.SourcePlay(p.source)
  83. return nil
  84. }
  85. // Inactive or Stopped state
  86. if state == al.Initial || state == al.Stopped {
  87. // Sets file pointer to the beginning
  88. err := p.af.Seek(0)
  89. if err != nil {
  90. return err
  91. }
  92. // Fill buffers with decoded data
  93. for i := 0; i < playerBufferCount; i++ {
  94. err = p.fillBuffer(p.buffers[i])
  95. if err != nil {
  96. if err != io.EOF {
  97. return err
  98. }
  99. break
  100. }
  101. }
  102. p.nextBuf = 0
  103. // Clear previous goroutine response channel
  104. select {
  105. case _ = <-p.gchan:
  106. default:
  107. }
  108. // Starts playing and starts goroutine to fill buffers
  109. al.SourcePlay(p.source)
  110. go p.run()
  111. return nil
  112. }
  113. return nil
  114. }
  115. // Pause sets the player in the pause state
  116. func (p *Player) Pause() {
  117. if p.State() == al.Paused {
  118. return
  119. }
  120. al.SourcePause(p.source)
  121. }
  122. // Stop stops the player
  123. func (p *Player) Stop() {
  124. state := p.State()
  125. if state == al.Stopped || state == al.Initial {
  126. return
  127. }
  128. al.SourceStop(p.source)
  129. // Waits for goroutine to finish
  130. <-p.gchan
  131. }
  132. // CurrentTime returns the current time in seconds spent in the stream
  133. func (p *Player) CurrentTime() float64 {
  134. return p.af.CurrentTime()
  135. }
  136. // TotalTime returns the total time in seconds to play this stream
  137. func (p *Player) TotalTime() float64 {
  138. return p.af.info.TotalTime
  139. }
  140. // Gain returns the current gain (volume) of this player
  141. func (p *Player) Gain() float32 {
  142. return al.GetSourcef(p.source, al.Gain)
  143. }
  144. // SetGain sets the gain (volume) of this player
  145. func (p *Player) SetGain(gain float32) {
  146. al.Sourcef(p.source, al.Gain, gain)
  147. }
  148. // MinGain returns the current minimum gain of this player
  149. func (p *Player) MinGain() float32 {
  150. return al.GetSourcef(p.source, al.MinGain)
  151. }
  152. // SetMinGain sets the minimum gain (volume) of this player
  153. func (p *Player) SetMinGain(gain float32) {
  154. al.Sourcef(p.source, al.MinGain, gain)
  155. }
  156. // MaxGain returns the current maximum gain of this player
  157. func (p *Player) MaxGain() float32 {
  158. return al.GetSourcef(p.source, al.MaxGain)
  159. }
  160. // SetMaxGain sets the maximum gain (volume) of this player
  161. func (p *Player) SetMaxGain(gain float32) {
  162. al.Sourcef(p.source, al.MaxGain, gain)
  163. }
  164. // Pitch returns the current pitch factor of this player
  165. func (p *Player) Pitch() float32 {
  166. return al.GetSourcef(p.source, al.Pitch)
  167. }
  168. // SetPitch sets the pitch factor of this player
  169. func (p *Player) SetPitch(pitch float32) {
  170. al.Sourcef(p.source, al.Pitch, pitch)
  171. }
  172. // Looping returns the current looping state of this player
  173. func (p *Player) Looping() bool {
  174. return p.af.Looping()
  175. }
  176. // SetLooping sets the looping state of this player
  177. func (p *Player) SetLooping(looping bool) {
  178. p.af.SetLooping(looping)
  179. }
  180. // InnerCone returns the inner cone angle in degrees
  181. func (p *Player) InnerCone() float32 {
  182. return al.GetSourcef(p.source, al.ConeInnerAngle)
  183. }
  184. // SetInnerCone sets the inner cone angle in degrees
  185. func (p *Player) SetInnerCone(inner float32) {
  186. al.Sourcef(p.source, al.ConeInnerAngle, inner)
  187. }
  188. // OuterCone returns the outer cone angle in degrees
  189. func (p *Player) OuterCone() float32 {
  190. return al.GetSourcef(p.source, al.ConeOuterAngle)
  191. }
  192. // SetOuterCone sets the outer cone angle in degrees
  193. func (p *Player) SetOuterCone(outer float32) {
  194. al.Sourcef(p.source, al.ConeOuterAngle, outer)
  195. }
  196. // SetVelocity sets the velocity of this player
  197. // It is used to calculate Doppler effects
  198. func (p *Player) SetVelocity(vx, vy, vz float32) {
  199. al.Source3f(p.source, al.Velocity, vx, vy, vz)
  200. }
  201. // SetVelocityVec sets the velocity of this player from the specified vector
  202. // It is used to calculate Doppler effects
  203. func (p Player) SetVelocityVec(v *math32.Vector3) {
  204. al.Source3f(p.source, al.Velocity, v.X, v.Y, v.Z)
  205. }
  206. // Velocity returns this player velocity
  207. func (p *Player) Velocity() (float32, float32, float32) {
  208. return al.GetSource3f(p.source, al.Velocity)
  209. }
  210. // VelocityVec returns this player velocity vector
  211. func (p *Player) VelocityVec() math32.Vector3 {
  212. vx, vy, vz := al.GetSource3f(p.source, al.Velocity)
  213. return math32.Vector3{vx, vy, vz}
  214. }
  215. // SetRolloffFactor sets this player rolloff factor user to calculate
  216. // the gain attenuation by distance
  217. func (p *Player) SetRolloffFactor(rfactor float32) {
  218. al.Sourcef(p.source, al.RolloffFactor, rfactor)
  219. }
  220. // Render satisfies the INode interface.
  221. // It is called by renderer at every frame and is used to
  222. // update the audio source position and direction
  223. func (p *Player) Render(gl *gls.GLS) {
  224. // Sets the player source world position
  225. var wpos math32.Vector3
  226. p.WorldPosition(&wpos)
  227. al.Source3f(p.source, al.Position, wpos.X, wpos.Y, wpos.Z)
  228. // Sets the player source world direction
  229. var wdir math32.Vector3
  230. p.WorldDirection(&wdir)
  231. al.Source3f(p.source, al.Direction, wdir.X, wdir.Y, wdir.Z)
  232. }
  233. // Goroutine to fill PCM buffers with decoded data for OpenAL
  234. func (p *Player) run() {
  235. for {
  236. // Get current state of player source
  237. state := al.GetSourcei(p.source, al.SourceState)
  238. processed := al.GetSourcei(p.source, al.BuffersProcessed)
  239. queued := al.GetSourcei(p.source, al.BuffersQueued)
  240. //log.Debug("state:%x processed:%v queued:%v", state, processed, queued)
  241. // If stopped, unqueues all buffer before exiting
  242. if state == al.Stopped {
  243. if queued == 0 {
  244. break
  245. }
  246. // Unqueue buffers
  247. if processed > 0 {
  248. al.SourceUnqueueBuffers(p.source, uint32(processed), nil)
  249. }
  250. continue
  251. }
  252. // If no buffers processed, sleeps and try again
  253. if processed == 0 {
  254. time.Sleep(20 * time.Millisecond)
  255. continue
  256. }
  257. // Remove processed buffers from the queue
  258. al.SourceUnqueueBuffers(p.source, uint32(processed), nil)
  259. // Fill and enqueue buffers with new data
  260. for i := 0; i < int(processed); i++ {
  261. err := p.fillBuffer(p.buffers[p.nextBuf])
  262. if err != nil {
  263. break
  264. }
  265. p.nextBuf = (p.nextBuf + 1) % playerBufferCount
  266. }
  267. }
  268. // Sends indication of goroutine end
  269. p.gchan <- "end"
  270. }
  271. // fillBuffer fills the specified OpenAL buffer with next decoded data
  272. // and queues the buffer to this player source
  273. func (p *Player) fillBuffer(buf uint32) error {
  274. // Reads next decoded data
  275. n, err := p.af.Read(p.pdata, playerBufferSize)
  276. if err != nil {
  277. return err
  278. }
  279. // Sends data to buffer
  280. //log.Debug("BufferData:%v format:%x n:%v rate:%v", buf, p.af.info.Format, n, p.af.info.SampleRate)
  281. al.BufferData(buf, uint32(p.af.info.Format), p.pdata, uint32(n), uint32(p.af.info.SampleRate))
  282. al.SourceQueueBuffers(p.source, buf)
  283. return nil
  284. }