#!/usr/bin/env python3
"""Analyze all MIDI files - track types, note counts, pitch ranges."""
import os, struct

src = '/root/.openclaw/media/inbound'
mids = sorted([f for f in os.listdir(src) if f.endswith('.mid')])

for fname in mids:
    path = os.path.join(src, fname)
    with open(path, 'rb') as f:
        data = f.read()
    
    # Parse header
    fmt = struct.unpack('>H', data[8:10])[0]
    ntracks = struct.unpack('>H', data[10:12])[0]
    
    print(f"\n{'='*70}")
    print(f"📁 {fname}")
    print(f"   Format={fmt} Tracks={ntracks} Size={len(data)}")
    
    # Parse each track
    offset = 14
    for t in range(ntracks):
        tc = data[offset:offset+4]
        ts = struct.unpack('>I', data[offset+4:offset+8])[0]
        track_data = data[offset+8:offset+8+ts]
        offset += 8 + ts
        
        # Parse events
        notes = []
        cc_events = []
        prog_changes = []
        tempo = None
        text_events = []
        
        running_status = 0
        i = 0
        while i < len(track_data):
            # Delta time (VLI)
            delta = 0
            b = track_data[i]; i += 1
            while b & 0x80:
                delta = (delta << 7) | (b & 0x7F)
                if i >= len(track_data): break
                b = track_data[i]; i += 1
            delta = (delta << 7) | (b & 0x7F)
            
            if i >= len(track_data): break
            
            byte = track_data[i]
            
            if byte == 0xFF:  # Meta event
                i += 1
                mt = track_data[i]; i += 1
                length = 0
                b2 = track_data[i]; i += 1
                while b2 & 0x80:
                    length = (length << 7) | (b2 & 0x7F)
                    if i >= len(track_data): break
                    b2 = track_data[i]; i += 1
                length = (length << 7) | (b2 & 0x7F)
                
                if mt == 0x51:  # Set Tempo
                    tempo = (track_data[i]<<16)|(track_data[i+1]<<8)|track_data[i+2]
                    i += 3
                elif mt == 0x03:  # Text/Instrument name
                    text = track_data[i:i+length].decode('latin-1', errors='ignore')[:50]
                    text_events.append(f"[{delta}t] {text}")
                    i += length
                elif mt == 0x3F:  # End of track marker
                    pass
                else:
                    i += length
            elif byte == 0xF0 or byte == 0xF7:  # SysEx
                i += 1
                length = 0
                b2 = track_data[i]; i += 1
                while b2 & 0x80:
                    length = (length << 7) | (b2 & 0x7F)
                    if i >= len(track_data): break
                    b2 = track_data[i]; i += 1
                length = (length << 7) | (b2 & 0x7F)
                i += length
            elif byte < 0x80:  # Running status
                status = running_status
                
                msg_type = (status >> 4) & 0x0F
                channel = status & 0x0F
                
                if msg_type in [0,1]:  # note-off / note-on
                    d1 = track_data[i]; i += 1
                    d2 = track_data[i]; i += 1
                    if msg_type == 1 and d2 > 0:
                        notes.append((delta, channel, d1, d2))
                elif msg_type == 3:  # CC
                    cc_num = track_data[i]; i += 1
                    cc_val = track_data[i]; i += 1
                    if cc_num == 0x5B and cc_val > 0:  # reverb on
                        pass  # ignore for analysis
                elif msg_type == 4:  # Program Change
                    prog = track_data[i]; i += 1
                    prog_changes.append((delta, channel, prog))
                else:
                    if msg_type == 6:
                        d1 = track_data[i]; i += 1
                        d2 = track_data[i]; i += 1
                    else:
                        i += 1
            else:
                running_status = byte
                status = byte
                i += 1
                
                msg_type = (status >> 4) & 0x0F
                channel = status & 0x0F
                
                if msg_type in [0,1]:
                    d1 = track_data[i]; i += 1
                    d2 = track_data[i]; i += 1
                    if msg_type == 1 and d2 > 0:
                        notes.append((delta, channel, d1, d2))
                elif msg_type == 3:
                    cc_num = track_data[i]; i += 1
                    cc_val = track_data[i]; i += 1
                elif msg_type == 4:
                    prog = track_data[i]; i += 1
                    prog_changes.append((delta, channel, prog))
                elif msg_type == 6:
                    d1 = track_data[i]; i += 1
                    d2 = track_data[i]; i += 1
                else:
                    i += 1
        
        # Analyze
        note_names = {0:'C',1:'C#',2:'D',3:'D#',4:'E',5:'F',6:'F#',7:'G',8:'G#',9:'A',10:'A#',11:'B'}
        notes_by_channel = {}
        for d,ch,n,v in notes:
            if ch not in notes_by_channel:
                notes_by_channel[ch] = []
            notes_by_channel[ch].append((n, v))
        
        n_total = len(notes)
        pitches = sorted(set(n for _,n in notes))
        pitch_names = [f"{note_names[p%12]}{(p//12)-1}" for p in pitches] if pitches else []
        unique_pitches = len(pitches)
        
        # Program names guess
        prog_names = {}
        standard_programs = {0:'Acoustic Grand',1:'Bright Acoustic',3:'Electric Grand',4:'Honky-tonk',5:'Electric Piano',8:'Harpsichord',24:'Acoustic Guitar (nylon)',25:'Acoustic Guitar (steel)',29:'Electric Guitar (jazz)',27:'Electric Guitar (clean)',80:'Voice Oohs',87:'Lead 1 (square)',88:'Lead 2 (sawtooth)',96:'Bass & Lead'}
        for _,ch,prog in prog_changes:
            name = standard_programs.get(prog, f'Prg {prog}')
            if ch not in prog_names:
                prog_names[ch] = []
            prog_names[ch].append(name)
        
        print(f"   Track {t}:")
        print(f"      🎵 Total Notes: {n_total}")
        print(f"      🎸 Unique Pitches: {unique_pitches} ({', '.join(pitch_names[:15])}{'...' if len(pitch_names)>15 else ''})")
        
        if text_events:
            for te in text_events[:3]:
                print(f"      📝 {te}")
        
        if prog_names:
            for ch, names in sorted(prog_names.items()):
                print(f"      💡 Ch{ch+1}: {', '.join(set(names))}")
        
        # Channel summary
        for ch in sorted(notes_by_channel.keys()):
            npitches = len(set(n for n,v in notes_by_channel[ch]))
            nnotes = len(notes_by_channel[ch])
            avg_vel = sum(v for _,v in notes_by_channel[ch]) / max(1,nnotes)
            min_n = min(n for n,v in notes_by_channel[ch])
            max_n = max(n for n,v in notes_by_channel[ch])
            print(f"      🔤 Ch{ch+1}: {nnotes} notes, pitch range {note_names[min_n%12]}{(min_n//12)-1}-{note_names[max_n%12]}{(max_n//12)-1}, avg vel={avg_vel:.0f}")

print(f"\n{'='*70}")
print("✅ Analysis complete")
