AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Optimierung von Pixel

Ein Thema von EWeiss · begonnen am 7. Apr 2016 · letzter Beitrag vom 12. Apr 2016
Antwort Antwort
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#1

AW: Optimierung von Pixel

  Alt 10. Apr 2016, 08:43
Um das mit dem Buffer nochmal zu veranschaulichen: Stell dir vor, du hast einen Kaffeeautomaten (die BASS-Funktion), der dir immer genau eine Tasse Kaffee ausspuckt, wenn du auf den Knopf drückst. Wenn du jetzt Lust auf wenig Kaffee hast und nur eine Espresso-Tasse (zu kleiner Puffer) drunterstellst, dann gibt es eine Sauerei
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#2

AW: Optimierung von Pixel

  Alt 10. Apr 2016, 12:04
Um das mit dem Buffer nochmal zu veranschaulichen: Stell dir vor, du hast einen Kaffeeautomaten (die BASS-Funktion), der dir immer genau eine Tasse Kaffee ausspuckt, wenn du auf den Knopf drückst. Wenn du jetzt Lust auf wenig Kaffee hast und nur eine Espresso-Tasse (zu kleiner Puffer) drunterstellst, dann gibt es eine Sauerei
Jo dann gibt's ärger mit der Frau

gruss
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.688 Beiträge
 
Delphi 2007 Enterprise
 
#3

AW: Optimierung von Pixel

  Alt 10. Apr 2016, 22:32
Ich habe das Ganze mal unter Lazarus ans Laufen bekommen, und auch gefunden warum ich keinen gültigen Channel bekam: Du übergibst das Flag BASS_UNICODE ohne Wenn und Aber, aber ich habe nur Delphi 2007 im Büro. Daher war der Dateiname bei mir nicht in Unicode. Da wäre ggf. eine Fallunterscheidung nicht übel, die du zum Abspielen weiter unten sogar schon drin hast.

Die Ergebnisse sind zwischen Delphi und FPC sicherlich kaum zu vergleichen. Ich habe jetzt z.B. mit der 64Bit Variante der Bass.dll gearbeitet, weil Lazarus offenbar keinen Win32 Compiler installiert hat (und ich keine Lust hatte zu suchen wie ich das zurechtstückeln muss).
Ich habe ein fast genau 2min langes MP3 geladen, und brauchte trotz Verwendung von TCanvas.Pixels[] nur 2 Sekunden. Allerdings arbeitet TCanvas.Pixels[] in FPC auch komplett anders als unter Delphi, und Scanline gibt es erst gar nicht. Von daher praktisch keine Chance da für dich brauchbare Zeiten zu messen.

Was ich aber gemacht habe, ist zu messen wie lange die gesamte Prozedur dauerte, und wie viel davon auf das reine Malen entfielen. Bei 2sek gesamt wurden 1,25sek zum Zeichnen gebraucht. Der Rest war Bass-Daten abfragen, die Schleifen und Farbumrechnungen. (Was übrigens zumindest unter Lazarus sehr viel gefressen hat, war das immer wieder Abfragen von Radiobutton1.Checked!)

Hier mal, wie du ähnlich messen kannst. (Erheblich präziser als mit GetTickCount!) Die entsprechenden Zeilen habe ich mal via Kommentar markiert, damit sie besser auffallen.
Delphi-Quellcode:
procedure TForm1.SampleAudioStream(FileName: String);
Const
  BUFFER_SIZE = 256;
var
  Buffer: array of Single;
  Info: BASS_CHANNELINFO;
  i: integer;
  Progress: integer;
  H, S, L: double;
  Value: double;
  StreamLength: Int64;
  ScanLines: TArray<PRGBTriple>;
  P: PRGBTriple;
  R, G, B: Byte;
  pcFrequency: Int64; // <--------------------- Zeitmessung
  timeAll0, timeAll1, timeAll: Int64; // <----- Zeitmessung
  timeDraw0, timeDraw1, timeDraw: Int64; // <-- Zeitmessung
