[x86 Real] Audio spielen - ein Konzept

beepsoft

Well-Known Member
c-b Team
c-b Experte
#1
Hallo,
ich mal wieder :)
Ich würde gerne Audio über den PC Systemlautsprecher abspielen.
Ich habe dazu auch schon etwas funktionstüchtiges gebaut.
Und zwar nehme ich eine 8bit .wav mit 1khz Abtastrate.
Ich habe mir ein Programm geschrieben, dass je ein Byte lädt und bei <127 den Lautsprecher entspannt bei >127 spannt.
Das ergibt schon mal ein hörbares Ergebnis. Nun habe ich das Timing durch einen auf die Hardware zugeschnittenen sleep Befehl erreicht.
Das ist natürlich nicht ideal, da auf jeder anderen Hardware das Programm unbrauchbar wird.
Deshalb mein Plan:
Ich klinke mich in den Timer Int
und lasse den genau das selbe machen wie mein Programm bisher.
Jetzt habe ich da mal was geschrieben. Nur leider höre ich gar nichts.
Ich muss natürlich noch die Frequenz auf 1khz ändern.
Aber auch bei 18 HZ müsste ich doch Ton hören.
Oder mache ich komplett was falsch?

LG

Code:
cli                                             ;Sperre INT
xor ax,ax                                       ;AX=0
mov ES,AX                                       ;ES=AX
mov DI,1Ch * 04h                                ;DI=Intvektoradresse
mov AX,timerhandler                                      ;AX=Adresse der API
stosw                                           ;Schreibe Word
mov AX,cs                                       ;AX=CS
stosw                                           ;Schreibe Wort
sti                                             ;Erlaube INT



cli
mov al,$34
out $43 ,al
mov ax,76
out $40,al
mov al,ah
out $40,al
sti



mov byte [startplay],1











endl:
jmp endl
;############################################################################
;Hier verzweigt Int1Ch
;
sibuff dw 0
timerhandler:
inc word [lange]
cmp word [lange],64000
je beendeplay

cmp byte [startplay], 1
jne keinplay
push ax
push bx
push cx
push dx
push si

mov ax,0x4000
mov ds,ax
mov si,[sibuff]

sounda:                                                  ;Unterprogramm

lodsb

                                                        ;Lade Byte
cmp al,129                                              ;Wenn Byte kleiner 128 dann
jb ausxa                                                  ;schalte Speaker aus
jmp eina                                                 ;Ansonsten ein
entrya:
mov word [sibuff],si


pop si
pop dx
pop cx
pop bx
pop ax
keinplay:
iret



eina:
in al,61h
or al,00000011b                                         ;Schaltet Speaker ein
out 61h,al
jmp entrya
ausxa:
in al,61h
and al,11111100b                                        ;Schaltet Speaker ein
out 61h,al
jmp entrya







beendeplay:
mov byte [startplay],0

cli                                             ;Sperre INT
xor ax,ax                                       ;AX=0
mov ES,AX                                       ;ES=AX
mov DI,1Ch * 04h                                ;DI=Intvektoradresse
mov AX,timerhandlerb                                      ;AX=Adresse der API
stosw                                           ;Schreibe Word
mov AX,cs                                       ;AX=CS
stosw                                           ;Schreibe Wort
sti                                             ;Erlaube INT

timerhandlerb:
iret
 

Xpyder

Well-Known Member
c-b Experte
#2
Ich nutze/programmiere "Digitalsound über Speaker" schon seit Jahren. Da gibt es noch bessere Methoden.
Falls Interesse, kann ich da mal Beispiele geben, wie das geht.
Der Speaker hat auch einen Modus, mit dem man mehr als 1-Bit simulieren kann (ca. 6 bis 8 Bit Breite sind möglich, je nach Frequenz. Je höher die Frequenz, umso geringer die Möglichkeiten. Ich arbeite da mit Tabellen, um abhängig vom Eingangswert einen Ausgabewert zu erhalten. Diese Tabelle (256 Bytes) wird immer nur dann angepaßt, wenn sich die Abspielfrequenz ändert.
Wie ich aber sehe, benutzt Du schon die Möglichkeiten. z.B. die Tickerfrequenz ändern usw.
 

beepsoft

Well-Known Member
c-b Team
c-b Experte
#3
Hallo Xpyder,
vielen Dank für deine Nachricht.
Falls Interesse, kann ich da mal Beispiele geben, wie das geht.
Oh ja sehr gerne. vielen Dank.
Mein Ansatz bisher sieht so aus.
Ich nehme eine .wav mit 1000Hz und 8 bit.
Ich setze die Tickerfrequenz auf 1000Hz
Ich lade Byteweise und wenn der Wert<127 schalte ich den Beeper aus sonst an.
ich schätze mal es gibt aber elegantere Methoden die orginal Kurze zu simulieren.

Bin schon sehr gespannt.

LG
 

beepsoft

Well-Known Member
c-b Team
c-b Experte
#4
Hallo,
ich hab da mal ein bisschen Code :)
Ich habe den Teil der meine Wav Spielen soll (1000Hz/8bit) in den Timerint ausgelagert.
Meine Hoffnung war es, dass ich wenn ich die Frequenz auch annähernd auf 1000 Hz setze eine stabile Ausgabe erhalte.
Leider bleibt der Lautsprecher komplett stumm.
Was mache ich falsch?

