Adding SoundTrack at render time

On 20/06/2014 at 21:03, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   R15 
Platform:   Windows  ; Mac  ;  
Language(s) :     C++  ;


I am creating a Null object when I receive the MSG_MULTI_RENDERNOTIFICATION message in the RenderNotificationData->doc. It does not render the sound.  I can add geometry and it renders fine.  I can add the Null and soundtrack to the active document and it works perfectly.  Is it possible to add a soundtrack at render time and have it render the sound?


On 21/06/2014 at 09:49, xxxxxxxx wrote:

I have moved the code to insert the audio track to the CopyTo function ( happens before the render notification ).  Still does't render the sound.  Anybody have any ideas?  Is there something to do to initialize the track other than MSG_UPDATE?


On 21/06/2014 at 14:38, xxxxxxxx wrote:

Can anybody tell me the pipeline for Cinema4D recognizing an audio track when preparing to render?  It seems like it is queueing up the audio to render before it begins cloning the document data for the external render.  Is this correct?


On 22/06/2014 at 08:22, xxxxxxxx wrote:

I don't know about anyone else. But I have no idea what you're trying to do.

C4D doesn't "render" sound.
It only plays it back through your sound card. Or uses it's sound wave values to move things in the scene.
It doesn't "render" anything to any files that I know of.


On 22/06/2014 at 10:22, xxxxxxxx wrote:

If you create a sound track in the timeline and set a sound file it will render to the file in the output save includes sound.  I am trying to add a sound track at render time to do the same thing.  I think I am going to forgo the pain and add a prepare to render command that the user must execute before final renders.  It is a hack and a pain but I do not know of any other way.

On 22/06/2014 at 11:38, xxxxxxxx wrote:

That's a little bit clearer. But still leaves some unanswered questions.

- What kind of plugin are you writing this in?

- What is the code you're using to create the sound track?
I'm assuming it looks something like this?:

    //Add a sound track to it in memory only  
  CTrack *soundTrack = CTrack::Alloc(op, DescLevel(CTsound,CTsound,0));  
  if (!soundTrack) return FALSE;  
  //Insert the track into the timeline manager from memory  
  //Get your file path  
  Filename file = GeGetC4DPath(C4D_PATH_DESKTOP) + "myaudio.wav";

- Are you giving C4D time to load the sound file before rendering?
  Example: if( type == MSG_MENUPREPARE) Render the scene

If you're otherwise able to load your sound file with code. Then the problem is probably due to not giving C4D the time to load the sound track and the file before executing the render.
That's a very common problem when trying to create things through code in C4D. One that I encounter all of the time.
If I don't give C4D enough time to create things. It will either crash, or do strange things.
So I use the message system to get around that problem.


On 22/06/2014 at 13:00, xxxxxxxx wrote:

CTrack *track_Sound;
                track_Sound = CTrack::Alloc( object, DescLevel( CTsound, CTsound, 0 ) );
                if ( track_Sound != NULL )
                    object->InsertTrackSorted( track_Sound );
                    track_Sound->SetParameter( DescID( DescLevel( CID_SOUND_START, DTYPE_TIME, 0L ) ), data->GetTime( kSTART ), DESCFLAGS_SET_0 );
                   track_Sound->SetParameter( DescLevel( CID_SOUND_NAME ), data->GetFilename( kFILENAME ), DESCFLAGS_SET_0 );
                        track_Sound->Message( MSG_UPDATE );
                    object->Message( MSG_UPDATE );

This works fine in a command plugin.  I have interrogated the render document from the render notification message of the object and it is all there.  There is a big pause at the beginning of the render where I assume the sound is being loaded.  I guess the external renderer could be running the sound code on a worker thread which executes before the document is finished being copied.  Definitely problematic for me.

Is there a way to start the external render for the active document programmatically?  Sorry, totally out of context question I know.


On 22/06/2014 at 13:03, xxxxxxxx wrote:

Sorry, I forgot to mention what kind of plugin.  It is a object plugin.

On 22/06/2014 at 13:28, xxxxxxxx wrote:

There is RenderDocument().  If you were to use CallCommand(12099), it would be no different than the user clicking on the "Render to Picture Viewer" button.

On 22/06/2014 at 14:12, xxxxxxxx wrote:

It sounds like you're setting up your object plugin to monitor the rendering process.
In other words. The plugin is monitoring when the user renders the scene.

I'm wondering if it would smarter to use a button in your object plugin instead.
So when you press that button, the first thing it does is create a sound track. And then loads the .wav file. And then only after the .wav file is fully loaded does it attempt to render the scene.

I suppose you could even create the empty sound track ahead of time in the Init() method every time the plugin is used. Just to cut down on some cpu cycles when you actually load the sound file.
That way you aren't creating the track and loading the file at the same time.

I'm just thinking out loud.
I've never done anything like this before with sound files.


On 22/06/2014 at 15:50, xxxxxxxx wrote:

Tried the idea of creating the sound track and putting a sound in but disabling the use sound ( the sound data is in memory ).  Then switching the use sound bool at the render notification.  That doesn't work either.  I might be trying to do too much with Cinema.

thanks for the help and ideas!


On 22/06/2014 at 16:35, xxxxxxxx wrote:

Unfortunately, C4D is old software that still has some unusual framework and methodologies incumbent in its system and API.  In my case, providing and launching plugins from a dialog seems pretty much impossible.  The disparities between C4D's basic, Attribute Manager, and Dialog interfaces continues to assume an approach that feels antiquated and not well thought out.  In other words, a basic underlying framework that allows all of these interfaces to act similarly doesn't exist.  You either do it the standard, ole fashioned way, or you work too hard to find a workaround.  It is not C5D.  Audio seems tertiary to the goals of C4D.  It does 3D and animation but audio is almost an afterthought - something best reintegrated after the fact in After Effects or similar.  Hopefully, Yanuech can get some relevant information from the developers.

On 22/06/2014 at 16:50, xxxxxxxx wrote:

I'm having troubles with it too.

What I did was:
- Created a custom method that creates a sound track and loads a .wav file into it ( called addSoundTrack())

- Created a class member Bool type variable called "addTrack"

- In the object plugin's Message() method. In a MSG_MULTI_RENDERNOTIFACTION case. I look for a sound track on the active object. And if there isn't one. I set addTrack = TRUE; else FALSE;

- In the object plugin's GetVirtualObjects() method. I do this:
if(addTrack) addSoundTrack();

All the class member variable does is makes sure that the call to addSoundTrack() only executes once. And not repeatedly.
What I'm getting when I hit render is a new sound track is created properly.
And the file name is there in the "Sound" attribute too. That's also correct.
However... The actual sound does not get loaded into the timeline.

This is the same exact problem that we've had with Python.
But in Python we get this result even when using a CommandData plugin.

So I guess what we need is for Maxon support to tell us why this sound code stuff does not load the sound file into the timeline for ObjectData plugins. While it does work when being loaded with a Command Data plugin.
There must be some condition or requirement that it needs that is not being met. That gets met from CommandData plugins.


On 22/06/2014 at 17:01, xxxxxxxx wrote:

BaseObject *object = BaseObject::Alloc(Onull);
document->InsertObject( object, NULL, NULL );
CTrack *track_Sound;
track_Sound = CTrack::Alloc(object ,DescLevel(CTsound, CTsound, 0));
track_Sound->SetParameter(DescID(DescLevel(CID_SOUND_START, DTYPE_TIME, 0L)), start_Time, DESCFLAGS_SET_0 );
track_Sound->SetParameter(DescLevel(CID_SOUND_NAME), filename, DESCFLAGS_SET_0);
object->Message( MSG_UPDATE );

This works every time for me in the Message render notification or even in copy data ( when the doc is being cloned, assuming that is for a render ).  The issue is that it just doesn't render the sound.  It could definitely be that the sound is being loaded on a worker thread which means it is not finished when the render starts.  Not sure how to lock the render thread until the loading of the sound is complete ( if I knew when the sound was loaded, which I don't ).  In the end the best I can do is to set a long timer for the render thread lock and wait for the race condition to kick me in the head ).

Thanks for the discussion, Learning a lot.


On 22/06/2014 at 18:44, xxxxxxxx wrote:

It's not really working though. It's only filling in the link field.

When we load a sound file into the timeline correctly there's two major things that take place.
-The sound file is loaded into the "Sound" link field.
-The sound file is opened and read using some sort of internal IO file streamer code.
After the file has been read by the file streamer. The "Play Sound" file button is enabled and the height values for the sound are drawn as vertical lines in the timeline.

After you run your code. Look at the play button for the sound in it's AM pallet. I'll bet it's greyed out.
Also, in the timeline manager.  Twirl open the little arrow next to the sound track.
If the track loaded properly into the timeline you should see a lot of vertical lines that represent the sound waveforms values. But I'll bet yours is still empty like mine.
These indicate that the file was not read by the IO streamer.
This is also what happens in Python. Even with CommnadData plugins. And we've been ignored by Maxon every time we bring it up.

The file IO streamer in C++ only seems to be working properly if we use a CommandData plugin.
I don't know if this is intentional. Or if it's a bug.


On 23/06/2014 at 06:02, xxxxxxxx wrote:

Hmm...  Working here ( I am testing by playing the timeline and the audio plays ).

Is the file streamer executing on a different thread?


On 23/06/2014 at 15:57, xxxxxxxx wrote:

There is RenderDocument().  If you were to use CallCommand(12099), it would be no different than the user clicking on the "Render to Picture Viewer" button.

Thank you so much.  That is helping a lot.  Next question, is there a list of CallCommands?  I need the command for Make Preview as well.  Investigating Team Render.

Again, I really appreciate your help and hope to be able to return the favor someday.


On 23/06/2014 at 18:11, xxxxxxxx wrote:

Make Preview = CallCommand(1000974);

I don't know if "all" of them are here.
But there's a huge amount of them in this file: MAXON\Your Version\resource\res\menus\c4d_m_editor.res

A word of caution though about the CallCommand().
They have their own built-in Undos. So they can be very hard to undo properly in your code blocks.
I always recommend to people that it's best to avoid using them as much as possible. Unless you don't care about the Undos.


On 24/06/2014 at 03:28, xxxxxxxx wrote:

thank you!

Not concerned about undos when relating to initiating renders.  Everything, yes!