# Inject note-on (live=1) and measure master buffer energy while held. import ctypes, sys, time sys.stdout.reconfigure(encoding='utf-8', errors='replace') APP_PID = sys.argv[1] SHM_NAME = f'SonicForge_DAW_IPC_{APP_PID}' OFF_MQ = 2064 OFF_MQ_COUNT = 2832 OFF_CQ = 2836 OFF_CQ_COUNT = 11156 OFF_MASTER_L = 8 OFF_MASTER_R = 1032 MIDI_ENTRY = 12 CTRL_ENTRY = 1040 k32 = ctypes.WinDLL('kernel32', use_last_error=True) k32.OpenFileMappingA.restype = ctypes.c_void_p k32.OpenFileMappingA.argtypes = [ctypes.c_uint32, ctypes.c_int, ctypes.c_char_p] k32.MapViewOfFile.restype = ctypes.c_void_p k32.MapViewOfFile.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_size_t] k32.UnmapViewOfFile.argtypes = [ctypes.c_void_p] k32.CloseHandle.argtypes = [ctypes.c_void_p] h = k32.OpenFileMappingA(0x0002, 0, SHM_NAME.encode()) if not h: print('FATAL open', ctypes.get_last_error()); sys.exit(1) ptr = k32.MapViewOfFile(h, 0x0002, 0, 0, 0) if not ptr: print('FATAL map', ctypes.get_last_error()); sys.exit(1) def send_ctrl(type_, arg0): idx = ctypes.c_uint32.from_address(ptr + OFF_CQ_COUNT).value base = ptr + OFF_CQ + idx * CTRL_ENTRY ctypes.c_uint32.from_address(base + 0).value = type_ ctypes.c_uint32.from_address(base + 4).value = arg0 ctypes.c_uint32.from_address(ptr + OFF_CQ_COUNT).value = idx + 1 def send_midi(cmd, ch, pitch, vel, live, data2=0, data3=0): idx = ctypes.c_uint32.from_address(ptr + OFF_MQ_COUNT).value base = ptr + OFF_MQ + idx * MIDI_ENTRY ctypes.c_uint8.from_address(base + 0).value = cmd ctypes.c_uint8.from_address(base + 1).value = ch ctypes.c_uint8.from_address(base + 2).value = pitch ctypes.c_uint8.from_address(base + 3).value = vel ctypes.c_uint8.from_address(base + 4).value = data2 ctypes.c_uint8.from_address(base + 5).value = data3 ctypes.c_uint8.from_address(base + 6).value = 1 if live else 0 ctypes.c_uint8.from_address(base + 7).value = 0 ctypes.c_uint32.from_address(base + 8).value = 0 ctypes.c_uint32.from_address(ptr + OFF_MQ_COUNT).value = idx + 1 def energy(off): arr = (ctypes.c_float * 256).from_address(ptr + off) return sum(abs(v) for v in arr) def sample(label, n=8): tot = 0.0 for _ in range(n): tot += energy(OFF_MASTER_L) + energy(OFF_MASTER_R) time.sleep(0.05) print(f'{label}: avg energy = {tot/(2*n):.8f}') print('baseline (no note)') sample('before', 5) print('--- NOTE_ON ch=0 p=60 vel=100 live=1 ---') send_midi(0x9, 0, 60, 100, live=1) time.sleep(0.8) sample('held', 8) print('--- NOTE_ON ch=0 p=72 vel=120 live=1 ---') send_midi(0x9, 0, 72, 120, live=1) time.sleep(0.8) sample('held2', 8) print('--- NOTE_OFF ---') send_midi(0x9, 0, 60, 0, live=1) send_midi(0x9, 0, 72, 0, live=1) time.sleep(0.5) sample('after off', 5) k32.UnmapViewOfFile(ptr); k32.CloseHandle(h) print('DONE')