player.go 8.6 KB

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