在即時系統與遊戲開發中,如何在等待使用者輸入的同時播放背景音效,是一個經典課題。本文深度解析一套完整的組合語言聲音常式庫,實現「鍵盤輪詢與音效更新並行」的非阻塞架構,適用於 DOS 保護模式與即時應用開發。
get_keyinput:阻塞式等待按鍵,期間持續更新背景音效,直到有鍵盤資料才返回(AX 含鍵碼)。get_keyinput_to:帶逾時的非阻塞版本,入口 AX 為逾時計數(系統時鐘 18.2Hz),逾時返回 CF=1、AX=0;有鍵則 CF=0、AX 為鍵碼。音效表位於 sound_table,每筆 4 位元組(兩字):
DW duration_count ; 持續時間(時鐘節拍數)
DW tone_value ; 頻率值
; 以 DW 0 結束
範例表(註解掉):8, 45000(長低音)、2, 2000(短高音)。
sound_update兩個入口點共用此邏輯:檢查 sound_flag、比對目前時間(CX:AX)與 sound_time_m:l,到期則讀取下一筆音效資料,呼叫 sound_out_ax 設定頻率,並重設下次觸發時間。表尾觸發 turn_sound_off。
get_current_time:INT 1Ah AH=0 取得 32 位元系統時間(CX:DX,18.2Hz)。get_time_plus_ax:目前時間 + AX → 新 CX:AX,處理進位。test_current_time:目前時間 ≥ 目標時間?CF=0:是;CF=1:否。含午夜跨越修正邏輯。sound_out_ax:
; AX = 頻率值
in al, 61h ; 讀取喇叭控制埠
or al, 3 ; 開啟喇叭閘道 (bit 0,1)
out 61h, al
mov al, 0B6h ; 8253 模式 3,二進位計數
out 43h, al
out 42h, al ; 低位元組
xchg al, ah
out 42h, al ; 高位元組
mov sound_on_flag, 0FFh
ret
sound_off:
in al, 61h
and al, 0FCh ; 關閉喇叭閘道
out 61h, al
mov sound_on_flag, 0
ret
start_table_sound:以 BX 指向音效表啟動背景播放,設定 sound_flag=0FFh。flush_keyboard:清空 BIOS 鍵盤緩衝區(INT 16h AH=1/0 迴圈)。; 主程式片段
mov bx, offset my_sound_table
call start_table_sound
main_loop:
call get_keyinput_to ; 帶 5 秒逾時
jc timeout_handler
; 處理鍵盤輸入 AL
jmp main_loop
PUBLIC),易於連結至 C/其他模組。PUSH/POP BX, CX, DX),符合呼叫慣例。此程式碼展示了組合語言在硬體控制與即時調度上的極致效能與彈性,是系統程式設計師必讀的經典範例。