#!/usr/bin/env python3
"""Simple MIDI tempo converter - replaces set_tempo (0xFF 0x51) events to 136 BPM."""
import os, struct, zipfile

src_dir = '/root/.openclaw/media/inbound'
dst_dir = '/root/.openclaw/workspace/downloads/midi-136bpm'
os.makedirs(dst_dir, exist_ok=True)

# 136 BPM = 60_000_000 / 136 = 441176 µs per quarter note
NEW_TEMPO = struct.pack('>I', int(60_000_000 / 136))[1:]  # b'\x06\xb0\xf0'

def get_tempo(mididata):
    """Find all tempo events in MIDI data, return list of tempos in BPM."""
    tempos = []
    i = 0
    while i < len(mididata):
        if mididata[i] == 0xFF and i+1 < len(mididata) and mididata[i+1] == 0x51:
            # Length byte (variable length)
            length = 0
            j = i + 2
            while mididata[j] & 0x80:
                length = (length << 7) | (mididata[j] & 0x7F)
                j += 1
            length = (length << 7) | (mididata[j] & 0x7F)
            j += 1
            if length >= 3:
                tempo_bytes = mididata[j:j+3]
                tempo_val = (tempo_bytes[0]<<16)|(tempo_bytes[1]<<8)|tempo_bytes[2]
                bpm = 60000000 / tempo_val
                tempos.append((bpm, i, j, 3))
        i += 1
    return tempos

# Verify all files first
mids = sorted([f for f in os.listdir(src_dir) if f.endswith('.mid')])
print(f"Found {len(mids)} MIDI files:\n")

for fname in mids:
    path = os.path.join(src_dir, fname)
    with open(path, 'rb') as f:
        data = f.read()
    
    tempos = get_tempo(data)
    if tempos:
        bpms = [f'{t[0]:.1f}' for t in tempos]
        print(f"  {fname}: {bpms} BPM")
    else:
        print(f"  {fname}: ⚠️ NO TEMPO EVENT FOUND (maybe default 120 BPM?)")

print("\nConverting all to 136.0 BPM...\n")

converted = []
for fname in mids:
    src_path = os.path.join(src_dir, fname)
    
    with open(src_path, 'rb') as f:
        data = bytearray(f.read())
    
    new_data = bytearray()
    i = 0
    tempo_replaced = False
    
    while i < len(data):
        if data[i] == 0xFF and i+1 < len(data) and data[i+1] == 0x51:
            # Skip original length byte (variable length encoding)
            j = i + 2
            old_len_byte_count = 0
            while data[j] & 0x80:
                old_len_byte_count += 1
                j += 1
            old_len_byte_count += 1
            j += 1
            
            # Skip original tempo bytes (3 bytes)
            orig_tempo_end = j + 3
            
            new_data.extend(data[i:i+2])  # FF 51
            # Write new length (3 = b'\x03')
            new_data.append(3)
            # Write new tempo
            new_data.extend(NEW_TEMPO)
            i = orig_tempo_end
            tempo_replaced = True
        else:
            new_data.append(data[i])
            i += 1
    
    if tempo_replaced:
        base = os.path.splitext(fname)[0]
        dst_name = f'{base}_136bpm.mid'
        dst_path = os.path.join(dst_dir, dst_name)
        with open(dst_path, 'wb') as f:
            f.write(new_data)
        
        size = os.path.getsize(dst_path)
        # Verify
        new_tempos = get_tempo(bytes(new_data))
        print(f"  {fname} -> {dst_name} ({size} bytes) ✅")
        converted.append((dst_name, dst_path))
    else:
        # No tempo event - copy as-is (DAW defaults to 120 BPM)
        base = os.path.splitext(fname)[0]
        dst_name = f'{base}_no_tempo_event.mid'
        dst_path = os.path.join(dst_dir, dst_name)
        with open(dst_path, 'wb') as f:
            f.write(data)
        print(f"  {fname} -> {dst_name} (kopiert, kein Tempo-Event)")

# Zip
zip_path = os.path.join(dst_dir, 'midi-136bpm.zip')
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:
    for name, path in converted:
        zf.write(path, name)

print(f"\n✅ Done! {len(converted)} files converted to 136 BPM.")
print(f"📁 Dir: {dst_dir}")
print(f"📦 Zip: midi-136bpm.zip ({os.path.getsize(zip_path)} bytes)")
print(f"\n🌐 Download: http://187.124.177.164/downloads/midi-136bpm/midi-136bpm.zip")
