Autor Beitrag
ALF
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Di 12.07.11 14:37 
Zur zeit benutzte ich ein statisches Array
ausblenden Delphi-Quelltext
1:
Mygrid : Array [0..150..maxlen] of byte;					

schöner währe ein dynamisches da die Entgrösse ja eigentich nicht feststeht.
ausblenden Delphi-Quelltext
1:
Mygrid : Array [0..15of Array of Byte;					

Will ich nun an einer bestimmten Stelle was einfügen/entfernen muss alles verschoben werden
und die Werte mussen neu berechnet werden
Nun lese ich immer wieder, nimm gleich TList<type> für sowas. Angeschaut, gelesen und Bahnhof verstanden. :shock:
Grund, mir schwebt etwas in der Form vor wie eine Liste, nur wie umsetzten?
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
Trackindex(0-15)  Eventindex   ZeitWert integer     Event,(+Werte)=drei bytes
0                  0              0                  92,48,96 
0                  1              0                  92,60,96 
0                  2              96                 91,67,64 
0                  3              96                 90,76,32 
0                  4              192                82,48,64 
0                  5              0                  82,60,64 
0                  6              0                  81,67,64
0                  7              0                  80,76,64

Beim einfügen/entfernen in einem normalen Array müsste ich nun durch irritieren um die Zeitwerte und das Event dazu finden. Vom neuberechnen der Zeitwerte mal abgesehen.
Habe ich aber ein Eventindex so bräuchte ich nur den index löschen und die Werte währen auch weg bzw will ich was einfügen(insert) hätte ich den Eventindex und könnte an der Stelle was neues einfügen.

Nun zum eigentlichen, wie müsste den so eine TList erstellt werden das sie in etwa so aussieht.

Es kann natürlich auch sein das mein ganzer Ansatz dazu vollkommen falsch ist und ich mich an etwas festbeisse was vielleicht gar nicht Notwendig ist.
Nach tagelangen Suchen und ausprobieren komm ich einfach auf keine vernünftige Lösung dafür.

Hoffe ihr könnt wieder mal helfen.
Gruss Alf

PS: Es geht nicht um das auslesen von MidiDaten, sondern um MidiNoten selbst zu erstellen(zeichnen).
Sollte es etwas konfus sein hier mal ein link dazu
www.omega-art.com/midi/mfiles.html
www.camx.de/kurs_kap3.html

_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 12.07.11 16:11 
Moin!

user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
Nach tagelangen Suchen und ausprobieren komm ich einfach auf keine vernünftige Lösung dafür.
IMHO gehst du da ganz falsch ran. :nixweiss: Du willst auf dem Zieldatenprotokoll auch die Bearbeitung aufsetzen und deshalb wird das so schnell so komplex. :?

Du solltest das etwas abstrakter angehen, z.B. ein Objekt TMidiEvent (evtl. auch als Basisobjekt für abgeleitete Klassen) definieren und erstmal alle möglichen MIDI-Ereignisse als Datentypen anlegen. Dann gehst du hin und schreibst die Ereignisse in eine Liste pro MIDI-Track. So kannst du auf Ereignisbasis die Tracks bearbeiten. Tipp: du könntest dem TMidiEvent eine Eigenschaft .PreDelay verpassen, so dass die Midi-Ereignisse eine Kette bilden, die sich selbst timed. ;) Das ist zwar relativ effizient, aber auch etwas tricky beim Bestimmen der Einfügepositionen in anderen Tracks, wenn dort Ereignisse nicht exakt synchron abgelegt sind. Ein anderer Ansatz könnte ein festes, internes Zeitraster sein.

Wenn du dann ein Midi-File aus der Trackliste erzeugen willst, schreibst du erst im Midi-Protokoll die Bytestreams. Und zu diesem Zeitpunkt sind die einzelnen Objektgrößen im Zielformat klar, so dass es keine Probleme mehr geben sollte. :D

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.

Für diesen Beitrag haben gedankt: ALF
Bergmann89
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Di 12.07.11 16:32 
Hey,

wenn du noch D7 benutzt (wie das in deinem Profil steht) dann kannst du eh keine typisierten Listen nehmen. Die gibts erst später. Also enweder castest du jedesmal wenn du etwas aus der Liste liest, oder du benutzt ein Template:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
unit uMidiEvents;

interface

uses
  Classes, Contnrs, Windows, SysUtils;

type
  TMidiEvent = class(TIObject)
  {...}
  end;


  TListItem = TMidiEvent;

  {$I ObjectListTemplate.pas}

  TTMidiEventList = class(TObjectListTemplate); 

implementation

{$I ObjectListTemplate.pas}

end.


