#Jun-Hong Chen
#Make-Art Project

import array
import math
import audiobusio
import board
import neopixel
import time

from adafruit_led_animation.color import (
    AMBER, #(255, 100, 0)
    AQUA, # (50, 255, 255)
    BLACK, #OFF (0, 0, 0)
    BLUE, # (0, 0, 255)
    CYAN, # (0, 255, 255)
    GOLD, # (255, 222, 30)
    GREEN, # (0, 255, 0)
    JADE, # (0, 255, 40)
    MAGENTA, #(255, 0, 20)
    OLD_LACE, # (253, 245, 230)
    ORANGE, # (255, 40, 0)
    PINK, # (242, 90, 255)
    PURPLE, # (180, 0, 255)
    RED, # (255, 0, 0)
    TEAL, # (0, 255, 120)
    WHITE, # (255, 255, 255)
    YELLOW, # (255, 150, 0)
    RAINBOW # a list of colors to cycle through
    # RAINBOW is RED, ORANGE, YELLOW, GREEN, BLUE, and PURPLE ((255, 0, 0), (255, 40, 0), (255, 150, 0), (0, 255, 0), (0, 0, 255), (180, 0, 255))
)

INDIGO = (63, 0, 255)
VIOLET = (127, 0, 255)
MAROON = (128, 0, 0)


GOLD = (255, 222, 30)
colors = [RED, MAGENTA, ORANGE, YELLOW, GREEN, JADE, BLUE, INDIGO, VIOLET, PURPLE, BLACK]


PEAK_COLOR = GOLD
CURVE = 2
SCALE_EXPONENET = math.pow(10, CURVE * -0.1)

NUM_SAMPLES = 160

def constrain(value, floor, ceiling):
    return max(floor, min(value, ceiling))

def log_scale(input_value, input_min, input_max, output_min, output_max):
    normalized_input_value = (input_value - input_min) /\
                            (input_max - input_min)
    return output_min + \
        math.pow(normalized_input_value,SCALE_EXPONENET) \
        * (output_max - output_min)

def normalized_rms(values):
    minbuf = int(mean(values))
    samples_sum = sum(
        float(sample - minbuf) * (sample - minbuf)
        for sample in values
    )

    return math.sqrt(samples_sum / len(values))

def mean(values):
    return sum(values) / len(values)

def volume_color(volume):
    return 200, volume * (255//NUM_PIXELS), 0

strip_pin = board.A2
NUM_PIXELS = 30
strip = neopixel.NeoPixel(strip_pin, NUM_PIXELS, brightness = 0.5, auto_write = True)
strip.fill(0)
strip.show()

mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA, sample_rate = 16000, bit_depth = 16)

samples = array.array('H', [0] * NUM_SAMPLES)
mic.record(samples, len(samples))
input_floor = normalized_rms(samples) + 10

input_ceiling = input_floor + 500

peak = 0
while True:
    mic.record(samples, len(samples))
    magnitude = normalized_rms(samples)
    c = log_scale(constrain(magnitude, input_floor, input_ceiling), input_floor, input_ceiling, 0, NUM_PIXELS)

    strip.fill(0)
    for i in range(NUM_PIXELS):
        if i < c:
            strip[i] = GOLD
        if c >= peak:
            peak = min(c, NUM_PIXELS-1)
        elif peak > 0:
            peak = peak - 1
        if peak > 0:
            strip[int(peak)] = GOLD
        strip.show()
