ENGLISH VERSION |
|
Links | | | Forum | | | Kommentare | | | News melden |
Chat | | | Umfragen | | | Newsticker | | | Archiv |
amiga-news.de Forum > Suche | [ - Suche - Neue Beiträge - Registrieren - Login - ] |
|
||||||
jolo
Nutzer
24.07.2009, 18:02 Uhr [ - Direktlink - ] |
Thema: value to dezimal string
Brett: Programmierung @AGSzabo: Hi. Zitat: code:ValToDez: movem.l d2-d4/a1,-(a7) push a0 moveq #4,d1 move.l #10000,d3 moveq #0,d2 .lp1 moveq #-1,d4 .2 addq.w #1,d4 sub.w d3,d0 bpl.s .2 add.w d3,d0 divu.w #10,d3 add.w #$30,d4 tst.w d2 bne.b .4 cmp.b #"0",d4 beq.b .5 st d2 .4 move.b d4,(a0)+ .5 dbf d1,.lp1 cmp.l (a7)+,a0 bne.b .pop move.b #"0",(a0)+ .pop movem.l (a7)+,d2-d4/a1 rts Dieser Code wurde ursprünglich für eine 68000er CPU, bei der die Eingabe nie größer als 99999 ist, geschrieben. Aber lass Dich nicht ins Bockshorn jagen; ineffizient ist der Code mitnichten! Zudem unterdrückt er führende Nullen und testet auch korrekt ob 'd0' null ist, heißt, dann wird trotz Unterdrückung der führenden Nullen eine einzige Null in Deinen Puffer geschrieben. Leider wird der Puffer aber nicht NUL-Byte terminiert. Alles in allem ist dies Standard-Code der in den 80er Verwendung fand. Änderungen damit Langworte ausgegeben werden können; ausschließlich 68020(+): code:: moveq #4,d1 move.l #10000,d3 in moveq #9,d1 move.l #1000000000,d3 ändern. Und die Instruktionen: sub.w d3,d0 bpl.s .2 add.w d3,d0 divu.w #10,d3 gegen sub.l d3,d0 bpl.s .2 add.l d3,d0 divul.l #10,d3:d3 tauschen. Wie gesagt, 68020+ ist Voraussetzung. Wenn Du diesen abgeänderten Quellcode für 68000 kompatibel machen willst, musst Du nur 'd3' mittels Werten einer Tabelle (beginnend mit 1000000000 und endend bei 1) aktualisieren, dann entfällt auch 'divu.w' bzw. 'divul.l'. Grüße |
|||||
jolo
Nutzer
17.05.2009, 17:17 Uhr [ - Direktlink - ] |
Thema: Unicode auf OS3.x
Brett: Programmierung Aua, aua, aua - das zu lesen wird dauern... @Thore Zitat: Dateien ohne BOM sollten der Regelfall sein und mit BOM nur Ausnahmen, ansonsten zerstört man nämlich Systemdateien die in ASCII erstellt worden sind aber als UTF-8 gespeichert werden. Ohne BOM unterscheiden sich beide Dateien nicht. Zitat: Patch and burn! Oder anders: Watschen fürs Patchen... Ich hoffe, nachdem ich jetzt alle Beiträge gelesen habe, dass ihr nichts mehr patchen wollt? Zitat: Unter OS3 (ISO-8859-1), ja, unter MorphOS/AmigaOS4/AROS immer entsprechend der IANA-ID (Locale-Bibliothek) (Amiga-1251, ISO-8859-x, TIS-620, UTF-x). Da weder MorphOS/AmigaOS4/AROS Unterstützung für die chinesische Zeichenausgabe und Eingabe anbieten, kann hier nichts abgebildet werden, daher die vielen '?'. Da aber die MUI TextEditor MCC Klasse neu geschrieben werden müsste um UTF-Konformität zu erzielen ist UTF-x Unterstützung nur theoretisch vorhanden, also verbleiben noch Amiga-1251, ISO-8859-x und TIS-620 im Rennen wobei TIS-620 wiederum ausfällt, da es keine Einzelbyte-Kodierung ist, sondern ein Zeichen aus bis zu drei Bytes (drei Oktetts) besteht und die MUI TextEditor MCC Klasse dies nicht unterstützt. @Wanderer Zitat: Bloß nicht. UTF-8 ist ein Datenformat und nicht ein Wert irgendeiner Taste Deiner Tastatur. UTF - Datenformat (im RAM, Harddisk oder generelles Speichermedium) Unicode - Zeichensatz (im Gegensatz zu ASCII aber ein wenig umfangreicher) Code Point - Wert eines Zeichens Bitte nicht durcheinander bringen. Zitat: Das mag stimmen. Leider, wenn ich das noch recht in Erinnerung habe, hat aber TTEngine unter OS4 arge Probleme bereitet. Ist allerdings schon Jahre her. Um das Ganze zu verifizieren müsste ich die entsprechenden Emails heraus kramen und lesen. Alternativ könnest Du ein paar Beispiele erstellen und OS4 Benutzer zum Testen bereitstellen bevor Du Dir die Mühe machst, alles auf TTEngine zuzuschneiden. Meine Beispiele, die TTEngine verwandten, dürften mit dem letzten Head-Crash einer Festplatte verloren gegangen sein... Muss mal schauen, vielleicht haben einige doch überlebt. Zitat: Leider unterscheiden sich Ein-Byte-Zeichenfunktionen (die Du derzeit in TuiTED verwendest) grundlegend von Unicode Funktionen. Du wirst diese nicht verwenden können. Zudem ist die Limitierung auf 16-Bit sehr zeitraubend bedingt durch die Tests auf Surrogate-Code-Points, sofern Du nicht als Basis Unicode 3 verwendest, die allerdings veraltet ist. Du könntest wie in OS4 für jede unterstützte Sprache die entsprechenden Funktionen (StrCmp/ToLower/ToUpper) als eigenständiges Modul schreiben, was allerdings mit erheblichen Aufwand verbunden ist. Ich persönlich finde diesen Ansatz in Zeiten von Unicode aber nicht sehr elegant, jedoch immer noch besser als gar keine Funktionen anzubieten. @Thore Zitat: Wie, was? Das verstehe ich nicht. 16-Bit Code Points sind keine 2-Byte Zeichen. Oder verstehe ich hier etwas nicht richtig? Erklärung bitte! @Wanderer Zitat: Nee, kann es nicht. Unicode ist ein Zeichensatz, kein Datenformat wie IFF, PNG, UTF usw. . Der Unicode-Zeichensatz enthält eine viel größere Menge an Informationen bereit als der ASCII-Zeichensatz, auf die bei korrekter Implementierung eingegangen werden sollte. Ein Latin-1 oder ASCII-Texteditor kennt gar nicht alle Attribute aus die der Unicode-Zeichensatz besteht. Hier muss dann nachgebessert werden. @Wanderer Zitat: Das ist meinem Erachten nach kein günstiger Ansatz da alle Zeichenoperatoren dann für dieses spezielle Format nochmals vorliegen müssen. Einmal als Byte, dann als Wide-Char (16 Bits). Wäre mir persönlich nicht transparent genug. Zudem denke ich dass bei halbwegs korrekter Implementierung deinerseits Du sowieso nicht um volle 32-Bit Unterstützung herumkommen wirst. Ist aber nur Spekulation meinerseits. @Thore Zitat: Pweeh, ich hoffe ich schmeiße nicht alle Beiträge durcheinander - eurer Thread ist ein wenig lang und ich hatte keine Zeit in den letzten Tagen zu antworten. Was erwartest Du auf ungeraden Adressen zu finden wenn das Format als 16-Bit ausgelegt ist? Alle Code Points sind bei einem 16-Bit Format 'Words', d.h. sie sollten sowieso auf geraden Adressen liegen. 16-Bit ('Words') bedeutet aber nicht, das ein Zeichen aus einem einzelnen 'Word' besteht, es sei denn man beschränkt sich auf Unicode 3. Habe ich hier was nicht verstanden? Aufklärung bitte! @Wanderer Zitat: Autsch. Die Basis-Datei für Unicode 5.1 ist eine Textdatei die schon mal 1 Mbyte groß ist. Alle Basisinformationen, die durch diese Datei beschrieben werden, in ein maschinenlesbares Format umzusetzen ohne irgendwelche Kniffe anzuwenden, wird in einer Tabelle zwischen 3 und 4 Mbytes resultieren, je nachdem welche Informationen abgedeckt werden sollen. @Thore Zitat: Wie kommst Du an diese Information? Der Unicode-Zeichensatz (Zeichensalat) gibt keine vordefinierten oder festen Distanzen zur Bestimmung einer Information vor. Groß/Kleinbuchstaben können beliebig weit auseinander liegen - und das tun sie auch! Zitat: Nee, nix da. UnicodeData.txt ist euer Freund. @Wanderer Zitat: Du missachtest aber die Tatsache, dass Du erst einmal überprüfen musst, ob der betreffende Wert eines Zeichens (Code Point) in Deiner privaten Liste aufgeführt ist. Bei einem Spektrum von 1114109 Werten kommt dann Freude auf... Ich hab' zwar keine Ahnung wie Du vorgehen willst, aber mit einfachen Vergleichsoperationen (ist Code Point in meiner Liste oder nicht) wirst Du nicht weit kommen. Es dauert viel zu lange die betreffende Information einzuholen. Zitat: Da gebe ich Dir recht. Nur in diesem speziellen Fall glaube ich, dass Du sehr viel mehr Zeit aufwenden wirst, um eine halbwegs passable funktionierende ToLower/ToUpper Funktion zu schaffen, ganz zu schweigen um Code Point Attribute abzufragen. @Thore Zitat: Es gibt keine Ausnahmen. Der Unicode Zeichensatz ist nicht für eine einfache Indexierung geschaffen worden. Alles wäre einfacher falls dass Unicode Konsortium die Maschinen (CPU) in Mittelpunkt gestellt hätten und nicht den Menschen. Haben sie aber nicht. Anbei, ISO 8859-10 ist eine leicht geänderte Latin-1 Zeichenkodierung für nordeuropäischen Sprachen, demnach hat ISO 8859-10 nicht das Geringste mit dem Unicode-Zeichensatz zu tun. Zitat: Das ist so nicht richtig. Ersten gibt es kein '2 Byte Unicode' sondern Unicode 3 dass in 16 Bit Code-Units passt und Unicode 5.1 dass deren 32 (aktuell 21) benötigt. Zudem kann man auch Unicode 5.1 mittels 16 Bit Code-Units darstellen (Surrogate Code Points). 100000 Zeichen stimmt fast, es sind etwas mehr als 99000 definierte Zeichen vorhanden. Aber, Du verwechselst, falls ich das richtig interpretiere, definierte Zeichen mit Werten. Der Wertbereich in Unicode geht von 0 bis 1'114'109 (1.1 Millionen) wobei ca. 99'000 Zeichen eine Bedeutung haben, ob als grafisches Symbol oder als Kontrollcode spielt dabei keine Rolle. Zitat: Selbst wenn Deine Aussage stimmen würde (tut sie nicht) ist das Problem nicht Groß- zu Kleinbuchstaben zu wandeln sondern herauszufinden, ob ein Wert ein bestimmtes Attribut hat und es erlaubt ist, eine Aktion basierend auf den Wert bzw. dessen Attribut, auszuführen. Es gibt in Unicode keine feste Bindung zwischen einem Wert und seinen Attributen. Dein Fehler ist, dass Du zu sehr im Rahmen des griechischen Alphabets denkst. Unicode unterstützt das griechische Alphabet, ist aber nicht beschränkt auf seine Eigenheiten, ansonsten wäre Unicode nämlich unnütz. Thilo/Thore Ich will euch nicht vorschreiben, was ihr zu tun oder zu lassen habt, dazu habe ich auch keine Veranlassung. Ich möchte euch aber verdeutlichen, dass ihr es euch zu einfach macht. Unicode ist komplex. Selbst um nur eine kleine Teilmenge des Unicode-Standards zu implementieren wird schon sehr viel Zeit verschlingen. Ich spreche hier aus eigener Erfahrung. Demnach solltet ihr auch das was ich geschrieben haben, als Anregung auslegen und nicht als Bevormundung, was ich wirklich nicht beabsichtige. Zudem, ich bin kein Unicode-Spezialist und verfüge nur über allgemeines Wissen, nicht viel mehr als ihr beide auch habt. In diesem Sinne, viel Glück mit euren Unicode-Projekten, Grüße |
|||||
jolo
Nutzer
13.05.2009, 21:29 Uhr [ - Direktlink - ] |
Thema: Unicode auf OS3.x
Brett: Programmierung Hi. @Wanderer Zitat: Okay, das dürftest Du mittels UTF-8 und einem Filter um die originale Text()-Funktion sehr leicht hinbekommen. Zitat: Oje, da sind wir beide aber grundsätzlich verschiedener Meinung. Gerade komplexe Schriftbilder sind darauf angewiesen, dass die Non-Spacing-Marks auf die korrekten Positionen ausgerichtet werden ansonsten wird es unleserlich, nicht für Dich und mich, aber für die Menschen die diese Sprache beherrschen. Zitat: Das geht mittels UTF-8 und einem Filter um die Text()-Funktion. Zitat: Die Frage ist dann nur, welche Zeichen willst Du vordefinieren. Im Prinzip machst Du nämlich nichts anderes als einen Zeichensatz (Font) zu erstellen, der eine Untermenge an Unicode-Charakteren enthält, wie schon ein paar tausend FreeType und TrueType Zeichensätze. Wäre die FreeType2-Bibliothek nicht so komplex und ihre Benutzung ein wenig einfacher, würde ich Dir diese empfehlen. Du kannst ja erst einmal mit einer eigenen Zeichensatz-Implementierung beginnen und zu einem späteren Zeitpunkt die Benutzung der FreeType2-Bibliothek in Betracht ziehen. Zitat: Relativ einfach durchzuführen. Lade alle Dokumente als UTF-8 Texte, falls sie in diesem Format noch nicht vorliegen, konvertiere sie beim Laden. Du kannst nach wie vor die Text()-Funktion für Werte im Bereich 0 bis 127 verwenden, auch die normalen Funktionen zur Ermittlung der Zeichenbreite. Errechnete Werte im Bereich 128 bis 255 kannst Du auch noch mittels Text() ausgeben, allerdings nur über einen temporären Puffer, und erst bei Werten im Bereich von 256 bis einschließlich 1114109 kommt dann Dein 'Custom-Rendering' zum Einsatz. Zitat: Normalerweise kommt die FreeType2-Bibliothek als Linker-Bibliothek zum Einsatz. Eine offiziell genormte Schnittstelle für Amiga-Shared-Libs ist mir nicht bekannt, kann mich aber täuschen. Im Aminet müsste die FreeType2-Bibliothek sowohl als Linker- als auch als Shared-Lib für OS3 zu finden sein. Wie gesagt, ob die Schnittstelle genormt ist, entzieht sich meiner Kenntnis. Zitat: Soweit ich weiß benutzt MorphOS2.x TTEengine2 und die hat nicht mehr viele Gemeinsamkeiten mit TTEngine1 für OS3. @Wanderer Zitat: Betrifft nur TTEngine1. TTEngine2 krankt nicht daran. Zitat: Unter OS3? Nee, leider nicht. Die Identifizierung eines UTF-8 Textes musst Du leider selber vornehmen. Ist aber nicht sehr schwer. Alternativ kannst Du auch die CodeSets-Bibliothek dafür verwenden. Grüße |
|||||
jolo
Nutzer
11.05.2009, 20:34 Uhr [ - Direktlink - ] |
Thema: Unicode auf OS3.x
Brett: Programmierung @Der_Wanderer: Hi. Was Du benötigst wäre eine Render-Engine die Unicode unterstützt. Es gibt zwei für OS3. Beide arbeiten aber nur mäßig und sind sehr eingeschränkt im Umfang. Im Prinzip fast nutzlos. Die eine nennt sich TTEngine und die andere UCode. Vorab, falls Du einem Texteditor Unicode beibringen willst, sollte dieser: a) bidirektionale Zeichenausgaben beherrschen und auch diverse Methoden für Weak und Strong Characters anbieten b) zwischen Spacing und Non-Spacing Marks unterscheiden können c) Proportionale Schriftenausgabe beherrschen d) mehr als eine Schriftart pro Textzeile zulassen und diese Schriften zudem auch in unterschiedlicher Größe pro Textzeile darstellen können Alles andere wäre nur eigeschränkt Unicode fähig. Falls Du nur westliche Schriften unterstützen möchtest, reicht die Codesets-Bibliothek aus, um die Unicode-Werte auf den entsprechenden, westlichen Zeichensatz, abzubilden und dann mittels Text() das auszugeben, was abgebildet werden kann. Allerdings hat das in meinen Augen nichts mehr mit Unicode zu tun. Mein Rat an Dich wäre derzeit ein solches Projekt auf dem Amiga zurückzustellen und zu warten, bis irgendjemand eine voll funktionsfähige Unicode Render-Engine bereitstellt (z.B. Pango in Verbindung mit Cairo). Alles andere ist entweder halber Kram oder gänzlich Spielerei (siehe UCode). Grüße |
|||||
jolo
Nutzer
17.03.2009, 20:29 Uhr [ - Direktlink - ] |
Thema: Welcher Assembler ist der Beste?
Brett: Programmierung @AGSzabo: Falls Du beim Debuggen wirklich nicht weiter kommst, benutze "_kprintf" zur Ausgabe (linken mit debug.lib) und starte vorab Sushi (oder gleichwertiges Programm). Falls Dein Programm abstürzt, kannst Du hinter jeder "_kprintf" Ausgabe eine Zeitlang warten, mittels _LVODelay (falls Prozesse Deine Routinen aufrufen) oder mittels eines Busy-Loops des CIA-Bausteins (Tasks), so dass Du eine Ahnung bekommst, welche Routine den Absturz verursacht. Grüße |
|||||
jolo
Nutzer
30.10.2008, 23:18 Uhr [ - Direktlink - ] |
Thema: Keine Fenster Aktivierung bei Klick
Brett: Programmierung @Holger: Hoppala, was muss ich da lesen? Da arbeite ich bis spätabends und will noch kurz vor dem Rechner entspannen und dann so etwas. Ts, ts, ts. Solch verfasste Antworten bin ich von Menschen mit einer defizitären allgemeinen Intelligenz gewohnt, aber von einem Forumsmitglied... Holger, falls Du von mir ernst genommen werden willst, solltest Du eine andere Tonart anschlagen, falls nicht, auch nicht schlimm. Es mag zudem Menschen geben, die sich auf Deine Strohmann-Argumentation einlassen, ich jedoch zähle nicht dazu. Grüße -- Stupid mistakes are always made by others - we only make unavoidable errors |
|||||
jolo
Nutzer
27.10.2008, 23:02 Uhr [ - Direktlink - ] |
Thema: Keine Fenster Aktivierung bei Klick
Brett: Programmierung Hi! Zitat: Das Hauptfenster wird nicht deaktiviert. Zitat: Ich wollte das Thema Auffrischung (Refresh) bewusst ausklammern da es sehr komplex ist und ich mich auch noch nicht großartig mit diesem Thema befasst habe, noch das, was ich unten schreibe, bis ins kleinste Detail verifiziert habe. Nichtsdestotrotz, hier meine Sicht der Dinge... Ich unterscheide stark zwischen der Intuition-Bibliothek und der Layers-Bibliothek. Die Intuition-Bibliothek fußt auf der Layers-Bibliothek sowie die Layers-Bibliothek auf der Graphics-Bibliothek fußt. Intuition selber, auf dem Input-Task. Die Layers-Bibliothek verwaltet die Layers; dementsprechend ermittelt sie auch welche Regionen in der Bitmap sich überschneiden bzw. in ihrer Größe verändert wurden und welche Konsequenzen sich daraus ergeben. Die Intuition-Bibliothek nutzt nun diese Informationen um zu ermitteln ob und welche Bereiche der Fenster, und noch wichtiger, welche Fensterobjekte (Knöpfe, Fensterrahmen) wieder erneuert werden müssen. Intuition selber reagiert nur auf Benutzereingaben und auf explizit ausgeführte Aktionen. Die Grafikoperationen führt dabei nicht Intuition aus, sondern die Graphics-Bibliothek, denn alles was mit dargestellten Bitmaps zu tun hat ist ausschließlich Sache der Graphics-Bibliothek. Intuition veranlasst nur diese Dinge. Sie verlässt sich dabei auf Angaben der Layers-Bibliothek. Dementsprechend ist die Aussage die ich oben getroffen habe, dass die Layers-Struktur intakt bleibt und somit die Layers-Bibliothek entscheiden kann, welche Bereiche aufgefrischt werden müssen oder nicht, wobei der Auffrischvorgang (Refresh) von der Graphics-Bibliothek ausgeführt wird (primitive Grafikoperationen), wobei der Initiator Intuition ist, nach wie vor gültig. Zitat: Nehme an Du hast zehn Kindfenster geöffnet – dementsprechend bekommt Du laufend MOUSEMOVE-Nachrichten. Kommt jetzt ein INACTIVWINDOW schließt Du ein oder alle Kindfenster. Nichtsdestotrotz bekommst Du noch die Koordinaten (MOUSEMOVE) nachgereicht, die zum geschlossenen Kindfenster gehören. Falls Du hier, genauso wie ich ( ), keine sonderliche Sorgfalt walten lässt, wirst Du genau wie ich ( ), einen Systemabsturz erleben, da Du wohlmöglich nach wie vor eine grafische Operation in einem nicht mehr existenten Objekt durchführen willst, da Du ja die Koordinaten und die Aufforderung zum Zeichnen dazu erhalten hast... Ich hab’ die obere Erklärung abgegeben, weil ich zu diesem Zeitpunkt noch den Quellcode zum Beispiel mitliefern wollte, mich dann aber anders entschlossen habe. Dementsprechend war die Erklärung auf das nicht mitgelieferte Beispiel gemünzt. 'Tschuldigung. Zitat: Ja, habe ich ja auch so programmiert. Und zu zwei: Mir fällt auf die Schnelle kein Fall ein wo es sinnvoll wäre. Zitat: Was hat bitteschön, der Layer->Window Zeiger mit Zeichenoperationen zu tun? Nochmals, dieser Zeiger dient einzig und alleine zur Eingabestromumleitung. Auch solltest Du nicht außer Acht lassen, dass man Requester (unsichtbare, mit einer Größe von 0x0 Punkten) zum Blockieren des Eingabestroms für normale Fenster verwendet, die jegliche Auffrischungsnachricht für ein Fenster solange blockieren, wie der Requester aktiv ist. Kommt dadurch das Erscheinungsbild des Schirms durcheinander? Zitat: Sehr umständlich zu handhaben... Requester, sofern man kein eigenes Layer generiert, operieren im Layer des Fensters dass man bei der Initialisierung angibt, sprich eine so genannte Clipping Rectangle wird verwendet und somit sind Zeichenoperationen auf das darunter liegende Fenster beschränkt. Zitat: Frag' mal einen MorphOS oder AmigaOS4 Entwickler, ob es sich hierbei um einen Hack handelt oder um ein Vorgehen, das systemkonform ist. Ich würde auf letzteres tippen. Lade neues Beispiel (inkl. Quellcode hoch): GoInActive.lha Bitte, steinigt mich nicht für das lausige Beispiel und den verwendeten Quellcode; hatte leider nicht viel Zeit... Grüße -- Stupid mistakes are always made by others - we only make unavoidable errors |
|||||
jolo
Nutzer
26.10.2008, 11:59 Uhr [ - Direktlink - ] |
Thema: Keine Fenster Aktivierung bei Klick
Brett: Programmierung Hi! Zitat: Nö, wennste ( bin Niederrheiner, wir sprechen so ) schon den Zeiger für den Eingabestrom Deines Kindfensters auf Dein Hauptfenster "verbiegst", kriegtste ( ) auch die die Nachricht dort, wo der verbogene Zeiger hinzeigt; sprich Dein Hauptfenster. Allerdings existiert eine elegante Methode, um herauszufinden, ob nun irgendein Mausklick Dein Hauptfenster tangiert oder eines Deiner Kindfenster. Diesen Vorgang beschreibe ich weiter unten. Zitat: Wozu? Du kannst immer unterscheiden (kommt noch...), ob ein Mausklick in Deinem Hauptfenster stattfindet oder in einem Kindfenster. Falls der Klick im Hauptfenster gemacht wurde, schließt Du einfach das Kindfenster. Zitat: Solange Du Menüs oder Knöpfe, die von Intuition bzw. GadTools erstellt und verwaltet werden, ausschließlich in Deinem Hauptfenster darstellst, wirst Du keinerlei Probleme bekommen. Erst wenn Du versuchst, Knöpfe (Gadgets) oder Menüs in einem Deiner Kindfenster darzustellen sowie diese anzuwählen, wirst Du feststellen, dass diese tot sind solange der Layer->Window Zeiger nicht den Eingabestrom auf das betreffende Kindfenster umlenkt - und somit wieder das Hauptfenster inaktiv macht, was wir ja nicht wollen. Dementsprechend musst Du für alle Deine Kindfenster Deine eigenen Objekte darstellen und verwalten, ohne die Hilfe von Intuition oder GadTools. Dein Hauptfenster, solange alle Deine Kindfenster inaktiv sind, kann Dir nur die Mauskoordinate sowie das Drücken der linken bzw. rechten Maustaste sowie Tastatureingaben melden, mehr nicht. Nicht ob irgendein Menüeintrag (GadTools-Menü) oder Knopf gedrückt wurde. Wenn ich Dich aber richtig verstanden habe, stellt dies kein Problem für Dich dar? Zitat: Es ist die einzige mir bekannte Maßnahme um ein SuperBitMap-Layer mit einem Fenster zu koppeln. Dies ist auch so offiziell von Commodore Amiga publiziert worden, dementsprechend ist es kein Hack. Allerdings erstellt man hierbei die Zeichenfläche (Bitmap und Layer) von Hand und erst dann setzt man den Zeiger in der Layer-Struktur auf ein geöffnetes Fenster. Es ist auch nicht so, dass man den Window-Zeiger verbiegt, sondern nur in die Layer-Struktur das Empfangsfensters einträgt, im Falle dass der freche Nutzer die Maus zum Linksklicken benutzt und somit Intuition einen Anhaltspunkt hat, welche Zeichenfläche betroffen ist und ob der freche Nutzer unter Umständen eine andere Zeichenfläche nutzen möchte, d.h. er möchte ein anderes Fenster zur Eingabe auswählen und somit aktivieren. Die Window-Struktur ist *das* Bindeglied zwischen dem Input-Task und den einzelnen Zeichenflächen, mehr nicht. Layers sind die eigentlichen Grundgerüste für das, was wir Fenster nennen. Aber, vor lauter Fenstern sieht man die Layers nicht! Zitat: Doch, kann man. Es ist egal wie viele Fenster man öffnet, entscheidend ist nur, ob die geöffneten Fenster einen Zeiger auf das zu aktivierende Fenster innerhalb der Layer-Struktur setzen. Ein Fenster kann ja nur explizit (ActivateWindow()) oder mittels Linksklick aktiviert werden - und ausschließlich dazu dient dieser ominöse Zeiger in der Layer-Struktur (wer wird bei einer Aktivierung informiert bzw. wer bekommt den Eingabestrom ab: Layer->Window!). Ist Layer->Window == NULL wird dementsprechend "niemand" informiert. Zitat: Ja. Egal ob man den Zeiger innerhalb der Layer-Struktur ändert, die Layer-Struktur bleibt intakt und die Graphics- bzw. die Layer-Bibliothek kann den Refresh ausführen. Intuition ist nicht zuständig für die Erneuerung von Layern - sie kann es nur veranlassen bzw. hinauszögern. Ist leider ein zu komplexes Thema als dass ich es in ein paar Zeilen abhandeln könnte. Jetzt mal ein konkretes Beispiel: Man öffnet ein Fenster ganz gewöhnlich mit all seinen speziellen Eigenschaften und den IDCMP-Flaggen, die Benachrichtigungen auslösen sollen. Dementsprechend haben wir unser Hauptfenster. Nun öffnet man das Kindfenster, mit oder ohne irgendwelche Angaben von IDCMP-Flaggen; ist eigentlich egal. Bei Angaben von IDCMP-Flaggen, die so nicht im Hauptfenster vorhanden sind, muss natürlich das Hauptfenster mittels ModifyIDCMP() mitgeteilt werden, dass auch andere als die ursprünglich spezifizierten Flaggen eine Benachrichtigung auslösen sollen. Anbei, bitte nicht IDCMP_INACTIVEWINDOW oder IDCMP_ACTIVEWINDOW spezifizieren falls ein und derselbe MsgPort für das Hauptfenster und die Kindfenster verwendetet wird, ansonsten ist aus ersichtlichen Gründen ein Systemabsturz nicht fern! Bei der Initialisierung der Fensterbeschreibung (z.B. OpenWindowTagList()) wird eine Aktivierung des Fensters unterbunden (mittels "WA_Activate, FALSE"). Ansonsten deaktivieren wir beim Öffnen des Kindfensters das Hauptfenster... Ist wohl nicht gewollt. Falls das Öffnen klappte, haben wir ein Fenster, welches bei Angaben ohne IDCMPs (siehe oben) *keinen* eigenen MsgPort besitzt. Also erlauben wir dem Kindfenster den MsgPort des Hauptfensters zu benutzen: C code:if (Kindfenster->UserPort == NULL) Kindfenster->UserPort = Hauptfenster->UserPort; Jetzt müssen wir uns aber beeilen den Window-Zieger des Layers zu verbiegen, ansonsten wird ein Mausklick innerhalb des Kindfensters dieses aktivieren und unser ganzes Vorhaben geht den Bach runter: C code:Kindfenster->WLayer->Window = Hauptfenster; So, diese Arbeit ist getan; ein Klick in das Kindfenster sendet eine Nachricht ans Hauptfenster. Bleibt noch das Problem mit den Mauskoordinaten. Da alle Nachrichten an das Hauptfenster gesendet werden, müssen wir von diesem ausgehen um die Mauskoordinaten auf das Kindfenster umzumünzen. Hört sich aber schwieriger an als es ist: Unser Hauptfenster bekommt relative Koordinaten zum Ursprung seines Fensters, dementsprechend immer relativ zur oberen, linken Ecke (0,0). Addieren wir hier die obere, linke Ecke, haben wir die absolute Koordinate innerhalb des Schirms (Screen). Bei Verwendung von OS1.x müssen wir aber den Overscan-Modus berücksichtigen, was bei Benutzung von OS2 und höher durch das System erledigt wird. Ich gehe hier mal von OS2 und höher aus: C code:struct InutiMessage *msg; LONG x, y; /* Muss mit Vorzeichen arbeiten (speziell für OS1.x) */ struct Layer *welches; msg = (struct IntuiMessage *) GetMsg( Hauptfenster->UserPort); if (msg) { if (msg->Class == IDCMP_MOUSEMOVE) { x = (LONG) msg->MouseX; y = (LONG) msg->MouseY; /* x,y relativ zur linken, oberen Ecke des Hauptfensters */ x += Hauptfenster->LeftEdge; y += Hauptfenster->TopEdge; /* x,y absolut im Display */ /* Nun, welches Layer liegt unterhalb des Mauszeigers? */ welches = WhichLayer( Hauptfenster->WLayer->LayerInfo, x, y); if (welches) { /* Berechne relative Koordinate für das betreffende Layer */ x -= (LONG) welches->bounds.MinX; y -= (LONG) welches->bounds.MinY; /* "bounds" ist eine Struktur innerhalb der Layer-Struktur, die den Ursprung des Layers im Display beschreibt sowie dessen Ausmaße. */ } else { x = 0; y = 0; } } if (msg->Class == IDCMP_MOUSEBUTTONS) { /* Watt tun bei 'nem Klick? ( ;-) ) */ } } So, nun kann man noch eine Abfrage einbauen, ob eins der eigenen Kindfenster gemeint ist oder das Hauptfenster. Falls die Nachricht für das Hauptfenster ist, schließt man einfach die Kindfenster oder das Kindfenster: C code:void SchließeKindFenster( struct Window *kindFenster, struct Window *hauptFenster) { struct Message *msg; Forbid(); /* Teilen wir uns einen MessagePort mit dem Hauptfenster? */ if (kindFenster->UserPort == hauptFenster->UserPort) { kindFenster->UserPort = NULL; /* Extrem wichtig - ansonsten gibt CloseWindow( HauptFenster) den MsgPort ein zweites Mal frei --- CRASH! */ } else { /* Haben eigenen Port... */ while ( (msg = (struct Message *) GetMsg( kindFenster->UserPort)) ) ReplyMsg( msg); ModifyIDCMP( kindFenster, 0) } /* Man könnte noch ein: kindFenster->WLayer->Window = kindFenster; einbauen, muss man aber nicht. Es werden ja keine Nachrichten mehr empfangen. */ Permit(); CloseWindow( kindFenster); } Das war's. Habe eine Testdatei hochgeladen: ContextMenus.lha Grüße -- Stupid mistakes are always made by others - we only make unavoidable errors |
|||||
jolo
Nutzer
20.10.2008, 20:01 Uhr [ - Direktlink - ] |
Thema: Keine Fenster Aktivierung bei Klick
Brett: Programmierung Zitat: 'Tschuldige dass ich erst so spät antworten kann, leider bin ich im Moment zeitlich sehr eingeschränkt. Zu Deiner Frage: Theoretisch müsste es möglich sein. Einschränkend muss ich aber sagen, dass ich Deine, Dir selbst gestellte Aufgabe, so noch nicht programmiert habe. Unter Umständen, bei Verwendung von BOOPSI-Klassen oder Intuition-Gadgets könnte es aber zu Problemen kommen, da diese nach einer Window-Struktur oder einer Requester-Struktur verlangen, die bei der Initialisierung vorhanden sein muss. Ich müsste es mal selber ausprobieren um hier eine definitive Aussage treffen zu können. Leider ist es eine Aufgabe, die ich erst kommendes Wochenende machen könnte; vielleicht bist Du hier schon ein wenig weiter als ich und kannst mir mitteilen, wie weit Du gekommen bist? Gruß -- Stupid mistakes are always made by others - we only make unavoidable errors |
|||||
jolo
Nutzer
18.10.2008, 18:33 Uhr [ - Direktlink - ] |
Thema: Keine Fenster Aktivierung bei Klick
Brett: Programmierung Zitat: Hi. Du musst zwischen Zeichenoberflächen (Layers) und Fenstern (Windows) unterscheiden. Layers sind Grafik-Bausteine (struct Layer) und haben nichts mit Intuition im herkömmlichen Sinn zu tun. Intuition ist nur ein verlängerter Arm des Input-Devices und verlangt dementsprechend nach einer eigenen Struktur (struct Window). Ereignisse des Input-Device treten auch ohne Fenster auf, jedoch leitet das Input-Device unter Normalbedingungen diese Ereignisse an Intuition weiter, wobei Intuition aufgrund der Fenster-Struktur (Window) entscheidet, an welchen Message-Port die Nachricht bzw. das Ereignis gesendet wird. Zitat: Hat mit Aktivierung eines Layers nichts zu tun. Im Prinzip gibt es nämlich keine aktiven Layers sondern nur aktive Fenster. Layer = Grafik, Window = Input. Ein Layer ist nichts anderes als ein Teil einer BitMap (Screen) oder die Zeichenfläche einer ganzen BitMap (SuperBitMap-Layer), aber immer ausschließlich eine Zeichenfläche. Intuition dockt seine Windows-Struktur an eine vorhandene Layer-Struktur an, damit Intuition ermitteln kann, welchem Programm (Message-Port) es eine Nachricht zukommen lassen muss, falls ein Ereignis auftaucht. Dazu geht Intuition davon aus, dass das Layer, welches das aktive Fenster repräsentiert, die Ereignisse erhalten soll. Nachtrag: Layers sind Lösungen um mehreren gleichzeitig laufenden Programmen exklusive Zeichenflächen zu bieten, ohne dass sich der Programmierer um die Bereichsgrenzen kümmern müsste, d.h. dass er nicht unabsichtlich fremde Zeichenbereiche überschreibt/übermalt, aber Layers haben rein gar nichts mit Ereignissen zu tun. Layers werden von Intuition nur "vergewaltigt", damit Intuition cleverer erscheint als es ist. Gruß -- Stupid mistakes are always made by others - we only make unavoidable errors |
|||||
jolo
Nutzer
16.10.2008, 18:00 Uhr [ - Direktlink - ] |
Thema: Keine Fenster Aktivierung bei Klick
Brett: Programmierung Zitat: Innerhalb der Layers-Struktur den Window-Zeiger auf ein Fenster Deiner Wahl verbiegen oder Nullen. Gruß |
|||||
jolo
Nutzer
19.12.2007, 21:25 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung Hallo. Ich habe mit Hilfe von Maik die Bibliothek dahingehend zum Laufen gebracht, dass nun diese Knackser während der Aufnahme und dem gleichzeitigen Betrieb eines kommerziellen Programms nicht mehr aufgezeichnet werden. Ein kleiner Trick hilft hier - meines Wissens nach von Bert Jahn (WHDLoad) - und als Interrupt Acknowledge Fix bekannt: Unter schnellen Prozessoren (68040 und höher) kann es passieren, dass ein Interrupt-Acknowledge unter geht, falls kurzeitig danach der Supervisor-Modus (Interrupts werden im Supervisor-Modus abgearbeitet) verlassen wird (rte). Was hier hilft, ist vor dem eigentlichen Bestätigen (Acknowledge) eines Interrupts und verlassen des Supervisor-Modus eins der CIA-Register oder eins der Custom-Register auszulesen. Dann klappt es wieder mit der Bestätigung (im ROM). Maik hat mich mit der Nase darauf gestoßen... Ich ziehe meinen Hut vor Bert Jahn - ich selber wäre nie auf die Idee gekommen... Neue Version inklusive Quellcode kann unter http://www.amimedic.de heruntergeladen werden. Gruß |
|||||
jolo
Nutzer
05.12.2007, 19:01 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @Holger: Hi. Zitat: Das ist ein wunder Punkt - Maik und ich probieren derzeit ein wenig herum, da anscheinend Störungen von außen die Daten am parallelen Port beeinträchtigen. Auch habe ich zwei Fehler in der Ire-Bibliothek ausgemacht: 1. Der CIA-A Interrupt wurde mit einer falschen Maske gestartet. 2. INTENA und INTREQ wurden vertauscht - was unter einem echten Chip-Satz fatale Folgen haben kann. Dementsprechend habe ich das schon korrigiert - INTENA und INTREQ werden jetzt auch nicht mehr benutzt. Wenn's denn irgendwann so läuft wie es laufen soll, wird der Quell-Code beigefügt - im Moment sind zu viele #ifdefs drin und ein Mix aus Deutsch und Englisch... Zitat: Das ist richtig - allerdings fällt mir keine bessere Lösung ein um das hier unter WinUAE auszuprobieren. Ich könnte natürlich von Windows aus Daten auf den Port zaubern - aber um ehrlich zu sein, ich hatte schon mal gravierende Probleme bezüglich des Timings unter XP dass ich da lieber die Hände von lasse... Zitat: In neueren Versionen wird der parallele Port gelockt - allerdings hat das meines Wissens nach keinen Einfluss auf irgendwelche Werte, da hier nur sichergestellt wird, dass ausschließlich ein Nutzer einen Baustein (Centronics) verwenden kann. Was ich derzeit mache, ist das DDRA und das DDRB Register zu initialisieren, abgesehen vom Generieren des Interrupts. Maik hat mittels eines anderen Digitizer herausgefunden, dass die Störgeräusche auch unter diesem aufgezeichnet werden. Verantwortlich dafür scheint ein kommerzielles Programm zu sein, welches einen CIA-B Timer-B Interrupt generiert um eine Hardware-Erweiterung nutzbar zu machen. Verantwortlich ist allerdings das falsche Wort: Ich gehe davon aus, dass dieses kommerzielle Programm alles richtig macht, jedoch es dadurch zu Störungen des Sound-Samplers (sprich Digitizer) kommt. Und hier muss ich jetzt irgendwie eine Lösung finden, die beiden, also diesem kommerziellen Programm als auch dem Digitizer der Ire-Bibliothek gerecht wird. Mal schauen ob ich's hinbekomme. Gruß |
|||||
jolo
Nutzer
01.12.2007, 10:14 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi. Zitat: Für mich sind das Senden von Infrarotsignalen und das Digitalisieren zwei Paar Schuhe - dementsprechend zwei Programme. Beim Senden von Infrarotsignalen bist Du auf Signale vom Interrupt angewiesen um das Timing hinzubekommen; beim Digitalisieren aber nicht. Das Beispiel, dass Du aufzeigst, dient dem Digitalisieren - nicht dem Senden von Infrarotsignalen. Zitat: Habe übers Forumsformular Dir meine Email-Adresse zukommen lassen. Zitat: Nee, daran dass man oft bei der Amiga-Programmierung auf Programmierer stößt, die ein bestimmtes Verhalten voraussetzen - was aber nie von Commodore als solches dokumentiert wurde. Mache solche Fehler selber… Zitat: Eigentlich schon. Da aber Deine Timing-Intervalle an die Grenzen des Machbaren stoßen, wird's ein wenig kritisch. Gruß |
|||||
jolo
Nutzer
30.11.2007, 19:47 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi. Zitat: Ja, schon. Trotzdem kann ich es testen. Habe drei Möglichkeiten: 1) Die Bibliothek besteht zusätzlich aus einer Audio-Datei (2,2 Mbytes). Im Interrupt wird nicht das Datenbyte vom parallelen Port gelesen sondern das entsprechende Byte in der Audio-Datei. 2) Am Ende des Interrupt-Codes wird ein Byte der Audio-Datei auf den parallelen Port geschrieben. 3) AudioGrabber.asm wurde abgewandelt um aus einer Audio-Datei das entsprechende Byte auf den parallelen Port zu schreiben - hat allerdings den Nachteil, dass damit nur Frequenzen bis zu 7 kHz verwendet werden können (wie gesagt, WinUAE ist bei der Emulation des Chip-Satzes nicht so schnell wie die echte Hardware). Zitat: Was glaubst Du?!?!? Ich bin kein Hellseher. Zitat: Ja, mach das. Dann habe ich zumindest einen Anhaltspunkt. Zitat: Ich kann nicht mit 22 kHz digitalisieren - sondern bis maximal 14. Dementsprechend sind 200004 Bytes durch 14840 Bytes/Sekunde 13,4 Sekunden und nicht 16,1. Die Funktion TIMER ist mehr als ungenau. Zitat: Komisch. Hier funktioniert es ohne Knackser - dementsprechend muss ich etwas übersehen haben, was WinUAE ignoriert die originale Hardware aber nicht. Gruß |
|||||
jolo
Nutzer
28.11.2007, 22:35 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi. Zitat: Leider wurden hier auf meiner Maschine Abschnitte doppelt wiedergegeben - das habe ich auf ein Minimum in der letzten Version reduzieren können (60 Hz / 50 Hz Timing). Zitat: Hier geht's. Hast Du das normale Signal-Handling abgeschaltet? - Dann kann es nicht funktionieren. Zitat: Wie oft pro Sekunde kommen diese vor (schätzungsweise)? Zitat: Hier funktioniert das nicht so gut. Zitat: Was heißt Monitorausgabe? code:REM Zwei Macken sind mir in MBasic aufgefallen: REM Umlaute mag es gar nicht und CALL funktioniert nicht so wie in AmigaBasic REM ON BREAK GOTO FastOut REM BREAK ON LIBRARY "exec.library" DECLARE FUNCTION AllocVec&() LIBRARY DECLARE FUNCTION FreeVec&() LIBRARY DECLARE FUNCTION xWait&() LIBRARY LIBRARY "dos.library" DECLARE FUNCTION xOpen&() LIBRARY DECLARE FUNCTION xWrite&() LIBRARY DECLARE FUNCTION xClose&() LIBRARY DECLARE FUNCTION Delay&() LIBRARY LIBRARY "ire.library" DECLARE FUNCTION InitIRQ&() LIBRARY DECLARE FUNCTION StartIRQ&() LIBRARY DECLARE FUNCTION DeleteIRQ&() LIBRARY DECLARE FUNCTION GetIRQAttrI&() LIBRARY DECLARE FUNCTION SetIRQAttrI&() LIBRARY LIBRARY OPEN "exec.library" LIBRARY OPEN "dos.library" LIBRARY OPEN "ire.library" CONST PGROESSE& = 40000 REM --- Puffergroesse CONST Hz& = 14880 REM --- Frequenz CONST MEMF_CLEAR& = 65536 CONST MODE_NEWFILE& = 1006 CONST SIGBREAKF_CTRL_C& = 4096 CONST THIS_SIGBIT_DBUF_FULL& = 1 CONST THIS_DBUF_FULL& = 16 CONST THIS_IRQ_SIGBIT& = 2 CONST DISABLE_SIGNALLING& = 4 CONST ENABLE_SIGNALLING& = 8 CONST THIS_FREQUENCY& = 32 CONST THIS_PERIOD& = 256 CONST THIS_SAMPLE_POS& = 1024 CONST TOGGLE_DMA_ACCESS& = 64 CONST TOGGLE_MAKE_AUDIBLE& = 128 CONST TOGGLE_16BIT& = 512 REM $NOEVENT REM $NOOVERFLOW REM $NOLINES REM --- Los geht's REM POKEB &hBFD000,2 --- Paper Out signalisieren POKEB &hBFE301,0 REM --- Parallel-Port auf Eingang Index& = 0 REM --- Dateinamenerweiterung MySample1& = AllocVec&( PGROESSE&, MEMF_CLEAR&) MySample2& = AllocVec&( PGROESSE&, MEMF_CLEAR&) IF MySample1& <> 0 AND MySample2& <> 0 THEN DIM pufferliste&(12) pufferliste&(0) = MySample1& pufferliste&(1) = MySample2& pufferliste&(2) = 0 REM --- Interrupt und benötigte Strukturen initialisieren ihandle& = InitIRQ&( Hz&, SADD("MBasic Digitizer"+CHR$(0)), 0, 0, VARPTR( pufferliste&(0) ), PGROESSE&) IF ihandle& <> 0 THEN REM --- Signal-Bit für "Puffer-Ist-Voll" holen und in Maske wandeln sigmask& = ( 1 << GetIRQAttrI&( ihandle&, THIS_SIGBIT_DBUF_FULL&) ) REM --- Normales Interrupt-Signal-Handling ausschalten junk& = SetIRQAttrI&( ihandle&, DISABLE_SIGNALLING&) REM --- Audio-Ausgabe aus/anschalten REM junk& = SetIRQAttrI&( ihandle&, TOGGLE_MAKE_AUDIBLE&) REM --- DMA Audio-Ausgabe einschalten junk& = SetIRQAttrI&( ihandle&, TOGGLE_DMA_ACCESS&) junk& = Delay&( 50) REM --- 1 Sekunde warten REM --- Interrupt starten junk& = StartIRQ&( ihandle&) DO PRINT "Starte Timer..." t! = TIMER REM --- Zeit des Starts festhalten REM --- Warten bis irgendetwas passiert... received& = xWait&( sigmask& OR SIGBREAKF_CTRL_C&) IF received& AND SIGBREAKF_CTRL_C& THEN EXIT LOOP ELSE t! = TIMER-t! REM --- Und Ende festhalten (TIMER ist seeeehr ungenau: REM --- bei 200004 Bytes 13,76 Sek. mit Stoppuhr aber 16,18 Sek. laut TIMER)! CALL WriteBuffer( GetIRQAttrI&( ihandle&, THIS_DBUF_FULL&), PGROESSE&) REM --- Benötigte Zeit wiedergeben PRINT PGROESSE& "Bytes wurden innerhalb von" t! "Sekunden mit"; PRINT GetIRQAttrI&( ihandle&, THIS_FREQUENCY&) "Hz digitalisiert." PRINT "Diese Angabe ist mit Vorsicht zu genießen!" END IF LOOP REM --- Interrupt beenden und Ressourcen freigeben FastOut: junk& = DeleteIRQ&( ihandle&) END IF END IF IF MySample2& <> 0 THEN REM --- Puffer freigeben junk& = FreeVec&( MySample2&) END IF IF MySample1& <> 0 THEN REM --- Puffer freigeben junk& = FreeVec&( MySample1&) END IF REM --- Alle geoeffneten Bibliotheken schliessen LIBRARY CLOSE END REM ---- PROGRAMMENDE ---- REM --- Pufferinhalt als Datei schreiben. SUB WriteBuffer( adr&, xlen&) fh& = xOpen&( SADD("RAM:sample_raw"+STR$(Index&)+CHR$(0)), MODE_NEWFILE&) IF fh& <> 0 THEN junk& = xWrite&( fh&, adr&, xlen&) junk& = xClose&( fh&) END IF Index& = Index& + 1 END SUB Habe die Demo-Version von MBasic runtergeladen und Dein Programm abgewandelt. Hier funktioniert es. Gruß |
|||||
jolo
Nutzer
28.11.2007, 00:15 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi. Zitat: Das wird nicht funktionieren, da beide, die Audio-Hardware und die CIA-Chips unterschiedliche Taktfrequenzen haben. Zitat: Ja, Klangeinbußen gibt es - aber das Timing (CIA zu Audio) war nicht akkurat (50 Hz vs. 60 Hz...). Zudem hat die DMA-freie Audioausgabe keinerlei Probleme mit Abschnitten die doppelt wiederholt werden. Es wird analog das ausgegeben, was rein kommt. Zitat: Nur wenn Deine Routine innerhalb des Interrupt aufgerufen wird (usersCode, usersData). Ansonsten, wenn's auf Prozess-Ebene läuft, nicht. Zitat: Nein, für normale Interrupt-Aufgaben, also alles ohne Digitalisierung, bleibt alles beim Alten. Nur für die Audio-Ausgabe wird eine Neuberechnung durchgeführt. Mir ist allerdings ein Malheur passiert und ich habe eine Version mit halber Ablaufverfolgung hochgeladen, die eigentlich nur für mich bestimmt war. Dementsprechend müsste es bei Deiner Version zu Störungen bei der Wiedergabe kommen (Abschnitte werden des Öfteren wiederholt). Zitat: Zu 1) Du digitalisierst auf Prozess-Ebene? Dementsprechend benutzt Du von Basic aus einen Interrupt, um 22000-mal in der Sekunde ein Signal zu empfangen - und wenn es eintrifft liest Du den Wert der am parallelen Port anliegt? Wenn dem so ist kann ich Dir jetzt schon sagen, dass Du das niemals auf Prozess-Ebene schaffen wirst - okay, vielleicht mit einem neuen OS und einer CPU die um ein vielfaches schneller ist als Deine 68060 - aber nicht mit der jetzigen Software und Hardware. Extra für diesen Zweck habe ich einen Digitizer auf Interrupt-Ebene entworfen. Er sollte Dir die Arbeit abnehmen. Zu 2) Wie schon im letzten Beitrag von mir geschildert, soll die Audio-Ausgabe nur grob einen Überblick über die tatsächliche Digitalisierung geben. Leider, wie oben geschildert, habe ich eine Version hochgeladen, die mit dem falschen Compiler-Aufruf erstellt worden ist - hier ist die Wiedergabe nicht ganz so genau wie bei der Version die Du eigentlich verwenden müsstest. Um eine Ablaufverfolgung zu starten, löscht die Version die Du jetzt besitzt, alle Audio-Interrupt-Quellen und wartet solange, bis diese durch die Hardware neu gesetzt wurden. Dementsprechend kann ich exakt bestimmen, wie viele Bytes pro Sekunde von der Audio-Hardware ausgegeben werden, bzw. wie viele Bytes pro Sekunde der Interrupt zu langsam oder zu schnell läuft. Der Nachteil der damit erkauft wird, ist, dass die Audio-Hardware kurzzeitig aus dem Tritt gebracht wird, da sie selber auf diese Audio-Interrupt-Quellen angewiesen ist, bzw. für einen Störungsfreien Ablauf diese Quellen nicht zurückgesetzt werden dürfen. SampleManager (hallo Thilo - nettes Programm!) habe ich mal runtergeladen und über die Dateien gejagt, die ich hier digitalisiere. Es sagt mir kein Crackle (Knistern?). Dementsprechend gehe ich davon aus, dass der Interrupt-Code in Ordnung ist. Bleibt nur noch die Frage was mit den Daten vom parallelen Port geschieht. Ich kann mir nicht vorstellen, dass der CIA-A Interrupt irgendwelchen Einfluss auf die Daten vom parallelen Port hat, da ansonsten das von Commodore vorgesehen Handshake zwischen CIA-A und CIA-B beim Senden oder Empfangen von Daten am parallelen Port gestört sein würde - und ich das als Hardwarebug bezeichnen würde, der mindestens mit dem Erscheinen des ECS-Chipsatz hätte verschwunden sein müssen. Zudem bist Du Dir auch nicht sicher, ob es an Deinem Programm liegt oder an der Bibliothek. Daher würde ich Dich bitten, mir Klarheit zu verschaffen. Tauchen Probleme beim Digitalisieren mittels Digi auf oder nicht? Zum CIA-B Interrupt: Meiner Meinung nach sollte dieser gar nicht verwendet werden, jedenfalls nicht bei gleichzeitiger Benutzung der Audio-Hardware - da die Audio-Hardware Interrupts der Ebene 4 generiert und bei der Benutzung eines Level-6 Interrupts diese nicht zum korrekten Zeitpunkt erstellt werden können - womit die Audio-Hardware dann aus dem Tritt kommt und es zu Störungen bei der Wiedergabe kommen muss (jedenfalls geschieht dies hier unter WinUAE). Somit ist das ASM-Beispiel eigentlich ein gutes Beispiel wie man es nicht machen sollte... Anbei, SetIRQAttrI( ihandle, 512) schaltet vom 8-Bit Modus in den 16-bittigen und umgekehrt. Dementsprechend kannst Du die Audio-Ausgabe über AHI bewerkstelligen, falls Du möchtest. Um die aktuelle Position in Deinem FAST-RAM Puffer zu erfahren, kannst Du: GetIRQAttrI( ihandle, 1024) benutzen - es retourniert die Position des aktuellen Samples im Puffer (FAST-RAM) - bei 16-Bit Samples musst Du den Wert mit 2 multiplizieren - dann hast Du die Byte-Position. Dementsprechend kannst Du z.B. auf Position 32 warten und dann mittels AHI die Audio-Daten ausgeben - falls Du dies möchtest. Neue Version ohne Ablaufverfolgung wurde hochgeladen. Gruß |
|||||
jolo
Nutzer
25.11.2007, 15:44 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi. Zitat: Ohne Dir zu nahe treten zu wollen: Wenn ich schon Schwierigkeiten habe dass korrekte Timing hinzubekommen, wie willst Du dann von Basic aus vorgehen? Zitat: Höre ich da leichte Kritik bezüglich meiner BASIC-Programmierkenntnisse? ;-) Zitat: Das dürfte normal sein - das Timining-Verhalten ist bei DMA-freier Wiedergabe was gänzlich anderes als mit DMA. Nichtsdestotrotz ist es die einzige Möglichkeit ein absolut exaktes Timing hinzubekommen. Zitat: Heißt das, dass Deine eigenen Routinen zum Digitalisieren diese Knackser beinhalten und TimerIRQ solche Mätzchen nicht macht? Habe jetzt so was wie die endgültige Fassung der Bibliothek fertig gestellt. Das Timing wurde komplett geändert. Es basiert nicht mehr auf 60 Hz Netzspannungen... War ein Fehler zur Berechnung der Periode (Audio-Ausgabe). Jetzt wird die Periode anhand der Frequenz berechnet und danach die Frequenz anhand der Periode. Danach wird aufgrund der neu berechneten Frequenz einer der beiden CIA-A Timer mit dem korrekten Wert initialisiert. Beispiel: Falls Du 14880 Hz als "callsPerSecond" spezifizierst, wird stattdessen eine Frequenz von 14840 verwandt. Du kannst das abfragen, indem Du GetIRQAttrI( 32) aufrufst. Um die Periode zu ermitteln, kannst Du GetIRQAttrI( 256) verwenden. Als nächstes habe ich die DMA-freie Audio-Ausgabe überarbeitet: Das INTEN-Bit im Interrupt-Kontrollregister wird jetzt immer gelöscht - damit man DMA-freie und DMA-unterstützende Ausgabe während der Audio-Wiedergabe wechseln kann. Hoffentlich hat das keine negativen Seiteneffekte auf den Blitter/Copper… Das Programm Digi wechselt alle 5 Sekunden den Modus während es digitalisiert. Voreingestellt ist jetzt der Typ DMA-freie Audio-Ausgabe. Falls Du das nicht willst, musst Du SetIRQAttrI( 64) einmalig aufrufen. Das Programm Digi digitalisiert wirklich - es schreibt Dateien mit maximal 540000 Bytes in die RAM-Disk - allerdings kann eine einzige Audio-Ausgabe aus mehreren solcher Dateien bestehen. CTRL-C beendet es wie gewohnt. Habe das Programm SampleEngine beigefügt (dafür muss die noise.library ins LIBS-Verzeichnis), mit dem Du diese Dateien abspielen kannst. Ist allerdings ein Uralt-Tool - könnte ein paar Macken haben. Eine ist z.B. dass die einzuladende Datei komplett ins CHIP-RAM passen muss - ich hoffe Du hast 1 bis 2 MBytes CHIP-RAM? Wenn keine Audio-Ausgabe erfolgt, kann das an einem Bug im Programm liegen. Einfach solange den Play Button betätigen bis es geht (evt. solange warten, bis der Warten-Mauszeiger verschwindet). Mit diesem Programm kannst Du verifizieren, dass die Audio-Ausgabe mehr oder weniger unabhängig von dem Digitalisieren ist, was bedeutet, das selbst eine inkorrekte Audio-Ausgabe nicht gleichzusetzen ist mit einer inkorrekten Digitalisierung. Probiere es mal aus - dann verstehst Du was ich meine. Anbei, DMA-unterstützende Audio-Wiedergabe (also mittels CHIP-RAM Puffer) sollte jetzt seltener einen Abschnitt doppelt wiedergeben - bedingt durch die korrekte 50 Hz Initialisierung. Ach ja, und zu guter Letzt: Cause() kann doch nicht beliebig oft innerhalb einer Sekunde aufgerufen werden. Es wäre nett, wenn Du mir sagen könntest, ob mittels Digi digitalisierte Dateien und mittels SampleEngine wiedergegebene Dateien korrekt sind - d.h. ob keine Fehler (Blips) darin enthalten sind. Gruß |
|||||
jolo
Nutzer
23.11.2007, 00:25 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi. Zitat: Stimmt schon - allerdings *fühlt* sich Amithlon wie ein echter Amiga an. Ist kein Vergleich zu (Win)UAE. Da es nicht mehr vertrieben und weiterentwickelt wird und die meisten, die es besitzen, nicht verkaufen/missen wollen, kommt man kaum noch an Amithlon ran. Zitat: In Ordnung. Wird gemacht. Zitat: Das Assembler-Beispiel benutzt einen der beiden CIA-B Timer. Wie Du aus meinen Postings ersehen kannst, möchte ich das Ganze auf Basis der CIA-A Timer belassen und zwar weil dadurch das System nicht bei unsachgemäßer, sprich übergebührlicher Benutzung in die Knie geht. Falls es mit dem CIA-A Timern klappt, lassen wir es so wie es ist, falls allerdings nicht, stelle ich auf CIA-B um. Zitat: Ja, aber man könnte dem mit einigem Aufwand entgegentreten - ich persönlich kann aber mit diesen kurzen Blips gut leben, da diese ja nicht als Daten in die FAST-RAM Puffer übernommen werden. Zitat: Nee, nur AllocVec() ohne MEMF_CLEAR Flagge - dementsprechend ist der Puffer (CHIP-RAM) in einen undefinierten Zustand - verwende ich, um Initialisierungs-Fehler aufzuspüren. Wird zu einem späteren Zeitpunkt - wenn alles klappt wie es soll, geändert. Zitat: Hier missverstehen wir uns. Deine Puffer (FAST-RAM) werden mit Werten gefüllt - sie werden aber nicht für die Audio-Ausgabe verwendet. Dafür fordert InitIRQ() vom System CHIP-RAM an. Dieser CHIP-RAM Puffer ist allerdings privat, d.h. Du hast keinen Zugriff darauf. CHIP-RAM bremst eine CPU ein - im FAST-RAM Bereich kann die CPU mit voller Geschwindigkeit werkeln. Dementsprechend sollte man nur dann CHIP-RAM verwenden, wenn es unbedingt nötig ist (Custom-Chips) und die CPU soweit möglich, nicht auf diesen Speicherbereich zugreifen lassen. Eine 68060 die aufs CHIP-RAM zugreifen muss, ist nur unwesentlich schneller als eine 68000er. Anbei, die letzte wie auch die aktuelle Version verwenden überhaupt keinen CHIP-RAM Puffer - obschon dieser nach wie vor alloziert wird. Die Audio-Ausgabe erfolgt ohne DMA - das heißt ohne Speicherzugriffe seitens der Custom-Chips. Zitat: Mache ich gerne weil es mir Spaß bereitet, die Hardware wieder direkt anzusprechen. Zitat: Das habe ich befürchtet - Mist! Komisch, nachdem ich alle Preprozessor-Kommandos durch Laufzeitvariabeln ersetzt habe, lief es plötzlich auch hier. Nach mehreren Tests hat sich herausgestellt, dass im Falle einer Veränderung am Inhalt des Audio-Puffers (CHIP-RAM), der ja eigentlich bei der Verwendung der Audio-Hardware ohne DMA, dass heißt Speicherzugriffe durch die Custom-Chips, keinerlei Bedeutung hat, diese Veränderung am Pufferinhalt von der Audio-Hardware registriert und in irgendeiner Weise mit negative Folgen quittiert wird. Hmmm, nachdem der CHIP-RAM Puffer nicht mehr verändert wird, kann selbst unter WinUAE DMA-freie Audio-Ausgabe erzeugt werden. Kann mir jemand dieses Verhalten erklären? Um noch einen drauf zu setzen: Cause() kann beliebig oft innerhalb einer Sekunde aufgerufen werden. Meine Spekulation bezüglich des Timings ist vollkommen falsch. Dies bedeutet im Umkehrschluss, dass es mittels des Timer-Device theoretisch möglich sein sollte, zigtausend Prozessor-Unterbrechungen pro Sekunde zu generieren. Auch unter MorphOS/OS4! Dementsprechend brauch man/frau keine CIAs. Kann aber noch nicht sagen, welche Voraussetzungen für das Timer-Device geschaffen werden müssen um das zu erreichen (doppelte Interrupt-Struktur?). Zitat: Der Digitizer-Code funktioniert - und schmiert nicht ab? Okay, das mit der Pufferliste ist easy. Wenn Du nur einen Puffer verwenden willst, muss die Pufferliste acht Bytes groß sein - wegen des terminierenden NULL-Pointers. Pufferliste 0 - 0xnnnnnnnn Adresse Deines Puffer (also hier die Adresse die AllocVec() zurück gibt eintragen) 4 - 0x00000000 NULL-Pointer Ende der Pufferliste InitIRQ() erwartet nun die Adresse der besagten acht Bytes - also einen einfachen Zeiger. Im Prinzip könntest Du AllocVec() mit acht Bytes aufrufen - die zurückgegebene Adresse ist dann die Pufferliste. Jetzt allozierst Du 50000 Bytes und trägst die retournierte Adresse an erster Stelle in Deine Pufferliste. Das Langwort an zweiter Stelle in der Pufferliste musst Du jetzt löschen - das war's. Oder für zwei Puffer: pufferliste = AllocVec( 12, MEMF_CLEAR) puffer1 = AllocVec( 50000, MEMF_CLEAR) puffer2 = AllocVec( 50000, MEMF_CLEAR) Nehme jetzt mal an, 'pufferliste' liegt ab Adresse 3000 im Speicher, 'puffer1' ab 15000 und 'puffer2' ab 90000. Dann müsste nach der korrekten Initialisierung der Speicherbereich ab 3000 so aussehen: (3000 = $BB8, 15000 = $3A98, 90000 = $15F90, 3016 = $BC8) code:__________1. Langwort 2. Langwort 3. Langwort 4. Langwort 00000BB8: 00 00 3A 98 00 01 5F 90 00 00 00 00 XX XX XX XX 00000BC8: XX XX XX XX usw. InitIRQ() benötig in diesem Beispiel als fünften Parameter den Wert $BB8 - ab diesem Speicherbereich stehen die Langworte (Adressen) zu den einzelnen Puffern. Und solange es kein Langwort dessen Wert null ist findet, interpretiert es jedes gesetzte Langwort als Adresse (in oberen Beispiel zwei). Nehme zudem an, dass ab Adresse 9999 der String steht, der dem Interrupt einen Namen gibt, dann lautet der Aufruf für InitIRQ mit 22050 Hz wie folgt: InitIRQ( 22050, 9999, 0, 0, 3000, 50000) oder ausgeschrieben - in C: InitIRQ( 22050, "Test", 0, 0, pufferliste, 50000) Im Prinzip ganz einfach zu handhaben. Und ja, Deine Puffer dürfen im FAST-RAM Bereich liegen - sie werden vom Interrupt nur gefüllt (ein Byte pro Timer-Tick) und dann nicht weiter beachtet. Neue Version wurde hochgeladen. Benutzt weiterhin einen CIA-A Interrupt und eine DMA-freie Audio-Ausagbe. DMA-frei bedeutet, dass kein CHIP-RAM Puffer verwendet wird. Du kannst das ändern, indem Du SetIRQAttrI( ihandle, 64) aufrufst (habe ich aber noch nicht ausprobiert). Ein nochmaliger Aufruf stellt den voreingestellten Modus wieder her. Gleiches gilt für die Audio-Ausgabe: Die Audio-Ausgabe kannst Du unterdrücken, indem Du SetIRQAttrI( ihandle, 128) verwendest - oder wieder einschalten, bei nochmaligen, gleich lautenden Aufruf. Habe ich auch noch nicht ausprobiert... Die Werte 64 und 128 sind Kippschalter. An, aus, an, aus, an, aus... Sag mir mal ob jetzt die Audio-Ausgabe ansatzweise in Ordnung ist. Gruß |
|||||
jolo
Nutzer
21.11.2007, 23:46 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung Hi. Zitat: Das Problem einer jeden Emulation ist, dass diese sukzessiv vorgehen muss - denke ich zumindest. Ich habe noch keine geschrieben - und habe es auch nicht vor. Der Amiga und seine Custom-Chips verarbeiten aber Daten parallel zueinander, d.h. unabhängig von einander. Dementsprechend sind die Zeitabstände in denen eine Aktion stattfinden kann, auf der echten Hardware immer kleiner als unter einer Emulation - zudem laufen die meisten Emulationen noch unter einem Host-Betriebssystem, d.h. im Multitasking. Amithlon ist hier eine Besonderheit und daraus resultiert auch eine mehrfach höhere Ausführungsgeschwindigkeit gegenüber (Win)UAE. Und ja, Maik hat Recht - unter der echten Hardware sind ohne Probleme Frequenzen bis zu 28000 Hz möglich, da die CIA-Chips Hardwarebausteine sind denen es egal ist, ob die CPU mitkommt oder nicht, da diese eh keine Ahnung von der Existenz einer CPU haben. Man legt von Außen eine Taktfrequenz an und die CIAs werkeln vor sich hin - entsprechend dem Inhalt ihrer Register. Die CPU kann hier eingreifen falls sie nicht mitkommt - aber das ist ein anderes Thema. Nehmen wir mal unser Beispiel zum Digitalisieren: Die Emulation muss bei 14 kHz Frequenz 14000-mal pro Sekunde das Verhalten des CIA-Chips emulieren, 4 * 14000-mal das Verhalten der Audio-Hardware (abgesehen davon, das 8-Bit Sounds in 16-bittige gewandelt werden müssen), 14000-mal das Verhalten der Centronics-Schnittstelle und das Abgleichen mit der Host-Hardware. Zudem kommt noch hinzu, das eine CPU emuliert werden muss und die Video-Ausgabe. Lange Rede, kurzer Sinn: Je mehr Aufgaben eine Emulation gleichzeitig zu bewältigen hat, desto weiter entfernt sie sich vom Original. Gruß |
|||||
jolo
Nutzer
21.11.2007, 23:31 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi. Zitat: Habe ich bis dato nicht wahrgenommen - aber es stimmt. Zitat: Bei nur 500 MHz würde ich Amithlon empfehlen. WinUAE läuft erst ab 2 GHz aufwärts manierlich. Zitat: Meines Wissens nach spielt es keine Rolle beim Lesen von Daten die an der parallelen Schnittstelle anliegen, ob Eingang oder Ausgang spezifiziert wurde; es wird immer der aktuelle Wert der anliegt, zurückgegeben. Falls ich mich täusche berichtige ich das im Programm-Code. Zitat: Du meinst anstelle des CIA-A Interrupts einen CIA-B? Kann ich machen - hatte aber hier Probleme, da der CIA-B sich nicht richtig mit der Audio-Hardware verträgt und der Cause()-Aufruf, der die Audio-Hardware in Gang setzt, nur zu bestimmten Zeiten eine Aktion durchführt. Bei der Verwendung des CIA-A Interrupts konnte ich die Audio-Hardware von innerhalb des Interrupts starten - ohne Umweg über Cause(). Zitat: Der Puffer ist genau für eine Sekunde Abspielzeit ausreichend - falls aber der Interrupt nicht genügend Daten, sprich Bytes bereit stellt, werden aufgrund des mangelnden Timings nur ca. 2/3 des Puffers innerhalb einer Sekunde gefüllt. Der Audio-Hardware Interrupt beginnt dann schon wieder diesen Puffer abzuspielen (nach exakt einer Sekunde), während die Routine, die mit dem Interrupt synchronisiert ist, sich erst bei 2/3 des Puffer-Inhalts und damit bei 2/3 einer Sekunde wähnt. Wie gesagt, bis 14 KHz klappts, danach läuft der CIA-A Interrupt aus dem Ruder, sprich, er kann nicht so oft pro Sekunde ausgeführt werden. Zitat: Na, dann war ja meine Mühe nicht ganz umsonst. Zitat: Jetzt verstehe ich so langsam. Es könnte sein, dass dem CIA-A-CHIP dadurch mitgeteilt wird, das Daten anstehen. Müsste das aber erst mal nachlesen. Probehalber wird jetzt der FLAG-Interrupt unterdrückt. Zitat: 1. Parameter: Frequenz pro Sekunde. 2. Parameter: Adresse Zeichenkette für Namen des Interrupt. 3. Parameter: Benutzer definierter Code der im Interrupt ausgeführt werden soll. 4. Parameter: Daten/Struktur für Benutzer definierten Code (halt irgendwelche Argumente). 5. Parameter: Pufferliste - zeigt auf einen Speicherbereich, in dem die Adresse(n) Deine(s)(r) FAST-RAM Puffer vermerkt sind; InitIRQ() zählt die gesetzten Langworte und interpretiert diese als Adressen zu den einzelnen Puffern. Deshalb muss als letztes Element ein NULL-Zeiger gesetzt sein (Ende der Pufferliste). Da ich kein Basic verstehe, habe ich den POKEL-Befehl falsch eingesetzt - so wie Du es macht müsste es klappen. 6. Parameter: Größe in Bytes eines einzelnen Puffers - das heißt dann aber auch, das alle Puffer von der gleichen Größe sein müssen. In Deinem Beispiel allozierst Du 200004 Bytes für einen Puffer - sagst InitIRQ() aber, dass der Puffer nur 50000 Bytes groß ist. Warum? Und ja, falls eine Pufferliste spezifiziert wird, also nicht NULL ist, wird die Audio-Hardware in Gang gesetzt. Falls Du das nicht wünscht, kann ich das ausbauen. Weshalb bei Dir der Digitizer abschmiert kann ich (derzeit) noch nicht sagen. Probiere mal TimerIRQ() - wenn's damit klappt, ist dein Basic-Programm für die Hits verantwortlich (falsche Parameter?). Allerdings ist auch ein Programmierfehler meinerseits nicht auszuschließen. Habe die Bibliothek wieder ein klein wenig modifiziert und dabei festgestellt, dass das CIA-A Kontrollregister eine falsche Bitmaske abbekam - zudem wird jetzt auch der FLAG-Interrupt gesperrt (zuständig für das Handshake-Signal des parallelen Ports). Die Audio-Ausgabe habe ich dahingehend geändert, dass kein Puffer mehr verwendet wird. Kann das aber hier nicht ausprobieren weil WinUAE da nicht mehr mitspielt (zu viele Daten in zu kurzen Intervallen). Wenn's leiert oder blechern klingt baue ich das wieder raus. Ich verwende nach wie vor noch einen CIA-A Interrupt - falls es wider Erwarten damit Probleme gibt, werde ich einen CIA-B Interrupt verwenden - dann muss ich die Audio-Ausgabe aber wieder gepuffert durchführen. Tut mir leid, dass Du das Versuchskaninchen spielen musst - aber ich habe wirklich keine Lust, meinen A4000 wieder zu reanimieren. Neues Archiv wurde hochgeladen. Gruß |
|||||
jolo
Nutzer
20.11.2007, 20:33 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung Hi Maik, ich habe vorhin diverse Tests durchgeführt und alles was ich sagen kann ist, dass selbst hier unter WinUAE und einem nicht geraden langsamen PC ca. 14000 Aufrufe pro Sekunde das Maximum sind, dass der CIA-A Interrupt im Multitasking-Betrieb mit diversen anderen Interrupts eingeschaltet, imstande ist zu signalisieren, ohne aus dem Ruder zu laufen. Alles was darüber hinausgeht, klappt hier bei mir nicht! Ich habe eine gefakte Bibliothek dafür benutzt, die einen Sound beinhaltet, der mit 14880 Hz (Periode 240) abgespielt werden muss. Tests mit 18896 erbrachten, dass maximal 15000-mal pro Sekunde ein Interrupt generiert wurde - anstelle von fast 19000-mal. Aber wie gesagt, die Schmerzgrenze liegt irgendwo im Bereich von 14000. Betreffend der Störungen: Dazu kann ich im Moment nicht viel sagen, da mein 4000er im Keller schön verpackt dahin vegetiert - und ich derzeit keine Motivation verspüre, diesen neu aufzubauen (Festplatte und diverse Kleinigkeiten fehlen). Dementsprechend kann ich nicht selber digitalisieren. Wie oben schon erwähnt, versuch es mal mit 12000 bzw. 14000 Hz - und benutze zu Testzwecken mal TimerIRQ - es zeigt Dir an, wie viele Daten pro Sekunde wirklich gesampelt werden können (der Wert den TimerIRQ ausgibt entspricht nicht hundertprozentig dem gewählten Wert bedingt durch die Integer-Arithmetik - sollte aber nichtsdestotrotz einen groben Überblick gewähren). Bei Abweichungen von mehr als 400 Samples kannst Du davon ausgehen, dass Dein gewählter Wert zu groß ist. Ich habe die Bibliothek auch dahingehend geändert, dass der parallele Port nun auf Eingang geschaltet wird. Die Wiederholungen resultieren aus der nicht hundertprozentigen Synchronisation - allerdings wird jetzt die Audio-Hardware dahingehen ausspioniert, wie viele Bytes (annähernd) pro Sekunde ausgegeben werden und dementsprechend wird die Abspiellänge beschnitten (ac_len). Das sollte schon mal etwas bessere Ergebnisse liefern; aber wie gesagt, hundertprozentig bekomme ich das ohne vorherige Synchronisation nicht hin. Zitat: Klappt das? Wäre schön - dann funktioniert nämlich etwas. Zitat: Autsch. Natürlich. Manchmal bin ich nicht im Vollbesitz meiner geistigen Kräfte... Zitat: Sollte mit der neueren Version besser gelingen, allerdings, wie gesagt, musst Du dann Deine Ansprüche (Hz) herunterschrauben. Ob's allerdings nach wie vor knackt, kann ich nicht sagen - hier hilft nur ausprobieren. Wiederholungen sollten jetzt seltener auftreten - da ja die Abspiellänge auf einen regulären Wert beschnitten wird. Neue Version (auch die getürkte) kann von der bekannten Seite heruntergeladen werden. Archiv ist jetzt allerdings 2.6 MBytes groß - bedingt durch den Sound. Installiere mal die getürkte Bibliothek anstelle der echten und rufe TimerIRQ mit 14880 Hz auf - die Anzahl Bytes die der CIA-A Interrupt der Audio-Hardware pro Sekunde zur Verfügung stellt, wird ausgegeben - und das sollte eine Orientierungshilfe sein. Wenn der Wert unter 14400 liegt weißt Du, dass der CIA-A Interrupt überfordert ist. Gruß |
|||||
jolo
Nutzer
18.11.2007, 12:17 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung Hallo Maik, Zitat: Wie, UAE ist kein echter Amiga? Soll das heißen, isch haabe gaar keinen Amiga? Ische nix Amiganer? Nee, Recht hast Du - aber was ich eigentlich sagen wollte ist, dass ich unter WindowsXP arge Probleme hatte, ein korrektes Timing hinzubekommen - dementsprechend war ich einigermaßen erfreulich erstaunt, dass das Timer-Device unter WinUAE ziemlich genau arbeitet. Zitat: Normalerweise sollte das Empfangen der Daten keinen Einfluss auf einen der beiden Timer haben, ansonsten wären die Timer nur Makulatur. Ich könnte aber die anderen Interrupts sperren die nicht benötigt werden - allerdings wird dann nichts mehr richtig funktionieren, was die serielle Schnittstelle betrifft - und das will ich vermeiden. Was mir aber aufgefallen ist, dass Du einen Wert "peekst", ohne das gelesene Datenbyte vorzeichengerecht zu erweitern (+128) - müsste in etwas so aussehen: code:POKEB MySample&+count&, PEEKB(&hBFE101) + 128 INCR count& Anbei, das kleine Tool "TimerIRQ" kannst Du benutzen um festzustellen, ob der von mir favorisierte CIA-A Timer überhaupt mit der Seriellen-Schnittstelle harmonisiert. Um Deinem Beispiel zu folgen, brauchst Du nur "timerirq 16000" im CLI zu tippen. Es digitalisiert dann mit 16000 Hz. Was mir zudem aufgefallen ist, dass Du das Digitalisieren wieder auf Prozess-Ebene verlagerst, wo wir uns doch einig waren, dass das nie und nimmer richtig funktioniert kann. Wieso benutzt Du nicht den "eingebauten" Digitizer? Dafür habe ich ihn ja geschrieben. Im Prinzip musst Du nur einen Speicherbereich allozieren/definieren, der groß genug ist, die Zeiger auf die einzelnen Puffer aufzunehmen; bei einem Puffer also 8 Bytes, weil ja der zusätzliche, letzte Zeiger genullt werden muss. code:DIM pufferListe 8 REM 8 Bytes reservieren = 2 Langworte Jetzt musst Du die Adresse von "MySample" dort als erstes Langwort eintragen: code:POKEL pufferliste&, VARPTR(MySample&) und zum Schluss das zweite Langwort nullen: code:POKEL pufferlist& + 4, 0 REM Ende der Puffer-Liste Das war's. Jetzt kannst Du den eingebauten Digitizer verwenden: code:ihandle& = InitIRQ&( 16000, "DigiTest", 0, 0, pufferListe&, 200004) REM Puffergröße = 200004 Bytes Das "normale" Signal-Handling solltest Du dann auch ausschalten, ansonsten wird Dein Prozess 16000-mal pro Sekunde wieder aufgeweckt - was nicht gerade im Sinne des Erfinders ist. code:SetIRQAttrI&(ihandle&, 4) REM Normales Signal-Handling ausschalten Beim Eintreffen des "Puffer ist voll" Signals ( sigmask&=(1<<GetIRQAttrI&(ihandle&,1)) ) kannst Du den Interrupt und damit auch den Digitizer beenden. Am Besten wäre es aber, wenn Du eine kleine Mini-Funktion mitlaufen lassen würdest, die entscheidet, wann ein "normales" Signal zum Hauptprogramm gesendet wird, um den Hauptprogramm zu irgendeiner Aktivität (Goertzel) verleitet sobald genug Daten bereitstehen. Wie gesagt, die Mini-Funktion wird im Interrupt-Code ausgeführt und muss dementsprechend die Register auf die von MaxonBasic verwendete verbiegen, ansonsten ist ein Crash nicht fern. Wie schon gesagt, falls Deine Mini-Funktion null retourniert, wird *kein* Signal an Dein Hauptprogramm gesendet, nur wenn Deine Mini-Funktion irgendeinen Wert ungleich null zurückgibt, wird der Interrupt-Code, der Deine Mini-Funktion aufrief, dem Hauptprogramm das "normale" Signal signalisieren. Anbei, das ist der echte Interrupt-Code der u.a. auch Deinen Code (Mini-Funktion) aufruft/aufrufen könnte: C code:SUPERIOR ULONG CIAA_Code( REG(a1, struct TimeOutIRQData *tid) ) { LONG i; i = 2; /* Dürfen wir eine Aktion ausführen? */ if ( tid->TimeOutFlag == ALIVE ) { if (tid->IntType == IRQ_DIGITIZE) CallDigitizerCode( tid); /* Rufe Digitizer auf */ /* Falls Benutzer-Code vorhanden, diesen jetzt anspringen */ if (tid->IRQUsersCode) tid->SendSignal = (LONG) tid->IRQUsersCode( (APTR) tid->IRQUsersData); /* Falls SendSignal != 0 wird Signal gesendet! */ if (tid->SendSignal) Signal( tid->TimeOutTask, (1 << tid->TimeOutSignal) ); } else /* Nee, keine Aktion ausführen. Ende? */ { if (tid->TimeOutFlag == KILL) /* DeleteIrq() setzt dies - hat für uns */ tid->TimeOutFlag = KILLED; /* aber eigentlich Bedeutung, da wir */ } /* diesen Punkt nie erreichen (Interrupt */ /* schon gestoppt falls KILL gesetzt) */ return i - 2; } Gruß |
|||||
jolo
Nutzer
17.11.2007, 11:42 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @whose: Tach, Zitat: Zu Deiner Information: Auch hier ist das Timer-Device sehr genau - und dass unter WindowsXP/WinUAE. Also gehe ich davon aus, dass er einen simplen Programmierfehler irgendwo eingebaut hat. Habe leider keine Zeit gefunden, den anderen Thread zu lesen. Werde das aber nächste Woche mal nachholen. Vielleicht fällt mir irgendetwas Ungewöhnliches auf. Zitat: Wenn Du mich schon so fragst: Wie wird das Wetter nächste Woche? Gruß |
|||||
jolo
Nutzer
17.11.2007, 11:39 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung Hi Maik, habe mein Versprechen gehalten und eine Bibliothek für Dein Problem erstellt. Kriege ich jetzt meinen Lutscher? Zitat: Diese Aussage von mir hat ihre Gültigkeit und war dafür verantwortlich, dass die Audio-Hardware nicht störungsfrei betrieben werden konnte... Zitat: Zitat: Ja, Du hast Recht. Siehe erstes Zitat. Es hat sich herausgestellt, dass der CIA-B Interrupt wirklich die Audio-Hardware stört - dementsprechend verwende ich jetzt einen CIA-A Interrupt. Jetzt sind die hörbaren Störungen minimal - die gesammelten Daten waren ja davon nie betroffen (FAST-RAM Puffer). Zitat: Benchmark-Ergebnisse sind generell mit Vorsicht zu genießen - zu viele Faktoren beeinflussen das Ergebnis. Das Audio-Device (also die Hardware) hat, auch wenn Du mir das nicht glaubst, rein gar nichts mit der CPU und ihrer Last zu tun. Die CUSTOM-CHIPS sind entworfen worden, um die CPU zu entlasten. Das einzige was die CPU und die CUTSOM-CHIP gemeinsam verwenden ist der Daten- und Adressbus. Nur wenn beide auf ein- und demselben Speicherbereich zugreifen wollen, gibt es Konflikte - sprich eine Verzögerung. Diese liegen aber im Millisekundenbereich. Zitat: Und dafür brauchst Du CD Qualität (44,1 kHz) ? So, nun zu der Bibliothek: Diese nennt sich "ire" und muss ins Libs-Verzeichnis. Die "bmap" Datei habe ich mittels "fd2pragma" erstellt und sollte von Dir ohne weitere Anpassung unter MaxonBasic benutzt werden können. Es gibt nur 5 Funktionen: InitIRQ StartIRQ DeleteIRQ SetIRQAttrI GetIRQAttrI InitIRQ kann sowohl normale Interrupts auslösen als auch digitalisieren. void * InitIRQ( ULONG callsPerSecond, STRPTR irqname, LONG (*usersCode)(), APTR usersData, UBYTE **buffers, ULONG singleBufSize) (d0,a0,a1,d1,a2,d2) callsPerSecond --- wie oft pro Sekunde soll der Interrupt aufgerufen werden, z.B. 16668. irqname --- Name Deines Interrupts, z.B. "Maik's Interrupt". usersCode --- Zeiger auf die Funktion die innerhalb des Interrupts aufgerufen wird - oder null falls keine eigene Routine aufgerufen werden soll. usersData --- Zeiger auf eine Struktur oder Variable die dein "usersCode" auf dem Stack empfängt, darf auch null sein. buffers --- falls gesetzt, wird der Digitizer aufgerufen! buffers zeigt auf einen Speicherbereich, in dem Du die Adressen Deiner FAST-RAM Puffer vermerkt hast. Der letzte Eintrag muss NULL (0) sein. singleBufSize --- die Größe *eines* Puffer, d.h. falls Du jeden Puffer eine Größe von 20000 Bytes zugewiesen hast, musst Du hier 20000 eintragen. Bei zwei Puffern (buffers: Puffer1, Puffer2, NULL) macht das Summa Summarum 40000 Bytes FAST-RAM. Die einzelnen Puffer dürfen nicht in der Größe variieren! Ein paar Beispiele: ihandle = InitIRQ( 50, "Maik's Interrupt", NULL, 0, NULL, 0) Hier wird dann jede fünfzigstel Sekunde ein Interrupt ausgelöst und ein Signal zu Deinem Hauptprogramm gesendet. Du kannst mittels: GetIRQAttr( ihandle, 2) das Signal-Bit ermitteln, welches Dir signalisiert wird (z.B. für die Verwendung mit Wait() ). Für Wait() musst Du das Signal-Bit in eine Signal-Maske umwandeln: sigmask = (1 << GetIRQAttr( ihandle, 2)) ihandle = InitIRQ( 50, "Maik's Interrupt", (*usersCode)() &yourcode, &counter, NULL, 0) Wie oben, nur wird hier noch deine "yourcode"-Routine aufgerufen und bekommt als Argument auf dem Stack die Adresse der Variable "counter". Falls "yourcode" null zurückgibt, wird kein Signal an Dein Hauptprogramm gesendet. Nur wenn Du irgendeinen Wert zurückgibst, wird das Signal gesendet. Du musst wissen, welche Prozessor-Register MaxonBasic benötigt und deren Inhalt irgendwo vor Aufruf von StartIRQ() ablegen und dann innerhalb von "yourcode" diese Registerinhalte restaurieren - und beim Verlassen von "yourcode" die ursprünglichen Registerinhalte für den originalen Interrupt-Code, der "yourcode" aufgerufen hat, wieder instand setzen. ------------------------------------- ihandle = InitIRQ( 50, "Maik's Interrupt", SADD yourcode, SADD counter, 0, 0) #asm move.l a4,inhaltA4 move.l a5,inhaltA5 move.l a6,inhaltA6 #endasm StartIRQ( ihandle) ------------------------------------ SUB yourcode( arg) STATIC #asm move.l 4(sp),argument ; Adresse von "counter" movem.l D2-D7/A2-A6,-(sp) movea.l inhaltA4,A4 movea.l inhaltA5,A5 movea.l inhaltA6,A6 #endasm Dein Basic-Code hier - "argument" zeigt aufs Argument für "yourcode" returnWert = 0 ; Kein Signal senden #asm movem.l (sp)+,D2-D7/A2/A6 move.l returnWert,D0 rts ; Muss RTS für Basic angegeben werden? #endasm ------------------------------------- DIM pufferListe (12) DIM puffer1 (20000) DIM puffer2 (20000) POKEL( pufferListe(0), SADD puffer1) POKEL( pufferListe(4), SADD puffer2) POKEL( pufferListe(8), 0) ihandle = InitIRQ( 16668, "Maik's Interrupt", 0, 0, SADD pufferListe, 20000) Da wir nicht wollen, dass wir ein Signal für jeden Eintritt in den Interrupt erlangen, müssen wir das Signal-Handling für normale Signale ausschalten: SetIRQAttrI( ihandle, 4) Jetzt kann man (frau auch) StartIRQ( ihandle) aufrufen. Und da wir informiert werden wollen, wann einer der beiden Puffer voll ist, müssen wir dessen Signal-Bit ermitteln: sigmask = (1 << GetIRQAttr( ihandle, 1)) Jetzt mittels Wait( sigmask) horchen, ob eine Nachricht eintrifft. Um die Adresse des Puffers zu erfahren, welcher voll ist, muss man dies verwenden: vollerPuffer = GetIRQAttr( ihandle, 16) Flaggen für Get/SetIRQAttrI(): 1 = (get) - hole Signal-Bit das signalsiert, das ein Puffer voll ist. 2 = (get) - hole Signal-Bit das signalsiert, das Interrupt aufgerufen wurde. 4 = (set) - normale Signal-Handhabung ausschalten (Interrupt wird nicht signalsiert). 8 = (set) - normale Signal-Handhabung einschalten (Interrupt wird signalsiert). 16 = (get) - hole Adresse des Puffers, welcher voll ist. Ich spreche kein Basic, daher weiß ich nicht ob das was ich oben verbrochen habe, so von einem Basic-Compiler/Interpreter akzeptiert wird - ich glaube kaum... Archiv kann unter http://www.amimedic.de heruntergeladen werden. Das (nährlose) Beispiel TimerIRQ digitalisiert und kann auch mit anderen Werten betrieben werden: TimerIRQ 28801 - digitalsiert mit 28801 Hz! Gruß |
|||||
jolo
Nutzer
10.11.2007, 10:04 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi. Zitat: Das Knacken rührt daher, weil die Audio-Abtastrate nicht hundertprozentig dem der Abtastrate des CIA-B Interrupts entspricht. Du solltest Dir vergegenwärtigen, dass die Audio-Hardware unabhängig von Deinem Interrupt werkelt. Du sagst dieser nur, wie schnell sie von dem Puffer Daten lesen soll (Periode 214 oder 124) und wo das erste Byte des Puffers zu finden ist (Anfangsadresse) und wie groß der Puffer ist (Endadresse). Danach macht sie alles selbstständig - wenn die Endadresse erreicht wurde, beginnt sie wieder mit der Ausgabe bei der Anfangsadresse - und das fortlaufend. Zwischenzeitlich und unabhängig davon werkelt Dein CIA-B Interrupt - der die Daten einliest, die die Audio-Hardware ausgeben soll. Falls nun der CIA-B Interrupt etwas langsamer Daten einliest als die Audio-Hardware ausgibt, gibt die Audio-Hardware die Daten aus, die beim letzten Durchlauf gesammelt worden sind - und nicht die, die beim jetzigen Durchlauf aktuell sind. Wie gesagt, dies passiert aber nur bei der Wiedergabe in Echtzeit - die Daten, die der Interrupt sammelt, sind davon nicht betroffen. Zweiter Grund (falls die Audio-Hardware keinen Prefetch benutzt - müsste das mal selber nachlesen - also ist diese Aussage nur mit Vorsicht zu genießen): Je kleiner der verwendete Puffer, desto mehr Störgeräusche. Da der CIA-B Interrupt und die Audio-Hardware sich einen Speicherbereich teilen, und es sein kann, dass beide zum gleichen Zeitpunkt auf ein bestimmtes Datenword zugreifen wollen, bedingt durch die nicht hundertprozentige analoge Abtastrate, bekommt derjenige den Zugriff, der die höhere Priorität hat - und das ist der CIA-B Interrupt. Somit kommt es kurzzeitig zu diesem Effekt. Probiere wie im letzten Posting beschrieben AUDSIZE eine andere Größe zu geben und den STARTOFFSET auf die Hälfte von AUDSIZE zu setzen. Dann nämlich fängt die Audio-Hardware erst dann an, wenn der CIA-B Interrupt die Hälfte des Puffers schon gefüllt hat. Dann ist das Ganze aber zeitlich versetzt... Zitat: Theoretisch ja, praktisch kann ich nichts dazu beisteuern, da ich es nie selber ausprobiert habe. Da die Datenmenge, die die Custom-Chips, welche ja nach wie vor mit 7 MHz getaktet werden, bewältigen müssen um den Faktor 2 ansteigen würde (jeweils für Audio und Video), könnte es zu viel des Guten sein. Aber wie gesagt, ich selber habe es nicht ausprobiert. Zitat: Nein, tun sie nicht. Die Audio-Hardware hat rein gar nichts mit Deiner CPU zu tun. Zitat: Zitat: Du vergleichst da Äpfel mit Birnen. 44kHz in 16-Bit sind was anderes als 44kHz in 8-Bit. Du hast im Amiga kein 16-Bit Sound, nur 8-Bit, es sei denn Du benutzt eine Soundkarte. Wenn Du 16-Bit Samples benötigst, musst Du erst die 8-Bit Samples in 16-bittige umwandeln bevor Du diese als solche benutzen kannst. Und Digitizer für Amigas waren immer als 8-Bit Lösungen ausgelegt - nicht 16 Bit. Zitat: Da widerspreche ich Dir - zwar ungern, aber tue es trotzdem. AudioGrabber2 bietet Dir beides. Schau Dir das Beispiel mal an. Zitat: Studiere mal die Beispiele - speziell die Interaktion zwischen Interrupt und Programm (Task). Dann weißt Du wie es gemacht wird. Aber abgesehen davon, selbst das Senden eines CTRL-C Signals wird Dir nichts bringen - denn eine Frage bleibt: Wo hat das Programm (AudioGrabber) nun die Daten versteckt - und was passiert, wenn es ein CTRL-C Signal empfängt? Beim Eintreffen des Signals werden alle Ressourcen freigegeben - und somit auch der Datenpuffer. Dementsprechend existieren die Daten nicht mehr! Zitat: Brauchst Du eine FD oder SFD Datei um eine BMAP Datei zu erstellen? Zitat: 1000 oder 1500 Signale pro Sekunde bedeuten nicht, dass Du 1000 oder 1500 Hz verwendest. Der Zeitabstand zwischen den einzelnen Zyklen ist ausschlaggebend. Dieser muss konstant sein. Hz bedeutet das etwas in periodischen Abständen auftritt - und nicht soundsooft innerhalb eines bestimmten Zeitrahmens. Ich kann in der ersten halben Sekunde die 1500 Signale raushauen und die restliche Zeit warten. Das hat dann allerdings nichts mit periodischen Intervallen zu tun. Zitat: Auf Task-Ebene bestimmt nicht... aber annähernd sollte es schon funktionieren. Gehe ich recht in der Annahme, dass Du *nicht* am Anfang Deines Loops die "Auszeit" spezifizierst sowie DoIO anstelle von SendIO verwendest? Müsste ungefähr so aussehen damit es richtig funktioniert: code:LOOP SendIO( timerrequest) .... Sende Infrarot-Signal .... signale = Wait( (1 << TimerSigBit) ) IF signale AND (1 <<TimerSigBit) <> 0 GOTO LOOP ENDIF ENDLOOP Zitat: Du würdest das nicht behaupten, wenn Du die betreffenden Routinen mal disassembliert hättest. Diejenigen, die das originale AmigaOS programmierten, verstanden effizient und ressourcenschonend zu programmieren. Leider hat das aber auch seine Kehrseiten... Zitat: Ihr könnt mich ja dumm sterben lassen aber es wäre nett von euch wenn ihr mir stattdessen mal sagt, über welches Programm ihr euch unterhaltet... Erbarmen, bitte... Zitat: Verwendet ihr DoIO()? Dann habt ihr euer Wait() gefunden... Forbid() in einer Schleife zu verwenden ohne entsprechendes Permit() wird das System lahm legen. Vergiss die Existenz von Forbid()! Zitat: Nö. code:_WriteBufferContents movem.l D2-D4/A6,-(sp) movea.l _DOSBase(pc),A6 move.l _DateiName(pc),D1 move.l #1006,D2 jsr _LVOOpen(A6) move.l D0,D4 beq.s _error move.l D0,D1 move.l _PufferAdresse(pc),D2 move.l _PufferLaenge(pc),D3 jsr _LVOWrite(A6) move.l D0,D2 move.l D4,D1 jsr _LVOClose(A6) cmp.l D2,D3 bne.s _error moveq #1,D0 _out movem.l (sp)+,D2-D4/A6 rts _error moveq #0,D0 bra.s _out _DOSBase ds.l 1 DateiName ds.l 1 PufferAdresse ds.l 1 PufferLaenge ds.l 1 Zitat: http://gega.homelinux.net/AmigaDevDocs/ Zitat: Selbst mit dem Beispiel für Software-Interrupts kann man nachvollziehen, wie oft pro Sekunde der Interrupt aufgerufen wurde - man braucht dazu nur die Ausgabe im Auge zu behalten. Gruß |
|||||
jolo
Nutzer
10.11.2007, 09:45 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @whose: Moin Moin Zitat: Ungeachtet dessen behauptet Maik, dass mittels einer Schleife und ausgeschalteten Multitasking er 18000 Hz erreichen kann - was ich aber anzweifle da 18000 Lesezugriffe pro Sekunde nicht gleichzusetzen sind mit 18000 Hz. Es kommt auf die Zeitspanne zwischen den einzelnen Lesezyklen an - ist diese immer gleich (kontinuierlich) für alle Lesezugriffe, so könnte er mit Fug und Recht behaupten, dass er das auf Task-Ebene schafft - aber das wage ich zu bezweifeln, da ihm alle mögliche Interrupts einen Strich durch die Rechnung machen. Es kann sein, dass ein Teil der Lesezyklen tatsächlich in gleichen Abständen gelesen wird, aber der Rest? Somit kommt es beim Einsatz eines Prozesses für diese Aufgabe zu Unregelmäßigkeiten, die in einer verfälschten Wiedergabe resultieren. Zitat: Hmmm, wie kann ich Dir nur schonend beibringen, dass ich diesen Abschnitt heutzutage als nicht mehr aktuell betrachte - ohne dass Du mich gleich steinigst. :} Wir müssen uns heutzutage auch mit AROS, MorphOS und OS4 auseinander setzen - und dies beinhaltet, dass Interrupts dort ganz anders aussehen weil ja die Hardware eine andere ist. Okay, für Classics mag das alles noch seine Gültigkeit besitzen, aber schon unter einer Emulation kann ein VBlank Interrupt-Code, der unter Classics fünfzig Mal in der Sekunde aufgerufen wird, weitaus öfter aufgerufen werden. Unter WinUAE ist es keine Schwierigkeit, einen VBlank zweihundert Mal pro Sekunde zu initiieren. Das Timer-Device bleibt davon allerdings verschont... CIA Interrupts, um die es in diesen Beispielen geht, werden auch nicht von Exec verwaltet sondern von der betreffenden Ressource - somit ist die Abhandlung im RKM nicht vollständig. Wer allerdings die Interna verstehen will, der sollte Deinem Rat folgen und diese Abhandlung im RKM lesen. Anbei, C-Compiler berücksichtigen heutzutage solche Feinheiten wie Interrupts (vbcc geht hier noch einen Schritt weiter als gcc, da vbcc, wenn ich es richtig verstanden habe, auch anbietet Interrupts mit einem "rte" beenden zu lassen, was hilfreich ist, falls man einen Interrupt-Server/Handler schreiben will oder die Auto-Vektoren direkt, ohne Umweg übers Betriebssystem benutzt). Auch bin ich persönlich der Meinung, dass gerade Anfänger, nicht Programmieranfänger sondern in Bezug auf Interrupts, nicht zu viel auf einmal zugemutet werden sollte - man kann einfache Dinge auch verkomplizieren. Als es noch Stand der Dinge war, Intros/Demos zu schreiben, haben wir ja die Auto-Vektoren direkt benutzt und deren Handhabung ist ja wirklich alles andere als schwer. Zitat: Viele Dinge haben einen Einfluss darauf. Die verwendete Programmiersprache zum Beispiel - Basic ist langsamer als C. Wenn dann noch der verwandte Basic-Compiler nicht der schnellste ist, wird's langsam eng (je mehr Sicherheit geboten wird desto langsamer muss das erstellte Programm sein; alle Überprüfungen kosten Laufzeit). Zudem haben viele Leute den Wunsch, das Aussehen der Oberfläche aufzupeppen - wenn dann noch Patches verwandt werden, die sich unsauber ins System einklinken und Ressourcen verschwenden, geht die CPU-Last rauf und die Leistungsfähigkeit runter. Es kann aber auch sein, das ein simpler Fehler in seinem Programm so drastische Unterschiede zu Tage bringt. Kann man irgendwo einen Blick auf seinen Code werfen? Zitat: Wenn er den gleichen Algorithmus meint wie ich und er mit 28kHz oder gar 44kHz digitalisieren will, wird das nicht in Echtzeit unter Basic gehen - zumindest nicht mit 'ner 030 CPU. Tschö! |
|||||
jolo
Nutzer
08.11.2007, 19:35 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi, Zitat: Diese Störungen sind nur während der Datenaufzeichnung und dem gleichzeitigen Abspielen hörbar. Es hat nichts mit der Aufzeichnung selber zu tun. Da der CIA-B Timer nicht hundertprozentig im Takt mit der Audio-Ausgabe läuft, kommt es zu Überschneidungen, die diese Störgeräusche verursachen. Ein größerer CHIP-RAM Puffer für die Audio-Hardware ("AUDSIZE EQU 65535") wirkt dem entgegen sowie die Leseintervalle um einen Tick erhöhen (41 anstatt 42 (_PAL_NTSC_TIMES)) - denn wenn die Audio-Hardware schneller Daten ausgibt als der CIA-B-Interrupt Daten liest, kommt es unweigerlich zu Störungen - aber wie gesagt, diese Störungen hörst Du nur während des Digitalisierens - nicht beim Abspielen der aufgezeichneten Daten zu einem späteren Zeitpunkt. Nochmals, diese Knackgeräusche werden nicht aufgezeichnet! Ach ja, Du kannst STARTOFFSET auch einen größeren Wert zuweisen - dann startet die Audio-Ausgabe verzögert und somit stehen mehr Daten bereit, bevor eine hörbare Ausgabe erfolgt (kannst ja mal die halbe Größe von AUDSIZE probieren). STARTOFFSET ist hier zu finden: code:Original: cmpi.l #4,D0 ; Indicator for start audio (leading bytes) bne.s .out ; If not... in cmpi.l #AUDSIZE/2,D0 ; Indicator for start audio (leading bytes) bne.s .out ; If not... ändern. Zitat: Da die maximale Sampling-Frequenz 28801 Hertz beträgt (Hardware-Limit), entspricht dieser Wert einer Periode von 124 (für die Audio-Hardware müssen Hertz-Werte in Perioden-Werte umgerechnet werden) - also musst Du im Beispiel 214 durch 124 ( 1 / (28801 * 0.000000279365) = 124,28 ) ersetzen - und das für alle vier Audio-Kanäle. Zudem musst Du die Leseintervalle verkürzen: _PAL_NTSC_TIMES 25,25 -> 709379/28801 bzw. für 60 Hz-Netzspannungen: 715909/28801 Anbei, wieso sind 16000 Hz nicht ausreichend? Ich habe früher mit 14000 Hz digitalisiert - und zwar ganze Musikstücke und diese sind selbst nach heutigen Standards noch ganz manierlich anzuhören. Zitat: Selbst das Senden eines CTRL-C Signals bringt Dir alleine rein gar nichts - weißt Du wo die Daten liegen, damit diese von Deinem Hauptprogramm aus gelesen werden können? Und, gibt es überhaupt einen Datenbereich? Weiterhin, was passiert, wenn das Programm ein CTRL-C Signal empfängt? Das Beispielprogramm (ASM) in seiner jetzigen Form ist dafür gänzlich ungeeignet - das zweite, in C verfasste Beispiel (AudioGrabber2) schon eher. Zitat: Solange Du keine fehlerfreie Installation von vbcc hast, wird das nichts. Ich kann Dir alternativ anbieten, eine Shared-Library für Dein Problem zu programmieren - falls Du diese von Basic aus benutzen kannst. Allerdings kann ich schon jetzt sagen, dass ich dies diese Woche nicht mehr schaffe. Zitat: Das ist doch schon mal ein Anfang. Frage: Meinst Du auf Prozess/Task-Ebene oder das Beispiel mit dem Software-Interrupt? Was ich vergessen habe zu erwähnen ist, dass der Agnus-Baustein bedingt durch das Zusammenspiel aller Hardware-Komponenten nur in festgelegten Intervallen Software-Interrupts auslösen darf/kann. Weil ich mich aber nie damit tiefer beschäftigt habe, gehe ich davon aus, dass nur entsprechend der Bildschirmwiederholfrequenz Software-Interrupts ausgelöst werden. Um das zu verifizieren müsste ich aber erstmal das Hardware-Reference-Manual wieder finden... (dem Betreffenden, der eine abfällige Bemerkung über meinen Ordnungssinn macht, haue ich die Kartoffel vom Kopf ). Wie gesagt, ich benutze Software-Interrupts in abgewandelter Form - bei mir wird 50-mal in der Sekunde eine Aktion durchgeführt - und nicht 14000 oder gar 28000-mal. Das überfordert den Agnus-Chip. Es würde mich interessieren, ob unter MorphOS/OS4 diese Einschränkung weiterhin besteht. Auf Prozess/Task-Ebene wage ich zu bezweifeln, ob Du das Timing überhaupt in den Griff bekommst - zu viele Faktoren spielen hier eine Rolle. Gruß |
|||||
jolo
Nutzer
07.11.2007, 23:22 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @MaikG: Hi Maik, Kannst Du das Beispiel mittels Holgers Hinweis assemblieren? Gruß |
|||||
jolo
Nutzer
07.11.2007, 23:19 Uhr [ - Direktlink - ] |
Thema: Registerzugriff in C
Brett: Programmierung @uho: Zitat: Nee, Danke. Seit 1992 benutze ich ausschließlich Devpac 3 für meine Assembler-Projekte. Devpac heißt die gesamte IDE, GenAm ist der Assembler, MonAm der Debugger und der Devpac nennt sich auch der Texteditor und es ist wohl das Beste kommerzielle Assembler Paket, dass je für den Amiga entwickelt wurde. Vorher habe ich wie viele andere auch den ASSEM-Assembler (MetaComCo) und ALink verwendet, als dann SEKA rauskam, den SEKA-Assembler, der war sehr viel schneller als die Verbindung ASSEM und ALink - und man brauchte nur eine Diskette, auf der die System-Dateien (S, C, LIBS etc. - die Workbench war ja was für Memmen ) sowie der Assembler Platz fanden. Das waren noch Zeiten... Zitat: Yep, damit habe ich nicht gerechnet... Ich habe vorausgesetzt, dass Maik schon eigenständig Programme in Assembler verfasst hätte. Mein Fehler... Gruß |
|||||
|
Impressum |
Datenschutzerklärung |
Netiquette |
Werbung |
Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten. |