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!