Page 1 of 1

Update Progressbar

Posted: Wed Oct 21, 2020 3:31 am
by Lena
Hi.
I try update value on FMX project but no effect. How is it correct?
Thanks.

Code: Select all

progress := 0;
    repeat
      len := BASS_StreamGetFilePosition(str, BASS_FILEPOS_END);
      if (len = DW_Error) then
        break; //something's gone wrong! (eg. BASS_Free called)
      progress := BASS_StreamGetFilePosition(str, BASS_FILEPOS_BUFFER) * 100 div len;
      ProgressBar1.Value := progress;
      //Application.ProcessMessages(); //no effect
      //ProgressBar1.Repaint(); //no effect
     until
      (progress > 75) or (BASS_StreamGetFilePosition(str, BASS_FILEPOS_CONNECTED) = 0); // over 75% full (or end of download)

     //test
     ShowMessage(IntToStr(Trunc(ProgressBar1.Value))); //75 OК!


Re: Update Progressbar

Posted: Wed Oct 21, 2020 4:07 am
by HsiaLin
try
ProgressBar1.Update();

Re: Update Progressbar

Posted: Wed Oct 21, 2020 4:35 am
by Lena
HsiaLin wrote: Wed Oct 21, 2020 4:07 am try
ProgressBar1.Update();
Hi.
In FMX no method Update for ProgressBar.

Re: Update Progressbar

Posted: Thu Oct 22, 2020 2:16 pm
by rlebeau
Using Repaint() should have worked. That being said, your loop probably should be in a separate worker thread instead, not in the main UI thread. Then that worker thread can post updates to the UI as needed, and let the main UI thread handle painting updates normally.

Re: Update Progressbar

Posted: Fri Oct 23, 2020 6:37 am
by Lena
rlebeau wrote: Thu Oct 22, 2020 2:16 pm your loop probably should be in a separate worker thread instead, not in the main UI thread. Then that worker thread can post updates to the UI as needed, and let the main UI thread handle painting updates normally.
Can you show the structure of the code how it should look?

P.S.
Maybe so?

Code: Select all

var
 aTask: ITask;
begin
 aTask := TTask.Create(
   procedure
   begin
     //here my loop with progress
     TThread.Synchronize(TThread.Current,
       procedure
       begin
         ProgressBar1.Value := progress;
       end);
   end);
   aTask.Start;

Re: Update Progressbar

Posted: Sat Oct 24, 2020 3:43 am
by Lena
I tried to use the indicator but I can't see it.

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);//Play Button usually loading audio stream 2-10 seconds

var
  check :boolean;
  Len, progress: DWORD;
Begin
   AniIndicator1.Enabled := True;//no effect
   AniIndicator1.Visible := True;
   AniIndicator1.Repaint;

   progress := 0;
   BASS_StreamFree(str);
   //****************other code*******************
   
   
   AniIndicator1.Enabled := FALSE;
   AniIndicator1.Visible := FALSE;

Re: Update Progressbar

Posted: Mon Oct 26, 2020 11:10 am
by rlebeau
Lena wrote: Sat Oct 24, 2020 3:43 am I tried to use the indicator but I can't see it.
What is in your "other code" exactly? If you are doing everything in the OnClick handler, blocking the main UI message loop, then it makes sense why the Indicator doesn't show anything. DO NOT block the main UI thread!

Re: Update Progressbar

Posted: Sat Nov 07, 2020 5:53 am
by Lena
What is in your "other code" exactly?

Code: Select all

AniIndicator1.Enabled := True;
   AniIndicator1.Visible := True;
   AniIndicator1.Repaint();

   BASS_StreamFree(str);
   str := BASS_StreamCreateURL(PChar('http://91.199.194.34:8000'), 0, BASS_UNICODE, nil, nil);

   If BASS_ErrorGetCode = 40 Then
   ShowMessage('...');
   exit;
    End;

  If BASS_ErrorGetCode = 0 Then
  Begin

      BASS_ChannelSetSync(str, BASS_SYNC_META, 0, @MetaSync, nil);
      BASS_ChannelPlay(str, FALSE);
      Viewport3D1.Visible := True;
      FloatAnimation1.Enabled := True;
      AniIndicator1.Enabled := FALSE;
      AniIndicator1.Visible := FALSE;
 

   End;

Re: Update Progressbar

Posted: Sat Nov 07, 2020 8:33 am
by Lena
I try this:

Code: Select all

var
ercode: DWORD;
//***
ercode := 100;

TThread.CreateAnonymousThread(procedure ()
    begin
      TThread.Synchronize (nil, 
      procedure ()
      begin
       
        AniIndicator1.Enabled := True;
        AniIndicator1.Visible := True;
      end);

      BASS_StreamFree(str);
      str := BASS_StreamCreateURL(PChar('http://91.199.194.34:8000'), 0, BASS_UNICODE, nil, nil);
      ercode := BASS_ErrorGetCode;

      If BASS_ErrorGetCode = 40 Then
              Begin
               ShowMessage('Sorry maintenance work on the music server.');
               BASS_SampleFree (smp);
               exit;
              End;

       If BASS_ErrorGetCode = 0 Then
              Begin
               BASS_ChannelSetSync(str, BASS_SYNC_META, 0, @MetaSync, nil);
               BASS_ChannelPlay(str, FALSE);

              End;


       TThread.Synchronize(nil,
             procedure ()
                begin
                if ercode = 0 Then Begin
                   Viewport3D1.Visible := True;
                  FloatAnimation1.Enabled := True;
                  AniIndicator1.Enabled := FALSE;
                  AniIndicator1.Visible := FALSE;
                 end;

                end);

  end).Start;