begin
  Channel := BASS_MusicLoad(false, PChar(FileName), 0, 0,
    BASS_MUSIC_DECODE OR BASS_MUSIC_STOPBACK OR BASS_MUSIC_CALCLEN {$IFDEF UNICODE} OR BASS_UNICODE {$ENDIF} OR BASS_SAMPLE_FLOAT, 0);
  if Channel = 0 then
  begin
    Channel := BASS_StreamCreateFile(false, PChar(FileName), 0, 0,
      BASS_STREAM_DECODE OR BASS_MP3_SETPOS OR BASS_SAMPLE_FLOAT {$IFDEF UNICODE} OR BASS_UNICODE {$ENDIF});
  end;

  if Channel = 0 then
  begin
    Exit;
  end;

  Form2.ProgressBar1.position := 0;
  Form2.Show;

  BASS_ChannelGetInfo(Channel, Info);
  StreamLength := BASS_ChannelGetLength(Channel, BASS_POS_BYTE);
  Bitmap.Height := 256;
  Bitmap.Width := (StreamLength div 512 div 4) div Info.chans;

  PB.Width := Bitmap.Width;
  PB.Height := Bitmap.Height;
  PB.Parent.DoubleBuffered := true;

  S := 0.9;

  SetLength(Buffer, BUFFER_SIZE);
  ColumnCounter := 0;

  QueryPerformanceFrequency(pcFrequency); // <------ Zeitmessung
  QueryPerformanceCounter(timeAll0); // <----------- Zeitmessung
  timeDraw := 0; // <------------------------------- Zeitmessung

  if RadioButton1.Checked then
  begin
    SetLength(ScanLines, Bitmap.Height);
    for i := 0 to Length(ScanLines) - 1 do
      ScanLines[i] := Bitmap.Scanline[i];
  end;

  while BASS_ChannelIsActive(Channel) <> BASS_ACTIVE_STOPPED do
  begin
    BASS_ChannelGetData(Channel, Pointer(Buffer), BASS_DATA_FFT512);
    for i := 0 to BUFFER_SIZE - 1 do
    begin
      Value := SQRT(SQRT(Buffer[i]));
      H := 0 + Value / 1.5;
      L := Value;

      if RadioButton1.Checked then
      begin
        QueryPerformanceCounter(timeDraw0); // <-------------------- Zeitmessung
        P := ScanLines[BUFFER_SIZE - i];
        if Assigned(P) then
          HSLtoRGB(H, S, L, P^.rgbtRed, P^.rgbtGreen, P^.rgbtBlue);
        QueryPerformanceCounter(timeDraw1); // <------------------- Zeitmessung
        timeDraw := timeDraw + (timeDraw1-timeDraw0); // <--------- Zeitmessung
      end
      else
      begin
        QueryPerformanceCounter(timeDraw0); // <------------------- Zeitmessung
        HSLtoRGB(H, S, L, R, G, B);
        Bitmap.Canvas.Pixels[ColumnCounter, BUFFER_SIZE - i] := RGB(R, G, B)
        QueryPerformanceCounter(timeDraw1); // <------------------- Zeitmessung
        timeDraw := timeDraw + (timeDraw1-timeDraw0); // <--------- Zeitmessung
      end;
    end;

    if RadioButton1.Checked then
    begin
      for i := 0 to Length(ScanLines) - 1 do
        Inc(ScanLines[i]);
    end
    else
      Inc(ColumnCounter);

    Progress := trunc(100 * (Bass_ChannelGetPosition(Channel, BASS_POS_BYTE) / BASS_ChannelGetLength
          (Channel, BASS_POS_BYTE)));

    if (Form2.ProgressBar1.position <> Progress) then
    begin
      Form2.ProgressBar1.position := Progress;
      PB.Refresh;
    end;
  end;

  QueryPerformanceCounter(timeAll1); // <-------------------------------------------------- Zeitmessung
  timeAll := timeAll1-timeAll0; // <------------------------------------------------------- Zeitmessung

  Label1.Caption := 'Gesamtzeit: '+FloatToStrF(timeAll/pcFrequency, ffFixed, 8, 3); // <--- Zeitmessung
  Label2.Caption := 'Draw-Zeit: '+FloatToStrF(timeDraw/pcFrequency, ffFixed, 8, 3); // <--- Zeitmessung

  Form2.Hide;
  Bass_StreamFree(Channel);

  Channel := BASS_StreamCreateFile(false, PChar(FileName), 0, 0, 0 {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});
  if Channel = 0 then
  begin
    Channel := BASS_MusicLoad(false, PChar(FileName), 0, 0,
      BASS_MUSIC_RAMPS or BASS_MUSIC_POSRESET or BASS_MUSIC_PRESCAN {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF}, 0);
    if (Channel = 0) then
      Exit;
  end;

  DestBitmap.Width := PB.Width;
  DestBitmap.Height := PB.Height;
  BitBlt(DestBitmap.Canvas.handle, 0, 0, PB.Width, PB.Height, Bitmap.Canvas.handle, 0, 0, SrcCopy);
  bpp := BASS_ChannelGetLength(Channel, BASS_POS_BYTE) div PB.Width;
  BASS_ChannelSetSync(Channel, BASS_SYNC_END or BASS_SYNC_MIXTIME, 0, LoopSyncProc, nil);
  BASS_ChannelPlay(Channel, false);
  Timer1.Enabled := true;
end;
Die Zeit wird hierbei in Sekunden angegeben. (Deshalb die 3 Nachkommastellen um die Anzeige bis auf Millisekunden genau zu haben.)
Das könnte gut dabei helfen zu ermitteln, ob das eigentliche Zeichnen wirklich der Flaschenhals ist, und ob es sich lohnt in dessen Optimierung überhaupt noch viel Zeit zu stecken. (Ich kann mir gut vorstellen, dass das Berechnen des Fortschritts wegen der vielen Calls zur Bass.dll auch ganz schön zu Buche schlägt. Tut's zumindest unter Lazarus nicht. Der Unterschied ist im normalen Schwankungsbereich.)
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)

