A simple audio engine for Go with an SDL2 back-end and others to come eventually.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
2.5 KiB

  1. package sdl
  2. import (
  3. "github.com/veandco/go-sdl2/mix"
  4. "github.com/veandco/go-sdl2/sdl"
  5. )
  6. // Track is a music or sound effect file.
  7. type Track struct {
  8. isMusic bool // false = is sound effect
  9. // If isMusic
  10. mus *mix.Music
  11. // Sound effect
  12. wav *mix.Chunk
  13. channel int
  14. }
  15. // LoadMusic loads a music file from disk.
  16. func (e *Engine) LoadMusic(filename string) (Track, error) {
  17. mus, err := mix.LoadMUS(filename)
  18. return Track{
  19. isMusic: true,
  20. mus: mus,
  21. }, err
  22. }
  23. // LoadMusicBin loads a music file from bytes data.
  24. func (e *Engine) LoadMusicBin(data []byte) (Track, error) {
  25. // Create an SDL RWOps from the binary.
  26. rw, err := sdl.RWFromMem(data)
  27. if err != nil {
  28. return Track{}, err
  29. }
  30. mus, err := mix.LoadMUSRW(rw, 0)
  31. return Track{
  32. isMusic: true,
  33. mus: mus,
  34. }, err
  35. }
  36. // LoadSound loads a wave file from disk.
  37. func (e *Engine) LoadSound(filename string) (Track, error) {
  38. wav, err := mix.LoadWAV(filename)
  39. return Track{
  40. isMusic: false,
  41. wav: wav,
  42. channel: -1,
  43. }, err
  44. }
  45. // LoadSoundBin loads a wave file from bytes data.
  46. func (e *Engine) LoadSoundBin(data []byte) (Track, error) {
  47. // Create an SDL RWOps from the binary.
  48. rw, err := sdl.RWFromMem(data)
  49. if err != nil {
  50. return Track{}, err
  51. }
  52. wav, err := mix.LoadWAVRW(rw, false)
  53. return Track{
  54. isMusic: false,
  55. wav: wav,
  56. channel: -1,
  57. }, err
  58. }
  59. // Play the track.
  60. func (t *Track) Play(loops int) error {
  61. if t.isMusic {
  62. return t.mus.Play(loops)
  63. }
  64. // Normalize the `loops` value for sound effects to work around
  65. // a quirk in the SDL mixer between Music and Sound behaviors:
  66. //
  67. // For music:
  68. // loops=0 plays it one time
  69. // loops=1 plays it one time
  70. // loops=2 plays it twice
  71. // For sounds:
  72. // loops=0 plays it one time
  73. // loops=1 plays it twice!
  74. // loops=2 plays it three times!
  75. //
  76. // For both, a loops of -1 plays it on an infinite loop. So to make
  77. // the API consistent on our end, subtract 1 from a Sound loop only
  78. // when the given value is >= 1 itself.
  79. if loops > 0 {
  80. loops--
  81. }
  82. channel, err := t.wav.Play(-1, loops)
  83. t.channel = channel
  84. return err
  85. }
  86. // Pause the track.
  87. func (t Track) Pause() error {
  88. if t.isMusic {
  89. mix.PauseMusic()
  90. return nil
  91. }
  92. mix.Pause(t.channel)
  93. return nil
  94. }
  95. // Stop the track.
  96. func (t Track) Stop() error {
  97. if t.isMusic {
  98. mix.HaltMusic()
  99. return nil
  100. }
  101. mix.HaltChannel(t.channel)
  102. return nil
  103. }
  104. // Destroy the track.
  105. func (t Track) Destroy() error {
  106. if t.isMusic {
  107. t.mus.Free()
  108. return nil
  109. }
  110. t.wav.Free()
  111. return nil
  112. }