Sie ermöglicht fast ohne Prozessorlast mehrkanälige Musik und Soundeffekte.
Möglicherweise ist erst die Spitze des Eisbergs ihrer Fähigkeiten bekannt, und es gibt noch mehr Möglichkeiten zur Erzeugung von komplexeren und organischeren Klängen. Immerhin ist der Yamaha OPL-3 Chip in der Lage, Sprache zu synthetisieren, und das ist sehr komplex.
Hier habe ich mal grundlegende Ansteuerungsroutinen für Pascal in einer Unit zusammengetragen.
Mir war bisher nicht bewusst, dass die AdLib auch detektiert werden kann.
Ich habe alles in Assembler geschrieben, Parameter müssen den Prozeduren über Register übergeben werden, so wie das z.B. auch bei BIOS-Funktionen ist. Das hat technisch mehrere Vorteile.
Ich werde diese Unit noch weiterbauen und sie in einem AdLib Tracker (Musikprogramm) verwenden, den ich schreiben möchte, und der anders klingen wird als man es bisher von der AdLib gewohnt ist.
Code: Alles auswählen
Unit ADLIB;
(* Unit for accessing the AdLib Card *)
(* Version 1 by Zatzen 6 Jan 2022 *)
INTERFACE
Var
ADL_detected: ByteBool;
ADL_either_timer_exp: ByteBool;
ADL_timer1_exp: ByteBool;
ADL_timer2_exp: ByteBool;
Procedure AdLib_status;
Procedure AdLib_reset_Timers_and_INTs;
Procedure AdLib_detect;
Procedure AdLib_clear_registers;
IMPLEMENTATION
Procedure AdLib_status; ASSEMBLER;
ASM
MOV DX, 0388H
IN AL, DX
MOV ADL_either_timer_exp, AL
MOV ADL_timer1_exp, AL
MOV ADL_timer2_exp, AL
AND ADL_either_timer_exp, 10000000B
AND ADL_timer1_exp, 01000000B
AND ADL_timer2_exp, 00100000B
END;
Procedure AdLib_selectREG; ASSEMBLER;
(* AL: Number of Register *)
ASM
MOV DX, 0388H
OUT DX, AL
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
END;
Procedure AdLib_dataWRITE; ASSEMBLER;
(* AL: Value *)
ASM
MOV DX, 0389H
OUT DX, AL
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
IN AL, DX
(* 36x, unrolled to keep this as quick as possible *)
END;
Procedure AdLib_reset_Timers_and_INTs; ASSEMBLER;
(* Reset both timers and interrupts *)
ASM
(* Reset both timers by writing 60h to register 4 *)
MOV AL, 4
CALL AdLib_selectREG
MOV AL, 060H
CALL AdLib_dataWRITE
(* Enable the interrupts by writing 80h to register 4 *)
MOV AL, 080H
CALL AdLib_dataWRITE
END;
Procedure AdLib_detect; ASSEMBLER;
ASM
(* Reset both timers and interrupts *)
CALL AdLib_reset_Timers_and_INTs;
(* Read the status Register (port 388h. Store the result *)
DEC DX
IN AL, DX
MOV BH, AL
(* Write FFh to register 2 (Timer 1) *)
MOV AL, 2
CALL AdLib_selectREG
MOV AL, 0FFH
CALL AdLib_dataWRITE
(* Start timer 1 by writing 21h to register 4 *)
MOV AL, 4
CALL AdLib_selectREG
MOV AL, 021H
CALL AdLib_dataWRITE
(* Delay for at least 80 microseconds *)
MOV CX, 07FH
@LOOP:
IN AL, DX
LOOP @LOOP
(* Read the status register (port 388h). Store the result *)
DEC DX
IN AL, DX
MOV BL, AL
(* Reset both timers and interrupts *)
CALL AdLib_reset_Timers_and_INTs;
(* Test the stored results by ANDing them with E0h. *)
AND BX, 0E0E0H
(* BH should be 0, BL should be C0H *)
(* AL = 0 if no AdLib detected, AL = 1 if AdLib detected *)
XOR AL, AL
CMP BX, 0C0H
JNE @SKIP
INC AL
@SKIP:
MOV ADL_detected, AL
END;
Procedure AdLib_clear_registers; ASSEMBLER;
ASM
MOV CX, 0F5H
@LOOP:
MOV AL, CL
CALL AdLib_selectREG
XOR AL, AL
CALL AdLib_dataWRITE
DEC CX
JNZ @LOOP
END;
begin
end.
(* Thanks to Jeffrey S. Lee for his Documentation *)
(* "Programming the AdLib/Sound Blaster FM Music Chips" *)
(* Version 2.1 (24 Feb 1992) *)
(* http://www.shipbrook.net/jeff/sb.html *)