Geändert von Medium (10. Apr 2016 um 22:38 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#4

AW: Optimierung von Pixel

  Alt 11. Apr 2016, 00:59
(Ich kann mir gut vorstellen, dass das Berechnen des Fortschritts wegen der vielen Calls zur Bass.dll auch ganz schön zu Buche schlägt. Tut's zumindest unter Lazarus nicht. Der Unterschied ist im normalen Schwankungsbereich.)
Ganz normale Calls sind in der Regel zu vernachlässigen. Hat man natürlich bisschen Overhead durch das Pushen der Rücksprungadresse und je nach Aufrufkonvention der Parameter, aber Performance-kritisch wird das nicht.
Frequente Aufrufe bestimmter Windows APIs können allerdings durch den Kontext-Switch in Kernel-Mode und wieder zurück (SYSENTER) extrem teuer sein.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#5

AW: Optimierung von Pixel

  Alt 11. Apr 2016, 06:16
Zitat:
Du übergibst das Flag BASS_UNICODE ohne Wenn und Aber, aber ich habe nur Delphi 2007 im Büro. Daher war der Dateiname bei mir nicht in Unicode. Da wäre ggf. eine Fallunterscheidung nicht übel, die du zum Abspielen weiter unten sogar schon drin hast.
Oh.. ja habe ich im ersten BASS_StreamCreateFile Call vergessen.
Man schaut immer zu sehr auf seine eigene Developer Umgebung.

Zitat:
Von daher praktisch keine Chance da für dich brauchbare Zeiten zu messen.
Würde auch nicht viel sinn machen mit unterschiedlichen Sprachen.

Zitat:
Was übrigens zumindest unter Lazarus sehr viel gefressen hat, war das immer wieder Abfragen von Radiobutton1.Checked
Sollte das kleinste Problem sein
Werde da mal eine Variable für anlegen um den zugriff auf das Control zu verhindern.

QueryPerformanceCounter ist natürlich etwas genauer als GeTickCount.. wird umgebaut.

Danke für das Testen wenn auch unter Lazarus.

Anbei vergleich von Pixel/ScanLine als Bilder und neue Version mit deiner Zeitmessung incl. Variable anstelle von Radiobutton1.Checked.
BASS_UNICODE ist abgesichert..

gruss

Geändert von EWeiss (11. Jul 2019 um 16:07 Uhr)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.688 Beiträge
 
Delphi 2007 Enterprise
 
#6

AW: Optimierung von Pixel

  Alt 11. Apr 2016, 08:22
Man schaut immer zu sehr auf seine eigene Developer Umgebung.
Kenn ich was von *schäm*

Zitat:
Würde auch nicht viel sinn machen mit unterschiedlichen Sprachen.
Hab jetzt leider einen Aussentermin, aber heute Nachmittag mal schauen wie es hier im Büro aussieht. Jetzt weiss ich ja wie ich an einen gültigen Kanal komme

Zitat:
QueryPerformanceCounter ist natürlich etwas genauer als GeTickCount.. wird umgebaut.
Ich finde an dem so praktisch, dass es damit tatsächlich aussagekräftige Ergebnisse gibt, selbst wenn man nur eine kleine Zeile misst. Ohne das wäre das Aufsummieren der Zeichenaufrufe kaum drin. Hab mir den mittlerweile angewöhnt.

Zitat:
Anbei vergleich von Pixel/ScanLine als Bilder und neue Version mit deiner Zeitmessung incl. Variable anstelle von Radiobutton1.Checked.
Das sind SEHR ähnliche Werte wie bei mir (Bei Nutzung von Pixel[])
300ms zum Zeichnen sind schon gar nicht so übel. Vor allem weil es ja nur ca. 30% der Gesamtzeit ausmacht. So ganz so viel ist da dann gar nicht mehr herauszuholen.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#7

AW: Optimierung von Pixel

  Alt 11. Apr 2016, 08:29
Zitat:
Das sind SEHR ähnliche Werte wie bei mir (Bei Nutzung von Pixel[])
300ms zum Zeichnen sind schon gar nicht so übel. Vor allem weil es ja nur ca. 30% der Gesamtzeit ausmacht. So ganz so viel ist da dann gar nicht mehr herauszuholen.
Denke ich auch..
Die Ergebnisse sind schon mal nicht schlecht
Danke für deine Zeit die du geopfert hast.
Vielleicht ist es ja auch etwas für andere die so was schon immer mal realisieren wollten.

gruss
  Mit Zitat antworten Zitat
Antwort Antwort

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:14 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