Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Diskussion zum Thema Programmierung unter DOS (Intel x86)
Antworten
Benutzeravatar
Thomas
DOS-Kenner
Beiträge: 426
Registriert: Mi 22. Jun 2016, 12:29
Wohnort: Nähe von Limburg / Lahn

Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von Thomas »

Guten Morgen, liebe Forengemeinde.

Ich habe von Mitte/Ende 2017 bis Weihnachten 2019 (mit längeren Unterbrechungen) einen 2D horizontal scrollenden Space-Arcade Shooter im R-Type Stil programmiert.
Seit 2017 programmiere ich auch richtig. Das bisschen Schulpascal bleibt hier Mal außen vor.
Sprache meiner Wahl war BASIC da ein Kumpel mit mir damals kleinere Games und GUIs entwickelt hat. Er Programmierung und Musik, ich Grafik und SFX. Auch ohne es zu können war ich dadurch ja schon mit BASIC vorbelastet. Und seien wir mal ehrlich, es ist schon allein durch die ausgezeichnete online Hilfe sehr einfach zu erlernen.
Zurück zu mir: Durch ausgiebiges Webstudium waren meine ersten Gehversuche in BASIC das Kopieren von Disketten, sowohl in einer Kommandozeilenversion ala diskcopy als auch in Screen 9 mit Pseudografikoberfläche. Anschließend beschäftigte ich mich mit dem Tutorial zum Auslesen von Bootsektoren auf der Homepage von Andre Klein und mit den DOS/BIOS Interrupts so dass am Ende tatsächlich ein funktionierendes Formatierungsprogramm heraus kam.
Dann kam die Idee zu einem Spiel. Nach weiterem belesen, überwiegend auf der Seite von Thomas Antoni, stieß ich auf drei hervorragende Game Libs für Quickbasic. DirectQB, FutureLib und die UGL. Aus Bequemlichkeitsgründen entschied ich mich für die ausgezeichnet dokumentierte DirectQB denn mein Spiel sollte absolut retro werden also war die 320x200x256 Auflösung keine Beschränkung, sondern Ideal. Nach ersten erfolgreichen Grafik- und DigiSound Versuchen stand die Frage nach der Musik in Raum.
Midis mit QMidi? Nein. Der FM Sound ist absolut grottig und es muss ein Creative Treiber geladen werden was bei mir aus unerfindlichen Gründen nicht per SHELL "" funktionierte. Dann stieß ich auf ein Basic Modul welches HSC Tracker Files abspielen kann. Hier scheiterte es dann aber leider an der Erstellung der Musicfiles. Irgendwann fiel mir dann der Beni Tracker in die Hände. Perfekt. Einfach zu bedienender Editor und ein Player Modul welches nur als Modul im Main-Programm geladen werden muss. Würde sich seine EMS Routine nicht mit DirectQB beißen.
Nun packte mich der Ehrgeiz. Die Player Routine so umgestrickt dass sie die EMS Funktionen von DirectQB nutzt. Voller Erfolg. Weitere Funktionen Ergänzt: Pseudostereo per zeitverzögerter Ausgabe der selben Note je Links und Rechts. Eigentlich mehr Echo als Stereo. Dokumentation zum OPL3 gewälzt, Routine auf echtes Stereo umgebaut. Dabei Kanal 1 und 3 hart links, 2 und 4 hart rechts, die restlichen 5 auf beiden. Super. Als nächstes dann, sofern von der Soundkarte unterstützt, OPL3 in den OPL3 Modus geschaltet um an die zusätzlichen 4 Wellenformen zu kommen. Naja, die Umschaltung eigentlich schon vorher programmiert, die braucht man ja auch für Stereo. Alles in allem habe ich jetzt FM Tracker Module mit 9 Kanälen, Stereo und 8 Wellenformen. Quasi ein Virtual OPL3 Mode. 4OP Sound war für mich nicht unbedingt erforderlich und zugegebener Maßen dann auch zu kompliziert.
Wie dem auch sei. Das Game hat nun ein einfaches Intro, einen Titelbildschirm, einen ersten Level und einen Abspann wenn gewonnen.
Als ich nun daran ging alle Files in ein großes Datafile zu packen, welches komprimiert und verschlüsselt, warf mir meine IDE nach zwei bis drei Zeilen neuen Codes, Fehlermeldungen an den Kopf. Meistens "Platz für Stringspeicher nicht ausreichend"
Jetzt kam mir die Idee alles auf Pascal zu übertragen. Dazu hatte ich auch schon ein Interessantes Gespräch mit Zatzen im Thread Probleme mit VRetrace. Da ich das aber nicht mit meinem Anliegen zu Texten möchte, mache ich hier Mal einen neuen Thread auf.
Als erstes hatte ich Mal probiert die ASM Quellen von DirectQB für Pascal zu assemeblieren. Irgendwie dachte ich mir aber schon dass es nicht nur durch das ersetzen des Schlüsselwortes Basic mit Pascal getan sei. Ich vermute ich muss mindestens noch das Memorymodell anpassen. DQB verwendet hier Medium für Basic. Was aber braucht man für Pascal?
Laut eines Tutorials wäre es large. Auch das Copy/Paste aus den sourcen in den Inlineassembler geht (natürlich?) nicht.
Kennt sich hier jemand mit solch einer Portierung aus?
Momentan arbeite ich an einer eigenen Unit from Scratch. Die kann bis jetzt nicht viel. Screenmodus 3 (0 in (BASIC) und 13 setzen, einen Pixel in 13 setzen, EMS und XMS Speicher reservieren und freigeben. Alles via Inlineassembler.
Gut, eine Circle und Box Funktion ist jetzt auch nicht mehr schwer. Die dann allerdings in native Pascal über meine Pset Funktion.
Circle und Box laufen jetzt auch und Locate sowie drei verschiedene Print Funktionen (normal, mit absoluter Zeile-/Spaltenangabe und Buchstabe für Buchstabe) für den Textmode habe ich auch noch geschrieben.
Liebe Grüße,
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
GMBigB
Norton Commander
Beiträge: 141
Registriert: Fr 5. Mär 2010, 13:30

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von GMBigB »

Also zunächst mal: direkt helfen kann ich dir leider nicht. Aber ich kenne deine Probleme - die hatte ich auch mal so vor gefühlt 25 Jahren. QuickBasic ist toll, aber sobald mal diverse Librarys einbindet, ist der Speicher schnell verbraucht. DirectQB kenne ich sogar - fand aber damals die FutureLib besser. Mit Pascal kenne ich mich leider gar nicht aus.

Weshalb ich antworte: kennst du FreeBasic? Das ist zu 99% QuickBasic-kompatibel und erzeugt 32-Bit Anwendungen für DOS. Du hast also keine Speicherprobleme mehr. Als Game Library empfiehlt sich dann Allegro. Für den Sound gibt es DUMB oder MikMod. Was man benötigt, sind entsprechende Header-Files, die dann in FreeBasic eingebunden werden. Für Allegro sind die verfügbar, für DUMB und MikMod nicht, aber ich glaube, da würdest du im (sehr aktiven) FreeBasic-Forum Hilfe bekommen. Es würde mich auch nicht wundern, wenn es da ein Tool gibt, dass aus C-Header-Dateien die entsprechende .BI-Datei für FreeBasic generiert.
Benutzeravatar
Thomas
DOS-Kenner
Beiträge: 426
Registriert: Mi 22. Jun 2016, 12:29
Wohnort: Nähe von Limburg / Lahn

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von Thomas »

Hi, vielen Dank für Deine Hilfe!
Darf ich fragen warum du die FutLib besser fandest? Interessiert mich einfach mal. Am Anfang meines Game(chens) hatte ich nämlich zwischen der, DQB und der UGL hin und her überlegt.
Die FutureLib kann halt auch noch XMS.
Denke aber auch nicht dass die mein Speicherproblem löst. Bei DQB habe ich ja noch den Vorteil dass ich für gewisse Sprites und die Hintergründe keine Arrays belegen muss da die in den EMS ausgelagert werden.

Allegro habe ich. Allerdings noch nicht probiert. Wie muss ich die denn kompilieren dass sie zB mit FB läuft? Oder noch besser, kann ich die für Pascal kompilieren?

FreeBasic habe ich mir Mal kurz angesehen aber nie probiert da ich dachte dass man damit nur für Windows proggen könne. Das das auch DOS Progs erstellt wusste ich gar nicht :-O
Die Header Dateien in das passende Basic Format zu konvertieren dürfte kein Problem sein. In beide Syntaxen kann ich mich einlesen und die FreeBasic .Bi sollten sich ja nicht ZU sehr von den Quickies unterscheiden.
Aber wie ist das denn, wenn Du sagst, erstellt 32Bit Programme für DOS? Muss ich dann nicht im Protected Mode coden?
:???:
Das kann ich nicht. Ich bin bei weitem kein semi-Profi. Wie gesagt, 2017 von Null angefangen mit BASIC und jetzt seit kurzem Pascal und minimal ASM.
Derzeit schreibe ich den FM Player den ich in meinem Game verwendet habe in Pascal um aber ich denke so einfach ist das nicht. Allein die Tatsache dass Pascal kein ELSEIF kennt (Kann man noch umgehen) und bei Case keine Vergleiche möglich sind.
Aber ich gebe nicht auf, dafür macht es viel zu viel Spaß :-D
Sollte der Player dann irgendwann laufen musste ich noch herausknobeln wie ich den Timer Interrupt abfragen kann damit alles im Hintergrund läuft. Sprich: On Timer ... Gosub/Return und Timer On ersetzen. Was das Playermodul macht: Zunächst wird der Timer umprogrammiert auf 50hz. Dann wird über die Basic Timer Funktion nach jeder Anweisung geprüft ob eine Einheit des Timers verstrichen ist, also 50 Mal pro Sekunde und das Modul springt in den Hauptteil und dudelt das Mod.

Naja, ich probiere erstmal weiter. Mit dem "Böhmischen Dorf" Assembler hat es ja auch schon ganz gut geklappt. Push, Pop, Mov, Out/In und Int kein Problem. Das kam sogar mit der Erkenntnis, hey, ist ja gar nicht so schwer. Allerdings mit dem Timer schon wieder ganz anders... Da habe ich einige Tutorials und Beispiele zu gefunden aber irgendwie verstehe ich das noch nicht Recht. Wie weiß denn jetzt mein Pas Proggi dass es nach jeder Anweisung prüfen soll wie der Timer steht und wenn ein gewisser wert I erreicht ist, dass es eine Marke anspringen soll?
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
GMBigB
Norton Commander
Beiträge: 141
Registriert: Fr 5. Mär 2010, 13:30

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von GMBigB »

Thomas hat geschrieben:Hi, vielen Dank für Deine Hilfe!
Darf ich fragen warum du die FutLib besser fandest? Interessiert mich einfach mal. Am Anfang meines Game(chens) hatte ich nämlich zwischen der, DQB und der UGL hin und her überlegt.
Die FutureLib kann halt auch noch XMS.
Denke aber auch nicht dass die mein Speicherproblem löst. Bei DQB habe ich ja noch den Vorteil dass ich für gewisse Sprites und die Hintergründe keine Arrays belegen muss da die in den EMS ausgelagert werden.
Das ganze ist 20 Jahre her... ich habe echt keine Ahnung mehr. Die FutureLib hatte einen sehr guten VESA-Support. Man konnte hochauflösende Modi setzen. An was ich mich noch erinnere, war das AntiAliasing für Lines und Primitives. Das sah schon echt hübsch aus damals.
Thomas hat geschrieben: Allegro habe ich. Allerdings noch nicht probiert. Wie muss ich die denn kompilieren dass sie zB mit FB läuft? Oder noch besser, kann ich die für Pascal kompilieren?
Du kannst ein vorkompiliertes Allegro verwenden. FreeBasic nutzt die GCC Toolchain und kann C-Bibliotheken einfach einbinden. Du brauchst nur eine Freebasic-Header-Datei, damit der Compiler weiß, welche Funktionen die Bibliothek bereitstellt. Mit Pascal kenne ich mich nicht aus - keine Ahnung wie da die Schnittstelle für externe Bibliotheken aussieht.
Thomas hat geschrieben: FreeBasic habe ich mir Mal kurz angesehen aber nie probiert da ich dachte dass man damit nur für Windows proggen könne. Das das auch DOS Progs erstellt wusste ich gar nicht :-O
Die Header Dateien in das passende Basic Format zu konvertieren dürfte kein Problem sein. In beide Syntaxen kann ich mich einlesen und die FreeBasic .Bi sollten sich ja nicht ZU sehr von den Quickies unterscheiden.
Aber wie ist das denn, wenn Du sagst, erstellt 32Bit Programme für DOS? Muss ich dann nicht im Protected Mode coden?
:???:
Das kann ich nicht. Ich bin bei weitem kein semi-Profi. Wie gesagt, 2017 von Null angefangen mit BASIC und jetzt seit kurzem Pascal und minimal ASM.
FreeBasic erzeugt Programme, die im Protected Mode laufen, aber das braucht dich ja nicht zu kümmern. Du kannst ganz normal programmieren. Auch der Inline-Assembler funktioniert wie gewohnt. Du kannst halt nur keine Interrupts auslösen, also z.B. so Geschichten wie "mov ax,13" mit anschließendem "int 10h" um in den Mode 13 zu gehen (320x200x256). Dazu muss man vorher zurück in den RealMode schalten. Ich weiß nicht, ob FreeBasic da eine Schnittstelle bietet, aber ich glaube das ist zunächst nicht wichtig für dich. Allegro stellt ja alles für Grafik, I/O und Filehandling zur Verfügung. Timer kann man auch setzen. Für den Otto-Normal-Entwickler gibt es eigentlich keinen Grund noch Interrupts auszulösen.
Benutzeravatar
Thomas
DOS-Kenner
Beiträge: 426
Registriert: Mi 22. Jun 2016, 12:29
Wohnort: Nähe von Limburg / Lahn

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von Thomas »

GMBigB hat geschrieben:
Das ganze ist 20 Jahre her... ich habe echt keine Ahnung mehr. Die FutureLib hatte einen sehr guten VESA-Support. Man konnte hochauflösende Modi setzen. An was ich mich noch erinnere, war das AntiAliasing für Lines und Primitives. Das sah schon echt hübsch aus damals.
Ok, nachvollziehbar. Aber Vesa möchte ich für meine Projekte ja nicht.
GMBigB hat geschrieben: Du kannst ein vorkompiliertes Allegro verwenden. FreeBasic nutzt die GCC Toolchain und kann C-Bibliotheken einfach einbinden. Du brauchst nur eine Freebasic-Header-Datei, damit der Compiler weiß, welche Funktionen die Bibliothek bereitstellt. Mit Pascal kenne ich mich nicht aus - keine Ahnung wie da die Schnittstelle für externe Bibliotheken aussieht.
Bei Pascal kann man kompilierte C und ASM Bibliotheken als Objekt Dateien einbinden. Im Programm macht man dann wie in BASIC auch die Prozeduren und Funktionen bekannt wie sie in der Bibliothek definiert sind. Oder alternativ eben auch mit Includes/Header Dateien.
GMBigB hat geschrieben: FreeBasic erzeugt Programme, die im Protected Mode laufen, aber das braucht dich ja nicht zu kümmern. Du kannst ganz normal programmieren. Auch der Inline-Assembler funktioniert wie gewohnt. Du kannst halt nur keine Interrupts auslösen, also z.B. so Geschichten wie "mov ax,13" mit anschließendem "int 10h" um in den Mode 13 zu gehen (320x200x256). Dazu muss man vorher zurück in den RealMode schalten. Ich weiß nicht, ob FreeBasic da eine Schnittstelle bietet, aber ich glaube das ist zunächst nicht wichtig für dich. Allegro stellt ja alles für Grafik, I/O und Filehandling zur Verfügung. Timer kann man auch setzen. Für den Otto-Normal-Entwickler gibt es eigentlich keinen Grund noch Interrupts auszulösen.
Hmm, ok. Pascal kann auch Programme für den PM erzeugen aber dennoch muss man den PM kennen und entsprechend die Eigenheiten beachten.

Joa, für mein Game brauche ich keine Interrupt Aufrufe. Werde mir das Mal näher ansehen.
Und als Otto Normalentwickler würde ich mich auch nicht bezeichnen. Nicht einmal als richtiger Entwickler. Gerade das altbackene wie Interupts macht ja so Spaß dabei. Ich progge ja von einem gewissen Retrostandpunkt aus und wollte auch gern im RealMode bleiben. Naja, genauer im V386 Mode.

Vielen Dank für Deine Tipps.
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: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von zatzen »

Hallo!

Ich habe mich gerade mal über dieses ELSEIF informiert.
Ich zititiere mal den Beispielcode aus der Erklärung:

Code: Alles auswählen

IF condition-1 THEN
  branch-1
ELSEIF condition-2 THEN
  branch-2
ELSEIF condition-3 THEN
  branch-3
. . .

ELSEIF condition-n THEN
  branch-n
ELSE
  else-branch
END IF
Da ist beschrieben, dass die Konditionen alle nacheinander geprüft werden.
Pascal hat zwar kein ELSEIF als Begriff, aber man kann es einfach so formulieren:

Code: Alles auswählen

if condition-1 then
begin
  branch-1
end
else if condition-2 then
begin
  branch-2
end
...
else if condition-n then
begin
  branch-n
end
else
begin
  else-branch
end;
begin/end ist hier nur nötig wenn "branch" mehrere Zeilen bzw. Kommandos umfasst.
Wenn es zeitkritisch ist sollte man längere Entscheidungszweige aber lieber nicht mit IF-Kaskaden lösen (da alles nacheinander durchgeprüft wird bis eine Condition passt) sondern über eine Sprungtabelle, mittels Assembler. Das kann ich bei Interesse näher erläutern. Es kommt allerdings auf die Art der Bedingungen an, ob das mit einer Sprungtabelle machbar ist.

Wenn Du tatsächlich nur im Real Mode programmieren willst hast Du mit Pascal (mit integriertem Assembler) unmittelbaren und unkomplizierten Zugriff darauf, so jedenfalls mein Eindruck. Das kann aber auch daran liegen dass ich auf Pascal umgestiegen bin bevor ich in QuickBASIC fortgeschrittenere Dinge gemacht habe.
mov ax, 13h
int 10h

while vorne_frei do vor;
Benutzeravatar
Thomas
DOS-Kenner
Beiträge: 426
Registriert: Mi 22. Jun 2016, 12:29
Wohnort: Nähe von Limburg / Lahn

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von Thomas »

Danke für die Hilfe, Zatzen.

Ja, so wie Du es beschreibst habe ich es ja auch gemacht in Pascal. War halt nur so ein erster Gedanke das elseif was anderes ist als else if in Pascal. Dann kann ich ja das schonmal als Fehlerquelle ausschließen.
Wobei ich gerade überlege, elseif wird ja nur mit einem anderen Komperator überprüft wenn die Überprüfung des vorherigen Komperators false ergeben hat.
Könnte man da nicht gänzlich auf Else verzichten und riesige Nested IFs bauen?
Ach nee, beim Schreiben kam mir direkt der Denkfehler: Das ginge ja nur wenn die vorherige Bedingung = true ist.
Ah, da fällt mir gerade noch eine wichtige Frage zu ein:
Im original Basic Quellcode des players werden normale Datenvariablen oft auf true überprüft ala

Code: Alles auswählen

IF eh THEN
Das heißt aber doch jetzt nichts anderes als

Code: Alles auswählen

IF eh = -1 THEN
oder?
Denn so habe ich es in Pascal geschrieben da Pascal das so ja nicht unterstützt.
Also statt

Code: Alles auswählen

IF eh THEN
habe ich

Code: Alles auswählen

IF eh = -1 THEN
geschrieben.
Welche Werte entsprechen denn in Pascal false und true? Auch -1 = true und <> -1 = false?
Per Google hab ich es nicht herausgefunden. Vielleicht suche ich aber auch falsch.[/s]

Neues Update zu den IFs: Manchmal sieht man ja den Wald vor lauter Bäumen nicht, sucht an der falschen Stelle nach der falschen Ursache oder ist einfach zu faul oder zu dämlich. Ich hätte mir gleich einmal die Mühe machen sollen, die Variablen genau zu analysieren, dann wäre mir sicher aufgefallen, das zB die Anzahl der Pattern nicht negativ sein kann. Ebenso sollte sie auch nicht null sein. Ergo:
BASICs Statement

Code: Alles auswählen

IF eh THEN
übersetzt sich in Pascal dann so:

Code: Alles auswählen

If eh > 0 Then
Manchmal scheint es doch zu simpel um gleich darauf zu kommen!

Weitere Bug Vermutungen: Beim Öffnen des MODs wird falsch eingelesen. Komisch ist nämlich dass überhaupt kein Ton kommt. Nichteinmal Müll.

Die Register- und Wertausgabe an den Chip schliese ich aus. Das sind nur 6 Zeilen.

Code: Alles auswählen

SUB opl.out (reg%, vlu%)
DEFINT A-Z
Out &H388, reg
a = INP &H388
OUT &H389, vlu
a = INP &H388
a = INP &H388
a = INP &H388
END SUB
Draus gemacht habe ich in Pascal:

Code: Alles auswählen

Procedure OPL_Out (Register, Value: Byte);
Var InpBuf: Byte;

Begin
       Port [$388] := Register;
       For I := 1 To 6 Do InpBuf := Port [$388];	{Wartezeit nach RegWrite, bei OPL3 eigentlich nicht mehr nötig}
       Port [$389] := Value;
       For I := 1 To 36 Do InpBuf := Port [$388];	{Wartezeit nach DataWrite}
End;
Auch mit WORD Variablen und PortW kein erfolg.
Aber da dürfte nun wirklich kein Fehler drin stecken oder?

Weitere Vermutung: Die vier EMS Routinen die von und zu EMS kopieren. Die Songdaten werden im EMS abgelegt.

Ich prüfe erstmal die Laderoutine zum Song laden. Den code poste ich später. Muss jetzt erstmal weg.

So, hier nun noch die Laderoutine in original BASIC und was ich daraus gemacht habe:

Code: Alles auswählen

FUNCTION readb (fh)		'fh ist die Dateinummer aus der LoadMOD Routine. Die Datei wird dort als BINARY ACCESS READ geöffnet.
	b$ = CHR$(0)
	GET fh, , b$
	readb = ASC(b$)
END FUNCTION
Ich verstehe noch nicht wirklich was er da genau macht. Ich versuche mal zu interpretieren: b$ wird zunächst mit 256 Nullen gefüllt, also gelöscht/initialisiert. Dann wird ein Byte aus der Datei gelesen und in B$ gespeichert. Der Rückgabewert der Funktion wird zum ASCII Code des eingelesenen (Zeichen-)Bytes. Als zB liest die Funktion aus der Datei "║" ist die Rückgabe der Funktion = 186.

In Pascal habe ich es dann so implementiert:

Code: Alles auswählen

Function Readb: Word;
Var 	B		: Char;
	BRead	: Integer;
	AscCod	: Byte;	
	
Begin
	B := Chr(0);
	BlockRead (FileVar, B, 1, BRead);	{FileVar ist die FileVariable, B siehe oben, nur ein record (Byte) lesen und BRead ist auch klar, oder?}
	If BRead = 0 Then Exit;			{Nix eingelesen? Dann raus!}
	AscCod := Ord(B);				{ASCII Code des eingelesenen Zeichens holen}
	Readb := AscCod;				{Wert dem Rückgabewert der Funktion zuweisen}
End;
Dass Assign und Reset Gedönse:

Code: Alles auswählen

Assign (FileVar, SongFile);		{FileVar vom Typ File, klar! Sollte es typisiert sein mit File of Char? SongFile Dateiname als String}
Reset (FileVar, 1)			{Öffnen zum nur lesen mit RecordSize 1 (Byte?)}
Im original Code werden dann Variablen und Arrays mit den Werten aus der Datei gefüllt und in den EMS "gepoked":

Code: Alles auswählen

SUB loadmod (filenm$)
OPEN filenm$ FOR BINARY ACCESS READ AS #1
.
.
.
DIM ptnmap(0 TO nptns - 1)		{Temporäres Array da in SUB deklariert, oder?}
FOR a = 0 TO nptns - 1
	ptnmap(a) = readb(1)
NEXT a
.
.
.
END SUB
[/s]
So, das soll es ersteinmal gewesen sein.
Zuletzt geändert von Thomas am So 22. Jan 2023, 15:10, insgesamt 3-mal geändert.
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
Thomas
DOS-Kenner
Beiträge: 426
Registriert: Mi 22. Jun 2016, 12:29
Wohnort: Nähe von Limburg / Lahn

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von Thomas »

Update:

Die Laderoutine kann ich auschliessen (FUNCTION readb), die läuft. Geprüft über die Ausgabe sowohl des ASCII-Zeichens als auch des -Codes
Sprich, sie gibt zurück was sie soll.
Beim EMS bin ich nicht sicher. Im BASIC Source ist es so, das die Songdaten in den EMS Pageframe gepoked werden:

Code: Alles auswählen

DEF SEG = emsseg
.
.
.
FOR row = 0 TO 63	'Die Zeilen im Pattern
	b1 = readb(1)
	b2 = readb(1)
	el = readb(1)
	n = b1 \ 16
	o = (b1 \ 2] AND 7
	i = (16 * (b1 AND 1)) OR (b2 \ 16)
	eh = b2 AND 15
	POKE ofs, n: ofs = ofs +1	'wofür die Variablen stehen kann ich nur raten: n = Notenwert?
	POKE ofs, o: ofs = ofs +1	'o = ???
	POKE ofs, i: ofs = ofs +1	'i = Instrument?
	POKE ofs, eh: ofs = ofs +1	'eh = Effekt high?
	POKE ofs, el: ofs = ofs +1	'el Effekt low?
NEXT row
.
.
.
DEF SEG
Jetzt konkret zu POKE:
Wäre die erste POKE Zeile in Pascal so richtig?

Code: Alles auswählen

.
.
.
MemW [EMSSeg:Ofs]:=N; Inc(Ofs);
.
.
.
Und dann noch eine weitere Frage zu einer Basic eigenheit:
Im original Code ist an der selben Stelle wie im obigen Ausschnitt weiter oben ofs so definiert:

Code: Alles auswählen

.
.
.
FOR a = 0 TO nptns - 1
	ptn = ptnmap(a)
	ofs = 320& * ptn
.
.
.
NEXT a
Was bedeutet in BASIC ganz speziell dieses kaufmännische und (&) hinter der 320? Ich habe es mit und ohne PRINTen lassen und die Werte waren gleich... & steht ja normal für einen LongInt, als welcher ofs auch geDIMt ist.
Muss ich in Pascal nun so vorgehen:

Code: Alles auswählen

.
.
.
Ofs := LongInt(320) * Ptn;
.
.
.
Oder einfach nur 320 schreiben?

Ja, Fragen über Fragen. Bitte entschuldigt, ich schaffe mich da völlig ohne Fachliteratur hinein weil ich mir diese nicht leisten kann und will. Es ist nur ein Hobby und auf dicke Wälzer für 40€ das Stück wollte ich eigentlich verzichten.
Nun möchte ich auch keine fertigen Lösungen präsentiert bekommen sondern lediglich Tipps und Hinweise wie "Informier dich mal zu dem Befehl BlaXY" zB.

Wenn ich in der Zwischenzeit etwas selber herausfinde, teile ich das selbstredend hier mit.

Ach und noch etwas:
Bitte keine Antworten ala "Warum quälst Du dich damit ab?" Oder "Wer proggt denn heutzutage noch unter DOS und noch dazu im RealMode?"
Antwort: Weil ich es will!
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: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von zatzen »

Ersteinmal zu Deinem ersten folgenden Post:
Man kann auch schreiben

if boolean(eh) then ...

Wie man's eben lieber mag.


In Deiner Pascal OPL Routine fällt mir auf, dass I nicht definiert ist. Wenn die Routine funktioniert, dann nur weil außerhalb der Routine eine Variable I definiert ist, aber an der schraubt die Subroutine dann eben global rum, vielleicht führt das zu Fehlverhalten. Du kannst I innerhalb der Procedure definieren, dann gilt diese nur innerhalb und die globale bleibt unangetastet.
mov ax, 13h
int 10h

while vorne_frei do vor;
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von zatzen »

Okay, noch zum zweiten Post.

memW steht ja dafür, dass das adressierte Speicherelement ein Word ist. Das ergibt im Zusammenhang damit, dass ofs jeweils nur um 1 hochgezählt wird keinen Sinn. Scheinbar werden hier Bytes geschrieben, daher wohl auch eh und el. Also stattdessen: mem. Und dann ist mem[segment:offset] := wert und inc(ofs) schon richtig.

Das mit dem \ in Basic wusste ich auch noch nicht, das Pendant in Pascal ist DIV, also
a := b div 16
ergibt das gleiche wie
a := trunc(b / 16)
nur einfacher und schneller, allein vom Rechnen her.

2^n-fache lassen sich noch effizienter mittels SHL oder SHR (Bit-Shifting) berechnen, Beispiele:
a := b div 16
wäre:
a := b shr 4
oder Multiplikation, Beispielsweise mit 8:
a := b shl 3


So würde die BASIC Zeile:
i = (16 * (b1 AND 1)) OR (b2 \ 16)
in Pascal werden zu:
i := ((b1 and 1) shl 4) or (b2 shr 4);

Naja, sieht jetzt geschrieben nicht wirklich kompakter aus, wird aber schneller berechnet.
Ich schreibe immer alles klein, weil es für mich bequemer ist.

Ich kann mir an dieser Stelle nicht die Effizienz von Assembler verkneifen, würde man obige Variable a selbst durch z.B. 4 dividieren wollen, schreibt man einfach nur:
shr a, 2


Zu der Sache mit dem &:

Ich kann zu BASIC nichts mit Sicherheit sagen, ich kenne es von Pascal aber so, dass man manchmal wenn man hohe Werte erwartet, z.B. eine Word-Variable vorübergehend als LongInt "definieren" muss, indem man schreibt z.B.:
bla := 30000 * longint(variable)
Da sonst nur in 16 Bit Breite gerechnet wird und das Ergebnis nicht reinpasst bzw. überläuft.
Möglicherweise ist es in Deinem Code so angestellt, weil es (meines Wissens) in BASIC keine Words gibt, sondern nur vorzeichenbehaftete Integer, aber zur Adressierung verwendet man vorzeichenlose Words.

Wenn Ofs also eine Variable für die Offset-Adressierung im Real Mode ist und die Werte innerhalb 65535 bleiben, dann reicht in Pascal Ofs := 320 * Ptn. Aber es kann natürlich sein, gerade weil Du ja mit EMS arbeitest, dass Ofs tatsächlich Werte jenseits 65535 annimmt. Wenn ich das richtig verstehe würde es mit Ofs als Word aber funktionieren, wenn es nicht mehr als 203 Patterns gibt. 320 Byte für ein Pattern können es aber andererseits auch wieder nicht sein, bei 64 Zeilen/Pattern hätte man dann ja nur einen Kanal wenn jede Zeile 5 Byte belegt.
mov ax, 13h
int 10h

while vorne_frei do vor;
Benutzeravatar
Thomas
DOS-Kenner
Beiträge: 426
Registriert: Mi 22. Jun 2016, 12:29
Wohnort: Nähe von Limburg / Lahn

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von Thomas »

Guten Morgen.
Vielen Dank für deine vielen Tipps, Zatzen. Der Player läuft jetzt halbwegs. Es war tatsächlich ein Problem des lokalen und globalen deklarierens der Variablen. Einziger Bug ist allerdings jetzt noch, das der Song Anfang nicht ganz passt. Da spielt er irgendwie ab der Hälfte eines Patterns weiter hinten statt das erste von vorne. Und die Effekte verarbeitet er auch nicht ganz richtig. Zumindest wird "F" für das Tempo ignoriert.
Sollte da evtl. Doch nochmal die Laderoutine und den riesen Case Block für die Effekte prüfen. Müssen die einzelnen Case Möglichkeiten auch in Begin und end wenn mehrere Befehle verarbeitet werden sollen? Ohne meckert er jedenfalls aber in der TP Hilfe ist keine Rede davon.

Edit 13.01.20, 23:50:
Habe experimentell mal statt des Case Zweigs die Abfrage für das Tempo in den äußeren Bereich der Routine gepackt, also wo es auf jeden Fall ausgeführt wird:

Code: Alles auswählen

If EH = $F Then
Nichts. Eine Ausgabe von EH und EL zeigt für Beide null.

Edit:
Oben bei den Problemen mit den IFs habe ich geschrieben "...die Pattern können weder negativ, noch null sein..."
Ich glaube da ist mir ein Irrtum unterlaufen. EH ist eher (fast sicher, eigentlich) das HighByte der Effekte. Und EL das LowByte. Die Pattern müssten in P gespeichert sein. Dann sollte ich vielleicht da nochmal ansetzen. Dennoch denke ich eher das es am Laden scheitert. Ist ja nur der Anfang der zickt, ab dem 2. Pattern läuft es wie es soll und auch der Patternjump "B" ist einwandfrei, wo dass Mod dann wiederholt werden soll. Beim zweiten Durchlauf kommt allerdings auch wieder der Fehler. Ich werde mir nach der Arbeit Mal den Wert von P zu Beginn ausgeben lassen.

Wenn dann alles läuft muss ich nur noch eine Möglichkeit finden dass alles im Hintergrund läuft, so wie mit ON TIMER GOSUB in BASIC.

Edit2:
Ich habe mich jetzt mal etwas zu Interrupts belesen, viel mehr den entsprechenden Vektoren. Eine Musterlösung habe ich dabei nicht gefunden aber wenn ich das richtig verstehe, muss ich doch "einfach" nach folgendem, stark vereinfachen, Schema vorgehen:
Vektortabelleneintrag von INT08H berechnen und die Adresse der ISR auslesen. Alte ISR von dieser Asr sichern und mit der Adresse meiner Playerroutine ersetzen. Davor und danach natürlich INTs deaktivieren (INT Flag) bzw. Wieder aktivieren. Am Ende eines Durchlaufs auf die alte ISR weiterleiten, damit der Timer weiter erhöht wird.
Müsste ich jetzt nur noch in Pascal (mit Inline ASM) umsetzen.

OK, bin jetzt doch noch hier über die SuFu fündig geworden:
http://www.dosforum.de/viewtopic.php?f= ... grammieren
Das werde ich mir erstmal in Ruhe zu Gemüte führen und dann melde ich mich wieder. Freue mich aber dennoch über lehrreiche Posts.
Zuletzt geändert von Thomas am Mo 13. Jan 2020, 23:52, insgesamt 1-mal geändert.
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: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von zatzen »

Zu Assembler in Pascal möchte ich zwischendrin noch etwas sagen.
Zumindest in Borland 7 Pascal ist der bequem über das "asm" Statement einzubinden.
Und damit geht der Assembler-Code direkt in den Pascal Code ein, ohne irgendwelche Dinge drumherum. Und Pascal "verträgt" das auch so gut wie immer, zumindest wenn man nur an den gewöhnlichen Registern AX-DX, ES, SI, DI dreht.
DS braucht Pascal selber fürs Datensegment, kann man sich aber "leihen" indem man es zwischensichert. Bei Freepascal (z.B. für Windows) sieht das schon wieder anders aus, da scheint der Compiler nicht mit Assembler-Instruktionen zu "rechnen" bzw. optimiert den Code seinerseits auf Assembler-Ebene.
Also, um Interrupts zu sperren bietet sich an:
asm cli end;
Dann entsteht nur ein Byte Code.
Naja, ich weiss ja nicht, wie belesen Du in Assembler bist und ob ich Dir hier diesbezüglich noch Tipps geben kann.

Was das Argument angeht, heute noch in Dos im Real Mode zu programmieren:
Es gibt ja bei allem Vor- und Nachteile. Nachteile von Dos sind, dass man die heutige hochpotente Hardware nicht ausreizen kann. Aber wenn man als Hobbyprogrammierer gar nicht erst die Fähigkeiten für so ein aufgebrezeltes Spiel hat oder gar nicht erst den Anspruch, dann hat der Dos-Realmode klare Vorteile, denn hier kann man ohne zig Bibliotheken nutzen zu müssen direkt die Hardware programmieren. Am deutlichsten zeigt sich das ja am Grafikmodus 320x200x256, einfach in den Speicher schreiben und fertig. Aus Freepascal habe ich bis heute noch keine Grafik rausbekommen, geschweige denn Ton.
mov ax, 13h
int 10h

while vorne_frei do vor;
Benutzeravatar
Thomas
DOS-Kenner
Beiträge: 426
Registriert: Mi 22. Jun 2016, 12:29
Wohnort: Nähe von Limburg / Lahn

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von Thomas »

... oder gar nicht erst den Anspruch, dann hat der Dos-Realmode klare Vorteile, denn hier kann man ohne zig Bibliotheken nutzen zu müssen direkt die Hardware programmieren.
Und genau DAS ist der Knackpunkt. Ich will kein professioneller Programmierer werden und evtl. auch noch Geld verdienen. Ich will einfach in die Zeit abtauchen in der ich aufgewachsen bin und die meiste Freude mit PCs hatte (~91- 93) nur diesmal vom schöpferischen Standpunkt aus und nicht vom Konsumierenden. Ich hole quasi nach was ich seinerzeit verpasst habe weil ich zu faul war mich da rein zu wühlen und wohl auch weil es diese riesen Bibliothek noch nicht gab. Internet oder wie die heist. Fakt: Ich möchte unter MS DOS im realmode programmieren und später vielleicht mal Protected Mode ankosten. Definitiv aber kein Windows. Und mit einem verpixelten space shooter ala R-Type wie ich ihn in basic schon mit hilfe einer Library hinbekommen habe (was mit ner gut dokumentierten Library eigentlich aber auch keine Kunst ist) bin ich schon mehr als zufrieden.

So, nun zur Antwort auf deinen post:
Ja, der Inline Assembler in TP/BP7 ist mir bekannt und ich schätze den sehr.
Wie belesen ich darin bin: Naja, ich fange gerade erst damit an. Ich kann die Register auf dem Stack sichern und zurückholen, INTs auslösen, Portausgaben und -eingaben. Das war es. Bekomme aber mehr und mehr ein Verständnis dafür was da passiert. Allein durch lesen eines fremden Codes schon. Für was ist jetzt der Tipp mit dem Clear Interrupts gedacht? Den sollte ich absetzen bevor ich die Vectortable verbiege oder? Und im Anschluss wieder seten mit asm sti end;
Wie meinst Du das, DS leihen wenn man es sichert? Richtig in eine Variable (Pointer?) speichern oder einfach nur per push ds?
Ich denke Du kannst mir sehr viele Tipps geben, die ich auch gern dankend annehme. Stehe ja noch ganz am Anfang und mit fast 40 lernt es sich auch nicht mehr sooooo schnell.

Ich habe jetzt auch schon einmal mit einem Interrupt (08 Timer) experimentiert damit meine Player Routine im Hintergrund läuft, erzeugt aber einen Freeze. Muss irgendwie laut der BP Hilfe die ISR als Procedure; Interrupt deklarieren aber dass lässt BP mir nicht zu: "BEGIN erwartet"!
Ok, läuft jetzt. Allerdings viel zu schnell. OK, das liegt jetzt daran, dass die ISR ja bei JEDEM INT aufgerufen wird, was aber im normalen Play (immer bezogen auf das BASIC original) nur 50x in der Sekunde geschehen soll. Sollte sich ja einfach bewerkstelligen lassen mit entweder einem INT Counter oder durch eine simple Timer Änderung auf einen Startwert Divisor von 3. Habe zunächst letzteres ausprobiert. Also dem SetTimer statt des originalen Divisors 911, nur 3 übergeben. Resultiert in 54,6 Ticks. Wichtig wäre jetzt herauszufinden, warum das Play nicht mehr auf einen Tastendruck reagiert zum beenden und sich nach einer Zeit selbst aufhängt.
Sonst habe ich nur einen globalen "OldInt08Ptr" Pointer um die alte ISR zusichern und mache dass dann in der Playmod procedure. Die setzt den Timer Startwertteiler auf 911(50Hz) und soll dann per "ON TIMER(1)" in die Hauptprozedur springen die dann immer vom Timerinterrupt aufgerufen wird (<-- gilt jetzt nur für Basic).
Jetzt habe ich aus der BP Hilfe dort folgendes:

Code: Alles auswählen

.
.
.
Asm cli end;
GetIntVec ($08, OldInt08Ptr);
SetIntVec ($08, Addr(Main)); {Main ist die Hauptplayroutine die immer durchlaufen wird wenn der Timer den INT auslöst}
asm sti end;
End; {Procedureende}
Im StopMOD folgt dann nach dem silencen der Kanäle noch:

Code: Alles auswählen

.
.
.
Asm cli end;
SetIntVec ($08, OldInt08Ptr);
asm sti end;
End; {Procedureende}
Und das klappt auch. Würde gern mitteilen woran es lag aber ich weiß es nicht. Die Prozedur habe ich doch noch als Interrupt deklariert bekommen, aber schon vorher, bevor es überhaupt lief. Dazu darf sie aber nicht öffentlich sein, sprich, nicht im Interfaceteil.
Dann habe ich mit diversen Pushes und Pops experimentiert was aber auch nix brachte. Jetzt ist die Prozedur wieder wie vorher und sie läuft. Wenn ich das stopmod und removeplayer am Ende des Hauptprogramms weglasse, kann ich sogar in der Eingabeaufforderung herum spielen mit fröhlichem FM Gedudel im Hintergrund. Muss allerdings neustarten da kein Tastatur trap.
Jetzt muss ich nur noch herausbekommen warum der Song mit einem falschen Pattern anfängt und dann auch noch in der Mitte selbigens und warum die Effekte (zumindest Fxx = Tempo) ignoriert werden.

Ach sooooo, vielleicht wichtig:
Das ganze ist eine Unit und hat ganz am Anfang die Compilerdirektiven {$F+} für Far-Calls und {$N+} für den numerischen Co-Prozessor.
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
Thomas
DOS-Kenner
Beiträge: 426
Registriert: Mi 22. Jun 2016, 12:29
Wohnort: Nähe von Limburg / Lahn

Re: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von Thomas »

Update:
Zu früh gefreut. Es scheint wohl ein Zufall gewesen zu sein dass das eine Mod halbwegs fehlerfrei lief. Ich habe es jetzt Mal mit dem Track probiert der bei meinem Spiel während des Levels läuft und da passt gar nichts. Das geht sogar soweit das in einem Pattern die Kanäle aus unterschiedlichen Patterns gespielt werden.
Um Mal die Laderoutine ausschließen zu können, wie muss ich es genau coden in Pascal dass immer ein Byte gelesen wird und der Dateizeiger auch ein Byte weiter gesetzt wird? Die Basic Routine Readb habe ich als Unterroutine von LoadMOD eingebaut im Pascal Code und die Datei Variablen sind Global.
Hier noch einmal die Basic ReadB Funktion die über FOR Schleifen immer wieder von LoadMOD aufgerufen wird. LoadMOD wird aber nur einmal aufgerufen.

Code: Alles auswählen

FUNCTION readb (fh)
	b$ = CHR$(0)
	GET fh, , b$
	readb = ASC(b$)
END FUNCTION
fh ist die Dateinummer der OPEN Anweisung, im original mit 1 hard codiert.

Wäre eine typisierte Datei of Char in Kombination mit Read in Pascal denn überhaupt das richtige oder geht sowas nur mit BlockRead?

Wäre dieser Ansatz passend?

Code: Alles auswählen

{Globale Variablen}

FileVar : File;
Buffer : Array [1..1] of Char;
BytesRead : Integer;
Result : Integer;
.
.
.

{Datei öffnen in LoadMod}
Assign (FileVar, FileName);
Reset (FileVar, 1);
.
.
.
Function ReadB : Byte;

Begin
      Buffer [1] := Chr(0);
      BlockRead (FileVar, Buffer[1], 1, BytesRead);
      If BytesRead = 0 Then Exit;
      ReadB := Ord (Buffer[1]);
 End;
        
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: Allgemeine Hilfestellung zum Programmieren unter DOS gesucht

Beitrag von zatzen »

Code: Alles auswählen

function readB: byte;
  var buffer: byte;
begin
  blockread(filevar, buffer, 1);
  readB := buffer;
end;
Dürfte es tun, blockread liest aus der Datei in jeden gängigen Variablentyp, daher ist hier kein Umweg über char nötig.
Eine globale Puffervariable ist so wie ich das sehe nicht nötig, es sei denn die Laderoutine greift darauf nochmal zu. FileVar würde ich auch eher von global in die Laderoutine verlegen. Dann muss nur auch die kleine function mit in die Laderoutine, also:

Code: Alles auswählen

procedure LoadMOD;
...
  var FileVar;
...
  function readB: byte;
...
begin {LoadMOD}
...
Ich merke gerade dass ich sowas selber sehr selten mache. Vielleicht Geschmackssache, aber so hätte man kleine Funktiönchen schön in der einzigen Routine integriert die sie nutzt.

Blockread erhöht beim Typ File, 1 die Leseposition immer um so viele Bytes wie gelesen wurden.
Wieviel tatsächlich gelesen wurde (wird bei Dir in BytesRead geschrieben) habe ich bisher immer ausser acht gelassen, gewöhnlich gibt es da nur eine Abweichung wenn man versucht über das Ende der Datei hinaus zu lesen.

I/O-Fehler kann man generell mit einem vorübergehenden Compiler-Switch abfangen:
{$I-} zum Abschalten von I/O-Fehler-Runtimes, dann kann man mit IOresult prüfen ob ein Fehler passiert ist oder nicht
(IOresult = 0 wenn kein Fehler). Danach einfach wieder {$I+}.

Ungewöhnlich, dass eine Datei Byte für Byte gelesen wird und für jedes Byte dann zumindest in Pascal ein "schweres" Blockread bemüht wird. Ich ahne aber dass es damit zusammenhängt dass man in Basic scheinbar nur über Strings frei in einer Datei lesen kann. Blockread war auch ein nicht zu verachtender Grund für mich dass ich Pascal mochte. Ich kannte in BASIC nur BLOAD...
Aber wäre es nicht möglich, die Musikstücke etwas strukturierter in nur relativ wenigen Schritten einzulesen?

Wenn Du Lust hast kannst Du mir die LoadMOD mal zukommen lassen, und falls Du es hast das Dateiformat noch dazu, dann kann ich mir selber einmal einen Überblick verschaffen.
mov ax, 13h
int 10h

while vorne_frei do vor;
Antworten