MfG Bergmann.
Einloggen, um Attachments anzusehen!
_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
ALF Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Di 12.07.11 21:15 
Danke für die Anworten.
Ich glaub, ich hab wieder mal falsch formuliert.
Was die Midi-Events betrifft gibt es da weniger Probleme. Mir geht es um das Notenschreiben. Speziell Note-on, Note-off und deren Timewert. Solange alle Noten intereinanderkommen null problemo, dann währe das Array ja effektiv(einfügen und delete) anhand der Zeitwerte wo welche Note steht.
So wie ich es jetzt mache.
ausblenden Delphi-Quelltext
1:
2:
maxlen = 10000 
NotenTracks: Array [0..150..maxlen] of byte
funct ja auch wenn alle Noten hintereinander gezeichnet werden.
Nun gibt es ja auch Akkorde in der Musik und da fängt das Problem mit dem Array an.
Noten
also muss ne andere Lösung her.

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:

IMHO gehst du da ganz falsch ran. :nixweiss:
Vermute ich auch, hab mich vielleicht festgefahren mit meinem Array.

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Du willst auf dem Zieldatenprotokoll auch die Bearbeitung aufsetzen und deshalb wird das so schnell so komplex. :?
Jein. Ich lege zwar die Daten schon im Originalformat im Array ab, so das das abspielen nicht noch mal konvertiert werden muss.

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Du solltest das etwas abstrakter angehen, z.B. ein Objekt TMidiEvent (evtl. auch als Basisobjekt für abgeleitete Klassen) definieren und erstmal alle möglichen MIDI-Ereignisse als Datentypen anlegen.
Das ist ja kein Problem, im Prinzip hab ich so schon.

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
...Dann gehst du hin und schreibst die Ereignisse in eine Liste pro MIDI-Track.
Mehr mach ich mit meinem Array(16Tracks) ja auch nicht, für jeden Track und deren Noten.

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
So kannst du auf Ereignisbasis die Tracks bearbeiten. Tipp: du könntest dem TMidiEvent eine Eigenschaft .PreDelay verpassen, so dass die Midi-Ereignisse eine Kette bilden, die sich selbst timed. ;) Das ist zwar relativ effizient, aber auch etwas tricky beim Bestimmen der Einfügepositionen in anderen Tracks, wenn dort Ereignisse nicht exakt synchron abgelegt sind. Ein anderer Ansatz könnte ein festes, internes Zeitraster sein.
fehlt mir jedweiliger Ansatz dafür :?

Wie schon gesagt, wahrscheinlich zu sehr auf das Array von mir fixiert!

@Bergman89:
Profil geändert:wink:

Zur Zeit also totale leeeeere, um ne Lösung für das zwischenspeichern der selbstertellten Noten zu finden.
Ansätze ja - aber lande immer bei meinem Array. einfach nur blöd zur Zeit.

Gruss Alf
Einloggen, um Attachments anzusehen!
_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Di 12.07.11 22:01 
user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Hey,

..dann kannst du eh keine typisierten Listen nehmen. Die gibts erst später.


Wieso das ? :shock: Wenn irgendwas nicht richtig passt, dann steckt man das besser direkt in eine TObjectList und fertig. Die kann man sortieren und und...

_________________
Gruß
Hansa
ALF Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Di 12.07.11 23:24 
user profile iconhansa hat folgendes geschrieben Zum zitierten Posting springen:
Wieso das ? :shock: Wenn irgendwas nicht richtig passt, dann steckt man das besser direkt in eine TObjectList und fertig. Die kann man sortieren und und...

Er bezog das auf D7 mit TList<Typ>. Das gab es da noch nicht. Darum hat er ja den DL angehangen.

TList<Type>, TObjektList hab ich zwar schon gelesen. Problem bei mir, wie setzte ich es um?
Hab nicht mal nen Ansatz bezogen auf mein Problem. Auch die gefunden Beispiele geben mir da nix, weil ich die nicht in meinem Kontext bekomme :autsch:

Gruss Alf

_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
ALF Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Do 14.07.11 16:57 
Jo, ich pushe zwar nicht gern, mach es aber mal.
Dank user profile iconNarses und noch weitere suche hab ich entlich mal ein "simples" Beispiel gefunden, wie man mit Objektlisten umgeht.
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
type
   TEvent = class(TObject)
      Track: Integer;
      Deltatime: Integer;
      Event: Byte;
      Wert1: Byte;
      Wert2: Byte;
end;
...
...
TrackEvent: TObjectList;
...
...
{im Create}
TrackEvent:= TObjectList.Create;
{im close}
TrackEvent.Free;
...
...
procedure WriteEvent(Track, DTime: Integer; Event, aWert1, bWert2: Byte);
var
   newEvent: TEvent;
begin

    newEvent:= TEvent.Create;
    newEvent.Track:= CurrentTrack;
    newEvent.Deltatime:= DTime);
    newEvent.Event:= Event;
    newEvent.Wert1:= aWert1;
    newEvent.Wert2:= bWert2;

    TrackEvent.Add(newEvent);
end;

Also add, delete kein Problem. Insert etwas komplizierter und Editieren einer Note noch komplizierter :mrgreen:
Hoffe also das für den Anfang, ich es so richtig verstanden habe.
Allerdings bleibt erstmal ein Wunsch offen.
Würde die Zuordnung zum Track nicht in diesem Objekt machen, sondern die Events zum Track zuordnen :gruebel: so wie
ausblenden Delphi-Quelltext
1:
Tracks: Array[0..150..maxevents] of Byte.					

