2017-05-16 13 views
1

私はアセンブリで "サイモン"ゲームをしています。ボタンがオンになるたびにビープ音を鳴らす必要があります。ビープ音も互いに異なるはずです。 ありがとうアセンブリ8086 - DOSBOX - ビープ音を鳴らすには?

+1

[DOSBoxのSound Blasterデバイスで.wavファイルを再生する](http://stackoverflow.com/questions/41359112/playing-wav-files-on-dosboxs-sound-blaster-device) –

+1

あなたは相談しましたかDOS割り込みの参照? – Michael

答えて

6

speakerを使用すると、デザインを簡単にすることができます。
スピーカーを使用すると、異なる周波数の方形波を再生することができます。​​が関与します。

スピーカーは単なる電磁石であり、電流が流れると引き戻され、それ以外の場合はデフォルトの位置にとどまります。
スピーカーを前後に動かすことで、音波を作り出すことができます。

スピーカは、手動で、または同じポートであるのポート61Hの2
ビット0スピーカ源を制御する(0 =手動、1 = PIT)とビット1 PITのチャネルを用いて移動させることができる

PITを使用しているときは「スピーカー有効」ビット(スピーカー「使用しないときは「位置」)。ここで

は、手動駆動部を欠落している(このpageから)は概略です:

Speaker schematic

PITがポート40H-43Hを介して制御され、私たちはそれぞれの時間を設定するモード3(方形波発生器)を使用しますデバイダの両方のバイト。
PITは、約1.193180MHzで動作する発振器を有し、分周器は方形波の周期を制御するために使用される。
内部処理なし:PITオシレータの各ティックで、ロードされた分周器がデクリメントされます。方形波の周期は、分周器をゼロに減少させるためにPITが必要とする時間に等しい。

サウンドを生成することは、PITを所望のディバイダでプログラムし、スピーカを有効にすることだけです。
後で、それを無効にする必要があります。
これを行う簡単な方法は、1秒に18.2回と呼ばれるint 1chを使用することです。

サウンドを最初に再生したときに継続時間を変数に保存すると、int 1chの各ティックごとにデクリメントし、カウントがゼロになったときにスピーカーを無効にすると、ビープ音の持続時間を制御できます。

int 1chを使用するには、セットアップ機能(beep_setup)とティアダウン機能(beep_teardown)が必要です。元のコードの欠陥を固定するSep Roland

BITS 16 

ORG 100h 

__start__: 

;Setup 
call beep_setup 

;Sample beep of ~2sec 
mov ax, 2000 
mov bx, 36 
call beep_play 

;Wait for input 
xor ax, ax 
int 16h 

;Tear down 
call beep_teardown 

mov ax, 4c00h 
int 21h 

;------------------------------------------------- 

; 
;Setup the beep ISR 
; 

beep_setup: 
    push es 
    push ax 

    xor ax, ax 
    mov es, ax 

    ;Save the original ISR 
    mov ax, WORD [es: TIMER_INT * 4] 
    mov WORD [cs:original_timer_isr], ax 
    mov ax, WORD [es: TIMER_INT * 4 + 2] 
    mov WORD [cs:original_timer_isr + 2], ax 

    ;Setup the new ISR 

    cli 
    mov ax, beep_isr 
    mov WORD [es: TIMER_INT * 4], ax 
    mov ax, cs 
    mov WORD [es: TIMER_INT * 4 + 2], ax 
    sti 

    pop ax 
    pop es 
    ret 


; 
;Tear down the beep ISR 
; 

beep_teardown: 
    push es 
    push ax 

    call beep_stop 

    xor ax, ax 
    mov es, ax 

    ;Restore the old ISR 

    cli 
    mov ax, WORD [cs:original_timer_isr] 
    mov WORD [es: TIMER_INT * 4], ax 
    mov ax, WORD [cs:original_timer_isr + 2] 
    mov WORD [es: TIMER_INT * 4 + 2], ax 
    sti 

    pop ax 
    pop es 
    ret 

; 
;Beep ISR 
; 
beep_isr: 
    cmp BYTE [cs:sound_playing], 0 
    je _bi_end 

    cmp WORD [cs:sound_counter], 0 
    je _bi_stop 

    dec WORD [cs:sound_counter] 

jmp _bi_end 

_bi_stop: 
    call beep_stop 

_bi_end: 
    ;Chain 
    jmp FAR [cs:original_timer_isr] 

; 
;Stop beep 
; 
beep_stop: 
    push ax 

    ;Stop the sound 

    in al, 61h 
    and al, 0fch ;Clear bit 0 (PIT to speaker) and bit 1 (Speaker enable) 
    out 61h, al 

    ;Disable countdown 

    mov BYTE [cs:sound_playing], 0 

    pop ax 
    ret 

; 
;Beep 
; 
;AX = 1193180/frequency 
;BX = duration in 18.2th of sec 
beep_play: 
    push ax 
    push dx 

    mov dx, ax 

    mov al, 0b6h 
    out 43h, al 

    mov ax, dx 
    out 42h, al 
    mov al, ah 
    out 42h, al 


    ;Set the countdown 
    mov WORD [cs:sound_counter], bx 

    ;Start the sound 

    in al, 61h 
    or al, 3h ;Set bit 0 (PIT to speaker) and bit 1 (Speaker enable) 
    out 61h, al 


    ;Start the countdown 

    mov BYTE [cs:sound_playing], 1 

    pop dx 
    pop ax 
    ret 

;Keep these in the code segment 
sound_playing  db 0 
sound_counter  dw 0 
original_timer_isr  dd 0 

TIMER_INT  EQU  1ch 

感謝!

beep_playを使用してビープ音を鳴らすことができます。使用される単位は、上記で説明したハードウェア構成の「自然な」単位です。
周波数と期間が固定されている場合、これらのユニットは無償でコードを簡素化します。

指定された時間が経過するとビープ音が止まり、強制的に停止するにはbeep_stopを使用できます。

一度に複数の音を再生することは不可能です(PWM技術に頼らずに混合することも不可能です)。
別のビープ音が鳴っている間にbeep_playを呼び出すと、現在のビープ音を止めて新しいビープ音を鳴らす効果があります。

+0

優れた答えです。 +1しかし* beep_isr *割り込みルーチンには重要な問題があります!あなたは単に 'AX'レジスタを使うことはできず、それを保存しておくことはできません。 'cmp WORD [cs:sound_counter]、0'' je _bi_stop' 'dec WORD [cs:sound_counter]'は、この解決策は簡単です。 'AX'をまったく使う必要はありません。 –

+0

ありがとうございます@SepRoland!私はクレジットで答えを更新しています:) –

関連する問題