Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

9. Obsluha zvuku

Obsluha zvuku používá výstup na standardní reproduktor PC. U novějších PC tento reproduktor nebývá někdy nainstalován nebo zapojen, proto nejdříve zkontrolujte, zda je reproduktor funkční. Ověření můžete provést např. z příkazového řádku zadáním příkazu "echo •", kde parametrem příkazu echo je znak s kódem 7 (tj. znak pro zvonek, BEL), který získáte stiskem levé klávesy Alt a zadáním kódu 7 na numerické klávesnici (klávesu Alt uvolněte až po zadání kódu).

Do souboru PROGRAM.ASM, na konec části s "include", doplňte řádek %include "SOUND.ASM". Zrušte návěští PlaySound, PlayRepeat, SoundInt, BonusSound, StopTurnSound a TurnSound.Připravte soubor SOUND.ASM a naplňte jej následujícím obsahem:


; ============================================================================
;
;                            VEGASLOT - Sound
;
; ============================================================================

; ------------- Tone names (R=rest, M=-1 minus, S=# sharp)

STOP		equ	255	; stop of melody

R		equ	0	; rest

				; 1-10: octave -1
DM		equ	1
DMS		equ	2
EM		equ	3
FM		equ	4
FMS		equ	5
GM		equ	6
GMS		equ	7
AM		equ	8
AMS		equ	9
HM		equ	10
				; 11-22: octave 0
C0		equ	11
C0S		equ	12
D0		equ	13
D0S		equ	14
E0		equ	15
F0		equ	16
F0S		equ	17
G0		equ	18
G0S		equ	19
A0		equ	20
A0S		equ	21
H0		equ	22
				; 23-34: octave 1
C1		equ	23
C1S		equ	24
D1		equ	25
D1S		equ	26
E1		equ	27
F1		equ	28
F1S		equ	29
G1		equ	30
G1S		equ	31
A1		equ	32
A1S		equ	33
H1		equ	34
				; 35-46: octave 2
C2		equ	35
C2S		equ	36
D2		equ	37
D2S		equ	38
E2		equ	39
F2		equ	40
F2S		equ	41
G2		equ	42
G2S		equ	43
A2		equ	44
A2S		equ	45
H2		equ	46
				; 47-58: octave 3
C3		equ	47
C3S		equ	48
D3		equ	49
D3S		equ	50
E3		equ	51
F3		equ	52
F3S		equ	53
G3		equ	54
G3S		equ	55
A3		equ	56
A3S		equ	57
H3		equ	58
				; 59-70: octave 4
C4		equ	59
C4S		equ	60
D4		equ	61
D4S		equ	62
E4		equ	63
F4		equ	64
F4S		equ	65
G4		equ	66
G4S		equ	67
A4		equ	68
A4S		equ	69
H4		equ	70
				; 71-82: octave 5
C5		equ	71
C5S		equ	72
D5		equ	73
D5S		equ	74
E5		equ	75
F5		equ	76
F5S		equ	77
G5		equ	78
G5S		equ	79
A5		equ	80
A5S		equ	81
H5		equ	82
				; 83-94: octave 6
C6		equ	83
C6S		equ	84
D6		equ	85
D6S		equ	86
E6		equ	87
F6		equ	88
F6S		equ	89
G6		equ	90
G6S		equ	91
A6		equ	92
A6S		equ	93
H6		equ	94
				; 95-106: octave 7
C7		equ	95
C7S		equ	96
D7		equ	97
D7S		equ	98
E7		equ	99
F7		equ	100
F7S		equ	101
G7		equ	102
G7S		equ	103
A7		equ	104
A7S		equ	105
H7		equ	106
				; 107-118: octave 8
C8		equ	107
C8S		equ	108
D8		equ	109
D8S		equ	110
E8		equ	111
F8		equ	112
F8S		equ	113
G8		equ	114
G8S		equ	115
A8		equ	116
A8S		equ	117
H8		equ	118
				; 119-130: octave 9
C9		equ	119
C9S		equ	120
D9		equ	121
D9S		equ	122
E9		equ	123
F9		equ	124
F9S		equ	125
G9		equ	126
G9S		equ	127
A9		equ	128
A9S		equ	129
H9		equ	130

; ------------- Tone lengths (D=. dott)

L0		equ	1
L1		equ	2
L1D		equ	3
L2		equ	4
L2D		equ	6
L3		equ	8
L3D		equ	12
L4		equ	16
L4D		equ	24
L5		equ	32
L5D		equ	48
L6		equ	64
L6D		equ	96
L7		equ	128
L7D		equ	192
L8		equ	256

SECTION		.text

; ----------------------------------------------------------------------------
;                            Play sound or melody
; ----------------------------------------------------------------------------
; INPUT:	CS:AX=sound or melody string
; ----------------------------------------------------------------------------

PlaySound:	cli			; disable interrupts
		call	StopSound	; stop sound
		mov	byte [cs:SoundLength],1 ; length of old note
		mov	[cs:SoundNext],ax ; melody pointer
		sti			; enable interrupts
		ret

; ----------------------------------------------------------------------------
;                              Stop sound now
; ----------------------------------------------------------------------------

StopSound:	call	StopRepeat	; stop repeating
		mov	word [cs:SoundNext],0 ; no sound
		ret

; ----------------------------------------------------------------------------
;                          Play repeat sound or melody
; ----------------------------------------------------------------------------
; INPUT:	CS:AX=sound or melody string
; ----------------------------------------------------------------------------

PlayRepeat:	cli			; disable interrupts
		call	StopSound	; stop sound
		mov	word [cs:SoundRepeat],ax ; address of sound to repeat
		mov	byte [cs:SoundLength],1 ; length of old note
		mov	[cs:SoundNext],ax ; melody pointer
		sti			; enable interrupts
		ret

; ----------------------------------------------------------------------------
;                             Stop repeating of sound
; ----------------------------------------------------------------------------

StopRepeat:	mov	word [cs:SoundRepeat],0 ; no repeating
		ret

; ----------------------------------------------------------------------------
;                          Sound interrupt routine
; ----------------------------------------------------------------------------

; ------------- Test, whether it is playing

SoundInt:	cmp	word [cs:SoundNext],0 ; is it playing?
		je	SoundInt9	; it is not playing

; ------------- Counter of length

		dec	byte [cs:SoundLength] ; count length
		jnz	SoundInt9	; current note is playing

; ------------- Push registers

		push	ax		; push AX
		push	bx		; push BX
		push	si		; push SI

; ------------- Load next tone

		mov	si,[cs:SoundNext] ; BX <- melody pointer
SoundInt1:	mov	al,[cs:si]	; AL <- next tone

; ------------- Test, whether it is end of melody

		cmp	al,STOP		; is it end of melody?
		jne	SoundInt2	; it is not end of melody
		mov	si,[cs:SoundRepeat] ; sound to repeat
		or	si,si		; is it repeating?
		jnz	SoundInt1	; it is repeating

; ------------- Mute current tone
%ifndef NOSOUND
		in	al,61h		; AL <- peripheral interface B
		and	al,~3		; disable output to speaker
		out	61h,al		; set new state of speaker output

; ------------- Set standard frequency to speaker (920 Hz about)

		mov	al,0b6h		; AL <- command for counter 2, mode 3
		out	43h,al		; set command registers
		mov	al,5		; standard frequency
		out	42h,al		; set standard frequency LOW
		out	42h,al		; set standard frequency HIGH
%endif
		jmp	short SoundInt8	; it is not repeating

; ------------- Play rest

SoundInt2:	inc	si		; increment pointer
		cmp	al,R		; is it rest?
		jne	SoundInt3	; it is not rest

; ------------- Mute current tone
%ifndef NOSOUND
		in	al,61h		; AL <- peripheral interface B
		and	al,~3		; disable output to speaker
		out	61h,al		; set new state of speaker output
%endif
		jmp	short SoundInt7	; set length of rest

; ------------- Prepare tone divider

SoundInt3:	mov	ah,0		; AX = tone number
		shl	ax,1		; AX <- tone * 2
		add	ax,ToneTab-2	; AX <- address of divider
		xchg	ax,bx		; BX <- address of divider

; ------------- Set tone divider
%ifndef NOSOUND
		mov	al,0b6h		; AL <- command for counter 2, mode 3
		out	43h,al		; set command registers
		mov	al,[cs:bx]	; divider LOW
		out	42h,al		; set divider LOW
		mov	al,[cs:bx+1]	; divider HIGH
		out	42h,al		; set divider HIGH

; ------------- Enable output to speaker

		in	al,61h		; AL <- peripheral interface B
		or	al,3		; enable output to speaker
		out	61h,al		; set new state of speaker output
%endif
; ------------- Load length of tone

SoundInt7:	mov	al,[cs:si]	; AL <- length of tone
		inc	si		; increment pointer
		mov	[cs:SoundLength],al ; set length of tone

; ------------- Store new address of music

SoundInt8:	mov	[cs:SoundNext],si ; new address of music

; ------------- Pop registers

		pop	si		; pop SI
		pop	bx		; pop BX
		pop	ax		; pop AX
SoundInt9:	ret

; ----------------------------------------------------------------------------
;                                    Data
; ----------------------------------------------------------------------------

SoundRepeat:	dw	0		; address of melody (0=don't repeat)
SoundLength:	db	0		; counter of length of current tone
SoundNext:	dw	0		; pointer to next tone (0=none)

; ------------- Frequencies of tones (1.193182 MHz generator divider)
;		1 halftone interval = 2^(1/12) =~ 1.05946
;		reference note A3 = 440 Hz 

ToneTab:			; 1-10: octave -1
		dw	65009		; DM	18.35 Hz
		dw	61361		; DMS	19.45 Hz
		dw	57917		; EM	20.60 Hz
		dw	54666		; FM	21.83 Hz
		dw	51598		; FMS	23.12 Hz
		dw	48702		; GM	24.50 Hz
		dw	45968		; GMS	25.96 Hz
		dw	43388		; AM	27.50 Hz (exactly)
		dw	40953		; AMS	29.14 Hz
		dw	38655		; HM	30.87 Hz
				; 11-22: octave 0
		dw	36485		; C0	32.70 Hz
		dw	34437		; C0S	34.65 Hz
		dw	32505		; D0	36.71 Hz
		dw	30680		; D0S	38.89 Hz
		dw	28958		; E0	41.20 Hz
		dw	27333		; F0	43.65 Hz
		dw	25799		; F0S	46.25 Hz
		dw	24351		; G0	49.00 Hz
		dw	22984		; G0S	51.91 Hz
		dw	21694		; A0	55.00 Hz (exactly)
		dw	20477		; A0S	58.27 Hz
		dw	19327		; H0	61.74 Hz
				; 23-34: octave 1
		dw	18243		; C1	65.41 Hz
		dw	17219		; C1S	69.30 Hz
		dw	16252		; D1	73.42 Hz
		dw	15340		; D1S	77.78 Hz
		dw	14479		; E1	82.41 Hz
		dw	13667		; F1	87.31 Hz
		dw	12899		; F1S	92.50 Hz
		dw	12175		; G1	98.00 Hz
		dw	11492		; G1S	103.83 Hz
		dw	10847		; A1	110.00 Hz (exactly)
		dw	10238		; A1S	116.54 Hz
		dw	9664		; H1	123.47 Hz
				; 35-46: octave 2
		dw	9121		; C2	130.81 Hz
		dw	8609		; C2S	138.59 Hz
		dw	8126		; D2	146.83 Hz
		dw	7670		; D2S	155.56 Hz
		dw	7240		; E2	164.81 Hz
		dw	6833		; F2	174.61 Hz
		dw	6450		; F2S	185.00 Hz
		dw	6088		; G2	196.00 Hz
		dw	5746		; G2S	207.65 Hz
		dw	5424		; A2	220.00 Hz (exactly)
		dw	5119		; A2S	233.08 Hz
		dw	4832		; H2	246.94 Hz
				; 47-58: octave 3
		dw	4561		; C3	261.63 Hz
		dw	4305		; C3S	277.18 Hz
		dw	4063		; D3	293.66 Hz
		dw	3835		; D3S	311.13 Hz
		dw	3620		; E3	329.63 Hz
		dw	3417		; F3	349.23 Hz
		dw	3225		; F3S	369.99 Hz
		dw	3044		; G3	392.00 Hz
		dw	2873		; G3S	415.30 Hz
		dw	2712		; A3	440.00 Hz (exactly)
		dw	2560		; A3S	466.16 Hz
		dw	2416		; H3	493.88 Hz
				; 59-70: octave 4
		dw	2280		; C4	523.25 Hz
		dw	2152		; C4S	554.37 Hz
		dw	2032		; D4	587.33 Hz
		dw	1918		; D4S	622.25 Hz
		dw	1810		; E4	659.26 Hz
		dw	1708		; F4	698.46 Hz
		dw	1612		; F4S	739.99 Hz
		dw	1522		; G4	783.99 Hz
		dw	1437		; G4S	830.61 Hz
		dw	1356		; A4	880.00 Hz (exactly)
		dw	1280		; A4S	932.33 Hz
		dw	1208		; H4	987.77 Hz
				; 71-82: octave 5
		dw	1140		; C5	1046.50 Hz
		dw	1076		; C5S	1108.73 Hz
		dw	1016		; D5	1174.66 Hz
		dw	959		; D5S	1244.51 Hz
		dw	905		; E5	1318.51 Hz
		dw	854		; F5	1396.91 Hz
		dw	806		; F5S	1479.98 Hz
		dw	761		; G5	1567.98 Hz
		dw	718		; G5S	1661.22 Hz
		dw	678		; A5	1760.00 Hz (exactly)
		dw	640		; A5S	1864.66 Hz
		dw	604		; H5	1975.53 Hz
				; 83-94: octave 6
		dw	570		; C6	2093.00 Hz
		dw	538		; C6S	2217.46 Hz
		dw	508		; D6	2349.32 Hz
		dw	479		; D6S	2489.02 Hz
		dw	452		; E6	2637.02 Hz
		dw	427		; F6	2793.83 Hz
		dw	403		; F6S	2959.96 Hz
		dw	380		; G6	3135.96 Hz
		dw	359		; G6S	3322.44 Hz
		dw	339		; A6	3520.00 Hz (exactly)
		dw	320		; A6S	3729.31 Hz
		dw	302		; H6	3951.07 Hz
				; 95-106: octave 7
		dw	285		; C7	4186.01 Hz
		dw	269		; C7S	4434.92 Hz
		dw	254		; D7	4698.64 Hz
		dw	240		; D7S	4978.03 Hz
		dw	226		; E7	5274.04 Hz
		dw	214		; F7	5587.65 Hz
		dw	202		; F7S	5919.91 Hz
		dw	190		; G7	6271.93 Hz
		dw	180		; G7S	6644.88 Hz
		dw	169		; A7	7040 Hz (exactly)
		dw	160		; A7S	7458.62 Hz
		dw	151		; H7	7902.13 Hz
				; 107-118: octave 8
		dw	143		; C8	8372.02 Hz
		dw	135		; C8S	8869.84 Hz
		dw	127		; D8	9397.27 Hz
		dw	120		; D8S	9956.06 Hz
		dw	113		; E8	10548.08 Hz
		dw	107		; F8	11175.30 Hz
		dw	101		; F8S	11839.82 Hz
		dw	95		; G8	12543.85 Hz
		dw	90		; G8S	13289.75 Hz
		dw	85		; A8	14080.00 Hz (exactly)
		dw	80		; A8S	14917.24 Hz
		dw	75		; H8	15804.27 Hz
				; 119-130: octave 9
		dw	71		; C9	16744.04 Hz
		dw	67		; C9S	17739.69 Hz
		dw	63		; D9	18794.55 Hz
		dw	60		; D9S	19912.13 Hz
		dw	57		; E9	21096.16 Hz
		dw	53		; F9	22350.61 Hz
		dw	50		; F9S	23679.64 Hz
		dw	48		; G9	25087.71 Hz
		dw	45		; G9S	26579.50 Hz
		dw	42		; A9	28160.00 Hz (exactly)
		dw	40		; A9S	29834.48 Hz
		dw	38		; H9	31608.53 Hz

; ------------- Sounds and melodies

RefillSound:	db	C7,L0, STOP
CashSound:	db	C4,L1, STOP
TurnSound:	db	C0,L2, R,L2, STOP
BonusSound:	db	C1,L2, R,L2, STOP
WinSound:	db	C3,L2, E3,L2, G3,L2,
		db	C3,L2, E3,L2, G3,L2,
		db	C3,L2, E3,L2, G3,L2,
		db	C3,L2, E3,L2, G3,L2,
		db	C3,L2, E3,L2, G3,L2, STOP
TransSound:	db	E3,L2, A3,L2, E3,L2, A3,L2, STOP
StopTurnSound:	db	C2,L3, STOP
BetSound:	db	E3,L2, STOP
RiskWinSound:	db	G4,L2, R,L2, C5,L3, STOP
RiskLostSound:	db	C4,L2, R,L2, G3,L2, STOP
TossSound:	db	E2,L2, STOP
TossWinSound:	db	C4,L2, E4,L2, A4,L2, STOP
TossLossSound:	db	A3,L2, E3,L2, C3,L2, STOP

; ----------------------------------------------------------------------------
;          Uninitialized data (60 KB area in place of VGA graphics)
; ----------------------------------------------------------------------------

SECTION		.bss

PC speaker je připojen na výstup 16-bitové programovatelné děličky o frekvenci 1.193182 MHz. Tabulka ToneTab obsahuje dělící konstanty pro jednotlivé tóny. Lze ji snadno vygenerovat např. programem Excel. Základem pro výpočet tónů je tón A4 s frekvencí 440 Hz. Oktávy mají vůči sobě dvojnásobnou frekvenci. Jedna oktáva je rozdělena na 12 pravidelných intervalů (půltónů) vzdálených od sebe o 2^(1/12) násobek (tj. asi 1.05946). V tabulce jsou připraveny frekvence pro 130 tónů, tj. téměř 10 oktáv.

Přehrávání melodie (zvuku) probíhá funkcí SoundInt, která je pravidelně volána z obsluhy přerušení Int08 jednou za 7 ms. Funkce přehrává melodii, na kterou ukazuje ukazatel v proměnné SoundNext. Melodie je seznam dvojic bajtů, ve kterých prvním bajtem je číslo tónu v rozsahu 1 až 130 (pro zjednodušení zápisu jsou na začátku souboru uvedeny symboly not), druhým bajtem je délka tónu v násobcích 7 ms (na začátku souboru jsou uvedeny symboly typických délek not). Tón s hodnotou 0 představuje prodlevu. Konec melodie je zakončen bajtem STOP (=255).

Obsluha přehrávání nejdříve testuje, zda se nějaká melodie přehrává (zda není ukazatel SoundNext nulový) a poté čítá čítač délky SoundLength. Po dosažení nulové hodnoty čítače se pokračuje načtením dalšího tónu. Je-li dalším bajtem STOP (hodnota 255), obnoví se ukazatel melodie z proměnné SoundRepeat, která zajišťuje opakování. Je-li její adresa 0, výstup na reproduktor se utlumí a přehrávání se ukončí. Má-li přehrávaný tón hodnotu 0, jedná se o pauzu, výstup se utlumí a pokračuje se načtením délky prodlevy. V ostatních případech se jedná o tón. Příslušná dělící konstanta se načte z tabulky ToneTab, nastaví se jí dělička generátoru tónu a povolí se výstup na reproduktor. Nakonec se načítá bajt délky tónu, jeho hodnota se uloží do proměnné SoundLength. Jak si můžete povšimnout v kódu, funkce neřeší opakované přehrávání melodie, obsahující pouze samotný kód STOP, taková "melodie" by způsobila zablokování programu.

Funkce StopRepeat zastaví opakování přehrávání melodie. Vynuluje proměnnou s adresou opakování melodie. Aktuálně přehrávaná melodie se přitom nepřeruší. Funkce StopSound zastaví okamžitě přehrávání zvuku. Ke skutečnému přerušení přehrávaného tónu však nedojde. Má-li být skutečně zastaven výstup na reproduktor, mělo by dojít k přehrátí melodie s obsahem "STOP". Funkce PlayRepeat zastaví přehrávání zvuku a zahájí opakované přehrávání zvuku. Čítač délky aktuálního tónu se nastaví na hodnotu 1, čímž se zajistí okamžitá nejbližší obsluha zahájení přehrávání melodie. Podobně funkce PlaySound zahájí přehrávání jedné melodie.

Přeložte a spusťte program. Během otáčení válců by mělo být slyšet vrčivý zvuk představující otáčení válců, po jejich zastavení by se měly ozývat tóny označující jejich zastavení. Běží-li program pod systémem Windows, může zvuk znít chrčivě.

Download zdrojového kódu obsluhy zvuku

Zpět na aplikaci VEGASLOT