LG

P.s.:
Die Daten stehen korrekt im Segment 0x4000.
Das habe ich überprüft.


Code:
cli
mov al,$34
out $43 ,al
mov ax,1193                          ;Setze den Frequenzteiler auf 1193 > ergibt ca. 1000 Hz
out $40,al
mov al,ah
out $40,al
sti

cli                                             ;Sperre INT
xor ax,ax                                       ;AX=0
mov ES,AX                                       ;ES=AX
mov DI,1Ch * 04h                                ;DI=Intvektoradresse
mov AX,timerhandler                                      ;AX=Adresse des Timerhandlers
stosw                                           ;Schreibe Word
mov AX,cs                                       ;AX=CS
stosw                                           ;Schreibe Wort
sti                                             ;Erlaube INT






;############################################################################
;Hier verzweigt Int1Ch
sibuffer dw 0                                         ;si Puffer
timerhandler:
cli                                                         ;Interrupts sperren
mov ax,0x4000                        
mov ds,ax
mov si,[sibuffer]                                  ;Lade Byte von 0x4000:si
sounda:                                                  ;Unterprogramm

mov [sibuffer],si                                                      ;sichere si

cmp al,128                                              ;Wenn Byte kleiner 128 dann
jb ausxa                                                  ;schalte Speaker aus
jmp eina                                                 ;Ansonsten ein
entrya:
jmp plays



eina:
in al,61h
or al,00000011b                                         ;Schaltet Speaker ein
out 61h,al
jmp entrya
ausxa:
in al,61h
and al,11111100b                                        ;Schaltet Speaker aus
out 61h,al
jmp entrya

 plays:
 mov al, 0x20                                              ;EOI        
out 0x20, al
sti                                                                ;Interrupts wieder zulassen
iret
 

Xpyder

Well-Known Member
c-b Experte
#5
Also, dann erkläre ich einfach mal, wie ich es mache,
Du kannst es so benutzen oder nicht - bei mir funktioniert es.
Zunächst einmal zwei Sachen:
1.) 1000 Hz sind sehr wenig! Selbst wenn es hörbar wird, wird es nervtötend sein. 1000 Hz ist als Trägerwelle für Sound ungeeignet, weil sie selbst noch im direkt hörbaren Bereich liegen. Falls Du wissen willst, wie es klingt: Erinnerst Du Dich daran, daß früher die TV-Sender bei Sendepausen/Sendeschluß ein Testbild/Ton gesendet haben? So klingt 1000 Hz.

2.) Ich hoffe, Du machst das ganze nicht unter Windows (oder wenn, dann hoffentlich in DOSbox). Aus zwei Gründen:

a) Falls unter XP, ist 1000 Hz auch die maximale Frequenz, auf die man den Ticker setzen kann - setzt man sie niedriger, wird das entsprechend "ausgeglichen", setzt man sie höher, wird auf 1000 Hz gesetzt (Grund: Windows selbst setzt den Ticker auf 1000 Hz. Setzt man selbst etwas niedrigeres, paßt NTVDM, das entsprechend so an, daß es die entsprechenden Anzahl Aufrufe pro Sekunde trotzdem macht. Nehme an, mit einem Wraparound-Ticker - so wie ich es auch mache, wenn ich mehrere Frequenzen brauche.)

