/* * cbl_close — выключить CBL, снять хук насоса и отпустить IM2-таблицу. * Идемпотентно; вызывается и из atexit. * * БУФЕР ТИШИНЫ НЕ ОСВОБОЖДАЕТСЯ. Раньше здесь стоял free(_cbl_silence), и * он один тянул malloc/free в резидент КАЖДОМУ приложению — включая те, что * cbl_open_silence() не зовут вовсе. Буфер живёт до выхода из программы и * переиспользуется при повторном открытии (см. cbl_open_silence.c). * * Порт 0x004E не гасится напрямую — вместо этого _cbl_port_sync() * пересчитывает нужное значение: если gfx_wait_vsync() ещё держит * ссылку (_cbl_port_refs > 0), останется "немой" режим ради бита * синхронизации; иначе порт гасится полностью. Он же заливает * аппаратный буфер тишиной — БЕЗ ЭТОГО ЗАКРЫТИЕ CBL НЕ ЗАКРЫВАЕТ ЗВУК: * пока bit7 держит vsync-ссылка, железо крутит по кругу оставшиеся в * буфере 256 байт последнего сэмпла и поёт ноту до следующего * cbl_open() (пойман Ctrl+S во время музыки, 2026-09-02; полный разбор * — в шапке _cbl.h). В MAME это не воспроизводится. * * Порядок обязателен: сначала снять хук (иначе насос долил бы буфер уже * после заливки), и только потом _cbl_port_sync с заливкой — вся * скобка под DI, чтобы между снятием хука и тишиной ничего не влезло. */ #include "_cbl.h" #include "../irq/_irq.h" void cbl_close(void) { if (!_irq_cbl_hook) return; IRQ_DISABLE(); _irq_cbl_hook = 0; _cbl_port_sync(); /* режим порта + заливка буфера тишиной */ IRQ_ENABLE(); _irq_table_unref(); }