So wie es ist , ist es ja ein Chaos, weil alles in einer Liste ist.

Währe schön für nen Hinweis oder wie das Objekt, Classe aussehen musste. :flehan:

Gruss Alf

_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
Bergmann89
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Do 14.07.11 19:36 
Hey,

ich versteh dein Problem iwie nicht. Du hast mehrere Tracks, also brauchst du ne Klasse die deine Tracks verwaltet. Dann hat jeder Track mehrere Events, also brauchst du noch ne Klasse die deine Events verwaltet. Ich würd das so in der Art machen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
TEvent = class(TObject)
private
  fDeltaTime: Integer;
  fEvent, Value1, Value2: Byte;  
public

end;

TTrack = class(TObject)
private
  fEventList: TObjectList<TEvent>; //du hast typisierte Listen, also nutz sie auch ;)
public
  procedure AddEvent(event: TEvent);
  procedure DelEvent(ID: Integer);
  {...}
end;

TTrackManager = class(TObjekt)
private
  fTrackList: TObjectList<TTrack>; 
public
  constructor Create(TrackCount: Integer); //legt 'TrackCount' Tracks an un speichert sie in fTrackList
end;

So hast du doch die Daten schön verpackt. Was ich nicht verstehe: Warum muss ein TEvent den Track wissen auf dem es liegt? Das kann doch dem Event egal sein, oder? Oder ich hab das Problem nicht richtig verstanden ^^

MfG Bergmann.

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^


Zuletzt bearbeitet von Bergmann89 am Do 14.07.11 21:05, insgesamt 1-mal bearbeitet
ALF Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Do 14.07.11 20:56 
user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Was ich nicht verstehe: Warum muss ein TEvent den Track wissen auf dem es liegt? Das kann doch dem Event egal sein, oder? Oder ich hab das Problem nicht richtig verstanden ^^
Jo, dem Event ist es egal. Ich habe Track nur mit reingenommen, weil ich keine andere Lösung hab um dieses Event zuzuordnen.

Für Deine Hilfe bin ich auch sehr Dankbar, nur verstehen tu ich es nicht :oops:
Brauch leider immer sehr lange bis ich so was ins Kleinhirn bekomme. Noch nie damit was gemacht und meine bildliche Vorstellung ist immer dieses blöde Array.

Nun vergleich ich mein kleines Beispiel mit Deins!
Das ist ja nun wieder ganz was anderes, omg.

Wozu diese beiden Prozeduren in TTrack, müssen die sein oder können die sein oder weil man es so macht?
Warum 2x Class(TObject) und einmal nicht? ist TTrackManager nicht eine classe? und und

Schon steh ich da ich alter Torr und bin so schlau wie zuvor.
Peinlich .

Gruss Alf

_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
Bergmann89
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Do 14.07.11 21:18 
Hey,

der TTrackManager muss natürlich eine class(TObject) sein, hab ich mich vertippt, sry (habs oben auch angepasst).
Das mit den Methoden bei TTrack kann man so machen, muss man aber nicht. Man könnte auch TTrack von TObjektList erben lassen: TTrack = class(TObjectList) oder man macht ein property auf fEventList um auf die Liste zuzugreifen: property EventList: TObjectList<TEvent> read fEventList; Das mit den extra Methoden ist zwar ein bischen mehr Aufwand, aber es ist übersichtlicher, wenn man die Klasse nutzen will (zumindest seh ich das so).
Du hattest ja das 2D-Array für die Tracks: Tracks: Array[0..150..maxevents] of Byte; Das ist aber sehr unübersichtlich, also hab ich das Ganze in die 3 Klassen zerlegt. [0..15] ist der TTrackManager der verwaltet alle Tracks (egal ob es 15, 20 oder 1000 sind). Das [0..maxevents] wird durch TTrack dargestellt. Auch hier wieder mit beliebig vielen Events, da die Liste dynamisch erweiterbar ist. Letzendlich wird nur noch das Event (bei dir der of Byte-Teil) in der Klasse TEvent gespeichert. Natürlich mit ein paar Zusatzinfos. Das meine Lösung auch zweidimensional ist sieht man daran, das eine Liste (fTrackList) ein Objekt verwaltet was wieder eine Liste besitzt (fEventList). Und ne Liste is intern auch nix anderes als ein Array, nur das die ganze Verwaltung (hinzufügen, löschen, ...) schon vorgefertigt ist. Und ein Array mal noch ein Array ist nun mal ein 2D-Array :)
Ich hoffe die Ausführungen konnten ein wenig Licht in das Dunkel bringen ^^

MfG Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^

Für diesen Beitrag haben gedankt: ALF
ALF Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Do 14.07.11 21:35 
Jo, nun hab ichs verstanden und damit auch ne bildliche Vorstellung :wink:
user profile iconBergmann89 Danke :zustimm:

Mach mich run ans umsetzten. Mal sehen wie weit ich komme!

Gruss Alf

_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 15.07.11 02:33 
Moin!