b) Windows selbst unterstützt den PC-Speaker nicht mehr nativ. Manchmal wird es noch zur Soundkarte umgeleitet, manchmal passiert gar nichts. Wenn NTVDM erkennt, daß man den Speaker für "den Digitalsound-Trick" benutzen will, schaltet es automatisch intern alles so weiter, daß die entsprechenden Daten zur Soundkarte gelangen. (Um "DOS-Zeug unter Windows" zu machen, ist WinXP (32bit) das beste was man machen kann. Emulator schön und gut - kostet aber Performance. Ich kann mit meinem DOS-Kram, wenn ich ihn unter WinXP benutze, auch die Sachen von WinXP benutzen, d.h. kann dann z.B. lange Dateinamen supporten usw, oder sogar auf die "Soundblaster-Karte" zugreifen (selbst wenn gar keine eingebaut ist!) - Dazu muß nur in der AUTOEXEC.NT die entsprechende SET BLASTER=Axxx Ix Dx... usw Zeile stehen und es wird automatisch umgemappt. Nach WinXP hätte es gar kein weiteres Win mehr gebraucht - die neuen sind nur größer und langsamer, aber können nicht mehr außer bunt. (Klar, Zugriff auf mehr Speicher/Platte - aber dafür hätte man sicher auch unter XP eine Lösung gefunden... - egal)

Wenn Du es unter reinem DOS - oder unter DOSbox - machst: Vergiß alles, was unter 2.) steht - das ist dann nicht wichtig.

So, jetzt zu den Dingen, die wirklich sind.
(A) Zuerst mal: Ja, Tickerfrequenz ist auf die richtige Art gesetzt - hier würde ich aber MINDESTENS 5000 Hz vorschlagen. Wenn des störende Pfeifen wegsoll, mindestens 8000 Hz. (Ich benutze 11 Khz, 16 KHz, 22 Khz... Aber OK - es hängt natürlich davon ab, was man für einen Rechner hat. So hohe Frequenz bei zu langsamem Rechner führt zu Abstürzen.)

(B) Ich "klinke" mich in den Ticker ein, d.h. lasse den normalen Ticker weiterlaufen, natürlich nicht mit der gleichen Frequenz wie der neu gesetzten, sondern mit der "Null-" also 65536-Frequenz. Das geht, indem man den errechneten Faktor (das wäre Dein 1193), also bei 11000 wäre es z.B. 1193180 div 11000, also 108 - immer wieder zu einem 16-Bit-Wert addiert und jedesmal, wenn das Carry gesetzt wird (d.h. bei einem Überlauf) dann auch die normale INT-Routine zusätzlich anspringt. Wichtig: NICHT den 16bit-Wert dann beim Überlauf auf 0 setzen oder sowas, sondern einfach "so lassen". Dadurch kann man total "krumme" Frequenzen nehmen und der normale Ticker wird trotzdem im Schnitt mit seinen 18.2064... mal pro Sekunde ausgeführt. (Festkommaarithmetik ist eins meiner Steckenpferde. Ohne sowas hätte ich meine Sound-Erzeugungsroutine, die quasi wie ein Software-Synthesizer arbeitet, nicht so hingekriegt. Ist auch gut für alles Grafische: Linien, Kreise... 3D-Zeug... Und man spart sich diesen ekligen LANGSAMEN Fließkommakram.)

(C) Die "gute" Methode, um mit dem Speaker Sound zu machen, ist eine, bei der man den Speaker in den sogenannten "One-Shoot" Mode setzt, ich schreib das jetzt alles nur mal in Pseudo-Code:
Port $43 auf $90 setzen (Port$43 = $90)
Bei Port $61 die unteren 2 Bit setzen (Port$61 = Port$61 or $03)

Rücksetzen auf "Normalzustand" geht genau umgekehrt:
Bei Port $61 die unteren 2 Bit löschen (Port$61 = Port$61 and $FC)
Port $43 auf $B6 setzen (Port $43 = $B6)
Ja, könnte jetzt raussuchen, was die Bits bedeuten usw. - aber das ist schon lange her. Ich mach das schon seit Jahren und es funktioniert.

So, und nun (nach setzen in "One Shoot") ist der "neue" Port für den Speaker nicht $61, sondern $42. In diesen Port kann man nun einen Wert setzen und der Speaker bleibt für "Anzahl Wert" Zyklen auf "ON" und geht danach auf "OFF" - wobei ein "Zyklus" eben wieder genau 1/1193180 sind, (also diese berühmten ca. 4.77 MHz durch 4). Ja - Speaker, Ticker und der ganze Kram hängen innen technisch alles zusammen.

