Einzelnen Beitrag anzeigen

Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#76

AW: Optimierung von Pixel

  Alt 10. Apr 2016, 23: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 23:38 Uhr)
  Mit Zitat antworten Zitat