Also so richtig gut sieht mir das Klassenmodell noch nicht aus, das scheint nicht wirklich die Realität abzubilden. Ich mach nochmal einen anderen Vorschlag. ;)

Vergessen wir mal kurz komplett alles, was wir über Midi-Files wissen und schauen uns an, wie ein, sagen wir mal "Lied", aufgebaut ist:
  • Zu irgendeinem Zeitpunkt, nennen wir ihn mal 0, startet das Lied, und zwar mit einem oder mehreren gleichzeitig erklingenden Tönen
  • Diese Töne haben eine bestimmte Dauer, die wollen wir mal in Millisekunden (ms) messen
  • Wenn alle Starttöne ihre Dauer durch haben, kommt entweder eine Pause (nix zu hören) oder wieder ein oder mehrere Töne, usw.
Man könnte also ein Lied als Liste von Tönen (oder Tongruppen = Akkorde) definieren, die einen Startzeitpunkt (in ms bezogen auf den Liedstart = 0) und eine Dauer (ebenfalls in ms) haben. Pausen werden nicht erfasst sondern ergeben sich implizit dadurch, dass diese Intervalle nicht in der Ton-Liste des Liedes enthalten sind. Interessant ist, dass diese Ton-Liste im Speicher noch nicht einmal sortiert sein muss, um trotzdem korrekt ein Lied abzubilden. :o Der einfacheren Verarbeitung halber könnte man die Töne aber z.B. aufsteigend nach Startzeitpunkt sortieren. :nixweiss:

Mit dieser Datenstruktur ist es relativ einfach, ein Lied zu "erstellen": man fügt einfach irgendwo ein Objekt mit den Eigenschaften Startzeitpunkt/Tonhöhe/Dauer in diese Liste ein und ist fertig. :D Diese Informationen könnte man relativ leicht aus einer GUI vom Benutzer entgegennehmen, wenn man z.B. eine Dauer als Vorgabe einstellt, als Y-Koordinate eine Klaviatur zeigt und aus der X-Koordinate des Mausklicks den Startzeitpunkt ableitet. :idea:

Schön, jetzt haben wir also unser Lied in dieser Liste. Wie macht man daraus nun ein MidiFile im korrekten Bytecode?! :shock: :gruebel: Konzept:
  • Wir gehen der Einfachheit halber mal nur von einem Track aus. Wenn man das mit einem Track kann, dann geht das mit 15 weiteren genauso. :zwinker:
  • Zunächstmal benötigen wir passende Objekte für die Midi-Ereignistypen: NoteOn und NoteOff mit den Eigenschaften Ereigniszeitpunkt und Tonhöhe
  • Diese Objekte "wissen", wie man "sich selbst" im Midi-Bytecode darstellt
  • Weiterhin brauchen wir noch eine Liste, die diese Objekte verwaltet und nach Ereigniszeitpunkt sortieren kann (oder auch gleich hält), nennen wir sie mal MidiTrack
  • Jetzt nehmen wir unsere Lied-Liste, gehen einfach die darin enthaltenen Objekte durch und erstellen passende NoteOn- (zum Startzeitpunkt) und NoteOff-Objekte (Startzeit+Dauer) in der MidiTrack-Liste (spannend ist: bis jetzt ist immer noch überhaupt keinerlei Sortierung notwendig 8))
  • Wenn die MidiTrack-Liste gefüllt ist (oder anders gesagt, das Lied abgearbeitet ist), sortieren wir die darin enthaltenen Midi-Ereignisse nach Zeitpunkt (falls die Liste das nicht schon beim Einfügen gemacht hat)
  • Abschließend gehen wir nun diese MidiTrack-Liste durch und lassen die darin enthaltenen Ereigniss-Objekte sich selbst in den Zieldatenstrom schreiben (-> das MidiFile). Dabei merken wir uns den letzten Ereigniszeitpunkt: ist der Zeitpunkt des nächsten Ereignisses der Gleiche, einfach weiter schreiben lassen, sonst für den Differenz-Zeitraum den Delay-Bytecode selbst erzeugen und schreiben
  • Das Ganze noch etwas mit dem MidiFile-Header und anderem Beiwerk dekoriert, fertig. ;)
Und damit das nicht so trocken ist, hier noch etwas Deklaration als Vorschlag (ich habe "nur" D7pro, deshalb mal darauf zugeschnitten):
ausblenden Delphi-Quelltext
1:
2:
3:
  TLied = class(TObjectList) // das ist unser "Lied"
    // hier werden TBasiston-Objekte verwaltet
  end;
