import numpy as np
import sounddevice as sd
import time

# -------------------------------
# HDGL Lattice Parameters
# -------------------------------
num_strands = 8
slots_per_strand = 4
total_slots = num_strands * slots_per_strand

phi = 1.6180339887
sqrt_phi = np.sqrt(phi)

# Ω scaling
n_base = np.arange(1,num_strands+1)
omega = 1 / (phi**n_base)**7

# Initialize lattice analogs D1-D32
lattice = np.random.uniform(0.5, 1.0, (num_strands, slots_per_strand))

# Phase offsets
phases = np.random.uniform(0, 2*np.pi, (num_strands, slots_per_strand))

# Audio parameters
fs = 44100             # sampling rate
block_duration = 0.05  # seconds per tick
block_size = int(fs * block_duration)
t = np.linspace(0, block_duration, block_size, endpoint=False)

# -------------------------------
# Audio callback for streaming
# -------------------------------
def lattice_audio_callback(outdata, frames, time_info, status):
    global lattice, phases
    
    # Step lattice analogs with weighted resonance
    lattice_new = np.copy(lattice)
    for s in range(num_strands):
        for i in range(slots_per_strand):
            lattice_new[s,i] += 0.02 * omega[s] * (1 + 0.05*i)
            resonance = np.sum([omega[j]*lattice[j,i] for j in range(num_strands) if j != s])
            lattice_new[s,i] += 0.01 * resonance
            if lattice_new[s,i] > sqrt_phi:
                lattice_new[s,i] = lattice_new[s,i]
            else:
                lattice_new[s,i] *= 0.8
            phases[s,i] += 0.05 * lattice[s,i]

    lattice[:] = lattice_new

    # Generate composite waveform
    waveform = np.zeros(frames)
    for s in range(num_strands):
        for i in range(slots_per_strand):
            freq = 200 + 300*lattice[s,i]       # frequency modulation
            amp  = 0.05 + 0.95*lattice[s,i]/np.max(lattice)
            waveform += amp * np.sin(2*np.pi*freq*t + phases[s,i])

    # Normalize to prevent clipping
    waveform /= np.max(np.abs(waveform))
    outdata[:] = waveform.reshape(-1,1)

# -------------------------------
# Start audio stream
# -------------------------------
with sd.OutputStream(channels=1, callback=lattice_audio_callback, samplerate=fs, blocksize=block_size):
    print("HDGL lattice audio streaming. Press Ctrl+C to stop.")
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("Streaming stopped.")
