1 /*
2     SuperCollider real time audio synthesis system
3     Copyright (c) 2002 James McCartney. All rights reserved.
4     http://www.audiosynth.com
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 */
20 
21 /*
22  * Having SequencedCommands allows performing actions that might otherwise require
23  * taking a mutex, which is undesirable in a real time thread.
24  * Some commands require several stages of processing at both the real time
25  * and non real time levels. This class does the messaging between levels for you
26  * so that you only need to write the functions.
27  */
28 
29 #pragma once
30 
31 #include "OSC_Packet.h"
32 #include "SC_World.h"
33 #include "SC_BufGen.h"
34 #include "sc_msg_iter.h"
35 #include "SC_SndFileHelpers.hpp"
36 #include <new>
37 
38 #define CallSequencedCommand(T, inWorld, inSize, inData, inReply)                                                      \
39     void* space = World_Alloc(inWorld, sizeof(T));                                                                     \
40     T* cmd = new (space) T(inWorld, inReply);                                                                          \
41     if (!cmd)                                                                                                          \
42         return kSCErr_Failed;                                                                                          \
43     int err = cmd->Init(inData, inSize);                                                                               \
44     if (err) {                                                                                                         \
45         cmd->~T();                                                                                                     \
46         World_Free(inWorld, space);                                                                                    \
47         return err;                                                                                                    \
48     }                                                                                                                  \
49     if (inWorld->mRealTime)                                                                                            \
50         cmd->CallNextStage();                                                                                          \
51     else                                                                                                               \
52         cmd->CallEveryStage();
53 
54 
55 class SC_SequencedCommand {
56 public:
57     SC_SequencedCommand(World* inWorld, ReplyAddress* inReplyAddress);
58     virtual ~SC_SequencedCommand();
59 
60     void Delete();
61 
62     void CallEveryStage();
63     void CallNextStage();
64 
65     virtual int Init(char* inData, int inSize);
66 
67     virtual bool Stage1(); //     real time
68     virtual bool Stage2(); // non real time
69     virtual bool Stage3(); //     real time
70     virtual void Stage4(); // non real time
71 
72     void SendDone(const char* inCommandName);
73     void SendDoneWithIntValue(const char* inCommandName, int value);
74 
75 
76 protected:
77     int mNextStage;
78     ReplyAddress mReplyAddress;
79     World* mWorld;
80 
81     int mMsgSize;
82     char* mMsgData;
83 
84     virtual void CallDestructor() = 0;
85 };
86 
87 ///////////////////////////////////////////////////////////////////////////
88 
89 class SyncCmd : public SC_SequencedCommand {
90 public:
91     SyncCmd(World* inWorld, ReplyAddress* inReplyAddress);
92 
93     virtual int Init(char* inData, int inSize);
94 
95     virtual bool Stage2(); // non real time
96     virtual bool Stage3(); //     real time
97     virtual void Stage4(); // non real time
98 
99 protected:
100     virtual void CallDestructor();
101     int mID;
102 };
103 
104 ///////////////////////////////////////////////////////////////////////////
105 
106 class BufGenCmd : public SC_SequencedCommand {
107 public:
108     BufGenCmd(World* inWorld, ReplyAddress* inReplyAddress);
109     virtual ~BufGenCmd();
110 
111     virtual int Init(char* inData, int inSize);
112 
113     virtual bool Stage2(); // non real time
114     virtual bool Stage3(); //     real time
115     virtual void Stage4(); // non real time
116 
117 protected:
118     int mBufIndex;
119     BufGen* mBufGen;
120     sc_msg_iter mMsg;
121     char* mData;
122     int mSize;
123     SndBuf mSndBuf;
124     float* mFreeData;
125 
126     virtual void CallDestructor();
127 };
128 
129 ///////////////////////////////////////////////////////////////////////////
130 
131 class BufAllocCmd : public SC_SequencedCommand {
132 public:
133     BufAllocCmd(World* inWorld, ReplyAddress* inReplyAddress);
134 
135     virtual int Init(char* inData, int inSize);
136 
137     virtual bool Stage2(); // non real time
138     virtual bool Stage3(); //     real time
139     virtual void Stage4(); // non real time
140 
141 protected:
142     int mBufIndex;
143     SndBuf mSndBuf;
144     int mNumChannels, mNumFrames;
145     float* mFreeData;
146 
147     virtual void CallDestructor();
148 };
149 
150 ///////////////////////////////////////////////////////////////////////////
151 
152 
153 class BufFreeCmd : public SC_SequencedCommand {
154 public:
155     BufFreeCmd(World* inWorld, ReplyAddress* inReplyAddress);
156 
157     virtual int Init(char* inData, int inSize);
158 
159     virtual bool Stage2(); // non real time
160     virtual bool Stage3(); //     real time
161     virtual void Stage4(); // non real time
162 
163 protected:
164     int mBufIndex;
165     float* mFreeData;
166 
167     virtual void CallDestructor();
168 };
169 
170 
171 ///////////////////////////////////////////////////////////////////////////
172 
173 
174 class BufCloseCmd : public SC_SequencedCommand {
175 public:
176     BufCloseCmd(World* inWorld, ReplyAddress* inReplyAddress);
177 
178     virtual int Init(char* inData, int inSize);
179 
180     virtual bool Stage2(); // non real time
181     virtual bool Stage3(); //     real time
182     virtual void Stage4(); // non real time
183 
184 protected:
185     int mBufIndex;
186 
187     virtual void CallDestructor();
188 };
189 
190 
191 ///////////////////////////////////////////////////////////////////////////
192 
193 
194 class BufZeroCmd : public SC_SequencedCommand {
195 public:
196     BufZeroCmd(World* inWorld, ReplyAddress* inReplyAddress);
197 
198     virtual int Init(char* inData, int inSize);
199 
200     virtual bool Stage2(); // non real time
201     virtual bool Stage3(); //     real time
202     virtual void Stage4(); // non real time
203 
204 protected:
205     int mBufIndex;
206 
207     virtual void CallDestructor();
208 };
209 
210 ///////////////////////////////////////////////////////////////////////////
211 
212 class BufAllocReadCmd : public SC_SequencedCommand {
213 public:
214     BufAllocReadCmd(World* inWorld, ReplyAddress* inReplyAddress);
215     virtual ~BufAllocReadCmd();
216 
217     virtual int Init(char* inData, int inSize);
218 
219     virtual bool Stage2(); // non real time
220     virtual bool Stage3(); //     real time
221     virtual void Stage4(); // non real time
222 
223 protected:
224     int mBufIndex;
225     float* mFreeData;
226     SndBuf mSndBuf;
227     char* mFilename;
228     int mFileOffset, mNumFrames;
229 
230     virtual void CallDestructor();
231 };
232 
233 ///////////////////////////////////////////////////////////////////////////
234 
235 class BufReadCmd : public SC_SequencedCommand {
236 public:
237     BufReadCmd(World* inWorld, ReplyAddress* inReplyAddress);
238     virtual ~BufReadCmd();
239 
240     virtual int Init(char* inData, int inSize);
241 
242     virtual bool Stage2(); // non real time
243     virtual bool Stage3(); //     real time
244     virtual void Stage4(); // non real time
245 
246 protected:
247     int mBufIndex;
248     char* mFilename;
249     int mFileOffset, mNumFrames, mBufOffset;
250     bool mLeaveFileOpen;
251     double mSampleRate;
252     virtual void CallDestructor();
253 };
254 
255 ///////////////////////////////////////////////////////////////////////////
256 
257 class SC_BufReadCommand : public SC_SequencedCommand {
258 public:
259     enum { kMaxNumChannels = 32 };
260 
261     SC_BufReadCommand(World* inWorld, ReplyAddress* inReplyAddress);
262     virtual ~SC_BufReadCommand();
263 
264 protected:
265     void InitChannels(sc_msg_iter& msg);
266     bool CheckChannels(int inNumChannels);
267     void CopyChannels(float* dst, float* src, size_t srcChannels, size_t numFrames);
268 
269 protected:
270     int mNumChannels;
271     int mChannels[kMaxNumChannels];
272 };
273 
274 ///////////////////////////////////////////////////////////////////////////
275 
276 class BufAllocReadChannelCmd : public SC_BufReadCommand {
277 public:
278     BufAllocReadChannelCmd(World* inWorld, ReplyAddress* inReplyAddress);
279     virtual ~BufAllocReadChannelCmd();
280 
281     virtual int Init(char* inData, int inSize);
282 
283     virtual bool Stage2(); // non real time
284     virtual bool Stage3(); //     real time
285     virtual void Stage4(); // non real time
286 
287 protected:
288     int mBufIndex;
289     float* mFreeData;
290     SndBuf mSndBuf;
291     char* mFilename;
292     int mFileOffset, mNumFrames;
293     virtual void CallDestructor();
294 };
295 
296 ///////////////////////////////////////////////////////////////////////////
297 
298 class BufReadChannelCmd : public SC_BufReadCommand {
299 public:
300     BufReadChannelCmd(World* inWorld, ReplyAddress* inReplyAddress);
301     virtual ~BufReadChannelCmd();
302 
303     virtual int Init(char* inData, int inSize);
304 
305     virtual bool Stage2(); // non real time
306     virtual bool Stage3(); //     real time
307     virtual void Stage4(); // non real time
308 
309 protected:
310     int mBufIndex;
311     char* mFilename;
312     int mFileOffset, mNumFrames, mBufOffset;
313     bool mLeaveFileOpen;
314     double mSampleRate;
315     virtual void CallDestructor();
316 };
317 
318 ///////////////////////////////////////////////////////////////////////////
319 
320 class BufWriteCmd : public SC_SequencedCommand {
321 public:
322     BufWriteCmd(World* inWorld, ReplyAddress* inReplyAddress);
323     virtual ~BufWriteCmd();
324 
325     virtual int Init(char* inData, int inSize);
326 
327     virtual bool Stage2(); // non real time
328     virtual bool Stage3(); //     real time
329     virtual void Stage4(); // non real time
330 
331 protected:
332     int mBufIndex;
333     char* mFilename;
334 #ifndef NO_LIBSNDFILE
335     SF_INFO mFileInfo;
336 #endif
337     int mNumFrames, mBufOffset;
338     bool mLeaveFileOpen;
339 
340     virtual void CallDestructor();
341 };
342 
343 ///////////////////////////////////////////////////////////////////////////
344 
345 class AudioQuitCmd : public SC_SequencedCommand {
346 public:
347     AudioQuitCmd(World* inWorld, ReplyAddress* inReplyAddress);
348 
349     virtual bool Stage2(); // non real time
350     virtual bool Stage3(); //     real time
351     virtual void Stage4(); // non real time
352 
353 protected:
354     virtual void CallDestructor();
355 };
356 
357 ///////////////////////////////////////////////////////////////////////////
358 
359 class AudioStatusCmd : public SC_SequencedCommand {
360 public:
361     AudioStatusCmd(World* inWorld, ReplyAddress* inReplyAddress);
362 
363     virtual bool Stage2(); // non real time
364 
365 protected:
366     virtual void CallDestructor();
367 };
368 
369 ///////////////////////////////////////////////////////////////////////////
370 
371 class NotifyCmd : public SC_SequencedCommand {
372 public:
373     NotifyCmd(World* inWorld, ReplyAddress* inReplyAddress);
374 
375     virtual int Init(char* inData, int inSize);
376 
377     virtual bool Stage2(); // non real time
378 
379 protected:
380     virtual void CallDestructor();
381 
382     int mOnOff;
383     int mID;
384 };
385 
386 
387 ///////////////////////////////////////////////////////////////////////////
388 
389 #define CallSendFailureCommand(inWorld, inCmdName, inErrString, inReply)                                               \
390     void* space = World_Alloc(inWorld, sizeof(SendFailureCmd));                                                        \
391     SendFailureCmd* cmd = new (space) SendFailureCmd(inWorld, inReply);                                                \
392     if (!cmd)                                                                                                          \
393         return kSCErr_Failed;                                                                                          \
394     cmd->InitSendFailureCmd(inCmdName, inErrString);                                                                   \
395     if (inWorld->mRealTime)                                                                                            \
396         cmd->CallNextStage();                                                                                          \
397     else                                                                                                               \
398         cmd->CallEveryStage();
399 
400 class SendFailureCmd : public SC_SequencedCommand {
401 public:
402     SendFailureCmd(World* inWorld, ReplyAddress* inReplyAddress);
403     virtual ~SendFailureCmd();
404 
405     virtual void InitSendFailureCmd(const char* inCmdName, const char* inErrString);
406 
407     virtual bool Stage2(); // non real time
408 
409 protected:
410     char *mCmdName, *mErrString;
411 
412     virtual void CallDestructor();
413 };
414 
415 ///////////////////////////////////////////////////////////////////////////
416 
417 #include "SC_GraphDef.h"
418 
419 class LoadSynthDefCmd : public SC_SequencedCommand {
420 public:
421     LoadSynthDefCmd(World* inWorld, ReplyAddress* inReplyAddress);
422     virtual ~LoadSynthDefCmd();
423 
424     virtual int Init(char* inData, int inSize);
425 
426     virtual bool Stage2(); // non real time
427     virtual bool Stage3(); //     real time
428     virtual void Stage4(); // non real time
429 
430 protected:
431     char* mFilename;
432     GraphDef* mDefs;
433 
434     virtual void CallDestructor();
435 };
436 
437 ///////////////////////////////////////////////////////////////////////////
438 
439 #include "SC_GraphDef.h"
440 
441 class RecvSynthDefCmd : public SC_SequencedCommand {
442 public:
443     RecvSynthDefCmd(World* inWorld, ReplyAddress* inReplyAddress);
444     virtual ~RecvSynthDefCmd();
445 
446     virtual int Init(char* inData, int inSize);
447 
448     virtual bool Stage2(); // non real time
449     virtual bool Stage3(); //     real time
450     virtual void Stage4(); // non real time
451 
452 protected:
453     char* mBuffer;
454     GraphDef* mDefs;
455 
456     virtual void CallDestructor();
457 };
458 
459 ///////////////////////////////////////////////////////////////////////////
460 
461 class LoadSynthDefDirCmd : public SC_SequencedCommand {
462 public:
463     LoadSynthDefDirCmd(World* inWorld, ReplyAddress* inReplyAddress);
464     virtual ~LoadSynthDefDirCmd();
465 
466     virtual int Init(char* inData, int inSize);
467 
468     virtual bool Stage2(); // non real time
469     virtual bool Stage3(); //     real time
470     virtual void Stage4(); // non real time
471 
472 protected:
473     char* mFilename;
474     GraphDef* mDefs;
475 
476     virtual void CallDestructor();
477 };
478 
479 ///////////////////////////////////////////////////////////////////////////
480 
481 class SendReplyCmd : public SC_SequencedCommand {
482 public:
483     SendReplyCmd(World* inWorld, ReplyAddress* inReplyAddress);
484 
485     virtual int Init(char* inData, int inSize);
486 
487     virtual bool Stage2(); // non real time
488 
489 protected:
490     virtual void CallDestructor();
491 };
492 
493 ///////////////////////////////////////////////////////////////////////////
494 
495 
496 typedef bool (*AsyncStageFn)(World* inWorld, void* cmdData);
497 typedef void (*AsyncFreeFn)(World* inWorld, void* cmdData);
498 
499 class AsyncPlugInCmd : public SC_SequencedCommand {
500 public:
501     AsyncPlugInCmd(World* inWorld, ReplyAddress* inReplyAddress, const char* cmdName, void* cmdData,
502                    AsyncStageFn stage2, // stage2 is non real time
503                    AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true
504                    AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true
505                    AsyncFreeFn cleanup, int completionMsgSize, void* completionMsgData);
506 
507     virtual ~AsyncPlugInCmd();
508 
509     virtual bool Stage2(); // non real time
510     virtual bool Stage3(); //     real time
511     virtual void Stage4(); // non real time
512 
513 protected:
514     const char* mCmdName;
515     void* mCmdData;
516     AsyncStageFn mStage2, mStage3, mStage4;
517     AsyncFreeFn mCleanup;
518 
519     virtual void CallDestructor();
520 };
521