Jetzt die Objekte für ein Lied:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
  TBasiston = class(TObject)
  private
    FStartzeit: Integer;
    FDauer: Integer;
  public
    property Startzeit: Integer read FStartzeit write FStartzeit;
    property Dauer: Integer read FDauer write FDauer;
    procedure WriteToMidiTrack(AMidiTrack: TMidiTrack); virtualabstract// Das Objekt muss sich selbst
    // in einen MidiTrack übersetzen können -> also NoteOn und NoteOff draus machen
  end;

  TTon = class(TBasiston) // einzelner Ton
  private
    FTonhoehe: Integer;
  public
    property Tonhoehe: Integer read FTonhoehe write FTonhoehe;
    procedure WriteToMidiTrack(AMidiTrack: TMidiTrack); override// hier werden dann Nachfahren von
    // TMidiEvent erzeugt, konkret hier: TNoteOn und TNoteOff mit der hier definierten Tonhöhe
    // und dem Zeitabstand aus dem Vorfahren
  end;

  TIntArray = array of Integer;

  TAkkord = class(TBasiston) // Akkorde definieren wir mal als mehrere Tonhöhen zum gleichen Zeitpunkt+Dauer
  private
    FTonhoehen: TIntArray;
    function GetCount: Integer;
    procedure SetCount(const Value: Integer);
    function GetTonhoehe(const Index: Integer): Integer;
    procedure SetTonhoehe(const Index, Value: Integer);
  public
    property Count: Integer read GetCount write SetCount;
    property Tonhoehen[const Index: Integer]: Integer read GetTonhoehe write SetTonhoehe;
    procedure WriteToMidiTrack(AMidiTrack: TMidiTrack); override// praktisch das gleiche, wie beim einzelnen Ton, nur mehrfach
  end;
Jetzt der MidiTrack:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
  TMidiTrack = class(TObjectList)
    // hier werden TMidiEvent-Objekte verwaltet
  private
    FTrackNr: Integer;
  protected
    procedure SortiereNachStartzeit;
  public
    property TrackNr: Integer read FTrackNr write FTrackNr;
    procedure WriteToStream(AStream: TStream); // hier steckt die Schleife drin, die die Delays zwischen Ereignissen
    // selbst als Bytecode generiert oder sonst die entsprechende Methode des MidiEreignisses aufruft
  end;
Und noch die Midi-Ereignisse (nur die Grundlegenden):
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
  TMidiEvent = class(TObject) // abstraktes Midi-Ereignis
  private
    FZeitpunkt: Integer;
  public
    property Zeitpunkt: Integer read FZeitpunkt write FZeitpunkt; // kennt nur einen Zeitpunkt
    procedure WriteToStream(AStream: TStream); virtualabstract// und muss sich selbst serialisieren können
  end;

  TNoteEvent = class(TMidiEvent) // abstrakter Ton
  private
    FTonhoehe: Integer;
  public
    property Tonhoehe: Integer read FTonhoehe write FTonhoehe; // hat zusätzlich eine Tonhöhe
  end;

  TNoteOn = class(TNoteEvent)
  public
    procedure WriteToStream(AStream: TStream); override// hier muss nur noch in Bytecode übersetzt werden
  end;

  TNoteOff = class(TNoteEvent)
  public
    procedure WriteToStream(AStream: TStream); override// dito
  end;
Dieses Konzept sollte dein Grundproblem, wie man ein Lied "malt", relativ gut kapseln. Schau mal drüber, ob du damit was anfangen kannst. :les:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
ALF Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Fr 15.07.11 18:44 
Ok, bitte nicht gleich alles auf einmal. Darum erst mal der Reihe nach.
user profile iconBergmann89Ich hab mal CP gemacht. Schanlls natürlich nicht.
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
type
   TEvent = class(TObject)
      Track: Integer;
      Deltatime: integer;
      Event: Byte;
      Wert1: Byte;
      Wert2: Byte;
end;

type
     TTrack = class(TObject)
  private
    fEventList: TObjectList<TEvent>; //du hast typisierte Listen, also nutz sie auch ;)
  public
    procedure AddEvent(event: TEvent);
    procedure DelEvent(ID: Integer);
    {...}
end;

type
    TTrackManager = class(TObject)
  private
    fTrackList: TObjectList<TTrack>;
  public
    constructor Create(TrackCount: Integer); //legt 'TrackCount' Tracks an un speichert sie in fTrackList
end;

type
  TForm1 = class(TForm)
  ...
  ...
private
  //TrackEvent: TObjectList;
  myTracks: TTrack;
  myTrackManager: TTrackManager;
var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor TTrackManager.Create(TrackCount: Integer);
var
  i: Integer;
begin
  inherited Create;
    // for i:= 0 to TrackCount do
     //begin
        // fTrackList.Add(TTrack);
        //fTrackList.Create;
     //end;
end;
{fehlt nich auch ein Destructor????}

procedure TTrack.AddEvent(event: TEvent);
begin

     fEventList.Add(event);
end;

procedure TTrack.DelEvent(ID: Integer);
begin
    //noch nicht vorgesehen
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
    //TrackEvent:= TObjectList.Create;
    myTracks:= TTrack.Create;
    myTrackManager:= TTrackManager.Create(2) ;//TTrackManager.Create(15);
    //mytrackmanager.Add(mytracks);

end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
    //TrackEvent.Free;
    myTrackManager.Free;
    myTracks.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  newEvent: TEvent;