Wozu ist das gut?
Naja, nun kann man eine Frequenz setzen und immer bei jeden Frequenztick gibt man dem Speaker einen Wert. Herauskommt dabei dann so etwas:
|11110000|11000000|11111000|11111111|00000000|11100000|......

Wobei jedes | ein Tick ist, (das wäre es, wenn man als "Tickerwert" 8 nehmen würde, dann wäre die Frequenz aber fast 150 kHz.... ist ja nur ein Beispiel).
So, d.h. WENN man die Frequenz so gesetzt hätte, könnte man dem Speaker 9 verschiedene Werte (0 - 8) geben (mit OUT $42,Wert), um festzulegen, wie lange der "ON" bleiben soll - denn mehr macht keinen Sinn, weil ja dann schon der neue "Tick" kommt. Je höher die gewählte Frequenz, umso weniger "Varianz" der Werte hat man. D.h. die oben gezeigten Einsen (1) und Nullen (0) geben an, wie der Speaker (und damit die Membran) gerade ist.
Mehr als ca. 20000 Hz machen beim Speaker keinen Sinn, das klingt nicht mehr wirklich gut - da wird es zwar "genauer" - aber eben auch leiser.
Nehmen wir an, man hätte die Frequenz 11000 gesetzt, (siehe oben: 108), dann könnte man Werte von 0 bis 107 (besser immer 1 weniger, damit sich das nicht "verheddert") nehmen.

So, wie macht man nun damit Sound, dessen Eingabewerte 8-Bit (Werte 0-255) sind?
Naja, je nach Frequenz kann man natürlich einfach die einfachere Methode wählen und einfach z.B. den Eingabewert um 1, 2 oder 3 (oder mehr) Bits nach rechts shiften, um Werte 0-127, 0-63, 0-31... zu haben..... ODER man kann auch "meine" Methode benutzen: Man schreibt sich ein kurzes Unterprogramm, das immer für die gewählte Frequenz (muß nur aufgerufen werden, wenn die Frequenz mal geändert werden soll) eine Look-Up-Table, eine Tabelle aus 256 Bytes generiert, die die realen 256 Werte auf die für den Speaker bei dieser Frequenz maximal möglichen Werte aufteilt. (Ja, da kommen dann einige/viele Werte hintereinander mehrmals vor, je nach Frequenz.)

