Guest User

Untitled

a guest
Nov 14th, 2018
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.77 KB | None | 0 0
  1. """
  2. Show a light for every beat.
  3. Show the BPM as text.
  4. Use 4/4 timing. Four beats to a bar.
  5.  
  6. Press space until the BPM gets to what you want.
  7. """
  8. import time
  9. import os
  10. import pygame as pg
  11.  
  12.  
  13. def average_bpm(times):
  14. """ For the list of times(seconds since epoch) return
  15. the average beats per minute.
  16. """
  17. spaces = []
  18. previous = times[0]
  19. for t in times[1:]:
  20. spaces.append(t - previous)
  21. previous = t
  22. avg_space = sum(spaces) / len(spaces)
  23. return 60.0 / avg_space
  24.  
  25.  
  26. class Bpm:
  27. """ Beats Per Minute.
  28.  
  29. By press()ing this, the bpm counter will change.
  30. """
  31.  
  32. def __init__(self):
  33.  
  34. self.space_between_beats = 0.5
  35. self.last_press = time.time()
  36. """ The time since epoch of the last press.
  37. """
  38. self.bpm = 120
  39. self.bpm_average = 120
  40. """ The average bpm from the last 4 presses.
  41. """
  42.  
  43. self.times = []
  44.  
  45.  
  46. self._last_update = time.time()
  47. self._elapsed_time = 0.0
  48. self._last_closeness = 1.0
  49.  
  50. self.on_beat = 0
  51. """ The time since the epoch when the last beat happened.
  52. """
  53.  
  54. self.beat_num = 0
  55. """ accumlative counter of beats.
  56. """
  57.  
  58. self.finished_beat = 0
  59. """ True for one tick, when 0.1 seconds has passed since the beat.
  60. """
  61.  
  62. self.first_beat = 0
  63. """ True if we are the first beat on a bar (out of 4).
  64. """
  65.  
  66. self.started_beat = 0
  67. """ This is true only on the tick
  68. """
  69.  
  70.  
  71. def press(self):
  72. """ For when someone is trying to update the timer.
  73. """
  74. press_time = time.time()
  75. self.space_between_beats = press_time - self.last_press
  76. self.last_press = press_time
  77. self.times.append(press_time)
  78. self.bpm = 60.0 / self.space_between_beats
  79.  
  80. if len(self.times) > 4:
  81. self.bpm_average = average_bpm(self.times[-4:])
  82. self.times = self.times[-4:]
  83. else:
  84. self.bpm_average = self.bpm
  85.  
  86.  
  87. def update(self):
  88. the_time = time.time()
  89. self._elapsed_time += the_time - self._last_update
  90. self._last_update = the_time
  91.  
  92. # if _elapsed_time 'close' to bpm show light.
  93. space_between_beats = 60.0 / self.bpm_average
  94. since_last_beat = the_time - self.on_beat
  95.  
  96. self.finished_beat = self.on_beat and (since_last_beat > 0.1)
  97. if self.finished_beat:
  98. self.on_beat = 0
  99.  
  100. closeness = self._elapsed_time % space_between_beats
  101. if closeness < self._last_closeness:
  102. self.on_beat = the_time
  103. self.finished_beat = 0
  104. self.dirty = 1
  105. self.beat_num += 1
  106. self.started_beat = 1
  107. self.first_beat = not (self.beat_num % 4)
  108. else:
  109. self.started_beat = 0
  110.  
  111. self._last_closeness = closeness
  112.  
  113.  
  114. class BpmCounter(pg.sprite.DirtySprite):
  115. """ For showing a text representing what the Beats Per Minute is.
  116. """
  117. def __init__(self, bpm):
  118. pg.sprite.DirtySprite.__init__(self)
  119. self.bpm = bpm
  120.  
  121. self.font = pg.font.SysFont("Arial", 24)
  122. self.image = self.font.render(
  123. "%s" % int(self.bpm.bpm_average), True, (255, 255, 255)
  124. )
  125. self.rect = self.image.get_rect()
  126.  
  127. def press(self):
  128. self.bpm.press()
  129. self.image = self.font.render(
  130. "%s" % int(self.bpm.bpm_average), True, (255, 255, 255)
  131. )
  132. self.rect = self.image.get_rect()
  133. self.dirty = 1
  134.  
  135. def events(self, events):
  136. for e in events:
  137. if e.type == pg.KEYDOWN and e.key == pg.K_SPACE:
  138. self.press()
  139.  
  140.  
  141. class BpmLight(pg.sprite.DirtySprite):
  142. """ Shows a red 'light' representing each beat.
  143. """
  144. def __init__(self, bpm):
  145. pg.sprite.DirtySprite.__init__(self)
  146. self.bpm = bpm
  147.  
  148. self.image = pg.Surface((20, 20))
  149. self.image.fill((255, 0, 0))
  150. self.rect = self.image.get_rect()
  151. self.rect.x = 50
  152. self.rect.y = 5
  153.  
  154. def press(self):
  155. self.image.fill((255, 0, 0))
  156. self.elapsed_time = 0.0
  157.  
  158. def update(self):
  159.  
  160. if self.bpm.finished_beat:
  161. self.image.fill((0, 0, 0))
  162. self.dirty = 1
  163. if self.bpm.started_beat:
  164. self.image.fill((255, 0, 0))
  165. self.dirty = 1
  166.  
  167. def main():
  168.  
  169. if pg.get_sdl_version()[0] == 2:
  170. pg.mixer.pre_init(44100, 32, 2, 512)
  171. pg.init()
  172. screen = pg.display.set_mode((640, 480))
  173. going = True
  174.  
  175. bpm = Bpm()
  176. bpm_counter = BpmCounter(bpm)
  177. bpm_light = BpmLight(bpm)
  178. clock = pg.time.Clock()
  179.  
  180. pygame_dir = os.path.split(os.path.abspath(pg.__file__))[0]
  181. data_dir = os.path.join(pygame_dir, "examples", "data")
  182. sound = pg.mixer.Sound(os.path.join(data_dir, "punch.wav"))
  183.  
  184. pg.display.set_caption('press space 4 times to adjust BPM timing')
  185.  
  186. background = pg.Surface(screen.get_size())
  187. background = background.convert()
  188. background.fill((0, 0, 0))
  189.  
  190. allsprites = pg.sprite.LayeredDirty([bpm_counter, bpm_light])
  191. allsprites.clear(screen, background)
  192.  
  193. while going:
  194. events = pg.event.get()
  195. for e in events:
  196. if e.type == pg.QUIT or e.type == pg.KEYDOWN and e.key in [pg.K_ESCAPE, pg.K_q]:
  197. going = False
  198.  
  199. bpm.update()
  200. # if bpm.started_beat and bpm.first_beat:
  201. # sound.play()
  202. if bpm.started_beat:
  203. sound.play()
  204.  
  205. bpm_counter.events(events)
  206. allsprites.update()
  207.  
  208. rects = allsprites.draw(screen)
  209.  
  210. # note, we don't update the display every 240 seconds.
  211. if rects:
  212. pg.display.update(rects)
  213. # We loop quickly so timing can be more accurate with the sounds.
  214. clock.tick(240)
  215. # print(rects)
  216. # print(clock.get_fps())
  217.  
  218. if __name__ == '__main__':
  219. main()
Add Comment
Please, Sign In to add comment