begin
       newEvent:= TEvent.Create;
    try
      newEvent.Track:= 0;
      newEvent.Deltatime:= 196;
      newEvent.Event:= $90;
      newEvent.Wert1:= $27;
      newEvent.Wert2:= $7f;
      mytrackmanager.fTrackList.Items[0].AddEvent(newEvent);
       //mytrackmanager.Items[0]AddEvent(newEvent);//     fTrackList.Items[0]:=
      //mytracks.AddEvent(newEvent);
     //mytracks.Add(newEvent)
      //TrackEvent.Add(newEvent);
    finally
       //newEvent.Free;
    end;
end;
kein Durchblick sorry, MyTrackManager, MyTracks = Nil
zumal wo bleibt den, die eigentliche Liste(TObjectList)?

user profile iconNarses möchte jetzt erst mal das vom Bergmann89 verstehen.
Dann Verstehe ich Deins wesentlich besser :wink: Deins ist natürlich Spitze! :zustimm:
Zitat:
Interessant ist, dass diese Ton-Liste im Speicher noch nicht einmal sortiert sein muss, um trotzdem korrekt ein Lied abzubilden.
hab ich bei meiner kleinen Liste(TObjektliste) auch festgestellt :wink:
Das da noch was passieren muss(sortieren und abspielbar machen) ist mir auch klar. Du hast ja schon gesagt:
Zitat:
Vergessen wir mal kurz komplett alles, was wir über Midi-Files wissen und schauen uns an, wie ein, sagen wir mal "Lied", aufgebaut ist:
und da ist mein Problem, Ich wollte ebend alles schon in der eigentlichen MidiForm, MeinFehler :?

Ich gehe mal davon aus, wenn ich Bergann89 seins verstanden habe, dürfte ich mit Deinem Vorschlag nur halb soviel schwierigkeiten haben(ausnahme werden die Berechnungen werden(delaytime)). Aber bis dahin muss ja erst mal das andere funcen.

Ich Danke erst mal, für eure Ausdauer mit mir.
EDIT:
QNarses, hab mit Deinem Vorschlag angefangen. komischerweise komme ich damit besser zurecht.
Ausser die Proceduren(klar die können ja noch nicht fertig sein)
Hab allerdings noch zwei hinzugefügt EditNote und DeleteNote.

Wahrscheinlich komm ich nicht mit:
fEventList: TObjectList<TEvent>;
fTrackList: TObjectList<TTrack>;
zurecht. Muss das nicht auch Createt werden bevor ich darauf zugreifen kann?


Gruss ALf

_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 15.07.11 23:44 
Moin!

user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconNarses möchte jetzt erst mal das vom Bergmann89 verstehen.
Wie du möchtest. ;) Allerdings will ich dich trotzdem noch auf zwei, IMHO wesentliche Dinge, hinweisen, die dort nicht umgesetzt sind und dich deshalb eher Zeit kosten, als Nutzen bringen: :nixweiss:

Du hast weiter oben dieses MidiEvent-Objekt eingeführt:
user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
type
   TEvent = class(TObject)
      Track: Integer;
      Deltatime: Integer;
      Event: Byte;
      Wert1: Byte;
      Wert2: Byte;
end;
Das Midi-Format ist AFAIR relativ in seinen Zeitbezügen aufgebaut. Das kommt vermutlich daher, dass man die Ereignisse von einem live eingespielten Ereignisstrom so einfach ablegen kann. Allerdings willst du einen anderen Weg gehen: du willst den Ereignisstrom designen, und da wirst du mit einem relativen Ansatz (genau das drückt Deltatime ja wohl aus) große Probleme haben. :idea: Mein Tipp: stell das auf ein absolutes Zeitraster um und mach erst in einem zweiten Schritt die Konversion auf relative Angaben. Du brichst dir beim Bearbeiten sonst noch die Finger... :? :lol:

Verabschiede dich als Speicherkontainer vom dem Array für den MidiBytecode und nimm Stream-Klassen, die verwalten ihre Größe selbst - das kann das Array nicht! Warum sich zusätzlich Arbeit aufhalsen. :think:

cu
Narses

//EDIT:
user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
Narses, hab mit Deinem Vorschlag angefangen. komischerweise komme ich damit besser zurecht.
Das liegt am absoluten Zeitraster. ;)

user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
Wahrscheinlich komm ich nicht mit:
fEventList: TObjectList<TEvent>;
fTrackList: TObjectList<TTrack>;
zurecht. Muss das nicht auch Createt werden bevor ich darauf zugreifen kann?
So ist es, ich bin mal davon ausgegangen, dass das klar ist. :?

//EDIT2: Also, falls das wirklich nicht klar ist :? die Klassen sind alle noch nicht vollständig ausdifferenziert, das ist sehr roh und nicht c&p-fähig. :lupe:

_________________
There are 10 types of people - those who understand binary and those who don´t.
Bergmann89
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Sa 16.07.11 00:30 
Hey,

wie Narses schon gesagt hat müssen die ganzen Variablen eines Objekts im Constructor initialisiert un im Destructor ggf freigegeben werden. Bsp.:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
constructor TTrackManager.Create(TrackCount: Integer);
var
  i: Integer;
