slam.lua 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. -- Simple LÖVE Audio Manager
  2. --
  3. -- Copyright (c) 2011 Matthias Richter
  4. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  5. -- of this software and associated documentation files (the "Software"), to deal
  6. -- in the Software without restriction, including without limitation the rights
  7. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. -- copies of the Software, and to permit persons to whom the Software is
  9. -- furnished to do so, subject to the following conditions:
  10. --
  11. -- The above copyright notice and this permission notice shall be included in
  12. -- all copies or substantial portions of the Software.
  13. --
  14. -- Except as contained in this notice, the name(s) of the above copyright holders
  15. -- shall not be used in advertising or otherwise to promote the sale, use or
  16. -- other dealings in this Software without prior written authorization.
  17. --
  18. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. -- THE SOFTWARE.
  25. --
  26. local newInstance = love.audio.newSource
  27. local stop = love.audio.stop
  28. ------------------
  29. -- source class --
  30. ------------------
  31. local Source = {}
  32. Source.__index = Source
  33. Source.__newindex = function(_,k) error(('Cannot write key %s'):format(tostring(k))) end
  34. local function remove_stopped(sources)
  35. local remove = {}
  36. for s in pairs(sources) do
  37. remove[s] = true
  38. end
  39. for s in pairs(remove) do
  40. sources[s] = nil
  41. end
  42. end
  43. local function get_target(target)
  44. if type(target) == 'table' then
  45. return target[math.random(1,#target)]
  46. end
  47. return target
  48. end
  49. local play_instance, stop_instance
  50. function Source:play()
  51. remove_stopped(self.instances)
  52. if self._paused then self:stop() end
  53. local instance = newInstance(get_target(self.target), self.how)
  54. -- overwrite instance:stop() and instance:play()
  55. if not (play_instance and stop_instance) then
  56. play_instance = getmetatable(instance).play
  57. getmetatable(instance).play = error
  58. stop_instance = getmetatable(instance).stop
  59. getmetatable(instance).stop = function(this)
  60. stop_instance(this)
  61. self.instances[this] = nil
  62. end
  63. end
  64. instance:setLooping(self.looping)
  65. instance:setPitch(self.pitch)
  66. instance:setVolume(self.volume)
  67. self.instances[instance] = instance
  68. play_instance(instance)
  69. return instance
  70. end
  71. function Source:stop()
  72. for s in pairs(self.instances) do
  73. s:stop()
  74. end
  75. self._paused = false
  76. self.instances = {}
  77. end
  78. function Source:pause()
  79. if self._paused then return end
  80. for s in pairs(self.instances) do
  81. s:pause()
  82. end
  83. self._paused = true
  84. end
  85. function Source:resume()
  86. if not self._paused then return end
  87. for s in pairs(self.instances) do
  88. s:resume()
  89. end
  90. self._paused = false
  91. end
  92. function Source:addTags(tag, ...)
  93. if not tag then return end
  94. love.audio.tags[tag][self] = self
  95. return Source.addTags(self, ...)
  96. end
  97. function Source:removeTags(tag, ...)
  98. if not tag then return end
  99. love.audio.tags[tag][self] = nil
  100. return Source.removeTags(self, ...)
  101. end
  102. function Source:isStatic()
  103. return self.how ~= "stream"
  104. end
  105. -- getter/setter for looping, pitch and volume
  106. for _, property in ipairs{'looping', 'pitch', 'volume'} do
  107. local name = property:sub(1,1):upper() .. property:sub(2)
  108. Source['get' .. name] = function(self)
  109. return self[property]
  110. end
  111. Source['set' .. name] = function(self, val)
  112. self[property] = val
  113. for s in pairs(self.instances) do
  114. s['set' .. name](s, val)
  115. end
  116. end
  117. end
  118. Source.isLooping = Source.getLooping
  119. --------------------------
  120. -- love.audio interface --
  121. --------------------------
  122. function love.audio.newSource(target, how)
  123. local s = {
  124. _paused = false,
  125. target = target,
  126. how = how,
  127. instances = {},
  128. looping = false,
  129. pitch = 1,
  130. volume = 1,
  131. }
  132. if how == 'static' and type(target) == 'string' then
  133. s.target = love.sound.newSoundData(target)
  134. end
  135. love.audio.tags.all[s] = s
  136. return setmetatable(s, Source)
  137. end
  138. function love.audio.play(source)
  139. assert(source and source.instances, "Can only play source objects.")
  140. return source:play()
  141. end
  142. function love.audio.stop(source)
  143. if source and source.stop then return source:stop() end
  144. stop()
  145. end
  146. ----------
  147. -- tags --
  148. ----------
  149. local Tag = { __mode = "kv" }
  150. function Tag:__index(func)
  151. -- calls a function on all tagged sources
  152. return function(...)
  153. for s in pairs(self) do
  154. assert(type(s[func]) == "function", ("`%s' does not name a function."):format(func))
  155. s[func](s, ...)
  156. end
  157. end
  158. end
  159. love.audio.tags = setmetatable({}, {
  160. __newindex = error,
  161. __index = function(t,k)
  162. local tag = setmetatable({}, Tag)
  163. rawset(t, k, tag)
  164. return tag
  165. end,
  166. })