# MIDI Cable
# Black - TX
# White - VCC 3.3v
# Brown - GND

import time
import board
import busio
import adafruit_midi
import asyncio

# from adafruit_midi.control_change import ControlChange
from adafruit_midi.note_off import NoteOff
from adafruit_midi.note_on import NoteOn

bpm = 120


def init():
    print("init")
    global midi
    uart = busio.UART(board.TX, board.RX, baudrate=31250, timeout=0.001)  # init UART
    midi_in_channel = 2
    midi_out_channel = 1
    midi = adafruit_midi.MIDI(
        midi_in=uart,
        midi_out=uart,
        in_channel=(midi_in_channel - 1),
        out_channel=(midi_out_channel - 1),
        debug=False,
    )
    print("Default output channel:", midi.out_channel + 1)


def trig(note_nr):
    # print("trig: " + str(note_nr))
    midi.send(NoteOn(note_nr, 127))
    # MD doesnt need note off
    # midi.send(NoteOff(note_nr, 0))


def div_to_ns(div):
    clk_pulse_per_second = 1000000000
    beat_per_bar = 4
    bar_ns = 60 / bpm * beat_per_bar * clk_pulse_per_second
    return bar_ns / div


def div_to_ms(div):
    clk_pulse_per_second = 1000
    beat_per_bar = 4
    bar_ns = 60 / bpm * beat_per_bar * clk_pulse_per_second
    return bar_ns / div


def md_note(nr):
    '''1-16'''
    md_notes = [36, 38, 40, 41, 43, 45, 47, 48, 50, 52, 53, 55, 57, 59, 60, 62]
    nr = min(nr, 16)
    nr = max(nr, 1)
    return md_notes[nr - 1]


def md_selftest():
    for i in range(1, 16 + 1):
        trig(md_note(i))
        time.sleep(0.01)


async def subdiv(div, note_nr):
    for i in range(0, div):
        trig(note_nr)
        await asyncio.sleep(div_to_ms(div) / 1000 * 0.99)


# NEW
# no load - 0.0223318ms / 44779.1Hz
# 1 subdiv(1) - 0.041875ms / 23880.6Hz
# 4 subdiv(1-8) - 0.112662ms / 8876.11Hz
# 8 subdiv(1-8) - 0.159569ms / 6266.89Hz
# 16 subdiv(1-16) - 27.792ms / 35.9816Hz

tracks = 8


async def bar():
    for i in range(1, tracks + 1):
        asyncio.create_task(subdiv(i, md_note(i)))


async def main():
    while True:
        asyncio.create_task(bar())
        await asyncio.sleep(div_to_ms(1) / 1000)


init()
asyncio.run(main())