completionMessage in Buffer.cueSoundFile

Dear users and developers,

While trying to shorten the following code example in VDiskIn (as well as in DiskIn),

// cue and play right away
SynthDef("help-VDiskin", { |out, bufnum = 0|,, bufnum,, 2.0)));
/* Code 1 */
x = Synth.basicNew("help-VDiskin");
m = { arg buf; x.addToHeadMsg(nil, [\bufnum, buf])};

b = Buffer.cueSoundFile(s,Platform.resourceDir +/+ "sounds/a11wlk01-44_1.aiff",0,1, completionMessage: m);
); b.close;;    // clean up

I drafted the following two codes:

/* Code 2*/
Buffer.cueSoundFile(s, Platform.resourceDir +/+ "sounds/a11wlk01-44_1.aiff", 0, 1, completionMessage:  { |buffer| fork{  {, buffer.bufnum, }.play } } )
/* Code 3*/
Buffer.cueSoundFile(s, Platform.resourceDir +/+ "sounds/a11wlk01-44_1.aiff", 0, 1, completionMessage:  { |buffer| {, buffer.bufnum, }.play; } )

Code 2 returns the following strings in the Post window when evaluating it after recompiling sclang:

β†’ Buffer(6, 32768, 1, 48000.0, nil)

Code 2 returns the following strings in the Post window each time when evaluating it after the first evaluation:

β†’ Buffer(7, 32768, 1, 48000.0, nil)
File β€˜β€™ could not be opened: System error : No such file or directory.

The same phenomenon occurs with Code 3.

Moreover, evaluating Code 2 returns sometimes the following error:

pitch ratio is greater than max allowed (see VDiskIn help)

Repeating the evaluation of Code 2 after evaluating Code 1 produces sounds, but evaluating Code 3 brings the error above again when evaluating Code 2. Therefore, to allow evaluating Code 2 to make sounds, I must reevaluate Code 1.

I cannot understand why this oddity happen.
Could someone explain the reason?
Could any revision of Code 2 or Code 3 produce sound?

What I do not understand at all is the influence of evaluating Code 3 and Code 2:

  • Evaluating Code 3 interrupts evaluating Code 2.
  • Evaluating Code 1 allows evaluating Code 2 to produce sound.

And… sadly, I seem to misunderstand something on completionMessage, but I cannot find what I misunderstand.

I am attaching a video related to this phenomenon:

Best regards,

A completionMessage function should return a single OSC message.

You cannot use it for complex actions like { }.play. This type of thing, you can do in an action function.

Note that the function given to is called action, while the function given to Buffer.cueSoundFile is called completionMessage. That is, they are not equivalent.

The way to use completionMessage to play immediately after cuing is:

  • Make a SynthDef to play the file.
  • completionMessage: { |buf| player = Synth.basicNew(\vdiskin).newMsg(args: [bufnum: buf]) }

(Substituting your own SynthDef name, args etc.)

Or you could use a Routine with s.sync, and then play the function.


1 Like

Thank you for the kind and detailed explanation.
I now understand why Code 3 in my initial post does not work. However, I still do not entirely understand why Code 2 in my initial post containing a routine returned using the method fork only properly works after evaluating Code 1. Why does the interference arise?

It’s the same reason.

There is only one thing that a completionMessage function is allowed to do: to create an array containing an OSC message for the server to evaluate.

Anything else is not allowed in a completionMessage function.

{ }.play sends a /d_recv message to the server, with its own completionMessage to play the synth – and it returns a Synth object.

This is not creating and returning an array with OSC message contents – so { }.play is not valid in a completionMessage function.

fork { } creates and returns a Routine object. A Routine is also not an array with OSC message contents – so this is also not valid in a completionMessage function.

Actually almost everything you can do, should not be done in a completionMessage function.

If you want to use completionMessage to play a synth after cuing, the function must return a /s_new message (which my .newMsg example will do). There is, quite literally, no other correct usage of completionMessage to play a synth. You could build the message by hand instead of using newMsg, but it must build a message (and only do this).

Method names ending in ...Msg are likely to help you with completionMessages.


1 Like

Thank you very much for the details. I have got it!

With deep appreciation,