If the Internet connection is good, I see the indicator for a couple of seconds and the music starts playing.
If the Internet connection is bad, then the indicator appears after five to seven seconds and the music starts playing.
How to see the indicator when the internet connection is bad?

Re: Update Progressbar

Posted: Mon Nov 09, 2020 11:42 am
by rlebeau
Lena wrote: Sat Nov 07, 2020 8:33 am How to see the indicator when the internet connection is bad?
Since you are creating the stream outside of the main UI thread, the display of the Indicator should not be affected by the speed of the API. That makes me think maybe you are still doing other things in the main UI thread while the thread is running.

That being said, I would suggest something more like the following for the thread, at least:

Code: Select all

TThread.CreateAnonymousThread(
  procedure
  var
    ercode: Integer;
    ermsg: string;
  begin
    TThread.Queue(nil, 
      procedure
      begin
        AniIndicator1.Enabled := True;
        AniIndicator1.Visible := True;
      end
    );

    BASS_StreamFree(str);
    str := BASS_StreamCreateURL(PChar('http://91.199.194.34:8000'), 0, BASS_UNICODE, nil, nil);
    ercode := BASS_ErrorGetCode;

    if ercode = BASS_OK then
    begin
      BASS_ChannelSetSync(str, BASS_SYNC_META, 0, @MetaSync, nil);
      BASS_ChannelPlay(str, FALSE);
      TThread.Queue(nil,
        procedure
        begin
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          Viewport3D1.Visible := True;
          FloatAnimation1.Enabled := True;
        end
      );
    end else
    begin
      BASS_SampleFree (smp);
      if ercode = BASS_ERROR_TIMEOUT then
        ermsg := 'Sorry maintenance work on the music server.'
      else
        ermsg := Format('Unable to create music stream. Error %d', [ercode]);
      TThread.Queue(nil,
        procedure
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          ShowMessage(ermsg);
        end
      );
    end;
  end
).Start;
The thread should not be blocked while the UI is updating, hence the use of TThread.Queue() instead of TThread.Synchronize(). And ShowMessage() is not thread-safe, so it needs to be synced as well. And you should turn off the Indicator regardless of whether the stream succeeds or fails, but you were turning it off only if the stream succeeds.

Re: Update Progressbar

Posted: Tue Nov 10, 2020 10:02 am
by Lena
Thank you very much rlebeau!
Everything looks right now. I also discovered my mistake. Before using CreateAnonymousThread, I was checking the Internet using my custom function. This is a mistake that did not allow to see AniIndicator1 when internet connection bad. I removed my function of checking the Internet connection. Now I want use BASS for chek Internet connection.
If there is no internet connection, I get error number 2 from BASS.
I gave up my internet check connection function. How to correctly insert this my new code internet connection into your Pascal code?

Code: Select all

if (ercode = BASS_ERROR_FILEOPEN) or (ercode = BASS_ERROR_NONET)  then
    begin
        TThread.Queue(nil,
        procedure
        begin
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          ShowMessage('No internet connection.' + sLineBreak + 'Нет интернет соединения.');
          exit;
        end
      );
    end;
I spent the whole day but I cannot correctly insert my new code because I am confused in if begin end
Pascal language is not very clear to me. :)
For example, I don't understand why your code works without a semicolon ";":
ermsg := 'Sorry maintenance work on the music server.'
:o

Re: Update Progressbar

Posted: Tue Nov 10, 2020 10:22 am
by Lena
Also I use this code from BASS for stop music:

Code: Select all

var
  Form1: TForm1;

  smp: HSAMPLE;
  str: HSTREAM;
 //**************
 
 procedure TForm1.Button2Click(Sender: TObject);
begin
 BASS_ChannelStop(str);
 BASS_SampleFree (smp);
end;
 
But I am not initializing anywhere smp! Why does it work and how is it correct for HSAMPLE initializing?

Re: Update Progressbar

Posted: Tue Nov 10, 2020 2:41 pm
by rlebeau
Lena wrote: Tue Nov 10, 2020 10:02 am If there is no internet connection, I get error number 2 from BASS.
Error 2 is BASS_ERROR_FILEOPEN, but the documentation says that 32 (BASS_ERROR_NONET) should be reported if there is no Internet connection. Sounds like a bug in the BASS library.
Lena wrote: Tue Nov 10, 2020 10:02 am How to correctly insert this my new code internet connection into your Pascal code?
You already know how - handle the BASS_ERROR_NONET error. I would not treat BASS_ERROR_FILEOPEN as an Internet connection error. It could just be a wrong URL, or maybe the URL is temporarily offline because the server is down for maintenance at that moment, etc.