begin
  inherited Create;
  fTrackList := TObjectList.Create(True); //wie genau der Konstruktor für typisierte Listen aussieht weiß ich nicht, die kann mein D7 noch nicht^^
  for i := 0 to TrackCount-1 do
    fTrackList.Add(TTrack.Create);
end;

destructor TTrackManager.Destroy;
begin
  fTrackList.Free;
  inherited Destroy;
end;


Bei Narses Lösung musst du die Listen nicht extra anlegen, da seine Objekte von den Listen erben un die dadurch im Konstructor erzeugt werden. Hast du schonmal richtig mit Klassen gearbeitet? Wenn nicht solltest du dir vlt erstmal ein Tutorial über die Möglichkeiten und Grenzen von Klassen durchlesen (und natürlich verstehen) eh du dir selbst eine Klassenstruktur aufbaust.

MfG Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
ALF Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Sa 16.07.11 02:17 
user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Hast du schonmal richtig mit Klassen gearbeitet? Wenn nicht solltest du dir vlt erstmal ein Tutorial über die Möglichkeiten und Grenzen von Klassen durchlesen (und natürlich verstehen) eh du dir selbst eine Klassenstruktur aufbaust.
jo hab ich 1mal type TScanThread = class(TThread) ewig her.
Tuts lese ich, leider in vielen Fällen sehr abstrakt gehalten und wenn ich die Theorie verstanden habe, scheiterts an der Praxis :? Und damit man sieht das es nicht nur CP ist:
ausblenden Delphi-Quelltext
1:
2:
fTrackList := TObjectList.Create(True); //wie genau der Konstruktor für typisierte Listen aussieht weiß ich nicht, die kann mein D7 noch nicht^^
fTrackList:= TObjectList<TTrack>.Create(True);//;)

Dabei reicht ja manchmal ein simples Beispiel aus. Nur die, die ich finde, bekomme ich meist nicht in meinem Kontext, mit Aussnahme meinem kleinem Beispiel oben, wo ich auch lange suchen musste.
Das ftracklist createt werden muss hab ich vermutet, aber ebend nur vermutet!
Das da ein destructor rein muss hatt ich vermutet, aber ebend nur vermutet!
Aber das evtl Wissen heist bei mir leider noch nicht das können(selbst wenn ich es in einem andern Kontext schon mal gemacht habe).
Egal, jetzt funct auch Deins 8)

@Narses:
DeltaTime hab ich nur aus Midi übernommen. Egentlich gibt es ja kein StartTime oder StopTime, es ist nur ein Zeitwert vor einem xbeliebigen Event. Es spielt also keine Rolle was für ein Event danach folgt. Auch wenn mann in diesem Fall bei NoteOn/NoteOff davon reden könnte. Was aber im "running status" schon nicht mehr stimmt.
Was den Zeitraster betrifft, verwende ich ihn ja schon, sonst könnt ich keine Note Zeichnen(zwischenspeichern), abspielen bzw wieder ins Grid zurückzeichnen :wink:
Was nun das graphische Zwischenspeichern betrifft, mit den Objeklisten, ist absolut genial!
Weil hier, wie Du schon sagst, die Reienfolge keine rolle spielt.
Nur, muss daraus jetzt auch die Reihenfolge erstellt werden(real) das ich es mal abspielen kann, was ich Design hab :lol:
also muss ja, der, die Track(s) ebenfalls schon fertig sein. Dies klappte ja bei der altbacken Methode von mir. Nur keine akkorde.

In der Theorie ist mir ja alles klar. Aaaaber die praktische Umsetztung in Code omg.
Mal sehen, wie weit ich jetzt mit der modernen komme, ohne Hilfe.
Wobei ich jetzt schon weiss, dass das Umwandeln zum abspielen, nen haufen Mathe ist omg!

THX an euch.

Gruss Alf

_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Sa 16.07.11 12:09 
Moin!

user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
DeltaTime hab ich nur aus Midi übernommen. Egentlich gibt es ja kein StartTime oder StopTime, es ist nur ein Zeitwert vor einem xbeliebigen Event.
Ich war ja schon drauf und dran gestern noch eine funktionsfähige Demo zu schreiben, aber ich bin dann leider doch an dem Midi-Timing gescheitert... :? Irgendwie kriege ich das mit der Bedeutung der Ticks und dem Wert im Header nicht auf die Reihe. Hast du verstanden, wie man daraus z.B. Millisekunden macht? :gruebel: :nixweiss:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
ALF Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Sa 16.07.11 14:35 
Ich soll was beschreiben ! Ich kanns versuchen.
Eine 1/4note ist fix nicht veränderbar, errechnet sich aus 60000000microsec/120bpm = 500000, wurde mal festgelegt. allerdings werden die 1/4noten mit 480000 geschrieben Warum keine ahnung
Verändere ich den bpm Wert, erhalte ich die zu speichernde Geschwindigkeit für den Header, in diesem Fall währe es auch 500000 microsec.

