zatzen hat geschrieben:Dabei fehlt mir noch das Know-How über CRC32, was ich gerne verwenden würde um z.B.
anhand der Patterndaten die Musikstücke eindeutig identifizieren zu können.
Ich habe noch nicht sonderlich viel dazu recherchiert, bis jetzt scheint mir:
- zu prüfende Daten kann man als eine seeeehr große Zahl verstehen,
die man durch das 32 (oder 33?)- Bit Polynom dividiert.
- das ganze passiert in der Praxis schrittweise durch Shiften und XOR
- Der Divisionsrest ergibt die Prüfsumme (?)
Ja, so in der Art. In der Praxis verwendet man da eine Tabelle mit 256 DWord-Werten.
Ich kann Dir mal ein Programmbeispiel zeigen.
zatzen hat geschrieben:
DOSferatu hat geschrieben:Ja, wie gesagt: Es eilt nicht. Daß ich meine Programme hier präsentiere verpflichtet nicht zur Benutzung.
Es wäre aber mal ganz spannend, ISM komplexe Musik spielen zu hören.
Ja, für mich auch.
zatzen hat geschrieben:
Dass ich mich in prISM noch nicht so gut zurechtfinde und man dort nicht einfach so drauflos
improvisieren kann ist allerdings eine Hürde. Statt eines Converters von Tracker nach ISM
wäre ein Tool sinnvoll, welches meine Trackerstücke analysiert und mir das ganze auf eine
übersichtliche Weise darstellt, was ich mir dann z.B. ausdrucken könnte, um es dann in
prISM unter Benutzung aller Möglichkeiten einzuprogrammieren.
Naja, wie gesagt: ISM/prISM ist eigentlich nicht
so sehr für Samples ausgelegt - während die normalen, "MOD"-artigen Tracker ja
ausschließlich mit Samples arbeiten - teilweise mit leider
viel zu großen Samples.
Ja, ich weiß: Samples sind nicht zu groß, solange 15 oder 31 Samples zusammen in die unteren 640 kByte passen... ABER: ISM ist zur Verwendung in Spielen gedacht. Spiele haben außer Musik auch noch Grafik, Steuerung und eine Menge "Drumherum", das dann ebenfalls noch in den Speicher passen muß und ich für meinen Teil bin NICHT bereit, 80%-90% des Speichers für große lange Samples bereitzustellen, so daß sich alles andere zusammen dann 50 bis 60 kByte teilen müßte.
Um "Real-Mode" (16-bit) Spiele zu machen, muß
JEDER Bereich sparen: Meine Grafiken, mit ihrer 4-Bit-Option, meine Steuerung, die über ASM-artigen Bytecode in einer in 100% ASM programmierten VM erfolgt und eben auch Musiken/Soundeffekte, die mit Synthesizing und allemal
kleinen Samples arbeiten sollten.
Das heißt natürlich nicht, daß man mit ISM nicht auch größere "standalone" "Musikprojekte machen könnte/sollte.
Und, wie bereits erwähnt: Mit den
Einfg/
Entf-Tasten sollte das "Improvisieren" dann einfacher gehen.
zatzen hat geschrieben:Wenn ich etwas im Tracker "komponiere", dann achte ich nämlich gar nicht auf die
Notennamen und Oktaven etc., ich höre nur hin wie es klingt, und kann im Nachhinein
gar nicht sagen welche Noten oder Harmonien ich da verwendet habe.
Naja - ich muß immer alles berechnen, anders traue ich dem Frieden nicht --- obwohl die normale "Tracker"-Ansicht natürlich auch etwas für sich hat - man sieht die Töne nebeneinander und wann sie einsetzen. Allerdings sind im "normalen MOD" Wiederholungen nur dann möglich, wenn sie gleichzeitig alle Stimmen betreffen und - mal abgesehen von den "ein Pattern in der Mitte starten/unterbrechen" Sub-Befehlen - nur auf ganze Patterns bezogen.
Was besser oder schlechter ist, läßt sich schwer beurteilen - wahrscheinlich die "MOD-Variante", weil so viele Leute sie seit Jahrzehnten erfolgreich benutzen ... - manche allerdings vielleicht auch, weil es die einzige Variante ist, die sie bisher kennen.
ISM ist eben ein komplett anderer Ansatz - und ja, mir ist bewußt, daß mit Trackern erfahrene Musiker hier eventuell Schwierigkeiten haben könnten. Aber siehe dazu meinen
nächsten/neuen Beitrag.
zatzen hat geschrieben:Zum Verständnis nur noch etwas: Wenn ich mir deine XPYDERZ.EXE mit ihren 166K ansehe, dann dünkt
es mir, dass man in Pascal mehr als 64K Code haben kann.
So ist es.
zatzen hat geschrieben:Aber dafür muss ja dann zwischendurch das Code-Segment geändert werden.
Genau!
zatzen hat geschrieben:Geschieht das evtl. für jede TPU?
Jein. Man kann einstellen, ob es für
jede TPU passiert oder diese auch "gruppieren", d.h. Pascal sucht dann aus, was noch alles in das gleiche Segment paßt.
zatzen hat geschrieben:Und wäre dann nicht jeder Funktionsaufruf aus einer TPU ein FAR Call?
Soweit ich weiß, schon (außer vielleicht, wenn alles in's gleiche Segment compiliert werden konnte).
Das "Problem" ist hier, daß eine Subroutine einer TPU ja "von überall im Programm" aufrufbar sein muß, auch von Stellen, die "zu weit entfernt" für einen near call sind. Man kann eine Subroutine aber leider nicht so programmieren, daß sie sowohl als near als auch als far aufgerufen werden kann - das liegt an den verschiedenen RET-Befehlen am Ende. Der "near RET" holt ja nur den Offset zurück (geht ins gleiche Segment), der "far RET" holt den Offset und das Segment. Selbst WENN man einen Mechanismus an's Ende einer Routine (procedure/function) manuell bastelt, der dann entscheiden würde, ob near oder far, muß die Routine ja auch WISSEN, als was sie aufgerufen wurde, um am Ende entsprechend zurückzuspringen.
D.h. man müßte der Routine das beim Aufruf mitteilen und am Ende wäre dann eine Entscheidung (evtl auch mit bedingten Sprüngen), die das ganze managt. --- Ob man DAMIT dann die Zeit rausholen würde, die einem durch den FAR CALL (statt NEAR CALL) "verlorengeht", wage ich ernsthaft zu bezweifeln.
Anmerkung: Mit dem Compilerschalter
$G kann man die "Gruppierung" anschalten und die Units nennen, die zur gleichen "Gruppe" gehören sollen (funktioniert natürlich nur so lange, wie alle aus den entsprechenden Units eincompilierten procedures/functions in ein Segment passen). Diese Segmentgrößen werden mit
$S festgelegt (default ist 16 kByte).
Dazu einmal mal die Hilfen zu $G und $S in Pascal aufrufen, jeweils die erste (also "Unitsegmente gruppieren" und "Segmentgröße").
Diese Schalter haben noch eine zweite Funktion, wenn man sie mit direkt folgendem + oder - benutzt (286er-Code generieren und Stack-Prüfung), das hat mit diesem Gruppieren nichts zu tun.
zatzen hat geschrieben:DOSferatu hat geschrieben:
IF-Kaskaden kann man unter anderem mit sogenannten Entscheidungstabellen verhindern.
Kann das bei Bedarf gern mal genauer erklären.
Ich habe das bei ZVIDVIEW auch schon umgesetzt, allerdings nicht mit Sprüngen sondern
mit CALLs. Ich weiss nicht genau was schneller ist, Sprünge oder eben CALLs.
CALLs sind natürlich etwas langsamer als Sprünge, weil bei CALLs der "Ausgangspunkt" vorher
auf den Stack gesichert wird, was bei Sprüngen entfällt. Sprünge "wissen" dafür nicht mehr,
wo sie hergekommen sind. Wenn die "Ziele" (also wohin gesprungen wird) immer nur von
einer einzigem Stelle aus angesprungen werden, ist ein kombinierter Sprung und Rücksprung
besser/schneller als ein CALL.
Anmerkung: Ich habe "Doppelrücksprünge" schon öfters mit PUSHs gelöst (z.B. benutze ich das öfter in GAMESYS).
Erklärung: Man springt irgendwo hin, innerhalb dieser Untersektion werden verschiedene CALLs
durchgeführt, die irgendetwas tun. Ist das letzte, was diese "Untersektion" macht, ebenfalls ein CALL und danach
folgt gleich ein Sprung oder Rücksprung zu X, habe ich das statt so:
so gelöst:
(der obige CALL ist in dem Fall ein NEAR CALL).
Was passiert? Ich lege die Rücksprungadresse auf den Stack. Und anstatt Beispiel zu "CALLen", springe ich nur dahin.
Am Ende von Beispiel (die ja eigentlich eine Subroutine ist, die einen CALL erwartet), ist ein RET. Und dieser RET holt sich dann X vom Stack und springt zurück. Somit habe ich mir einiges an Sprüngen/Aufrufen eingespart.
zatzen hat geschrieben:Für einfache Sprünge anhand Entscheidungstabellen fehlt mir das Wissen, wie
man die Adressen von Labels innerhalb von asm Anweisungen ermittelt.
Bzw. wie man einen JMP formuliert, der nicht an ein Label sondern an eine
Adresse springt, die sich z.B. in einem Register befindet.
Labeladresse in ein Register laden:
Wenn es um eine "dynamische" Adresse geht, die erst zur Laufzeit des Programms (also nicht
während des Compilierens) bekannt ist, hilft natürlich LEA:
Vor "irgendwas" setzt man dann das Segmentpräfix für das gewünschte Segment. lea ermittelt dann den Offset, den "irgendwas" zum Segment hat. Oder anders ausgedrückt: Wenn man
benutzt, steht danach in CS:[BX] die Adresse, wo @irgendwas anfängt. Ich weiß gerade nicht, ob hier ein Fehler ausgelöst wird, falls sich @irgendwas nicht gar nicht im Segment (also in den 64kByte ab Segmentanfang) befindet oder nicht.
zatzen hat geschrieben:Du erwähntest noch das Programmieren der AdLib Karte.
So schwierig ist das gar nicht, für mich war es leicht weil man nichts mit Samples
und Software Mixing zu tun hat. Also reicht es, wenn man keine Portamento-Effekte
machen will, wie auch bei meinem ZSM, nur jede neue Zeile einen Befehl zu senden.
Der FM-Synthesizer verlangt ca. einen dutzend Parameter pro Stimme, aber da bekommt
man nach kurzer Übung schnell brauchbare Sounds hin.
Mir geht es da weniger um die Programmierung/Ansteuerung der AdLib Register.
Und diese Warteschleifen-Problematik habe ich auch schon gelöst. Aber ich als
Formel-Mensch komme mit diesen komischen Dingen, wo ich aus zwei kombinierten
Sinuswellen einen Klang generieren soll, nicht klar - da habe ich keinen Nerv dafür,
wie ich mir dann daraus sowas unnatürliches wie Dreieck-/Rechteck-/Sägezahnwellen
basteln könnte, das ist mir zu kraß. Dafür müßte ich mir wohl ein Tool bauen.
zatzen hat geschrieben:Ich habe 1995 einen simplen Tracker in QuickBASIC geschrieben, die Musik habe
ich in Kotzman II benutzt.
Das einzig dumme an der AdLib ist, zumindest so wie sie in dem Buch beschrieben
wurde, dass man für bestimmte Register ein Delay einarbeiten muss, weil die
Daten sonst nicht richtig ankommen. Und ich hatte dann auch noch das Problem,
dass es beim ändern der Parameter für einen Kanal zu Soundmüll kam wenn
man das zwischendurch machte, bzw. habe ich damals auch die Delays so
eingeschätzt, dass sie sich nicht in den Ablauf eines Musikstücks integrieren
lassen. Deshalb habe ich für jeden Kanal nur einen festen Klang definiert.
Ja, das ist ein bekanntes "Problem". Oft wurden solche Dinge früher[tm] auch entweder
GAR NICHT eingebaut (weil die Rechner so langsam waren, daß diese Wartezeit
allein schon durch den Abstand zweier Befehle alleine erreicht wurde) oder mit
Warteschleifen - die auf zu schnellen Rechnern dann Über- oder Unterläufe
produzierten (ja, wir ALLE kennen die besagten Spiele, die man dann im SlowMode
laufen lassen muß, weil sie sonst mit Fehlermeldung aussteigen und selbst im
Slow hat man dann wenn man Pech hat, noch diese schicken "hängenden Noten"...)
Aber gut - genug erstmal davon. In meinem nächsten Beitrag geht es wieder um ISM/prISM...