Since you are now handling multiple errors, I would suggest a slightly different approach:

Code: Select all

TThread.CreateAnonymousThread(
  procedure
  var
    ercode: Integer;
    ermsg: string;
  begin
    TThread.Queue(nil, 
      procedure
      begin
        AniIndicator1.Enabled := True;
        AniIndicator1.Visible := True;
      end
    );

    BASS_StreamFree(str);
    str := BASS_StreamCreateURL(PChar('http://91.199.194.34:8000'), 0, BASS_UNICODE, nil, nil);
    ercode := BASS_ErrorGetCode;

    if ercode = BASS_OK then
    begin
      BASS_ChannelSetSync(str, BASS_SYNC_META, 0, @MetaSync, nil);
      BASS_ChannelPlay(str, FALSE);
      TThread.Queue(nil,
        procedure
        begin
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          Viewport3D1.Visible := True;
          FloatAnimation1.Enabled := True;
        end
      );
    end else
    begin
      BASS_SampleFree (smp);
      case ercode of
        BASS_ERROR_TIMEOUT: ermsg := 'Sorry maintenance work on the music server.';
        BASS_ERROR_FILEOPEN: ermsg := 'Sorry can't open the music file. Check the URL.';
        BASS_ERROR_NONET: ermsg := 'No internet connection.';
        // other error codes as needed..
      else
        ermsg := Format('Unable to create music stream. Error %d', [ercode]);
      end;
      TThread.Queue(nil,
        procedure
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          ShowMessage(ermsg);
        end
      );
    end;
  end
).Start;
Lena wrote: Tue Nov 10, 2020 10:02 am I spent the whole day but I cannot correctly insert my new code because I am confused in if begin end
Pascal language is not very clear to me. :)
Really? 'begin ... end' is just Pascal's equivalent to C/C++'s '{}' curly braces.
Lena wrote: Tue Nov 10, 2020 10:02 am For example, I don't understand why your code works without a semicolon ";":
That, on the other hand, can be tricky for Pascal beginners.

In Pascal, semicolon is a statement *separator*, not a statement *terminator*, like it is in C/C++. There is a difference. There are places in Pascal syntax where an explicit terminator is not needed, because the compiler knows there is a separation of statements, so the semicolon is optional in those places. Using a semicolon in those places just creates empty statements.

A semicolon is commonly used as a *terminator* in places it is not strictly needed, for consistency and portability between languages, and when beginners just don't know any better :-)
Lena wrote: Tue Nov 10, 2020 10:22 am But I am not initializing anywhere smp!
Well, then that is on you. You have a bug in your code that you need to fix. Stop trying to free something that you don't create. Or else create it properly.

Or, maybe you simply meant to call BASS_StreamFree(str) instead of BASS_SampleFree(smp)? That would make more sense, given the code you have shown so far. I haven't seen any code in your snippets that tries to free the HSTREAM returned by BASS_CreateStreamURL().
Lena wrote: Tue Nov 10, 2020 10:22 am Why does it work
BASS_SampleFree() fails if you give it an invalid handle. But you are not checking for that failure.
Lena wrote: Tue Nov 10, 2020 10:22 am how is it correct for HSAMPLE initializing?
I don't know. I don't use BASS. What are you trying to use the HSAMPLE for in the first place?

Re: Update Progressbar

Posted: Wed Nov 11, 2020 1:02 am
by Lena
Thanks a lot for the detailed explanation!
I removed from the code BASS_SampleFree.
My code contains three buttons PLAY, STOP, CLOSE

Code: Select all

//STOP play
procedure TForm1.Button2Click(Sender: TObject);
begin

 BASS_ChannelStop(str);
 //BASS_StreamFree(str);
 //BASS_SampleFree (smp);
 Text1.Text := ''; //title song
 FloatAnimation1.Enabled := False;
 Viewport3D1.Visible := False;
end;

//CLOSE app and remove service icon from tray
procedure TForm1.Image3Click(Sender: TObject);
begin
 BASS_ChannelStop(str);
 BASS_StreamFree(str);
 MainActivity.finish;
end;

procedure TForm1.FormCreate(Sender: TObject);
Begin

 if not BASS_Init(-1, 44100, 0, nil, nil) Then Begin
	   ShowMessage('Failed to initialize audio!' + sLineBreak + 'Не удалось инициализировать audio!');
     Exit;
     end;

 if FService = Nil Then Begin
  FService := TLocalServiceConnection.Create;
  FService.StartService('serPublic');
  end;
end;
  
//PLAY button contain your TThread.CreateAnonymousThread  
Now everything works as it should. Thanks!
One feature is not very good in BASS. Sometimes when the Internet is bad and I press the Play button, the stream is loaded without errors, but there is no sound.

Re: Update Progressbar

Posted: Wed Nov 11, 2020 11:38 am
by rlebeau
Lena wrote: Wed Nov 11, 2020 1:02 am One feature is not very good in BASS. Sometimes when the Internet is bad and I press the Play button, the stream is loaded without errors, but there is no sound.
You are going to have to take that up with BASS's author, or the BASS community.