Beim lesen des Headers, wird nun 6000000/500000 = 120, So hatt man wieder die eigentliche Geschwindikeit bpm.
Nun muss beim abspielen die sogenannten Wartezei errechnet werden bis man weiterlesen kann im Track.

timeWait:=((( 120 / (6000000/50000)) * Noteleange); in diesem Fall nehemen wir die 1/4Note
Notenlänge ist der Timewert vor einem Event!!!! eigentlich DeltaTime :wink: oder bei Dir StartTime, Stoptime. aber vorsicht mit diesen 2 Begriffen.

und nun das ganze mit gettickcount in einem thread ablaufen lassen
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
Tick:= Gettickcount + timwait;
while timewait > 0 do
begin
application.pocessmassage
timewait:= tick - Gettickcount
end

ist das abgelaufen wird das nächste Event gelesen und sofort ausgeführt, sofort der nächste Timwert gelesen und wieder an den thread übergeben usw bis das Songende erreicht ist.

Ich wünschte mir, das profesioneller zu beschreiben. Ich kann es aber nicht anders beschreiben sorry!

Gruss Alf

_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mo 18.07.11 00:55 
Moin!

user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
Ich wünschte mir, das profesioneller zu beschreiben. Ich kann es aber nicht anders beschreiben sorry!
Danke, kein Problem, hat schon gereicht.

Die entscheidende Erkenntnis ist, dass die MidiTicks eine relative Zeiteinheit sind, die nur ein Verhältnis der Notenwerte untereinander beschreibt. Das eigentliche "Timing" (also die Umsetzung in tatsächliche Zeitwerte) wird erst mit dem Metaevent $51 = Mikrosekunden pro Viertelnote gesetzt. :idea: Falls noch einer auf der Suche nach den Timing-Details im MidiFile-Format sein sollte: hier ist das ganz brauchbar erklärt. :les: ;) Weiterhin hilft dieses Tool extrem bei den ersten Gehversuchen. :zwinker:

So, jetzt aber zur Sache. 8) Ich habe mal eine Funktions-Demo meines Konzepts weiter oben gemacht. Damit sieht die Erstellung eines MidiFiles so aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
  var
    Lied: TLied;
    MidiFile: TMidiFile;
begin
  Lied := TLied.Create;
  try
    Lied.Add(TTon.Create(72,    0480)); // "Alle meine Entchen..."
    Lied.Add(TTon.Create(74,  480480));
    Lied.Add(TTon.Create(76,  960480));
    Lied.Add(TTon.Create(771440480));
    Lied.Add(TTon.Create(791920960));
    Lied.Add(TTon.Create(792880960));
    Lied.Add(TAkkord.Create(7240001920)); // C-Dur
    MidiFile := TMidiFile.Create;
    try
      MidiFile.AddTrack(TMidiTrack.CreateFromLied(Lied));
      MidiFile.WriteToFile(ExtractFilePath(Application.ExeName)+'Test.mid');
      ShowMessage('OK');
    finally
      MidiFile.Free;
    end;
  finally
    Lied.Free;
  end;
Im Anhang die zugehörige Unit mit den Klassen. Viel Spaß beim Experimentieren. :D

cu
Narses

//EDIT: StartTicks korrigiert.
Einloggen, um Attachments anzusehen!
_________________
There are 10 types of people - those who understand binary and those who don´t.


Zuletzt bearbeitet von Narses am Mo 18.07.11 16:28, insgesamt 1-mal bearbeitet

Für diesen Beitrag haben gedankt: ALF
ALF Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1085
Erhaltene Danke: 53

WinXP, Win7, Win10
Delphi 7 Enterprise, XE
BeitragVerfasst: Mo 18.07.11 15:36 
Hi,user profile iconNarses Dank für Deine Mühen und Ausdauer mit mir. Die links kenne ich, hab ich alle als Favoriten bei mir, selbst die engl obwohl ich kein engl kann. Würde mir gern das ganze anschauen, was Du sozusagen übernacht gemacht hast, um zu sehen wie ich es bei mir umsetzten kann. Hab ja im Prinzip alles schon da zum auslesen, nur nicht vom zeichnen zum abspielbaren File, also Musik erstellen. Mich interresiert nähmlich das berechnen! Musik ist ja nur Mathe mit Emotion :lol:
Mal sehen ob ich klar komme :wink:

Allerdings gleich ne frage dazu!

ausblenden Delphi-Quelltext
1:
2:
3:
4:
//                   Note  Startime    Notenlänge
Lied.Add(TTon.Create(72,  480,        480));
//zweiter ton             berchnet addiert von startbasis in diesem Fall 480
Lied.Add(TTon.Create(74,  960,        480));

Fange ich also bei meinem 'Grid bei startposition null an steht dann da
ausblenden Delphi-Quelltext
1:
2:
Lied.Add(TTon.Create(72,  0,        480));
Lied.Add(TTon.Create(74,  480,      480));
usw.
Da ich wieder im rechnen blöd bin, was für ein integerwert würde den da stehen wenn die letzte Note erst nach 6 oder 9 Minuten kommt??? Währe das nicht schon > FFFF7F??
Gruss ALf

_________________
Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!