AdLib Programmierung

Diskussion zum Thema Programmierung unter DOS (Intel x86)
Antworten
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

AdLib Programmierung

Beitrag von zatzen »

Die AdLib Karte ist praktisch das, was für den Amiga der Paula Chip und für den C64 der SID ist.
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 *)
mov ax, 13h
int 10h

while vorne_frei do vor;
Benutzeravatar
b20a9
BIOS-Flasher
Beiträge: 382
Registriert: Mi 16. Apr 2014, 23:54
Kontaktdaten:

Re: AdLib Programmierung

Beitrag von b20a9 »

Hallo Zatzen, ich verstehe leider nichts vom Programmieren, bin aber dafür ein um so größer FM-musik fan:-) Bin sehr gespannt, was du dem YM3812/YM-262 noch entlocken kannst und würde mich freuen, wenn du uns über deine Fortschritte hier auf dem Laufenden hältst. Ich denke auch, das die Fähigkeiten des Synths bei weitem nicht ausgenutzt wurden, was mich aber aufgrund der anspruchsvollen Programmierung wohl auch nicht weiter verwundert. Nicht jeder Musiker ist auch Programmierer und umgekehrt. Persönlich bin ich ein großer Fan von Hannes Seiferts Stücken, und sein Tracker war damals glaube ich auch Wegweisend. Aber wie gesagt ich bin nur Konsument und nicht Creator was das angeht:-) Viel Erfolg!
Acer AcerMate 386SX 33, Cyrix FasMath FPU, 6MB RAM, 3Com Etherlink Mit XT-IDE, Miro PCM1 Pro, 1GB Transcent Industrial CF
Benutzeravatar
Thomas
DOS-Kenner
Beiträge: 426
Registriert: Mi 22. Jun 2016, 12:29
Wohnort: Nähe von Limburg / Lahn

Re: AdLib Programmierung

Beitrag von Thomas »

Moin Zatzen.
Coole Idee mit so einer Unit. So ähnlich hatten wir 2 dass ja schonmal, als du den Beni Tracker für mich nach Pascal portiert hattest.
Kleine Korrektur: Der OPL3 kann keine Sprache synthetisieren, der OPL2 konnte das mit seinem CSM (Composite Speech Mode), wurde aber praktisch nie genutzt da er alle verfügbaren Operatoren nutzt und dann keine mehr für z.B. Musik zur Verfügungen stehen (Hypothese). Vermutlich wurde deshalb CSM beim OPL3 weggelassen.

Gruß,

Thomas
Ein bisschen DOS kann oft mehr als ein Haufen Fenster.

Gigabyte GA-586HX, P54C 100@75MHz, 24MB RAM, AVGA3-22-1M ISA, RTL8029AS PCI, Goldstar Prime 2 ISA, MA5ASOUND, Dreambl. X2 DB, HD 4x2GB, 48x CD, 3,5" Floppy, 2xRS232, 1xPar., PS/2 Maus
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: AdLib Programmierung

Beitrag von zatzen »

Hallo Thomas!

Bzgl. Sprache Synthetisieren dachte ich an den Soundblaster Pro, der das konnte, z.B. in dem Pseudo-KI Programm "Dr. Sbaitso". Und genau, da werden wohl alle Kanäle gewissermaßen zusammengeschaltet, nur für diesen einen Zweck.
Es kann natürlich sein, dass eine AdLib das nicht kann.

Ansonsten kann man bei einer Adlib Digitalsound ausgeben, indem man z.B. eine simple Sinuswelle auf einem Kanal konfiguriert, diese kurz anspielt und die Frequenz genau dann auf null schaltet, wenn die Halbwelle ihr maximum hat.
Dann kann man über den Dämpfungsparameter die Amplitude modulieren. Jedenfalls habe ich das Vorgehen so in Erinnerung.
Es erfordert natürlich ständige Eingriffe über einen getimeten Interrupt, und fordert entsprechende Opfer bei der Rechenperformance.
mov ax, 13h
int 10h

while vorne_frei do vor;
Antworten