A wearable ornament that can respond to music (spectrograph mode) or dancing (shaker mode). Based on an Adafruit Circuit Playground Bluefruit
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.

code.py 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. """
  2. Spectroshaker by The Dod:
  3. Adafruit CircuitPlayground Bluefruit dual-mode "bling"
  4. The RGB levels of neopixels around the circuit indicate:
  5. - Low/Mid/High sound levels (spectrogram mode)
  6. - X/Y/Z acceleration (shaker mode)
  7. Controls:
  8. slider switch: normal/standby mode
  9. button a: toggle between spectrogram/shaker mode
  10. button b: cycle between 4 brightness levels
  11. """
  12. import math
  13. import time
  14. from adafruit_circuitplayground import cp
  15. from teaandtechtime_fft import spectrogram
  16. NUM_PIXELS = 10
  17. # Like a clock, with connectors at 12 (USB) and 6 (power)
  18. LED_ANGLES = [
  19. i*math.pi/6.0
  20. for i in [11, 10, 9, 8, 7, 5, 4, 3, 2, 1]]
  21. minx = miny = minz = -5.0
  22. maxx = maxy = maxz = 5.0
  23. fft_size = 8 # power of 2
  24. samples = [0.0+0.0j]*fft_size
  25. MAX_2FREQ = 10.0 # After testing this a bit in the wild
  26. cp.pixels.brightness = 0.1
  27. MODE_SPECTRO = 1
  28. MODE_SHAKER = 2
  29. current_mode = MODE_SHAKER
  30. is_standby = cp.switch
  31. last_click = 0
  32. DEBOUNCE = 0.25
  33. def angles2level(led, val):
  34. led_angle = LED_ANGLES[led]
  35. val_angle = val * 2.0 * math.pi
  36. angle = led_angle - val_angle
  37. while angle > 2 * math.pi:
  38. angle -= 2*math.pi
  39. # the pow() makes sin() values sharper
  40. return int(255*pow(math.sin(angle/2), 4))
  41. while True:
  42. if time.monotonic() > last_click+DEBOUNCE:
  43. if is_standby != cp.switch:
  44. is_standby = cp.switch
  45. last_click = time.monotonic()
  46. if is_standby:
  47. for i in range(NUM_PIXELS):
  48. cp.pixels[i] = (0, 0, 0)
  49. if cp.button_a:
  50. last_click = time.monotonic()
  51. current_mode = (
  52. current_mode == MODE_SHAKER and MODE_SPECTRO
  53. or MODE_SHAKER)
  54. elif cp.button_b:
  55. last_click = time.monotonic()
  56. is_standby = False
  57. if cp.pixels.brightness >= 0.4:
  58. cp.pixels.brightness = 0.1
  59. else:
  60. cp.pixels.brightness += 0.1
  61. if not is_standby:
  62. samples.pop(0)
  63. samples.append(cp.sound_level+0.0j)
  64. x, y, z = cp.acceleration
  65. if x < minx:
  66. minx = x
  67. if y < miny:
  68. miny = y
  69. if z < minz:
  70. minz = z
  71. if x > maxx:
  72. maxx = x
  73. if y > maxy:
  74. maxy = y
  75. if z > maxz:
  76. maxz = z
  77. if current_mode == MODE_SHAKER: # accelerometer mode
  78. vals = (
  79. (x-minx)/(maxx-minx),
  80. (y-miny)/(maxy-miny),
  81. (z-minz)/(maxz-minz))
  82. else: # spectrogram mode
  83. raw_freqs = spectrogram(samples)
  84. pairs = [raw_freqs[i]+raw_freqs[i+1] for i in range(fft_size//2)]
  85. vals = [min(1.0, abs(x/MAX_2FREQ)) for x in pairs[:3]]
  86. for i in range(NUM_PIXELS):
  87. cp.pixels[i] = (
  88. angles2level(i, vals[0]),
  89. angles2level(i, vals[1]),
  90. angles2level(i, vals[2]))
  91. time.sleep(0.01)