![]() |
Timing problem
Ich verwende für mein Piano einen Loop um den Song zu spielen
Leider muss ich feststellen das dieser sehr CPU lastig ist. Also 25% hab ich dann schon.
Delphi-Quellcode:
Ich verwende zwar Winprocessmessages damit andere prozesse weiterlaufen können
// Starte den Song
while PlayingSong do begin //Weiterlaufen bis die 16.tel Note (Pause) abgelaufen ist while GetTickCount < Tick + TempoWait do Winprocessmessages; Tick := GetTickCount; PlayNotes; DrawGraphics(WinHandle); hsi.nPos := StartX + XSizeMid; SetScrollInfo(WinHandle, SB_HORZ, hsi, True); end; dadurch habe ich aber ein stocken im song ..
Delphi-Quellcode:
Hat jemand nen Tip für mich wie ich das besser Händeln könnte ?
procedure WinProcessMessages;
var ProcMsg: TMsg; begin while PeekMessage(ProcMsg, 0, 0, 0, PM_REMOVE) do begin if (ProcMsg.message = WM_QUIT) then Exit; TranslateMessage(ProcMsg); DispatchMessage(ProcMsg); end; end; gruss |
AW: Timing problem
Was hast du dagegen, wenn die CPU das macht wofür du sie gekauft hast, nämlich rechnen? So lange der Prozess CPU Zeit abgibt, wenn sie ein anderer Prozess benötigt, ist doch alles in Ordnung. Und dein ProcessMessages hat keinen Einfluss auf andere laufende Prozesse. Du hast ja selbst die Implementierung gepostet. Guck doch mal, was da passiert. Wenn du wirklich Rechenzeit abgeben willst, dann musst du Sleep aufrufen. Damit sagst du Windows, dass du den Rest deiner Zeitscheibe nicht mehr benötigst. Der Thread wird dann schlafen gelegt und die Rechenzeit kann von einem anderen Thread in einem anderen Prozess genutzt werden.
|
AW: Timing problem
Zitat:
Mich stört halt nur das die Anwendung bzw.. der Song dann stockt. Meinst das kann man nicht verhindern ? gruss |
AW: Timing problem
Du könntest mal die
![]() Ob das Timing präzise genug ist, um Musik damit abzuspielen, musst du ausprobieren. |
AW: Timing problem
Vielleicht wird es besser, wenn man anstelle einer Schleife einen
![]() Der sollte dafür gemacht sein. |
AW: Timing problem
Windows hat ein präemtives Multitasking System implementiert. Das heißt Windows teil den Threads Rechenzeit zu und entzieht sie ihnen auch wieder. Dadurch dass die Zeitscheiben, die ein Thread zur Nutzung der CPU zustehen, kurz gehalten sind, entsteht der Eindruck, dass Threads parallel laufen. Dabei ist für jeden Thread die Zeitscheibe gleich groß. Über das Setzen der Priorität kann man jetzt beeinflussen, wie oft ein Thread eine Zeitscheibe zugeteilt bekommt. Das nur mal zum Verständnis.
Du verursachst das Stcoken selber. Mit deinem Aufruf von ProcessMessages veranlasst du den Thread dazu die Schleife zu unterbrechen und Nachrichten aus der Nachrichtenschlange mit der Nachrichtenschleife abzuholen und zu verarbeiten. Ruf ProcessMessages nur alle 10 oder 100 oder 500 Schleifendurchläufe auf. |
AW: Timing problem
Zitat:
Es ist definitiv so wenn ich die Schleife belasse kann ich selbst mit Winprocessmessages die Anwendung nicht mehr schließen. Selbst eine PostQuitMessage(0) schafft es nicht diesen Loop zu Unterbrechen. Ich muss quasi das Lied erst über den Button beenden wenn ich die Anwendung schließen will. Das war mit eines der probleme warum ich das Timing problem angesprochen habe. Ob es mit dem Multimediatimer funktioniert müßte ich mal versuchen. Denke aber das er letztendlich auch nicht schneller ist wie der loop selbst. Könnte mir aber mehr zeit lassen für andere dinge anstelle von Winprocessmessages. Wobei die Frage ist ob dieser nicht das gleiche macht um anderen Prozessen Zeit zu verschaffen. gruss |
AW: Timing problem
Ein
Delphi-Quellcode:
gibt die Verarbeitung sofort an andere Threrads ab und beim nächsten Durchlauf wird sofort weitergearbeitet.
Sleep(0);
Wenn dein Programm wirklich für eine kurze Zeit nicht zu tun hat, kannst du damit die Rechenleistung an andere Programme weiterreichen. Bei Multiprozessorsystemen sollte Windows dein exzesiv rechnendes Programm, bzw. deinen Thread auf einem Kern laufen lassen und nahezu alle anderen Threads auf die restlichen Kerne verteilen ... dann sollten die anderen Programme auch nicht mehr gestört werden. Und wie schon gesagt, kannst du über die Prioritäten der anwendung und des entsprechenden Threads auch auf die CPU-auslastung Einfluß nehmen ... niedrige Priorität = mehr Zeit für Andere. Aber egal was du machst, sobald du dein Programm irgendwie ausbremst, muß du auch damit rechnen, daß es eben ein bissl langsamer läuft und eventuell auch mal etwas stockt. Tipp: Verschieb die Sounderzeugung in einen eigenen Thread und laß die Grafiksachen ruhig etwas langsamer rangehn (wenn die Grafik etwas/unmerklich stockt, isses ja nicht so schlimm) und wenn es getrennt ist, dann können sich anzeige und grafik nicht mehr so leicht gegenseit sörten ... und veriß im Soundthread den "Mist" mit der Messagebehandlung. [add] Zitat:
PS: Ein Multimediatimer ist quasi genau das Selbe wie ein TTimer (nur schneller). Und ob ein Timer für dich die Lösung ist, mußt du selber wissen. |
AW: Timing problem
Zitat:
Delphi-Quellcode:
Macht fast genau das gleiche wie ich es eh schon verwende ;)
procedure Delay(msecs: Longint);
var targettime: Longint; Msg: TMsg; begin targettime := GetTickCount + msecs; while targettime > GetTickCount do if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin if Msg.message = WM_QUIT then begin PostQuitMessage(Msg.wParam); Break; end; TranslateMessage(Msg); DispatchMessage(Msg); end; end; gruss |
AW: Timing problem
Zitat:
Und wie unterbricht die Schaltfläche die Schleife? Dann ruf den Code doch vor dem Schließen auf. |
AW: Timing problem
Zitat:
Die Messagen laufen den Loop davon. Was ich meine ist das sie ausgeführt werden bevor der Loop beendet wird. Denke die zeit ist einfach zu kurz. Ich habe ja ne BOOL Variable
Delphi-Quellcode:
Habe meine Proc so umgeschrieben das wenn man auf den Beenden Knopf clickt
while PlayingSong do
erst WM_QUIT aufgerufen wird.. dort habe ich dann veranlaßt das diese auf False gestellt wird. Nach dem WM_QUIT noch ein WM_DESTROY und anschlie0end in der HauptAnwendung selbst PostQuitMessage(0) damit alles sauber beendet werden kann. Aber! Kein Chance das teil läuft weiter.. Minimieren und Maximmieren das alles funktioniert auch beim spielen. gruss |
AW: Timing problem
Delphi-Quellcode:
Warum nicht einfach
while GetTickCount < Tick + TempoWait do
Winprocessmessages;
Delphi-Quellcode:
?
Sleep(TempoWait);
In einem eigenständigen Thread hättest du damit keinerlei Propleme und eine derartige Schleife macht absolut nix anderes, außer Rechnen und ständiges Nachsehn, ob es noch was zum Rechnen gibt. (also andere Programme können da garkeine Zeit von abgekommen, eher im Gegenteil ... du verbrätst sinnlos wertvolle Rechenzeit) Notfalls ginge es im Hauptthread auch noch so:
Delphi-Quellcode:
Wenn dein Programm aber mal viele/langwierige Messages zu verarbeiten hat, dann stockt es aber so oder so, es sei denn man versucht immer nur soviele Nachrichten zu verarbeiten, wie in TempoWait genögend Zeit finden und verschiebt den rest auf die nächsten Schleifendurchläufe.
Tick := GetTickCount + TempoWait;
Winprocessmessages; Dec(Tick, GetTickCount); if Integer(Tick) > 0 then Sleep(Tick); Fazit: Es liegt ein Designfehler vor wenn du eine derartige "Zeitkritische" Aufgabe, wie deine Soundausgabe, in den unberechenbaren Hauptthread legst. |
AW: Timing problem
Weil Tick gleicht GetTickCount und TempoWait das aktuell eingestellte Tempo ist mit welchen der Song abspielt.
Delphi-Quellcode:
Tick := GetTickCount;
// Starte den Song while PlayingSong do begin //Weiterlaufen bis die 16.tel Note (Pause) abgelaufen ist while GetTickCount < Tick + TempoWait do Winprocessmessages; Tick := GetTickCount; PlayNotes; DrawGraphics(WinHandle); hsi.nPos := StartX + XSizeMid; SetScrollInfo(WinHandle, SB_HORZ, hsi, True); end;
Delphi-Quellcode:
gruss
ID_TRACK_TEMPO:
begin MidiTracker.Tempo := SKAERO_GetTrackValue(SKAERO_GetMainItem(MainHandle, ID_TRACK_TEMPO)); TempoWait := 1000 div round((MidiTracker.Tempo / 15)); end; |
AW: Timing problem
Was passiert denn, wenn du alles was nicht mit dem Sound zu tun hat, raus haust. Hängt es dann immer noch?
Delphi-Quellcode:
Was genau macht PlayNotes bzw. wie ist es implementiert? Packt es die Noten in einen Puffer der dann (von was?) abgespielt wird? Oder spielt es die Noten gleich ab und blockiert damit die Schleife?
timeout := 10000;
while (PlayingSong) do begin sleep (1000); PlayNotes; timeout := timeout - 1000; if (timeout < 0) then begin break; end; end; Vielleicht erzeugst du auch gerade mit dem Warten das Geruckle. Ist das Ruckeln gleichmäßig? Du solltest erst die Ursache des Ruckeln bekämpfen und dann die anderen Sachen wie Grafik, Nachrichtenbehandlung, Tempo usw. hinzufügen. |
AW: Timing problem
Zitat:
![]() Zitat:
|
AW: Timing problem
@BUG: Ich weiß das, aber er macht ja kein Sleep. :zwinker:
also mit sleep gibt es die übrige Zeit ab
Delphi-Quellcode:
TempoWait und Tick sind ebenfalls Integer
// Starte den Song
Tick := GetTickCount; while PlayingSong do begin //Weiterlaufen bis die 16.tel Note (Pause) abgelaufen ist {while GetTickCount < Tick + TempoWait do Winprocessmessages;} X := TempoWait - (Integer(GetTickCount) - Tick); if X > 0 then Sleep(X); Tick := GetTickCount; PlayNotes; DrawGraphics(WinHandle); hsi.nPos := StartX + XSizeMid; SetScrollInfo(WinHandle, SB_HORZ, hsi, True); end; |
AW: Timing problem
Es läuft nicht nur der Sound sondern gleichzeitig werden intensive Grafische funktionen (Rechenoperationen) ausgeführt die
an dem Sound gekoppelt sind die kann man nicht einfach ausblenden. Das Grid wird gezeichnet die Abtastbar überprüft im Grid die eingegebenen Instrumente und Noten zusätzlich werden zeitgleich noch die Tasten dazu gedrückt. das ist alles nicht so einfach.. mal ebend was auslagern da alles zur selben zeit gebraucht wird. Ich habe es mal mit himitsu variante versucht.. Keine Chance solange der Song läuft kann ich mein Window nicht schließen. Wenn ich mein Window verschiebe hält der Song an. gruss |
AW: Timing problem
Zitat:
Und ich glaube dir auch. Es bringt mir keinen vorteil. Glaube es mir :) Ich versuche es nochmal mit deiner neuen Variante ;) EDIT: Nop mit deiner letzten version kann ich gar nichts mehr machen. Kein Fenster verschieben keinen Button drücken nur noch den Taskmanager verwenden zum beenden. gruss |
AW: Timing problem
Zitat:
|
AW: Timing problem
Ich verstehe noch nicht so ganz die Logik.
Was passiert während des Waits? (per was auch immer) Stell die Zeit doch mal extrem hoch und schau ob die Hänger gleichmäßig sind. Ich meine es gibt ja auch halbe, ganze Noten. Ganz zu schweigen von verschiedenen Akzenten Legato oder das Gegenstück Staccato. Vielleicht musst du am Ende die Schleife durch rennen lassen. Wenn die Funktionen gekapselt sind werden die vermutlich bald zurück kommen, wenn die nichts zu tun haben. Ist das ein Baukasten oder hast du dir einen solchen selbst zurecht programmiert? Vielleicht gibt es Beispiele für deine Schleife. Wer liefert die Noten? Also woher weiß "PlayNotes" welche Noten zu spielen sind? |
AW: Timing problem
Zitat:
Aber nicht das ich meine Anwendung aufgrund des Loops nicht mehr schließen kann. gruss |
AW: Timing problem
Und was macht
Delphi-Quellcode:
?
// Starte den Song
while PlayingSong do begin //Weiterlaufen bis die 16.tel Note (Pause) abgelaufen ist // while GetTickCount < Tick + TempoWait do sleep (1000); Winprocessmessages; Tick := GetTickCount; PlayNotes; DrawGraphics(WinHandle); hsi.nPos := StartX + XSizeMid; SetScrollInfo(WinHandle, SB_HORZ, hsi, True); end; |
AW: Timing problem
Zitat:
Und das muss ich auch gar nicht erst ausprobieren ;) Ich glaube da hilft nur noch die Knallharte Methode.. HALT; Und das will ich eigentlich nicht. gruss |
AW: Timing problem
Meinst du?
Was macht denn
Delphi-Quellcode:
> Leider muss ich feststellen das dieser sehr CPU lastig ist.
while true do
begin end; > Also 25% hab ich dann schon. 4 Kerne? Was anderes machst du mit WinProcessMessages derzeit nicht außer Nachrichten behandeln. (Es sei denn deine Implementierung sieht inzwischen anders aus.) |
AW: Timing problem
Zitat:
das bedeutet alle 1000ms wird dann bei mir das Fenster und alles andere was damit zu tun hat weiterverarbeitet. Was soll das werden wenn ich mir noch ne neue Bremse mit einbaue. Zitat:
Bild im Anhang. gruss |
AW: Timing problem
Aber ob deine Anwendung 1000 ms schläft oder 1000 ms in einer Schleife rennt, anstatt Musik zu spielen, das ist aus meiner Sicht das gleiche.
Und dass die 1000 ms nur der Platzhalter für das Tempo sind, ich dachte das wäre auch ohne Kommentar zu erkennen gewesen. Ich weiß ja nun immer noch nicht ob PlayNotes Zeit verbrät oder gleich zurück kommt. |
AW: Timing problem
Verarbeitest du auch Eingabegeräte? Soweit ich gelesen habe haben die bei der Echtzeitverarbeitung von Musik die gleichen Probleme.
Meiner Meinung nach Schreit das nach einen Thread pro Aufgabe. Ein Thread für das Formular und Nachrichtenbehandlung. Einer für die Grafik womit das Formular gefüttert wird (auch wenn du Fenster bewegst). Und einer für den Ton. Sagt dir Lugert Verlag Forte etwas? Das macht genau das was du versucht umzusetzen. Nur mit einfacher Grafik. |
AW: Timing problem
Zitat:
Delphi-Quellcode:
TNoteType = (BlankNote, StartingNote, ContinuingNote);
Nach Playnotes geht es in DrawGraphics wo mit GDI+ die grüne Abtastleiste gezeichnet wird. Und von da aus geht es dann in die Zeichnen routine für das Grid
Delphi-Quellcode:
DrawGrid(WinHandle);
Das ist im groben der ablauf. Und das kann ich nicht auslagern unmöglich da alles zusammenhängt. gruss |
AW: Timing problem
Zitat:
wenn du sehen willst was ich da mache. Eingabegeräte verwende ich keine. EDit: Forte 180.00EUR Euronen .. ;) gruss |
AW: Timing problem
> Eingabegeräte verwende ich keine.
Schade :) D.h. PlayNotes startet nur, aber wartet nicht auf das Ende der Note. Die Nachrichtenbehandlung wirst du für den Empfang von CloseQueries usw. schon brauchen. Nur solltest du das mit dem Sleep () kombinieren um deinen Wunsch nach weniger Auslastung gerecht zu werden. Ich habe die Erfahrung gemacht, wenn im Formular z.B. ein Button gedrückt wird der in eine Schleife rennt, wird für die Dauer die zweite Schleife im selben Thread nicht weiter ausgeführt (ist auch irgendwie logisch). Daher wirst du nichts anderes erwarten können, wenn du das Fenster durch die Gegend schiebst, dass die Musik stoppt. Mit dem Beispielcode wollte ich übrigens auch nur wissen ob die übrigen Anweisungen hängen. Das sind so die Probleme die ich bisher erlesen konnte. |
AW: Timing problem
> EDit:
> Forte 180.00EUR Euronen .. ;) Leider... ich habe daher auch nur die Free-Version. Aber auch in dieser kann man Fenster durch die Gegend bewegen während die Musik spielt. Ich vermute jedoch die Nutzen den Miditreiber für solche Spielchen. |
AW: Timing problem
Ach, ich sehe gerade. Du hast derzeit nur eine Spur und stellst damit eine Klaviatur dar. Ist auch eine Idee. Ich dachte erst die schwarzen und weißen Linien sind bereits die Spuren und sind nur zur optischen Kennung eingefärbt.
Was machst du wenn eine zweite Spur hinzukommen soll? Zum Beispiel ein zweites Instrument? Dann wäre es doch praktisch, wenn es sie mal geben sollte, den Grafik- und Tonthread einfach mit anderen Parametern zu starten? |
AW: Timing problem
Jo ist schade ;)
Delphi-Quellcode:
der loop wird deaktiviert wenn die Abtastleiste in DrawGraphics das Ende der Songlänge erreicht hat
if PlayX > SongLength then
begin PlayingSong := False; SKAERO_SetCTLText(SKAERO_GetMainItem(MainHandle, ID_PLAY), 'Play'); end; die vorher mit FindEndOfSong ermittelt wurde. So wie es aussieht komme ich nicht drumherum die Anwendung nach PostQuitMessage(0) mit Halt; zu beenden. Das der Song anhält ist normal wenn das Fenster verschoben wird darum ja auch Winprosessmessages damit die anderen Threads weiterarbeiten können. gruss |
AW: Timing problem
Zitat:
Jede Farbe auf den linken Bunten Button (EditButton) repräsentieren eine Spur Und jeder kannst du ein Instrument zuordnen aus der Bank .. Die mußt du allerdings erst füllen. Instrument aus der Bank auswählen Shift drücken und dann einen der Speicherplätze anklicken. Danach ist das Instrument gespeichert. gruss |
AW: Timing problem
Delphi-Quellcode:
Mit exit beendest du ja auch nur die Ausführung der Funktion. Die while PlayingSong do-Schleife wertet das Ergebnis der Nachrichtenbehandlung nicht aus. D.h. die rennt ungestört weiter...
procedure WinProcessMessages;
var ProcMsg: TMsg; begin while PeekMessage(ProcMsg, 0, 0, 0, PM_REMOVE) do begin if (ProcMsg.message = WM_QUIT) then Exit; TranslateMessage(ProcMsg); DispatchMessage(ProcMsg); end; end; // Starte den Song while PlayingSong do begin //Weiterlaufen bis die 16.tel Note (Pause) abgelaufen ist while GetTickCount < Tick + TempoWait do Winprocessmessages; ... Rückgabewert? Oder gleich ein PlayingSong := false? kA welche Sichtbarkeit deine Variablen haben. Nebenbei: Was passiert überhaupt wenn deine Anwendung Musik abspielt und etwas anderes (viel anderes bei Mehrkern) lastet dein System übermäßig aus? Achso, ich mach dann erstmal Feierabend ;) 8 Spuren? Du überrascht schon wieder... Und noch was weil ich es gerade sehe... du solltest solche Sachen wie DrawGraphics(WinHandle); nicht während des Herunterfahren der Anwendung ausführen. Und Halt wird dir vermutlich Speicherlecks bescheren... |
AW: Timing problem
Nein die rennt nicht ungestört weiter die beendet wenn die letzte note gespielt wurde.
Delphi-Quellcode:
Das funktioniert und arbeite einwandfrei nach dem ich auf den Stop Button klicke
procedure TMidiTracker.PlaySong(WinHandle: HWND);
var IntA: integer; begin // Verschieb den Grid Ausschnitt wenn die Rote Laufleiste nicht // auf dem Grid sichtbar ist if (ColumnX < StartX) or (ColumnX > StartX + XSize) then begin StartX := ColumnX; EndX := StartX + XSize; if StartX > 999 - XSize then begin StartX := 999 - XSize; EndX := 999; end; end; // Starte das Spielen von der roten Laufleisten position PlayX := ColumnX; GetColumn(WinHandle, StartX); hsi.nPos := StartX + XSizeMid; HasStarted := False; JustScrolled := False; DrawGrid(WinHandle); // Reset die alte Note und die alte Instrumenten Variablen for IntA := 0 to 7 do begin OldNote[IntA] := -1; OldInst[IntA] := -1; end; // Nach dem Ende des Songs suchen FindEndOfSong; Tick := GetTickCount; // Starte den Song while PlayingSong do begin //Weiterlaufen bis die 16.tel Note (Pause) abgelaufen ist while GetTickCount < Tick + TempoWait do Winprocessmessages; Tick := GetTickCount; PlayNotes; DrawGraphics(WinHandle); hsi.nPos := StartX + XSizeMid; SetScrollInfo(WinHandle, SB_HORZ, hsi, True); end; // Warte auf die Beendigung der Wiedergabe von der letzten 16.tel Note while GetTickCount < Tick + TempoWait do Winprocessmessages; // Alle Noten Stoppen for IntA := 0 to 7 do begin if SKAERO_GetCheckButtonStatus(SKAERO_GetMainItem(MainHandle, IntA + ID_HIDETRACK_FIRST)) = False then begin channel := IntA; if OldNote[IntA] > -1 then FlipStopNote(OldNote[IntA] mod 1000); end; end; hsi.nPos := 0; hsi.nTrackPos := 0; StartX := 0; SetScrollInfo(WinHandle, SB_HORZ, hsi, True); DrawGrid(WinHandle); end; oder der Song zu ende ist. gruss |
AW: Timing problem
> Nein die rennt nicht ungestört weiter die beendet wenn die letzte note gespielt wurde.
Es ging doch aber ums Beenden der Anwendung (während gespielt wird) ;) Nacht! |
AW: Timing problem
Zitat:
Wie soll ich das verhindern wenn ich nicht rechtzeitig bzw.. den loop beenden kann bevor ich die Anwendung Herunterfahre. Genau das ist mein Problem das meine Anwendung hängt und ich sie nicht beenden kann. Zitat:
gruss |
AW: Timing problem
Zitat:
Da alles im Hauptthread abläuft, kann wärend der Zeit der Schleife Pause vom Programm auch keine neue Nachricht erzeugt werden. Und Benutzereingaben des Benutzers werden innerhalb von maximal 62 Millisekunden abgehandelt. Für den Benutzer sollte diese Verzögerung fast garnicht auffallen. :gruebel: |
AW: Timing problem
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:40 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz