|
| 1 | +'''Adapted from the FFT Example: Waterfall Spectrum Analyzer |
| 2 | +by Jeff Epler |
| 3 | +https://learn.adafruit.com/ulab-crunch-numbers-fast-with-circuitpython/overview ''' |
| 4 | + |
| 5 | +import array |
| 6 | +import board |
| 7 | +import audiobusio |
| 8 | +import busio |
| 9 | +from ulab import numpy as np |
| 10 | +from ulab.scipy.signal import spectrogram |
| 11 | +import adafruit_is31fl3741 |
| 12 | +from adafruit_is31fl3741.adafruit_rgbmatrixqt import Adafruit_RGBMatrixQT |
| 13 | + |
| 14 | +# Manually declare I2c (not board.I2C()) to access 1 MHz speed for |
| 15 | +i2c = busio.I2C(board.SCL, board.SDA, frequency=1000000) |
| 16 | +# Declare is31 w/buffering preferred (low RAM will fall back on unbuffered) |
| 17 | +is31 = Adafruit_RGBMatrixQT(i2c, allocate=adafruit_is31fl3741.PREFER_BUFFER) |
| 18 | +# In buffered mode, MUST use show() to refresh matrix (see line 94) |
| 19 | + |
| 20 | +# brightness for the RGBMatrixQT |
| 21 | +# set to about 20% |
| 22 | +is31.set_led_scaling(0x19) |
| 23 | +is31.global_current = 0x03 |
| 24 | +is31.enable = True |
| 25 | + |
| 26 | +# array of colors for the LEDs |
| 27 | +# goes from purple to red |
| 28 | +# gradient generated using https://colordesigner.io/gradient-generator |
| 29 | +heatmap = [0xb000ff,0xa600ff,0x9b00ff,0x8f00ff,0x8200ff, |
| 30 | + 0x7400ff,0x6500ff,0x5200ff,0x3900ff,0x0003ff, |
| 31 | + 0x0003ff,0x0047ff,0x0066ff,0x007eff,0x0093ff, |
| 32 | + 0x00a6ff,0x00b7ff,0x00c8ff,0x00d7ff,0x00e5ff, |
| 33 | + 0x00e0ff,0x00e6fd,0x00ecf6,0x00f2ea,0x00f6d7, |
| 34 | + 0x00fac0,0x00fca3,0x00fe81,0x00ff59,0x00ff16, |
| 35 | + 0x00ff16,0x45ff08,0x62ff00,0x78ff00,0x8bff00, |
| 36 | + 0x9bff00,0xaaff00,0xb8ff00,0xc5ff00,0xd1ff00, |
| 37 | + 0xedff00,0xf5eb00,0xfcd600,0xffc100,0xffab00, |
| 38 | + 0xff9500,0xff7c00,0xff6100,0xff4100,0xff0000, |
| 39 | + 0xff0000,0xff0000] |
| 40 | + |
| 41 | +# size of the FFT data sample |
| 42 | +fft_size = 64 |
| 43 | + |
| 44 | +# setup for onboard mic |
| 45 | +mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA, |
| 46 | + sample_rate=16000, bit_depth=16) |
| 47 | + |
| 48 | +# use some extra sample to account for the mic startup |
| 49 | +samples_bit = array.array('H', [0] * (fft_size+3)) |
| 50 | + |
| 51 | +# sends visualized data to the RGB matrix with colors |
| 52 | +def waves(data, y): |
| 53 | + offset = max(0, (13-len(data))//2) |
| 54 | + |
| 55 | + for x in range(min(13, len(data))): |
| 56 | + is31.pixel(x+offset, y, heatmap[int(data[x])]) |
| 57 | + |
| 58 | +# main loop |
| 59 | +def main(): |
| 60 | + # value for audio samples |
| 61 | + max_all = 10 |
| 62 | + # variable to move data along the matrix |
| 63 | + scroll_offset = 0 |
| 64 | + # setting the y axis value to equal the scroll_offset |
| 65 | + y = scroll_offset |
| 66 | + |
| 67 | + while True: |
| 68 | + # record the audio sample |
| 69 | + mic.record(samples_bit, len(samples_bit)) |
| 70 | + # send the sample to the ulab array |
| 71 | + samples = np.array(samples_bit[3:]) |
| 72 | + # creates a spectogram of the data |
| 73 | + spectrogram1 = spectrogram(samples) |
| 74 | + # spectrum() is always nonnegative, but add a tiny value |
| 75 | + # to change any zeros to nonzero numbers |
| 76 | + spectrogram1 = np.log(spectrogram1 + 1e-7) |
| 77 | + spectrogram1 = spectrogram1[1:(fft_size//2)-1] |
| 78 | + # sets range of the spectrogram |
| 79 | + min_curr = np.min(spectrogram1) |
| 80 | + max_curr = np.max(spectrogram1) |
| 81 | + # resets values |
| 82 | + if max_curr > max_all: |
| 83 | + max_all = max_curr |
| 84 | + else: |
| 85 | + max_curr = max_curr-1 |
| 86 | + min_curr = max(min_curr, 3) |
| 87 | + # stores spectrogram in data |
| 88 | + data = (spectrogram1 - min_curr) * (51. / (max_all - min_curr)) |
| 89 | + # sets negative numbers to zero |
| 90 | + data = data * np.array((data > 0)) |
| 91 | + # resets y |
| 92 | + y = scroll_offset |
| 93 | + # runs waves to write data to the LED's |
| 94 | + waves(data, y) |
| 95 | + # updates scroll_offset to move data along matrix |
| 96 | + scroll_offset = (y + 1) % 9 |
| 97 | + # writes data to the RGB matrix |
| 98 | + is31.show() |
| 99 | + |
| 100 | +main() |
0 commit comments