Der Zugriff ist ja denkbar einfach: jeweils vorher LEA BX,Tabelle
und wenn in AL der 8bit-Wert drinsteht, einfach XLAT ausführen, schon steht danach der "gewandelte" Wert in AL. (man kann es natürlich auch mit anderen Registern machen - aber hier bietet es sich eben an, weil man AL sowieso braucht und weil XLAT eben automatisch aus
Segment:[BX+AL]
einen neuen Wert für AL holt. (Standardmäßig ist Segment=DS, aber man kann auch jedes andere nehmen.)
Wenn man die Frequenz nie ändern will, kann man natürlich die vorberechnete Tabelle auch einfach schon irgendwo fest hinlegen.

Und - voilà! - schon hat man den berühmten Speakersound. Anmerkung dazu: Man kann die Werte auch "rückwärts" speichern, d.h. daß der "0" entsprechende Tabellenwert den höchsten und der "255" entsprechende Wert den niedrigsten "Speaker-Wert" bekommt. Ich habe damit (subjektiv) etwas besser klingenden Sound erzeugt - prinzipiell ist es aber egal, in welche Richtung eine "Welle" geht.

Warum das Ganze funktioniert, liegt einfach an der physikalischen Trägheit der Speaker-Membran: In Wirklichkeit tickert die dann nicht 20000 mal pro Sekunde hin und her, sondern das rechteckigewird, Speakersignal wird in Wahrheit zu einer Welle "abgeschliffen".

Anm. 1: Man sollte hier einen RICHTIGEN Speaker, (also einen kleinen Lautsprecher), benutzen. Diese billigen PIEZO-Elemente, die manchmal eingebaut werden, können zwar gut piepen, aber für diesen "Digitalsound-Trick", sind sie nicht ganz so geeignet - hat physikalische Ursachen.

Anm. 2: Für den Fall, daß es doch nur "schnelle Nullen und Einsen" sein sollen (also ohne die "One-Shoot" Technik, sondern mit manuellem On-Off), habe ich auch mal eine "Pattern" Variante entwickelt (die recht naheliegend ist), und die auch bei einem Piezo-Element noch ganz gut geklappt hat - aber auch hier sollte die Frequenz nicht zu niedrig gestellt sein:

Man definiert einfach für verschiedene Amplituden verschiedene Bit-Patterns, die man entsprechend verteilt:
Beispiele:
0 = 00000000bin
64 = 10001000bin
128 = 10101010bin
192 = 11101110bin
255 = 11111111bin
D.h. man "dithert" den Sound. Kann man auch mit 16bit oder mehr machen. Beim Abspielen, hat man dann einen "Bit-Rotierer" mit drin, der dann zusätzlich zum Wert das entsprechende Bit herausholt - ja, das ist nicht ganz so genau, aber es wäre ja auch 1-Bit-Sound. Hier geht man davon aus, daß aufeinanderfolgende Werte etwas ähnlich sind. Man benutzt hier quasi für Sound das gleiche Prinzip wie man bei Grafik benutzen würde, um ein Graustufenbild in komplett monochrom zu rastern. Selbstverständlich wird auch hier mit einer Tabelle gearbeitet.
Ich habe diese Methode mal benutzt, weil ein Kumpel mal eine Lösung haben wollte für ein billiges Piezo-Knack-Element, bei dem etwas wie diese "bessere" Speakersound Technik nicht funktioniert hätte. Hat dann auch recht gut funktioniert.

Anm. 3: Und ja, das ist hier alles vielleicht nicht wissenschaftlich genug erklärt. Sicher findet sich wieder irgend ein Korinthenkacker, der wieder etwas dran auszusetzen hat. Es ging mir nur darum, eine funktionierende Lösung (bzw zwei) zu präsentieren. Und diese hier funktionieren.

@beepsoft: Falls noch irgend etwas unklar ist, einfach fragen.
 

beepsoft

Well-Known Member
c-b Team
c-b Experte
#6
Hallo Xpyder,
vielen Dank für deine ausführliche Antwort. Ich denke, ich versuche erst einmal überhaupt eine Variante zum Laufen zu kriegen.
Verbessern kann ich dann immer noch.
Ich bewege mich in meinem eigenen OS. Das heißt kein Typ aus Redmond wirft mir Steine dazwischen :)
Aber sag mal, die Variante mit 1000HZ müsste doch trotzdem Töne produzieren.
Bei mir bleibt o.g. nämlich stumm.
Hast du einen Tipp für mich?

Ich habe in meinem OS ja noch ein Problem.
8bit Wav mit 8000 Hz verbrauchen so viel Speicher, dass mein 64K Dateimodel langsam aber sicher an seine Grenen kommt.
Ggf. je nachdem wie es klingt (bzw. ob es überhaupt klingt) kriege ich halt mit 1000Hz mehr Audio in meine 64K.Im Prinzip könnte ich mir ja auch nen Converter schreiben, der mir bit wav ausspuckt.

LG
 

Xpyder

