Files
SonicForgeStudio/tools/shm_test_preview_fix.py
T
admin 7c22ae1f02 refactor(bridge): split fx bridge, stabilize VST3 host chain, drop old install engines
- remove diagnostic canaries from audio hot path (crackle fix) and
  stuck C5 note raw-MIDI test (Vst2Instrument::init noteOff)
- split native bridge into daw_vst_bridge (VSTi) + fx_vst_bridge (VST FX)
- VST3: processData prepare before setActive, zero input buses, accept
  both .vstpreset and bridge-state blob in RenderJob presets
- native_render/vst_engine: bridge-exe discovery + render_fx_chain + /fx-gui
- delete old install/ engine binaries (install via sidecar+resources now)
- add BUILD_LAYOUT.md, build_selfcheck, tools/ diagnostics
2026-08-20 09:42:42 +07:00

97 lines
3.7 KiB
Python

# SHM injection test for live-flag fix: verify transportStopped guard drops
# non-live note-ons but passes live ones (reserved[0]=1).
# Layout from SharedMemoryIPC.h (verified): base=2064 bytes, midiQueue 64x12 @2064,
# midiQueueCount @2832, controlQueue 8x1040 @2836, controlQueueCount @11156.
import ctypes, sys, time, os
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
APP_PID = sys.argv[1] if len(sys.argv) > 1 else '9712'
SHM_NAME = f'SonicForge_DAW_IPC_{APP_PID}'
OFF_MQ = 2064
OFF_MQ_COUNT = 2832
OFF_CQ = 2836
OFF_CQ_COUNT = 11156
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]
def get_shm():
h = k32.OpenFileMappingA(0x0002, 0, SHM_NAME.encode()) # FILE_MAP_WRITE first
if not h:
h = k32.OpenFileMappingA(0x0004, 0, SHM_NAME.encode()) # fallback FILE_MAP_READ
if not h:
err = ctypes.get_last_error()
print(f'FATAL: cannot open SHM {SHM_NAME} (err={err})')
sys.exit(1)
ptr = k32.MapViewOfFile(h, 0x0002, 0, 0, 0) # FILE_MAP_WRITE
if not ptr:
print(f'FATAL: MapViewOfFile err={ctypes.get_last_error()}')
sys.exit(1)
return h, ptr
def w32(ptr, off, val):
ctypes.c_uint32.from_address(ptr + off).value = val
def send_ctrl(ptr, type_, arg0, arg1=0, channel=0):
idx = ctypes.c_uint32.from_address(ptr + OFF_CQ_COUNT).value
if idx >= 8:
print('FATAL: control queue full')
sys.exit(1)
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(base + 8).value = arg1
ctypes.c_uint32.from_address(base + 12).value = channel
ctypes.c_uint32.from_address(ptr + OFF_CQ_COUNT).value = idx + 1
print(f'sent ctrl type={type_} arg0={arg0}')
def send_midi(ptr, cmd, channel, pitch, velocity, live, data2=0, data3=0):
idx = ctypes.c_uint32.from_address(ptr + OFF_MQ_COUNT).value
if idx >= 64:
print('FATAL: midi queue full')
sys.exit(1)
base = ptr + OFF_MQ + idx * MIDI_ENTRY
ctypes.c_uint8.from_address(base + 0).value = cmd
ctypes.c_uint8.from_address(base + 1).value = channel
ctypes.c_uint8.from_address(base + 2).value = pitch
ctypes.c_uint8.from_address(base + 3).value = velocity
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 # reserved[0] = live flag
ctypes.c_uint8.from_address(base + 7).value = 0
ctypes.c_uint32.from_address(base + 8).value = 0 # sampleOffset
ctypes.c_uint32.from_address(ptr + OFF_MQ_COUNT).value = idx + 1
print(f'sent midi cmd=0x{cmd:x} ch={channel} pitch={pitch} vel={velocity} live={live}')
h, ptr = get_shm()
print(f'SHM {SHM_NAME} mapped at {ptr:#x}')
# 1) transport STOP -> guard arms
send_ctrl(ptr, 3, 0) # TRANSPORT STOP
time.sleep(1.0)
# 2) non-live NOTE_ON -> must be dropped (no [midi] ON log)
send_midi(ptr, 0x9, 0, 60, 100, live=0)
time.sleep(1.0)
# 3) live NOTE_ON -> must pass
send_midi(ptr, 0x9, 0, 60, 100, live=1)
time.sleep(1.0)
# 4) non-live NOTE_ON again -> dropped (sanity)
send_midi(ptr, 0x9, 0, 62, 90, live=0)
time.sleep(1.0)
# 5) restore PLAY so app continues working
send_ctrl(ptr, 3, 1)
time.sleep(0.5)
k32.UnmapViewOfFile(ptr)
k32.CloseHandle(h)
print('DONE')