Asynchronous thread



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 22/10/2012 at 14:21, xxxxxxxx wrote:

    I would also like to see an example of using a thread while a dialog GUI is open.
    The only example I could find in the SDK was the MenuTest example. But the code in the execute method is commented out for some reason.

    What would be a great example to see is a very simple GeDialog plugin with one button and one slider gizmo on it.
    When the button is clicked. A sound file is loaded and starts playing.
    But the user can still drag the slider back and forth while the sound is playing.

    There really should be an example of something like this included in the SDK examples.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 23/10/2012 at 01:22, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I would also like to see an example of using a thread while a dialog GUI is open.
    The only example I could find in the SDK was the MenuTest example. But the code in the execute method is commented out for some reason.

    You can uncomment these lines in MenuTest::Execute() to run the tread code.

    Originally posted by xxxxxxxx

    What would be a great example to see is a very simple GeDialog plugin with one button and one slider gizmo on it.
    When the button is clicked. A sound file is loaded and starts playing.
    But the user can still drag the slider back and forth while the sound is playing.

    There really should be an example of something like this included in the SDK examples.

    Interesting idea, I take note of it.
    I agree there should be a useful example of an asynchronous thread in the SDK examples.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 23/10/2012 at 08:06, xxxxxxxx wrote:

    Hi Yannick,
    I did uncomment them. But I didn't notice any difference in the way that plugin ran.
    Which is probably a good thing and how it's supposed to work.

    But in my own plugin. when I load a sound file using it's own thread. And use the same type of code in my Execute() method to load it. It locks up the GUI.
    I used the example code that's in the SDK docs listed in the "GePlaySnd" section to load and play a sound file.

    This is what my thread code looks like :

      
    class SoundThread : public C4DThread  
    {  
      public:  
          virtual void Main(void);  
          virtual const CHAR *GetThreadName(void) { return "My Thread"; }  
    };  
      
      
    void SoundThread::Main()  
    {    
      MPThreadPool    mp;  
      LONG            i,cnt=GeGetCPUCount();   
      MPAlloc<SoundThread> thread;  
      AutoGeFree<C4DThread*> list = GeAllocType(C4DThread*,cnt);  
      if (!list || !thread.Init(cnt))  
      return;  
      
      Filename fn;  
      if (!fn.FileSelect(FILESELECTTYPE_ANYTHING, FILESELECT_LOAD, "Load Sound")) return;  
        
      AutoAlloc<BaseSound> sound;  
      if (!sound) return;  
        
      if (!sound->Load(fn)) return;  
        
      GeSndInfo sndinfo(sound);  
        
      AutoAlloc<GePlaySnd> playsound;  
      if (!playsound) return;  
        
      playsound->Open(sound);  
      playsound->Scrub(0, sndinfo.GetLength().Get());  
        
      while(playsound->IsPlaying())   
      {   
          GePrint("pos: " + RealToString(playsound->GetPositionEstimate()));   
      }  
      
    }
    

    This is what my execute method looks like :

    Bool myResDialog::Execute(BaseDocument *doc)  
    {  
      //My thread is named "SoundThread"  
      //The instance of it I named "PlaySoundThread"  
      SoundThread PlaySoundThread;  
      
      PlaySoundThread.Start(THREADMODE_ASYNC,THREADPRIORITY_NORMAL);//<---Does not work  
      
      dlg.Open(DLG_TYPE_ASYNC,PLUGIN_ID, -1, -1, 300,150);  
      return TRUE;  
    }
    

    Everything runs without errors.
    But the GUI is frozen until I stop the sound file from playing.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 23/10/2012 at 16:08, xxxxxxxx wrote:

    Hi, ScottA

    I really not good at English but I explain that.

    Originally posted by xxxxxxxx

     
    Bool myResDialog::Execute(BaseDocument *doc)  
    {  
      //My thread is named "SoundThread"  
      //The instance of it I named "PlaySoundThread"  
      SoundThread PlaySoundThread;  
     
      PlaySoundThread.Start(THREADMODE_ASYNC,THREADPRIORITY_NORMAL);//<---Does not work  
     
      dlg.Open(DLG_TYPE_ASYNC,PLUGIN_ID, -1, -1, 300,150);  
      return TRUE;  
    }  
    

    Bool myResDialog::Execute(BaseDocument *doc)
    is a function.
    so, SoundThread PlaySoundThread; <-- variale is local
    PlaySoundThread(allocated memory) is destroyed at Execute() return;

    so, you have to use pointer. like this
    (SoundThread* PlaySoundThread = gNew SoundThread ;)

    then memory is out there but you have to retun memory your-self to OS at Thread is end.

      
    SoundThread* PlaySoundThread;  
    Bool myResDialog::Execute(BaseDocument *doc)  
    {  
      //My thread is named "SoundThread"  
      //The instance of it I named "PlaySoundThread"  
      PlaySoundThread = gNew SoundThread ;  
      
      PlaySoundThread->Start(THREADMODE_ASYNC,THREADPRIORITY_NORMAL); //if uesd pointer it Still exist in memory  
     AsyncDlg = gNew dlg;  
      dlg->Open(DLG_TYPE_ASYNC,PLUGIN_ID, -1, -1, 300,150);  
      return TRUE;  
    }  
    

    then you can aceess to thread by pointer variable that PlaySoundThread and dlg

    so, this is complete code of play sound.

      
    //#include "windows.h"  // for check freeing memory with pop up  
    #include "c4d.h"  
    #include "c4d_symbols.h"  
    #include "lib_snd.h"  
      
    class wavThread : public C4DThread  
    {  
     void Main();  
       
    public:  
      wavThread();  
      ~wavThread();  
      BaseSound *sound;  
      GePlaySnd *playsound;  
      LReal PositionEstimate;  
      Bool isPlaying;  
      LONG error;  
      const  CHAR* GetThreadName();  
    };  
    wavThread::wavThread()  
    {  
    }  
    wavThread::~wavThread()  
    {  
      //GePrint("Deleted!!!!!!");  
    }  
    void wavThread::Main()  
    {  
      sound = BaseSound::Alloc();  
      if (!sound) {error = 1; End();}  
      
      if (!sound->Load(Filename("C:\\GangnamStyle.wav"))) error = 2;  
      
      GeSndInfo sndinfo(sound);  
      
      playsound = GePlaySnd::Alloc();  
      if (!playsound) {error = 3;End();}  
      
      playsound->Open(sound);  
      Real second = sndinfo.GetLength().Get();  
      playsound->Scrub(0, second);  
      
      while(isPlaying) //Playing music don't need this but this is support pause command.  
      {  
          GeSleep(1000);  
          GePrint("pos: " + RealToString(playsound->GetPositionEstimate()));  
          if(playsound->GetPositionEstimate() > second) break;  
      }  
      playsound->Close();  
      if(sound) BaseSound::Free(sound);  
      if(playsound) GePlaySnd::Free(playsound);  
    }      
    const CHAR* wavThread::GetThreadName()  
    {  
      return "wavSound";  
    }  
    class SoundDlg;  
    SoundDlg *dlg;  
    class SoundDlg : public GeDialog  
    {  
      private:  
          wavThread th;  
      public :  
          virtual Bool CreateLayout(void);  
          virtual Bool Command(LONG id,const BaseContainer &msg);  
          Bool KillTread();  
          Bool IsRunning();  
    };  
    Bool SoundDlg::IsRunning()  
    {  
      if(th.IsRunning()) return TRUE;  
      return 0;  
    }  
    Bool SoundDlg::KillTread()  
    {  
      th.isPlaying=0;  
      return 1;  
    }  
    Bool SoundDlg::CreateLayout()  
    {  
      GroupBegin(0,BFH_SCALEFIT|BFV_SCALEFIT,2,0,"",BFV_GRIDGROUP_ALLOW_WEIGHTS);  
              AddButton(1000,BFH_SCALEFIT|BFV_SCALEFIT,0,0,"Play Sound");  
              AddButton(1001,BFH_SCALEFIT|BFV_SCALEFIT,0,0,"Pause Sound");  
              AddButton(1002,BFH_SCALEFIT|BFV_SCALEFIT,0,0,"Stop Sound");  
              AddButton(1003,BFH_SCALEFIT|BFV_SCALEFIT,0,0,"Thread Stop");  
      GroupEnd();  
      return 1;  
    }  
    Bool SoundDlg::Command(LONG id,const BaseContainer &msg)  
    {  
      switch (id)  
      {  
          case 1000:  
              if(th.IsRunning())  
              {      
                  GePrint("running");  
                  th.playsound->StartAt(th.PositionEstimate); break;  
              }else{  
                  GePrint("new start");  
                  th.isPlaying = 1;  
                  th.Start();  
                  break;  
              }  
          case 1001:  
              if(th.IsRunning())   
              {  
                  th.PositionEstimate = th.playsound->GetPositionEstimate();  
                  th.playsound->Stop();  
              }  
              break;  
          case 1002:  
              if(th.IsRunning())   
              {  
                  th.playsound->Stop();  
                  th.PositionEstimate =0;  
              }  
              break;  
          case 1003:  
              if(th.IsRunning())   
              {  
                  th.playsound->Stop();  
                  th.playsound->Close();  
                  th.isPlaying = 0;  
                  th.End();  
              }  
              break;  
      }  
      return TRUE;  
    }  
    class PlaySoundCmd : public CommandData  
    {  
      public:  
          virtual Bool Execute(BaseDocument *doc);  
          virtual LONG GetState(BaseDocument *doc);  
    };  
      
    Bool PlaySoundCmd::Execute(BaseDocument *doc)  
    {      
      if(dlg) gDelete(dlg);  
      dlg = gNew SoundDlg;  
      
      dlg->Open(DLG_TYPE_ASYNC,1000011,-1,-1);  
      return TRUE;  
    }  
      
    LONG PlaySoundCmd::GetState(BaseDocument *doc)  
    {  
      return CMD_ENABLED;  
    }  
    #define ID_PlaySound 1000008   
    Bool RegisterPlaySoundCmd(void)  
    {  
      return RegisterCommandPlugin(ID_PlaySound,String("Play Sound"),0/*PLUGINFLAG_HIDEPLUGINMENU*/,NULL,String(),gNew PlaySoundCmd);  
    }  
    void FreeSounddlg()  
    {  
      if (dlg)   
      {      
          if(dlg->IsRunning()) dlg->KillTread();  
          gDelete(dlg);  
          //MessageBox(NULL,"Olleh !!","Notification",MB_OK);  
         // for check freeing memory with pop up. this is win api  
      }  
    }  
      
    

    main.cpp

      
    #include "c4d.h"  
    void FreeSounddlg();  
    Bool PluginStart(void)  
    {  
      if (!RegisterPlaySoundCmd()) return FALSE;  
      return TRUE;  
    }  
    Bool PluginMessage(LONG id, void *data)  
    {  
      switch (id)  
      {  
          case C4DPL_INIT_SYS:  
              if (!resource.Init()) return FALSE; // don't start plugin without resource  
              return TRUE;  
      
          case C4DMSG_PRIORITY:   
              return TRUE;  
      
          case C4DPL_ENDACTIVITY:  
              FreeSounddlg();    // you have to do this Freein memory  
              return TRUE;  
      }  
      return FALSE;  
    }  
    

    Even You don't have to use Thread that play sound.
    because dialog's variable is still exist until freeing the dialog.
    but I used Thread for help to you.

    Important thing is below

      
    // declaration  
    class SoundDlg;  
    SoundDlg *dlg;  
      
    // Allocate and get pointer address(dlg)  
    Bool PlaySoundCmd::Execute(BaseDocument *doc)  
    {      
      if(dlg) gDelete(dlg);  
      dlg = gNew SoundDlg;  
      
      dlg->Open(DLG_TYPE_ASYNC,1000011,-1,-1);  
      return TRUE;  
    }  
      
    // Freeing memory  
    main.cpp  
    case C4DPL_ENDACTIVITY:  
              FreeSounddlg();    // you have to do this Freeing memory  
              return TRUE;  
    

    I hope this is of some help to you.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 23/10/2012 at 21:04, xxxxxxxx wrote:

    That's really great information elasticmind.
    I always forget about that main.cpp file.

    Your code is working for me. But the sound file plays back a little bit choppy.
    I have a QuadCore system running Vista x64.
    And a 30meg .wav file plays back just a tad bit choppy.

    I'm not sure if that's got anything to do with your code though.
    It could just be a limitation on how many tasks C4D can do with threads at the same time.
    Or maybe it's just that my computer can't handle it?

    Thanks a lot for the code.👍

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 24/10/2012 at 02:10, xxxxxxxx wrote:

    I don't know how work that c4d GePlaySnd does but so easy to use.

    I think that problem is your harddisk's access speed.
    most S-ATA hard disk's access speed is 30 ~ 80mb / s.
    CPU is enough for handle this, C4D too. but harddisk does'nt.

    Actually, In the majority of cases, I'm used to DirectShow in windows for sound play

    http://msdn.microsoft.com/en-us/library/dd389098(v=vs.85).aspx

    this is demonstrates how to play a file as DirectShow programming. so easy to handle media file.
    however, this support many media file in windows

    In MAC OS X,
    https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Sound/Sound.html#//apple_ref/doc/uid/10000104-SW1

    This document contains articles that describe Cocoa's audio support.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 24/10/2012 at 08:28, xxxxxxxx wrote:

    Thanks for the link.
    I'll give that code a try and see what happens.

    I can use C4D very heavily while the .wav file is playing in Windows media player. And it doesn't skip, or chop up, the same way it does when run from a C4D plugin's thread.
    Sometimes I can get lucky reduce the chopping by stopping&starting the .wav file with the plugin's buttons. So maybe it's a caching (buffering) thing?
    Perhaps programs like Windows media player buffers the .wav files to make it play back smoothly. And this plugin thread does not?

    Also.
    There are still some small safety issues with your code.
    If the plugin is running. And the user clicks to load the plugin again. It crashes the plugin and makes C4D freeze.
    It's not a big deal. Just makes me wonder how to make it work better.
    We really never get much advice from Maxon about threading here(it rarely comes up). And it would be nice to know more about it. And how to use it properly.

    -ScottA

    *Update- I just created the C++ program at that link. And it plays back my .wav file smoothly.
    I don't know what this means. Other than it's choppy in a C4D thread. And not choppy in other kinds of programs.
    Does this mean I need to use direct show in my C4D plugin to get .wav files to play smoothly?



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 24/10/2012 at 10:18, xxxxxxxx wrote:

    One other thing I noticed.
    When the sound file starts playing it's choppy. But it eventually smooths out after about 20-30 seconds.

    I don't see anything in the BaseSound class that would let me cache the file before playing it to help get rid of this problem.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 24/10/2012 at 10:44, xxxxxxxx wrote:

    I think you have to understand c, c++ memory management.

    My code just show you that how to use allocate and freeing memory manually.
    I didn't test all case.

    Originally posted by xxxxxxxx

    If the plugin is running. And the user clicks to load the plugin again. It crashes the plugin and makes C4D freeze.

    This is because delete memory while Thread is running.

    Bool PlaySoundCmd::Execute(BaseDocument *doc)
    {   
      if(dlg) gDelete(dlg); 
    //  ->> Thread is running and C4D read memory, but Delete memory. then Crash....
      dlg = gNew SoundDlg;

    dlg->Open(DLG_TYPE_ASYNC,1000011,-1,-1);
      return TRUE;
    }

    Change code like this

    Bool PlaySoundCmd::Execute(BaseDocument *doc)
    {   
      if(dlg->IsRunning())
    {
          dlg->KillTread();
          gDelete(dlg);
      }
      dlg = gNew SoundDlg;

    dlg->Open(DLG_TYPE_ASYNC,1000011,-1,-1);
      return TRUE;
    }

    have to Stop Thread manually.

    progress
    1. Stop Thread
    2. TreadMain ===>     while() is break

    then,
      playsound->Close();   // Stop and Close sound
      if(sound) BaseSound::Free(sound);  // Free memory
      if(playsound) GePlaySnd::Free(playsound); // also

    3. gDelete(dlg); 
    4. gNew .....
    5. New memory be allocated by OS.

    Memory management is so hard to understand.

    I can't explain properly because I really not good at English.

    But I recommend that study part of C,C++ memory management.
    and use DirectShow or sound library to play file in windows.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 24/10/2012 at 11:23, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I can't explain properly because I really not good at English

    You're doing great.👍

    To be honest. All that I was really interested in was learning how to create a custom thread to do some work in the background while the plugin was still able to be used at the same time.
    And I think you've given me everything I need for that.
    This choppy sound file playback stuff is something that came up as a side effect.

    I will look into using DirectShow in my plugin. But Maxon doesn't like it when we use outside libraries and classes like this. They can't offer support to us when we do that. So I really hate to go that route.
    Since Maxon wrote a sound file class. I was just wondering why they never added anything to deal with caching the files so they play back smoothly?

    Maybe Maxon has a recommendation on loading(caching) the sound files so they play back better?

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/10/2012 at 09:07, xxxxxxxx wrote:

    I've added a simple threading plugin example (including the source code ) to the C++ plugin section on my website. https://sites.google.com/site/scottayersmedia/plugins

    I would still like to hear from Maxon their official opinion about how to load & run sound files. So that they don't play back choppy. Without using any third party classes and libraries.

    -ScottA


Log in to reply