Czy nie my¶licie czasem, jakby to by³o, gdyby mo¿na by³o wzbogaciæ swój program oprócz efektu wizualnego, tak¿e o efekt d¼wiêkowy?
Programowanie kart d¼wiêkowych (zw³aszcza tych nowoczesnych) mo¿e sprawiaæ niema³e k³opoty. Stary, poczciwy PC-Speaker jest jednak urz±dzeniem wzglêdnie prostym w programowaniu i to w³a¶nie tutaj udowodniê. Najpierw troszkê teorii, potem - do dzie³a!
Linux jest systemem dzia³aj±cym w pe³ni w trybie chronionym. Dlatego bez uprawnieñ administratora nie mo¿emy bezpo¶rednio pisaæ do interesuj±cych nas portów (42h, 43h, 61h).
Na szczê¶cie istnieje funkcja systemowa sys_ioctl (numer 54) i to ona nam pomo¿e w o¿ywieniu g³o¶niczka systemowego. Funkcja ta jako parametry przyjmuje:
Ale to nie wszystko. Chcemy, by nasz d¼wiêk chwilê potrwa³. W tym celu skorzystamy z funkcji sys_nanosleep (numer 162). Jej sk³adnia jest prosta:
struc timespec
{
.tv_sec rd 1
.tv_nsec rd 1
}
i zawieraj±cej wpisane ilo¶ci sekund i nanosekund, które nale¿y odczekaæ.Jak widaæ schemat dzia³ania naszego programu jest do¶æ prosty:
Przyk³adowy program wygl±da tak (u¿ywanie za³±czników z mojej biblioteki nie jest konieczne - w kodzie mówiê, jak i co zamieniæ):
; Program wytwarzaj±cy d¼wiêki z g³o¶niczka przez sys_ioctl
; Autor: Bogdan D.
; Kontakt: bogdandr (at) op (dot) pl
;
; kompilacja:
; fasm spkr.asm spkr
format ELF executable
entry _start
segment readable executable
include "bibl/incl/linuxbsd/fasm/fasm_system.inc"
KIOCSOUND = 0x4B2F
_start:
mov eax, sys_open ; sys_open = 5
mov ebx, konsola
mov ecx, O_WRONLY ; O_WRONLY = 1
mov edx, 777o
int 80h
cmp eax, 0 ; czy wyst±pi³ b³±d (EAX < 0) ?
jg .otw_ok
mov eax, 1 ; jak nie otworzyli¶my konsoli, piszemy
; na STDOUT (1)
.otw_ok:
mov ebx, eax ; EBX = uchwyt do pliku
mov eax, sys_ioctl ; sys_ioctl = 54
mov ecx, KIOCSOUND
xor edx, edx ; wy³±czenie ewentualnych d¼wiêków
int 80h
mov eax, sys_ioctl
mov edx, 2711 ; 2711 = 1234DDh/440. 440 Hz to d¼wiêk A
int 80h
mov cx, 0fh
mov dx, 4240h ; 0F4240h to 1 milion dziesiêtnie
call pauza
mov eax, sys_ioctl
mov ecx, KIOCSOUND
xor edx, edx ; wy³±czamy d¼wiêk
int 80h
cmp ebx, 2 ; sprawdzamy, czy u¿ywamy /dev/console
; czy STDOUT
jbe .koniec
mov eax, sys_close ; sys_close = 6
int 80h ; zamykamy otwarty plik konsoli
.koniec:
mov eax, 1
xor ebx, ebx
int 80h
pauza: ;procedura pauzuj±ca przez CX:DX milisekund
push ebx
push ecx
push edx
mov ax, cx
shl eax, 16
mov ebx, 1000000
mov ax, dx ; EAX = CX:DX
xor edx, edx
div ebx ; CX:DX dzielimy przez milion
mov [t1.tv_sec], eax ; EAX = liczba sekund
mov ebx, 1000
mov eax, edx ;EAX = pozosta³a liczba mikrosekund
mul ebx
mov [t1.tv_nsec], eax ; EAX = liczba nanosekund
mov eax, sys_nanosleep ; funkcja numer 162
mov ebx, t1
mov ecx, t2
int 80h
pop edx
pop ecx
pop ebx
ret
segment readable writeable
konsola db "/dev/console", 0
struc timespec
{
.tv_sec rd 1
.tv_nsec rd 1
}
t1 timespec
t2 timespec
Mam nadziejê, ¿e poda³em wystarczaj±co informacji, aby¶cie samodzielnie zaczêli programowaæ g³o¶niczek. Je¶li mi siê nie uda³o, to zawsze mo¿ecie skorzystaæ z gotowej procedury z mojej biblioteki.
Je¶li program nie powoduje wydawania ¿adnych d¼wiêków, mo¿e trzeba wkompilowaæ obs³ugê g³o¶niczka do j±dra (lub za³adowaæ odpowiedni modu³). Czasem mog± byæ potrzebne uprawnienia administratora.
To ju¿ koniec. Mi³ej zabawy!