Fix scvim regsitry file for updated filename (thanks Carlo Capocasa)
[supercollider.git] / server / scsynth / SC_SequencedCommand.cpp
blob2d462cc5b263288597d4568e10898a53fa17ed14
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
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.
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.
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
22 #include "SC_SequencedCommand.h"
23 #include "SC_CoreAudio.h"
24 #include "SC_Errors.h"
25 #include "scsynthsend.h"
26 #include "SC_Prototypes.h"
27 #include "SC_HiddenWorld.h"
28 #include "SC_Sem.h"
29 #include "SC_DirUtils.h"
30 #include "SC_StringParser.h"
31 #include "../../common/SC_SndFileHelpers.hpp"
33 #define GET_COMPLETION_MSG(msg) \
34 mMsgSize = msg.getbsize(); \
35 if (mMsgSize) { \
36 mMsgData = (char*)World_Alloc(mWorld, mMsgSize); \
37 msg.getb(mMsgData, mMsgSize); \
40 void PerformCompletionMsg(World *inWorld, OSC_Packet *inPacket);
42 #define SEND_COMPLETION_MSG \
43 if (mMsgSize) { \
44 OSC_Packet packet; \
45 packet.mData = mMsgData; \
46 packet.mSize = mMsgSize; \
47 packet.mReplyAddr = mReplyAddress; \
48 PacketStatus status = PerformCompletionMsg(mWorld, packet); \
49 if (status == PacketScheduled) { \
50 mMsgSize = 0; \
51 mMsgData = 0; \
52 } \
55 void SndBuf_Init(SndBuf *buf);
56 void SndBuf_Init(SndBuf *buf)
58 buf->data = 0;
59 buf->channels = 0;
60 buf->samples = 0;
61 buf->frames = 0;
62 buf->mask = 0;
63 buf->mask1 = 0;
64 buf->coord = 0;
65 buf->sndfile = 0;
68 char* allocAndRestrictPath(World *mWorld, const char* inPath, const char* restrictBase);
69 char* allocAndRestrictPath(World *mWorld, const char* inPath, const char* restrictBase){
70 char strbuf[PATH_MAX];
71 int offset = 0;
72 int remain = PATH_MAX;
74 // Ensure begins with the base
75 if(strncmp(inPath, restrictBase, strlen(restrictBase)) != 0){
76 strcpy(strbuf, restrictBase);
77 offset = strlen(restrictBase);
78 remain -= offset;
79 if(inPath[0]!='/' && strbuf[strlen(strbuf)-1]!='/'){
80 strbuf[offset] = '/';
81 ++offset;
82 --remain;
86 // Now copy string, but discard any ".." (which could be benign, but easy to abuse)
87 SC_StringParser sp(inPath, '/');
88 size_t tokenlen;
89 while (!sp.AtEnd()) {
90 const char *token = const_cast<char *>(sp.NextToken());
91 tokenlen = strlen(token);
92 // now add the new token, then a slash, as long as token is neither dodgy nor overflows
93 if(strcmp(token, "..")!=0 && remain > tokenlen){
94 strcpy(strbuf+offset, token);
95 offset += tokenlen;
96 remain -= tokenlen;
97 if(!sp.AtEnd()) {
98 strbuf[offset] = '/';
99 ++offset;
100 --remain;
105 // Now we can make a long-term home for the string and return it
106 char* saferPath = (char*)World_Alloc(mWorld, strlen(strbuf)+1);
107 strcpy(saferPath, strbuf);
108 return saferPath;
111 SC_SequencedCommand::SC_SequencedCommand(World *inWorld, ReplyAddress *inReplyAddress)
112 : mNextStage(1), mWorld(inWorld),
113 mMsgSize(0), mMsgData(0)
115 if (inReplyAddress) mReplyAddress = *inReplyAddress;
116 else mReplyAddress.mReplyFunc = null_reply_func;
119 SC_SequencedCommand::~SC_SequencedCommand()
121 if (mMsgData) World_Free(mWorld, mMsgData);
124 int SC_SequencedCommand::Init(char* /*inData*/, int /*inSize*/)
126 return kSCErr_None;
129 void SC_SequencedCommand::SendDone(const char *inCommandName)
131 ::SendDone(&mReplyAddress, inCommandName);
134 void SC_SequencedCommand::SendDoneWithIntValue(const char *inCommandName, int value)
136 ::SendDoneWithIntValue(&mReplyAddress, inCommandName, value);
139 void SC_SequencedCommand::CallEveryStage()
141 switch (mNextStage) {
142 case 1 : if (!Stage1()) break; mNextStage++;
143 case 2 : if (!Stage2()) break; mNextStage++;
144 case 3 : if (!Stage3()) break; mNextStage++;
145 case 4 : Stage4(); break;
147 Delete();
150 void DoSequencedCommand(FifoMsg *inMsg);
151 void DoSequencedCommand(FifoMsg *inMsg)
153 SC_SequencedCommand *cmd = (SC_SequencedCommand*)inMsg->mData;
154 cmd->CallNextStage();
157 void FreeSequencedCommand(FifoMsg *inMsg);
158 void FreeSequencedCommand(FifoMsg *inMsg)
160 SC_SequencedCommand *cmd = (SC_SequencedCommand*)inMsg->mData;
161 cmd->Delete();
165 void SC_SequencedCommand::CallNextStage()
167 bool sendAgain = false;
168 FifoMsg msg;
170 int isRealTime = mNextStage & 1;
171 switch (mNextStage) {
172 case 1 :
173 sendAgain = Stage1(); // RT
174 break;
175 case 2 :
176 sendAgain = Stage2(); // NRT
177 break;
178 case 3 :
179 sendAgain = Stage3(); // RT
180 break;
181 case 4 :
182 Stage4(); // NRT
183 break;
185 mNextStage++;
186 SC_AudioDriver *driver = AudioDriver(mWorld);
187 if (sendAgain) {
188 msg.Set(mWorld, DoSequencedCommand, 0, (void*)this);
189 // send this to next time.
190 if (isRealTime) {
191 // send to NRT
192 driver->SendMsgFromEngine(msg);
193 } else {
194 // send to RT
195 driver->SendMsgToEngine(msg);
197 } else {
198 if (isRealTime) {
199 Delete();
200 } else {
201 // can only be freed from RT.
202 msg.Set(mWorld, FreeSequencedCommand, 0, (void*)this);
203 driver->SendMsgToEngine(msg);
208 void SC_SequencedCommand::Delete()
210 CallDestructor();
211 World_Free(mWorld, this);
214 bool SC_SequencedCommand::Stage1()
216 return true;
219 bool SC_SequencedCommand::Stage2()
221 return false;
224 bool SC_SequencedCommand::Stage3()
226 return false;
229 void SC_SequencedCommand::Stage4()
234 ///////////////////////////////////////////////////////////////////////////
236 #include "sc_msg_iter.h"
237 #include <string.h>
239 SyncCmd::SyncCmd(World *inWorld, ReplyAddress *inReplyAddress)
240 : SC_SequencedCommand(inWorld, inReplyAddress)
244 int SyncCmd::Init(char *inData, int inSize)
246 sc_msg_iter msg(inSize, inData);
247 mID = msg.geti();
248 return kSCErr_None;
251 void SyncCmd::CallDestructor()
253 this->~SyncCmd();
256 bool SyncCmd::Stage2()
258 return true;
261 bool SyncCmd::Stage3()
263 return true;
266 void SyncCmd::Stage4()
268 small_scpacket packet;
269 packet.adds("/synced");
270 packet.maketags(2);
271 packet.addtag(',');
272 packet.addtag('i');
274 packet.addi(mID);
276 SendReply(&mReplyAddress, packet.data(), packet.size());
279 ///////////////////////////////////////////////////////////////////////////
281 BufAllocCmd::BufAllocCmd(World *inWorld, ReplyAddress *inReplyAddress)
282 : SC_SequencedCommand(inWorld, inReplyAddress)
286 int BufAllocCmd::Init(char *inData, int inSize)
288 sc_msg_iter msg(inSize, inData);
289 mBufIndex = msg.geti();
290 mNumFrames = msg.geti();
291 mNumChannels = msg.geti(1);
293 GET_COMPLETION_MSG(msg);
295 return kSCErr_None;
298 void BufAllocCmd::CallDestructor()
300 this->~BufAllocCmd();
303 bool BufAllocCmd::Stage2()
305 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
306 mFreeData = buf->data;
307 bufAlloc(buf, mNumChannels, mNumFrames, mWorld->mFullRate.mSampleRate);
308 mSndBuf = *buf;
309 return true;
312 bool BufAllocCmd::Stage3()
314 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
315 *buf = mSndBuf;
316 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
317 SEND_COMPLETION_MSG;
318 return true;
321 void BufAllocCmd::Stage4()
323 free(mFreeData);
324 SendDoneWithIntValue("/b_alloc", mBufIndex);
327 ///////////////////////////////////////////////////////////////////////////
329 #include "sc_msg_iter.h"
330 #include <string.h>
332 BufGenCmd::BufGenCmd(World *inWorld, ReplyAddress *inReplyAddress)
333 : SC_SequencedCommand(inWorld, inReplyAddress),
334 mData(0)
338 BufGenCmd::~BufGenCmd()
340 World_Free(mWorld, mData);
343 int BufGenCmd::Init(char *inData, int inSize)
345 mSize = inSize;
346 mData = (char*)World_Alloc(mWorld, mSize);
347 memcpy(mData, inData, mSize);
349 sc_msg_iter msg(mSize, mData);
350 mBufIndex = msg.geti();
352 int32 *genName = msg.gets4();
353 if (!genName) return kSCErr_WrongArgType;
355 mBufGen = GetBufGen(genName);
356 if (!mBufGen) return kSCErr_BufGenNotFound;
358 mMsg = msg;
360 return kSCErr_None;
363 void BufGenCmd::CallDestructor()
365 this->~BufGenCmd();
368 bool BufGenCmd::Stage2()
370 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
372 mFreeData = buf->data;
373 (*mBufGen->mBufGenFunc)(mWorld, buf, &mMsg);
374 if (buf->data == mFreeData) mFreeData = NULL;
375 mSndBuf = *buf;
376 return true;
379 bool BufGenCmd::Stage3()
381 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
382 *buf = mSndBuf;
383 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
384 return true;
387 void BufGenCmd::Stage4()
389 free(mFreeData);
390 SendDoneWithIntValue("/b_gen", mBufIndex);
394 ///////////////////////////////////////////////////////////////////////////
397 ///////////////////////////////////////////////////////////////////////////
400 BufFreeCmd::BufFreeCmd(World *inWorld, ReplyAddress *inReplyAddress)
401 : SC_SequencedCommand(inWorld, inReplyAddress)
405 int BufFreeCmd::Init(char *inData, int inSize)
407 sc_msg_iter msg(inSize, inData);
408 mBufIndex = msg.geti();
410 GET_COMPLETION_MSG(msg);
412 return kSCErr_None;
415 void BufFreeCmd::CallDestructor()
417 this->~BufFreeCmd();
420 bool BufFreeCmd::Stage2()
422 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
423 mFreeData = buf->data;
424 #ifndef NO_LIBSNDFILE
425 if (buf->sndfile) sf_close(buf->sndfile);
426 #endif
427 SndBuf_Init(buf);
428 return true;
431 bool BufFreeCmd::Stage3()
433 SndBuf *buf = World_GetBuf(mWorld, mBufIndex);
435 SndBuf_Init(buf);
436 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
437 SEND_COMPLETION_MSG;
439 return true;
442 void BufFreeCmd::Stage4()
444 free(mFreeData);
445 SendDoneWithIntValue("/b_free", mBufIndex);
448 ///////////////////////////////////////////////////////////////////////////
450 BufZeroCmd::BufZeroCmd(World *inWorld, ReplyAddress *inReplyAddress)
451 : SC_SequencedCommand(inWorld, inReplyAddress)
455 int BufZeroCmd::Init(char *inData, int inSize)
457 sc_msg_iter msg(inSize, inData);
458 mBufIndex = msg.geti();
460 GET_COMPLETION_MSG(msg);
462 return kSCErr_None;
465 void BufZeroCmd::CallDestructor()
467 this->~BufZeroCmd();
470 bool BufZeroCmd::Stage2()
472 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
473 memset(buf->data, 0, buf->samples * sizeof(float));
474 return true;
477 bool BufZeroCmd::Stage3()
479 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
480 SEND_COMPLETION_MSG;
481 return true;
484 void BufZeroCmd::Stage4()
486 SendDoneWithIntValue("/b_zero", mBufIndex);
489 ///////////////////////////////////////////////////////////////////////////
491 BufAllocReadCmd::BufAllocReadCmd(World *inWorld, ReplyAddress *inReplyAddress)
492 : SC_SequencedCommand(inWorld, inReplyAddress), mFreeData(0), mFilename(0)
496 int BufAllocReadCmd::Init(char *inData, int inSize)
498 sc_msg_iter msg(inSize, inData);
499 mBufIndex = msg.geti();
501 const char *filename = msg.gets();
502 if (!filename) return kSCErr_WrongArgType;
504 if(mWorld->mRestrictedPath){
505 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
506 }else{
507 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
508 strcpy(mFilename, filename);
511 mFileOffset = msg.geti();
512 mNumFrames = msg.geti();
514 GET_COMPLETION_MSG(msg);
516 return kSCErr_None;
519 BufAllocReadCmd::~BufAllocReadCmd()
521 World_Free(mWorld, mFilename);
524 void BufAllocReadCmd::CallDestructor()
526 this->~BufAllocReadCmd();
529 bool BufAllocReadCmd::Stage2()
531 #ifdef NO_LIBSNDFILE
532 SendFailure(&mReplyAddress, "/b_allocRead", "scsynth compiled without libsndfile\n");
533 scprintf("scsynth compiled without libsndfile\n");
534 return false;
535 #else
536 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
537 SF_INFO fileinfo;
538 memset(&fileinfo, 0, sizeof(fileinfo));
539 SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo);
540 if (!sf) {
541 char str[512];
542 sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL));
543 SendFailureWithBufnum(&mReplyAddress, "/b_allocRead", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str);
544 scprintf(str);
545 return false;
547 if (mFileOffset < 0) mFileOffset = 0;
548 else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames;
549 if (mNumFrames <= 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset;
551 // alloc data size
552 mFreeData = buf->data;
553 SCErr err = bufAlloc(buf, fileinfo.channels, mNumFrames, fileinfo.samplerate);
554 if (err) goto leave;
556 sf_seek(sf, mFileOffset, SEEK_SET);
557 sf_readf_float(sf, buf->data, mNumFrames);
559 leave:
560 mSndBuf = *buf;
561 sf_close(sf);
563 return true;
564 #endif
567 bool BufAllocReadCmd::Stage3()
569 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
570 *buf = mSndBuf;
571 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
572 SEND_COMPLETION_MSG;
574 return true;
577 void BufAllocReadCmd::Stage4()
579 free(mFreeData);
580 SendDoneWithIntValue("/b_allocRead", mBufIndex);
583 ///////////////////////////////////////////////////////////////////////////
585 BufReadCmd::BufReadCmd(World *inWorld, ReplyAddress *inReplyAddress)
586 : SC_SequencedCommand(inWorld, inReplyAddress),
587 mFilename(0)
591 int BufReadCmd::Init(char *inData, int inSize)
593 sc_msg_iter msg(inSize, inData);
594 mBufIndex = msg.geti();
596 const char *filename = msg.gets();
597 if (!filename) return kSCErr_WrongArgType;
599 if(mWorld->mRestrictedPath){
600 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
601 }else{
602 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
603 strcpy(mFilename, filename);
606 mFileOffset = msg.geti();
607 mNumFrames = msg.geti(-1);
608 mBufOffset = msg.geti();
609 mLeaveFileOpen = msg.geti();
611 GET_COMPLETION_MSG(msg);
613 return kSCErr_None;
616 BufReadCmd::~BufReadCmd()
618 World_Free(mWorld, mFilename);
621 void BufReadCmd::CallDestructor()
623 this->~BufReadCmd();
626 bool BufReadCmd::Stage2()
628 #ifdef NO_LIBSNDFILE
629 SendFailure(&mReplyAddress, "/b_read", "scsynth compiled without libsndfile\n");
630 scprintf("scsynth compiled without libsndfile\n");
631 return false;
632 #else
633 SF_INFO fileinfo;
635 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
636 int framesToEnd = buf->frames - mBufOffset;
637 if (framesToEnd <= 0) return true;
639 SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo);
640 if (!sf) {
641 char str[512];
642 sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL));
643 SendFailureWithBufnum(&mReplyAddress, "/b_read", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_read", str);
644 scprintf(str);
645 return false;
647 if (fileinfo.channels != buf->channels) {
648 char str[512];
649 sf_close(sf);
650 sprintf(str, "Channel mismatch. File '%s' has %d channels. Buffer has %d channels.\n", mFilename, fileinfo.channels, buf->channels);
651 SendFailureWithBufnum(&mReplyAddress, "/b_read", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_read", str);
652 scprintf(str);
653 return false;
656 if (mFileOffset < 0) mFileOffset = 0;
657 else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames;
658 if (mNumFrames < 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset;
660 if (mNumFrames > framesToEnd) mNumFrames = framesToEnd;
662 sf_seek(sf, mFileOffset, SEEK_SET);
663 if (mNumFrames > 0) {
664 sf_readf_float(sf, buf->data + (mBufOffset * buf->channels), mNumFrames);
667 if(buf->sndfile)
668 sf_close(buf->sndfile);
670 if (mLeaveFileOpen) {
671 buf->sndfile = sf;
672 } else {
673 sf_close(sf);
674 buf->sndfile = 0;
677 mSampleRate = (double)fileinfo.samplerate;
679 return true;
680 #endif
683 bool BufReadCmd::Stage3()
685 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
686 buf->samplerate = mSampleRate;
687 if (mLeaveFileOpen) buf->mask = buf->mask1 = -1;
689 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
690 SEND_COMPLETION_MSG;
691 return true;
694 void BufReadCmd::Stage4()
696 SendDoneWithIntValue("/b_read", mBufIndex);
699 ///////////////////////////////////////////////////////////////////////////
701 SC_BufReadCommand::SC_BufReadCommand(World* inWorld, ReplyAddress* inReplyAddress)
702 : SC_SequencedCommand(inWorld, inReplyAddress),
703 mNumChannels(0)
707 SC_BufReadCommand::~SC_BufReadCommand()
711 void SC_BufReadCommand::InitChannels(sc_msg_iter& msg)
713 mNumChannels = 0;
714 while (msg.nextTag(0) == 'i') {
715 int c = msg.geti();
716 if (mNumChannels <= kMaxNumChannels) {
717 mChannels[mNumChannels++] = c;
722 bool SC_BufReadCommand::CheckChannels(int inNumChannels)
724 for (int i=0; i < mNumChannels; ++i) {
725 if (mChannels[i] >= inNumChannels) {
726 return false;
729 return true;
732 void SC_BufReadCommand::CopyChannels(float* dst, float* src, size_t srcChannels, size_t numFrames)
734 for (int ci=0; ci < mNumChannels; ++ci) {
735 int c = mChannels[ci];
736 if (c >= 0 && c < srcChannels) {
737 for (size_t fi=0; fi < numFrames; ++fi) {
738 dst[fi*mNumChannels+ci] = src[fi*srcChannels+c];
740 } else {
741 for (size_t fi=0; fi < numFrames; ++fi) {
742 dst[fi*mNumChannels+ci] = 0.f;
748 ///////////////////////////////////////////////////////////////////////////
750 BufAllocReadChannelCmd::BufAllocReadChannelCmd(World *inWorld, ReplyAddress *inReplyAddress)
751 : SC_BufReadCommand(inWorld, inReplyAddress),
752 mFreeData(0), mFilename(0)
756 int BufAllocReadChannelCmd::Init(char *inData, int inSize)
758 sc_msg_iter msg(inSize, inData);
759 mBufIndex = msg.geti();
761 const char *filename = msg.gets();
762 if (!filename) return kSCErr_WrongArgType;
764 if(mWorld->mRestrictedPath){
765 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
766 }else{
767 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
768 strcpy(mFilename, filename);
771 mFileOffset = msg.geti();
772 mNumFrames = msg.geti();
774 InitChannels(msg);
776 GET_COMPLETION_MSG(msg);
778 return kSCErr_None;
781 BufAllocReadChannelCmd::~BufAllocReadChannelCmd()
783 World_Free(mWorld, mFilename);
786 void BufAllocReadChannelCmd::CallDestructor()
788 this->~BufAllocReadChannelCmd();
791 bool BufAllocReadChannelCmd::Stage2()
793 #ifdef NO_LIBSNDFILE
794 SendFailure(&mReplyAddress, "/b_allocReadChannel", "scsynth compiled without libsndfile\n");
795 scprintf("scsynth compiled without libsndfile\n");
796 return false;
797 #else
798 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
800 SF_INFO fileinfo;
801 memset(&fileinfo, 0, sizeof(fileinfo));
802 SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo);
803 if (!sf) {
804 char str[512];
805 sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL));
806 SendFailureWithBufnum(&mReplyAddress, "/b_allocReadChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str);
807 scprintf(str);
808 return false;
810 if (mFileOffset < 0) mFileOffset = 0;
811 else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames;
812 if (mNumFrames <= 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset;
814 if (mNumChannels == 0) {
815 // alloc data size
816 mFreeData = buf->data;
817 SCErr err = bufAlloc(buf, fileinfo.channels, mNumFrames, fileinfo.samplerate);
818 if (err) goto leave;
819 // read all channels
820 sf_seek(sf, mFileOffset, SEEK_SET);
821 sf_readf_float(sf, buf->data, mNumFrames);
822 } else {
823 // verify channel indexes
824 if (!CheckChannels(fileinfo.channels)) {
825 const char* str = "Channel index out of range.\n";
826 SendFailureWithBufnum(&mReplyAddress, "/b_allocReadChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str);
827 scprintf(str);
828 sf_close(sf);
829 return false;
831 // alloc data size
832 mFreeData = buf->data;
833 SCErr err = bufAlloc(buf, mNumChannels, mNumFrames, fileinfo.samplerate);
834 if (err) goto leave;
835 // alloc temp buffer
836 float* data = (float*)malloc(mNumFrames*fileinfo.channels*sizeof(float));
837 if (data == 0) goto leave;
838 // read some channels
839 sf_seek(sf, mFileOffset, SEEK_SET);
840 sf_readf_float(sf, data, mNumFrames);
841 CopyChannels(buf->data, data, fileinfo.channels, mNumFrames);
842 // free temp buffer
843 free(data);
846 leave:
847 mSndBuf = *buf;
848 sf_close(sf);
850 return true;
851 #endif
854 bool BufAllocReadChannelCmd::Stage3()
856 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
857 *buf = mSndBuf;
858 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
859 SEND_COMPLETION_MSG;
861 return true;
864 void BufAllocReadChannelCmd::Stage4()
866 free(mFreeData);
867 SendDoneWithIntValue("/b_allocReadChannel", mBufIndex);
870 ///////////////////////////////////////////////////////////////////////////
872 BufReadChannelCmd::BufReadChannelCmd(World *inWorld, ReplyAddress *inReplyAddress)
873 : SC_BufReadCommand(inWorld, inReplyAddress),
874 mFilename(0)
878 int BufReadChannelCmd::Init(char *inData, int inSize)
880 sc_msg_iter msg(inSize, inData);
881 mBufIndex = msg.geti();
883 const char *filename = msg.gets();
884 if (!filename) return kSCErr_WrongArgType;
886 if(mWorld->mRestrictedPath){
887 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
888 }else{
889 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
890 strcpy(mFilename, filename);
893 mFileOffset = msg.geti();
894 mNumFrames = msg.geti(-1);
895 mBufOffset = msg.geti();
896 mLeaveFileOpen = msg.geti();
898 InitChannels(msg);
900 GET_COMPLETION_MSG(msg);
902 return kSCErr_None;
905 BufReadChannelCmd::~BufReadChannelCmd()
907 World_Free(mWorld, mFilename);
910 void BufReadChannelCmd::CallDestructor()
912 this->~BufReadChannelCmd();
915 bool BufReadChannelCmd::Stage2()
917 #ifdef NO_LIBSNDFILE
918 SendFailure(&mReplyAddress, "/b_readChannel", "scsynth compiled without libsndfile\n");
919 scprintf("scsynth compiled without libsndfile\n");
920 return false;
921 #else
922 SF_INFO fileinfo;
924 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
925 int framesToEnd = buf->frames - mBufOffset;
926 if (framesToEnd <= 0) return true;
928 SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo);
929 if (!sf) {
930 char str[512];
931 sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL));
932 SendFailureWithBufnum(&mReplyAddress, "/b_readChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_read", str);
933 scprintf(str);
934 return false;
937 if (mNumChannels > 0) {
938 // verify channel indexes
939 if (!( CheckChannels(fileinfo.channels)) ) { // nescivi: && CheckChannels(buf->channels) (should not check here for buf->channels)
940 const char* str = "Channel index out of range.\n";
941 SendFailureWithBufnum(&mReplyAddress, "/b_readChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str);
942 scprintf(str);
943 sf_close(sf);
944 return false;
946 // nescivi: this also seems out of place: we want to read from a file with more channels than are in the buffer
947 // } else if (fileinfo.channels != buf->channels) {
948 // char str[256];
949 // sf_close(sf);
950 // sprintf(str, "Channel mismatch. File '%s' has %d channels. Buffer has %d channels.\n",
951 // mFilename, fileinfo.channels, buf->channels);
952 // SendFailure(&mReplyAddress, "/b_read", str);
953 // scprintf(str);
954 // return false;
957 if (mFileOffset < 0) mFileOffset = 0;
958 else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames;
959 if (mNumFrames < 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset;
960 if (mNumFrames > framesToEnd) mNumFrames = framesToEnd;
962 sf_seek(sf, mFileOffset, SEEK_SET);
963 if (mNumFrames > 0) {
964 if (mNumChannels == 0) {
965 // read all channels
966 sf_readf_float(sf, buf->data + (mBufOffset * buf->channels), mNumFrames);
967 } else {
968 // alloc temp buffer
969 float* data = (float*)malloc(mNumFrames*fileinfo.channels*sizeof(float));
970 if (data == 0) goto leave;
971 // read some channels
972 sf_seek(sf, mFileOffset, SEEK_SET);
973 sf_readf_float(sf, data, mNumFrames);
974 CopyChannels(buf->data + (mBufOffset * mNumChannels), data, fileinfo.channels, mNumFrames);
975 // free temp buffer
976 free(data);
980 leave:
981 if(buf->sndfile)
982 sf_close(buf->sndfile);
984 if (mLeaveFileOpen) {
985 buf->sndfile = sf;
986 } else {
987 sf_close(sf);
988 buf->sndfile = 0;
991 mSampleRate = (double)fileinfo.samplerate;
993 return true;
994 #endif
997 bool BufReadChannelCmd::Stage3()
999 SndBuf* buf = World_GetBuf(mWorld, mBufIndex);
1000 buf->samplerate = mSampleRate;
1001 if (mLeaveFileOpen) buf->mask = buf->mask1 = -1;
1003 mWorld->mSndBufUpdates[mBufIndex].writes ++ ;
1004 SEND_COMPLETION_MSG;
1005 return true;
1008 void BufReadChannelCmd::Stage4()
1010 SendDoneWithIntValue("/b_readChannel", mBufIndex);
1013 ///////////////////////////////////////////////////////////////////////////
1015 BufWriteCmd::BufWriteCmd(World *inWorld, ReplyAddress *inReplyAddress)
1016 : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0)
1020 #ifdef NO_LIBSNDFILE
1021 struct SF_INFO {};
1022 #endif
1024 int BufWriteCmd::Init(char *inData, int inSize)
1026 #ifdef NO_LIBSNDFILE
1027 SendFailure(&mReplyAddress, "/b_write", "scsynth compiled without libsndfile\n");
1028 scprintf("scsynth compiled without libsndfile\n");
1029 return false;
1030 #else
1031 sc_msg_iter msg(inSize, inData);
1032 mBufIndex = msg.geti();
1034 const char *filename = msg.gets();
1035 if (!filename) return kSCErr_WrongArgType;
1037 if(mWorld->mRestrictedPath){
1038 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
1039 }else{
1040 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
1041 strcpy(mFilename, filename);
1044 const char *headerFormatString = msg.gets("aiff");
1045 const char *sampleFormatString = msg.gets("int16");
1047 mNumFrames = msg.geti(-1);
1048 mBufOffset = msg.geti();
1049 mLeaveFileOpen = msg.geti();
1051 GET_COMPLETION_MSG(msg);
1053 memset(&mFileInfo, 0, sizeof(mFileInfo));
1054 return sndfileFormatInfoFromStrings(&mFileInfo, headerFormatString, sampleFormatString);
1055 #endif
1058 BufWriteCmd::~BufWriteCmd()
1060 World_Free(mWorld, mFilename);
1063 void BufWriteCmd::CallDestructor()
1065 this->~BufWriteCmd();
1068 bool BufWriteCmd::Stage2()
1070 #ifdef NO_LIBSNDFILE
1071 return false;
1072 #else
1073 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
1074 int framesToEnd = buf->frames - mBufOffset;
1075 if (framesToEnd < 0) framesToEnd = 0;
1076 mFileInfo.samplerate = (int)buf->samplerate;
1077 mFileInfo.channels = buf->channels;
1079 SNDFILE* sf = sf_open(mFilename, SFM_WRITE, &mFileInfo);
1080 if (!sf) {
1081 char str[512];
1082 sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL));
1083 SendFailureWithBufnum(&mReplyAddress, "/b_write", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_write", str);
1084 scprintf(str);
1085 return false;
1088 if (mNumFrames < 0 || mNumFrames > buf->frames) mNumFrames = buf->frames;
1090 if (mNumFrames > framesToEnd) mNumFrames = framesToEnd;
1092 if (mNumFrames > 0) {
1093 sf_writef_float(sf, buf->data + (mBufOffset * buf->channels), mNumFrames);
1096 if(buf->sndfile)
1097 sf_close(buf->sndfile);
1099 if (mLeaveFileOpen) {
1100 buf->sndfile = sf;
1101 } else {
1102 sf_close(sf);
1103 buf->sndfile = 0;
1106 return true;
1107 #endif
1110 bool BufWriteCmd::Stage3()
1112 SEND_COMPLETION_MSG;
1113 return true;
1116 void BufWriteCmd::Stage4()
1118 SendDoneWithIntValue("/b_write", mBufIndex);
1121 ///////////////////////////////////////////////////////////////////////////
1123 BufCloseCmd::BufCloseCmd(World *inWorld, ReplyAddress *inReplyAddress)
1124 : SC_SequencedCommand(inWorld, inReplyAddress)
1128 int BufCloseCmd::Init(char *inData, int inSize)
1130 sc_msg_iter msg(inSize, inData);
1131 mBufIndex = msg.geti();
1133 GET_COMPLETION_MSG(msg);
1135 return kSCErr_None;
1138 void BufCloseCmd::CallDestructor()
1140 this->~BufCloseCmd();
1143 bool BufCloseCmd::Stage2()
1145 #ifdef NO_LIBSNDFILE
1146 SendFailure(&mReplyAddress, "/b_close", "scsynth compiled without libsndfile\n");
1147 scprintf("scsynth compiled without libsndfile\n");
1148 return false;
1149 #else
1150 SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex);
1151 if (buf->sndfile) {
1152 sf_close(buf->sndfile);
1153 buf->sndfile = 0;
1155 return true;
1156 #endif
1159 bool BufCloseCmd::Stage3()
1161 SEND_COMPLETION_MSG;
1162 return true;
1165 void BufCloseCmd::Stage4()
1167 SendDoneWithIntValue("/b_close", mBufIndex);
1170 ///////////////////////////////////////////////////////////////////////////
1172 AudioQuitCmd::AudioQuitCmd(World *inWorld, ReplyAddress *inReplyAddress)
1173 : SC_SequencedCommand(inWorld, inReplyAddress)
1177 void AudioQuitCmd::CallDestructor()
1179 this->~AudioQuitCmd();
1182 bool AudioQuitCmd::Stage2()
1184 mWorld->hw->mTerminating = true;
1185 return true;
1188 bool AudioQuitCmd::Stage3()
1190 #if SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS
1191 SendFailure(&mReplyAddress, "/quit", "not allowed in AU host\n");
1192 scprintf("/quit : quit not allowed in AU host\n");
1193 return false;
1194 #else
1195 if (mWorld->hw->mShmem)
1196 mWorld->hw->mShmem->disconnect();
1197 return true;
1198 #endif
1201 void AudioQuitCmd::Stage4()
1203 SendDone("/quit");
1204 mWorld->hw->mQuitProgram->Release();
1207 ///////////////////////////////////////////////////////////////////////////
1209 AudioStatusCmd::AudioStatusCmd(World *inWorld, ReplyAddress *inReplyAddress)
1210 : SC_SequencedCommand(inWorld, inReplyAddress)
1214 void AudioStatusCmd::CallDestructor()
1216 this->~AudioStatusCmd();
1219 bool AudioStatusCmd::Stage2()
1221 // we stop replying to status requests after receiving /quit
1222 if (mWorld->hw->mTerminating == true)
1223 return false;
1225 small_scpacket packet;
1226 packet.adds("/status.reply");
1227 packet.maketags(10);
1228 packet.addtag(',');
1229 packet.addtag('i');
1230 packet.addtag('i');
1231 packet.addtag('i');
1232 packet.addtag('i');
1233 packet.addtag('i');
1234 packet.addtag('f');
1235 packet.addtag('f');
1236 packet.addtag('d');
1237 packet.addtag('d');
1239 packet.addi(1); // audio is always active now.
1240 packet.addi(mWorld->mNumUnits);
1241 packet.addi(mWorld->mNumGraphs);
1242 packet.addi(mWorld->mNumGroups);
1243 packet.addi(mWorld->hw->mGraphDefLib->NumItems());
1245 SC_AudioDriver *driver = mWorld->hw->mAudioDriver;
1246 packet.addf(driver->GetAvgCPU());
1247 packet.addf(driver->GetPeakCPU());
1248 packet.addd(driver->GetSampleRate());
1249 packet.addd(driver->GetActualSampleRate());
1251 SendReply(&mReplyAddress, packet.data(), packet.size());
1253 return false;
1256 ///////////////////////////////////////////////////////////////////////////
1258 NotifyCmd::NotifyCmd(World *inWorld, ReplyAddress *inReplyAddress)
1259 : SC_SequencedCommand(inWorld, inReplyAddress)
1263 int NotifyCmd::Init(char *inData, int inSize)
1265 sc_msg_iter msg(inSize, inData);
1266 mOnOff = msg.geti();
1268 return kSCErr_None;
1271 void NotifyCmd::CallDestructor()
1273 this->~NotifyCmd();
1276 bool NotifyCmd::Stage2()
1278 HiddenWorld *hw = mWorld->hw;
1280 if (mOnOff) {
1281 for (uint32 i=0; i<hw->mNumUsers; ++i) {
1282 if (mReplyAddress == hw->mUsers[i]) {
1283 // already in table - don't fail though..
1284 SendFailure(&mReplyAddress, "/notify", "notify: already registered\n");
1285 scprintf("/notify : already registered\n");
1286 return false;
1290 // add reply address to user table
1291 if (hw->mNumUsers >= hw->mMaxUsers) {
1292 SendFailure(&mReplyAddress, "/notify", "too many users\n");
1293 scprintf("too many users\n");
1294 return false;
1297 hw->mUsers[hw->mNumUsers++] = mReplyAddress;
1299 SendDone("/notify");
1300 } else {
1301 for (uint32 i=0; i<hw->mNumUsers; ++i) {
1302 if (mReplyAddress == hw->mUsers[i]) {
1303 // remove from list
1304 hw->mUsers[i] = hw->mUsers[--hw->mNumUsers];
1305 SendDone("/notify");
1306 return false;
1310 SendFailure(&mReplyAddress, "/notify", "not registered\n");
1311 scprintf("not registered\n");
1313 return false;
1316 ///////////////////////////////////////////////////////////////////////////
1318 SendFailureCmd::SendFailureCmd(World *inWorld, ReplyAddress *inReplyAddress)
1319 : SC_SequencedCommand(inWorld, inReplyAddress), mCmdName(0), mErrString(0)
1323 SendFailureCmd::~SendFailureCmd()
1325 World_Free(mWorld, mCmdName);
1326 World_Free(mWorld, mErrString);
1330 void SendFailureCmd::InitSendFailureCmd(const char *inCmdName, const char* inErrString)
1332 mCmdName = (char*)World_Alloc(mWorld, strlen(inCmdName)+1);
1333 strcpy(mCmdName, inCmdName);
1335 mErrString = (char*)World_Alloc(mWorld, strlen(inErrString)+1);
1336 strcpy(mErrString, inErrString);
1339 void SendFailureCmd::CallDestructor()
1341 this->~SendFailureCmd();
1344 bool SendFailureCmd::Stage2()
1346 SendFailure(&mReplyAddress, mCmdName, mErrString);
1347 return false;
1350 ///////////////////////////////////////////////////////////////////////////
1352 RecvSynthDefCmd::RecvSynthDefCmd(World *inWorld, ReplyAddress *inReplyAddress)
1353 : SC_SequencedCommand(inWorld, inReplyAddress), mBuffer(0)
1357 int RecvSynthDefCmd::Init(char *inData, int inSize)
1359 sc_msg_iter msg(inSize, inData);
1361 int size = msg.getbsize();
1362 if (!size) throw kSCErr_WrongArgType;
1364 mBuffer = (char*)World_Alloc(mWorld, size);
1365 msg.getb(mBuffer, size);
1367 GET_COMPLETION_MSG(msg);
1369 mDefs = 0;
1370 return kSCErr_None;
1373 RecvSynthDefCmd::~RecvSynthDefCmd()
1375 World_Free(mWorld, mBuffer);
1378 void RecvSynthDefCmd::CallDestructor()
1380 this->~RecvSynthDefCmd();
1383 bool RecvSynthDefCmd::Stage2()
1385 mDefs = GraphDef_Recv(mWorld, mBuffer, mDefs);
1387 return true;
1390 bool RecvSynthDefCmd::Stage3()
1392 GraphDef_Define(mWorld, mDefs);
1393 SEND_COMPLETION_MSG;
1394 return true;
1397 void RecvSynthDefCmd::Stage4()
1399 SendDone("/d_recv");
1402 ///////////////////////////////////////////////////////////////////////////
1404 LoadSynthDefCmd::LoadSynthDefCmd(World *inWorld, ReplyAddress *inReplyAddress)
1405 : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0)
1409 int LoadSynthDefCmd::Init(char *inData, int inSize)
1411 sc_msg_iter msg(inSize, inData);
1413 const char *filename = msg.gets();
1414 if (!filename) return kSCErr_WrongArgType;
1416 if(mWorld->mRestrictedPath){
1417 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
1418 }else{
1419 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
1420 strcpy(mFilename, filename);
1423 GET_COMPLETION_MSG(msg);
1425 mDefs = 0;
1426 return kSCErr_None;
1429 LoadSynthDefCmd::~LoadSynthDefCmd()
1431 World_Free(mWorld, mFilename);
1434 void LoadSynthDefCmd::CallDestructor()
1436 this->~LoadSynthDefCmd();
1439 bool LoadSynthDefCmd::Stage2()
1441 char* fname = mFilename;
1442 mDefs = GraphDef_LoadGlob(mWorld, fname, mDefs);
1443 return true;
1446 bool LoadSynthDefCmd::Stage3()
1448 GraphDef_Define(mWorld, mDefs);
1449 SEND_COMPLETION_MSG;
1450 return true;
1453 void LoadSynthDefCmd::Stage4()
1455 SendDone("/d_load");
1458 ///////////////////////////////////////////////////////////////////////////
1460 LoadSynthDefDirCmd::LoadSynthDefDirCmd(World *inWorld, ReplyAddress *inReplyAddress)
1461 : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0)
1465 int LoadSynthDefDirCmd::Init(char *inData, int inSize)
1467 sc_msg_iter msg(inSize, inData);
1469 const char *filename = msg.gets();
1470 if (!filename) return kSCErr_WrongArgType;
1472 if(mWorld->mRestrictedPath){
1473 mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath);
1474 }else{
1475 mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1);
1476 strcpy(mFilename, filename);
1479 GET_COMPLETION_MSG(msg);
1481 mDefs = 0;
1482 return kSCErr_None;
1485 LoadSynthDefDirCmd::~LoadSynthDefDirCmd()
1487 World_Free(mWorld, mFilename);
1490 void LoadSynthDefDirCmd::CallDestructor()
1492 this->~LoadSynthDefDirCmd();
1495 bool LoadSynthDefDirCmd::Stage2()
1497 mDefs = GraphDef_LoadDir(mWorld, mFilename, mDefs);
1499 return true;
1502 bool LoadSynthDefDirCmd::Stage3()
1504 GraphDef_Define(mWorld, mDefs);
1505 SEND_COMPLETION_MSG;
1506 return true;
1509 void LoadSynthDefDirCmd::Stage4()
1511 SendDone("/d_loadDir");
1514 ///////////////////////////////////////////////////////////////////////////
1516 SendReplyCmd::SendReplyCmd(World *inWorld, ReplyAddress *inReplyAddress)
1517 : SC_SequencedCommand(inWorld, inReplyAddress)
1521 int SendReplyCmd::Init(char *inData, int inSize)
1523 mMsgSize = inSize;
1524 mMsgData = (char*)World_Alloc(mWorld, mMsgSize);
1525 memcpy(mMsgData, inData, inSize);
1526 return kSCErr_None;
1529 void SendReplyCmd::CallDestructor()
1531 this->~SendReplyCmd();
1534 bool SendReplyCmd::Stage2()
1536 SendReply(&mReplyAddress, mMsgData, mMsgSize);
1537 return false;
1540 ///////////////////////////////////////////////////////////////////////////
1542 int PerformAsynchronousCommand(
1543 World *inWorld,
1544 void* replyAddr,
1545 const char* cmdName,
1546 void *cmdData,
1547 AsyncStageFn stage2, // stage2 is non real time
1548 AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true
1549 AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true
1550 AsyncFreeFn cleanup,
1551 int completionMsgSize,
1552 void* completionMsgData
1555 void* space = World_Alloc(inWorld, sizeof(AsyncPlugInCmd));
1556 AsyncPlugInCmd *cmd = new (space) AsyncPlugInCmd(inWorld, (ReplyAddress*)replyAddr,
1557 cmdName, cmdData, stage2, stage3, stage4, cleanup,
1558 completionMsgSize, completionMsgData);
1559 if (!cmd) return kSCErr_Failed;
1560 if (inWorld->mRealTime) cmd->CallNextStage();
1561 else cmd->CallEveryStage();
1562 return kSCErr_None;
1565 ///////////////////////////////////////////////////////////////////////////
1567 AsyncPlugInCmd::AsyncPlugInCmd(World *inWorld, ReplyAddress *inReplyAddress,
1568 const char* cmdName,
1569 void *cmdData,
1570 AsyncStageFn stage2, // stage2 is non real time
1571 AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true
1572 AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true
1573 AsyncFreeFn cleanup, // cleanup is called in real time
1574 int completionMsgSize,
1575 void* completionMsgData)
1576 : SC_SequencedCommand(inWorld, inReplyAddress),
1577 mCmdName(cmdName), mCmdData(cmdData),
1578 mStage2(stage2), mStage3(stage3), mStage4(stage4),
1579 mCleanup(cleanup)
1581 if (completionMsgSize && completionMsgData) {
1582 mMsgSize = completionMsgSize;
1583 mMsgData = (char*)World_Alloc(mWorld, mMsgSize);
1584 memcpy(mMsgData, completionMsgData, mMsgSize);
1588 AsyncPlugInCmd::~AsyncPlugInCmd()
1590 (mCleanup)(mWorld, mCmdData);
1591 if (mMsgData) World_Free(mWorld, mMsgData);
1594 void AsyncPlugInCmd::CallDestructor()
1596 this->~AsyncPlugInCmd();
1599 bool AsyncPlugInCmd::Stage2()
1601 bool result = !mStage2 || (mStage2)(mWorld, mCmdData);
1602 return result;
1605 bool AsyncPlugInCmd::Stage3()
1607 bool result = !mStage3 || (mStage3)(mWorld, mCmdData);
1608 if (result) SEND_COMPLETION_MSG;
1609 return result;
1612 void AsyncPlugInCmd::Stage4()
1614 bool result = !mStage4 || (mStage4)(mWorld, mCmdData);
1615 if (result && mCmdName && mReplyAddress.mReplyFunc != null_reply_func) SendDone((char*)mCmdName);