Well-Known Member
c-b Experte
#7
Hallo Xpyder,
vielen Dank für deine ausführliche Antwort. Ich denke, ich versuche erst einmal überhaupt eine Variante zum Laufen zu kriegen.
Verbessern kann ich dann immer noch.
Ich bewege mich in meinem eigenen OS. Das heißt kein Typ aus Redmond wirft mir Steine dazwischen
Hm. Hab grad in der RBIL nachgelesen. Tatsache, der INT $1C geht auch, weil er vom INT $08 aufgerufen wird. Ich klinke mich aber immer direkt in INT $08 ein.
Ich sag mal so: Die "normale" ISR am INT $08 ist ja nicht dafür gedacht, total hochfrequent zu laufen, weiß nicht, wieviel Khz die abkann, bevor der Rechner absegelt (deshalb ruf ich die trotzdem nur 18.2x pro Sekunde auf - und zwar, indem ich vorher schon $20 in Port $20 schreibe und das INT-Flag wieder setze! So kann sogar die normale ISR noch vom schnellen Ticker unterbrochen werden. Klingt tricky, ist aber logisch, wenn man drüber nachdenkt.

Aber sag mal, die Variante mit 1000HZ müsste doch trotzdem Töne produzieren.
Bei mir bleibt o.g. nämlich stumm.
Hast du einen Tipp für mich?
Aber ich hab Deinen Fehler gefunden. Ist ein richtig blöder Fehler. Facepalm-mäßig und so. (Es sei denn, Du hast an Deinem geposteten Code was weggelassen.)
Eigentlich sind's 2 Fehler.
Soweit ich das verstehe, soll der Sound ab Segment $4000 liegen.
Aber: An welcher Stelle HOLST Du AL? (Sehe ich nirgends. Du testest, ob AL<128 ist und so...)
Wie ich den Code interpretiere, ist der Plan, AL von DS:SI zu holen - passiert aber nirgends.
Und ich nehme weiterhin an, daß in "sibuffer" dieser Zähler drinsteht, der das Soundframe hochzählen soll, damit SI das immer von da holen kann.
Aber ich sehe nirgends, daß der mal irgendwo erhöht wird für das nächste Soundframe.
D.h. irgendwie Zeile 34 müßte noch mov AL,DS:[SI]; in SI; drinstehen. Oder eben LODSB (dann natürlich vorher irgendwo CLD setzen, damit er auch wirklich vorwärts zählt).

Ich habe in meinem OS ja noch ein Problem.
8bit Wav mit 8000 Hz verbrauchen so viel Speicher, dass mein 64K Dateimodel langsam aber sicher an seine Grenen kommt.
Ggf. je nachdem wie es klingt (bzw. ob es überhaupt klingt) kriege ich halt mit 1000Hz mehr Audio in meine 64K.Im Prinzip könnte ich mir ja auch nen Converter schreiben, der mir bit wav ausspuckt.
LG
Macht Sinn. Erstens: höhere Frequenz ist irgendwie besser als Bitbreite.
D.h. 1bit 16kHz klingt WESENTLICH besser als 16bit 1kHz.
Um es einfacher zu halten, wenn Du mehrere (gleichlange) Sounds brauchst, kannst Du ja auch die Sounds quasi "parallel" ablegen, d.h. jeder ist nur 1 Bit breit, liegt aber auf nem anderen Bit. So braucht man nur die Bitnummer angeben. Legt man sie hintereinander, braucht man statt des Bytezählers auch noch einen Bitzähler (bzw braucht dann so etwas wie:
Code:
mov SI,sibuffer
mov CX,SI
shr SI,3
and CL,7
inc CL
mov AL,DS:[SI]
ror AL,CL
und dann abhängig von Carry .....
oder das INC CL weglassen und stattdessen nach ROR AL,CL mit TEST AL,1 und abhängig vom Zeroflag...
Die "Parallelbit"-Methode würde einfach nur am Anfang festlegen, welches Bit
Und dann test AL,BITMASKE und abhängig vom Zeroflag...

Also wie gesagt: Daß nichts zu hören ist, liegt erstens daran, daß AL die ganze Zeit =$00 ist (weils noch vom Setzen von DS ($4000) immer noch 0 ist und nicht geändert wird und zweitens, weil SI bzw sibuffer auch nirgends hochgezählt wird, jedenfalls nicht für mich erkennbar.
Wenn man aber immer den gleichen Wert als Soundframe ausgibt, quasi eine "waagerechte Linie" als Sound, ist egal, auf welcher Höhe (Amplitude) die ist: Man hört nix.

Ich hoffe, ich konnte helfen.
 

Xpyder

Well-Known Member
c-b Experte
#8
Nachtrag: Eine intelligentere Methode wäre ein zusätzlicher Bitzähler. der gleich als Maske dient:
Code:
rol bitmask,1
adc SI,0
[/CODE[
So wird SI alle 8 Bit erhöht und man kann AL gleich mit test AL,bitmask testen.
 

beepsoft

Well-Known Member
c-b Team
c-b Experte
#9
Hallo Xpyder,
danke für deine umfangreiche Antwort.
Leider muss ich die Arbeit vorläufig einstellen. Ich muss erst meinen Computer flicken.
Der PC Lautsprecher gibt Töne von sich, auch ohne mein Zutun.
Wenn ich den Fehler gefunden habe geht es weiter
und dann habe ich bestimmt noch 100 Fragen :)

Bis dahin

LG

und vielen Dank
 

Xpyder

Well-Known Member
c-b Experte
#10
Vielleicht liegen die entsprechenden Kabel im Computer zu eng beieinander. Das kann Interferenzen verursachen, die über Lautsprecher hörbar sind. Bei alten Computern konnte man die manchmal "rechnen hören"...
 

beepsoft

Well-Known Member
c-b Team
c-b Experte
#11
Ich hab den Fehler gefunden.
Offenbar ist die Kühlung durch. Das Bios zeigt kurz nach dem Start bereits 80 Grad an.
Also schätze ich mal, wenn ich die Kühlung repariert habe sollte das wieder sinnig funktionieren.
Dürften ja sehr seltsame Dinge passieren, wenn ein Programm den Beeper steuert und gleichzeitig das BIOS seine Temperaturwarnung auspiepst.

LG
 

beepsoft

Well-Known Member
c-b Team
c-b Experte
#12
Hallo Xpyder,
ich hab noch ein bisschen an meinem Code gebaut und mir ist eine Laterne aufgegangen.
Mein Problem ist der RAM.
Und zwar muss ich ja si irgnedwo sichern. Weil wenn der Timerint mein Programm unterbricht kann sich ja im Hauptprogramm si ändern.
Bloß befindet sich mein Programm und somit meine si Sicherungslabel nicht im selben Segment wie die Wav.
Nun habe ich die Segmente entsprechend angepasst. Also bevor ich auf das si Sicherungslabel zugreife Setze ich ds auf 0x1000 und anschließend auf 0x4000 damit ich auf die Daten der Wav zugreifen kann.
Bloß es bleibt stumm.
Was mache ich falsch?

Bzw. gibt es eine elegantere Methode Register zu sichern, wenn ich mich in mehreren Segmenten gleichzeitig bewege?


LG


Code:
cli
mov al,$34
out $43 ,al
mov ax,149
out $40,al
mov al,ah
out $40,al
sti

cli                                             ;Sperre INT
xor ax,ax                                       ;AX=0
mov ES,AX                                       ;ES=AX
mov DI,1Ch * 04h                                ;DI=Intvektoradresse
mov AX,timerhandler                                      ;AX=Adresse der API
stosw                                           ;Schreibe Word
mov AX,cs                                       ;AX=CS
stosw                                           ;Schreibe Wort
sti                                             ;Erlaube INT


   enlich:
         jmp enlich


;############################################################################
;Hier verzweigt Int1Ch
sibuffer dw 0
tsegment dw 0x4000
timerhandler:
cli
mov ax,0x1000
mov ds,ax

mov word si,[sibuffer]
mov ax,0x4000
mov ds,ax
sounda:                                                  ;Unterprogramm

cld
lodsb
mov ax,0x1000
mov ds,ax

mov [sibuffer],si                                                      ;Lade Byte

cmp al,127                                              ;Wenn Byte kleiner 128 dann
jb ausxa                                                  ;schalte Speaker aus
jmp eina                                                 ;Ansonsten ein
entrya:
jmp plays



eina:
in al,61h
or al,00000011b                                         ;Schaltet Speaker ein
out 61h,al
jmp entrya
ausxa:
in al,61h
and al,11111100b                                        ;Schaltet Speaker ein
out 61h,al
jmp entrya

 plays:
 mov al, 0x20
out 0x20, al
sti
iret


;############################################################################
 

gargyle

Well-Known Member
c-b Experte
#13
Hi beepsoft.

Ein Interrupt-Handler sollte grundsätzlich kein Register verändert lassen. pusha ist hier dein Freund.
Code zwischen cli/sti sollte dies wenn Möglich auch nicht.

Beim Interrupt-Controller auch schauen ob der Sekundäre auch einen IRQ möchte.
 

beepsoft

Well-Known Member
c-b Team
c-b Experte
#14
Hallo gargyle,
im Prinzip hast du recht. Mit push verhindere ich, dass der Int Handler si ändert. Aber ich muss ja auch verhindern, dass das Hauptprogramm die Register des Int Handlers ändert. Weilt der Int 1Ch gibt ja nach Ausführung die Kontrolle an das Hauptprogramm zurück. Wenn das Hauptprogramm nun z.B. einen Text adressiert und der 1Ch kommt dann wieder... Dann zeigt ja si auf den Text und nicht mehr auf die WAV.
Wie meinst du das mit dem IRQ?


LG
 

gargyle

Well-Known Member
c-b Experte
#15
Die Kombi
Assembler:
mov al, 0x20
out XXXX, al
eventuell auch an den sekundären Controller senden.(Falls notwendig XXXX =A0)
 
Oben