Beispiel #1
0
void World_WaitForQuit(struct World *inWorld, bool unload_plugins)
{
	try {
		inWorld->hw->mQuitProgram->wait();
		World_Cleanup(inWorld, unload_plugins);
	} catch (std::exception& exc) {
		scprintf("Exception in World_WaitForQuit: %s\n", exc.what());
	} catch (...) {
	}
}
Beispiel #2
0
void World_WaitForQuit(struct World *inWorld)
{
	try {
		inWorld->hw->mQuitProgram->Acquire();
		World_Cleanup(inWorld);
	} catch (std::exception& exc) {
		scprintf("Exception in World_WaitForQuit: %s\n", exc.what());
	} catch (...) {
	}
}
Beispiel #3
0
void World_NonRealTimeSynthesis(struct World *world, WorldOptions *inOptions)
{
	if (inOptions->mLoadGraphDefs) {
		World_LoadGraphDefs(world);
	}
	int bufLength = world->mBufLength;
	int fileBufFrames = inOptions->mPreferredHardwareBufferFrameSize;
	if (fileBufFrames <= 0) fileBufFrames = 8192;
	int bufMultiple = (fileBufFrames + bufLength - 1) / bufLength;
	fileBufFrames = bufMultiple * bufLength;

	// batch process non real time audio
	if (!inOptions->mNonRealTimeOutputFilename)
		throw std::runtime_error("Non real time output filename is NULL.\n");

	SF_INFO inputFileInfo, outputFileInfo;
	float *inputFileBuf = 0;
	float *outputFileBuf = 0;
	int numInputChannels = 0;
	int numOutputChannels;

	outputFileInfo.samplerate = inOptions->mPreferredSampleRate;
	numOutputChannels = outputFileInfo.channels = world->mNumOutputs;
	sndfileFormatInfoFromStrings(&outputFileInfo,
		inOptions->mNonRealTimeOutputHeaderFormat, inOptions->mNonRealTimeOutputSampleFormat);

	world->hw->mNRTOutputFile = sf_open(inOptions->mNonRealTimeOutputFilename, SFM_WRITE, &outputFileInfo);
	sf_command(world->hw->mNRTOutputFile, SFC_SET_CLIPPING, NULL, SF_TRUE);

	if (!world->hw->mNRTOutputFile)
		throw std::runtime_error("Couldn't open non real time output file.\n");

	outputFileBuf = (float*)calloc(1, world->mNumOutputs * fileBufFrames * sizeof(float));

	if (inOptions->mNonRealTimeInputFilename) {
		world->hw->mNRTInputFile = sf_open(inOptions->mNonRealTimeInputFilename, SFM_READ, &inputFileInfo);
		if (!world->hw->mNRTInputFile)
			throw std::runtime_error("Couldn't open non real time input file.\n");

		inputFileBuf = (float*)calloc(1, inputFileInfo.channels * fileBufFrames * sizeof(float));

		if (world->mNumInputs != (uint32)inputFileInfo.channels)
			scprintf("WARNING: input file channels didn't match number of inputs specified in options.\n");

		numInputChannels = world->mNumInputs = inputFileInfo.channels; // force it.

		if (inputFileInfo.samplerate != (int)inOptions->mPreferredSampleRate)
			scprintf("WARNING: input file sample rate does not equal output sample rate.\n");

	} else {
		world->hw->mNRTInputFile = 0;
	}

	FILE *cmdFile;
	if (inOptions->mNonRealTimeCmdFilename) {
#ifdef _WIN32
		cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "rb");
#else
		cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "r");
#endif
	} else cmdFile = stdin;
	if (!cmdFile)
		throw std::runtime_error("Couldn't open non real time command file.\n");

	OSC_Packet packet;
	memset(&packet, 0, sizeof(packet));
	packet.mData = (char *)malloc(8192);
	packet.mIsBundle = true;
	packet.mReplyAddr.mReplyFunc = null_reply_func;

	int64 schedTime;
	if (nextOSCPacket(cmdFile, &packet, schedTime))
		throw std::runtime_error("command file empty.\n");
	int64 prevTime = schedTime;

	World_SetSampleRate(world, inOptions->mPreferredSampleRate);
	World_Start(world);

	int64 oscTime = 0;
	double oscToSeconds = 1. / pow(2.,32.);
	double oscToSamples = inOptions->mPreferredSampleRate * oscToSeconds;
	int64 oscInc = (int64)((double)bufLength / oscToSamples);

	if(inOptions->mVerbosity >= 0) {
		printf("start time %g\n", schedTime * oscToSeconds);
	}

	bool run = true;
	int inBufStep = numInputChannels * bufLength;
	int outBufStep = numOutputChannels * bufLength;
	float* inputBuses    = world->mAudioBus + world->mNumOutputs * bufLength;
	float* outputBuses   = world->mAudioBus;
	int32* inputTouched  = world->mAudioBusTouched + world->mNumOutputs;
	int32* outputTouched = world->mAudioBusTouched;
	for (; run;) {
		int bufFramesCalculated = 0;
		float* inBufPos = inputFileBuf;
		float* outBufPos = outputFileBuf;

		if (world->hw->mNRTInputFile) {
			int framesRead = sf_readf_float(world->hw->mNRTInputFile, inputFileBuf, fileBufFrames);
			if (framesRead < fileBufFrames) {
				memset(inputFileBuf + framesRead * numInputChannels, 0,
					(fileBufFrames - framesRead) * numInputChannels * sizeof(float));
			}
		}

		for (int i=0; i<bufMultiple && run; ++i) {
			int bufCounter = world->mBufCounter;

			// deinterleave input to input buses
			if (inputFileBuf) {
				float *inBus = inputBuses;
				for (int j=0; j<numInputChannels; ++j, inBus += bufLength) {
					float *inFileBufPtr = inBufPos + j;
					for (int k=0; k<bufLength; ++k) {
						inBus[k] = *inFileBufPtr;
						inFileBufPtr += numInputChannels;
					}
					inputTouched[j] = bufCounter;
				}
			}

			// execute ready commands
			int64 nextTime = oscTime + oscInc;

			while (schedTime <= nextTime) {
				float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5;
				float diffTimeFloor = floor(diffTime);
				world->mSampleOffset = (int)diffTimeFloor;
				world->mSubsampleOffset = diffTime - diffTimeFloor;

				if (world->mSampleOffset < 0) world->mSampleOffset = 0;
				else if (world->mSampleOffset >= bufLength) world->mSampleOffset = bufLength-1;


				PerformOSCBundle(world, &packet);
				if (nextOSCPacket(cmdFile, &packet, schedTime)) { run = false; break; }
				if(inOptions->mVerbosity >= 0) {
					printf("nextOSCPacket %g\n", schedTime * oscToSeconds);
				}
				if (schedTime < prevTime) {
					scprintf("ERROR: Packet time stamps out-of-order.\n");
					run = false;
					goto Bail;
				}
				prevTime = schedTime;
			}

			World_Run(world);

			// interleave output to output buffer
			float *outBus = outputBuses;
			for (int j=0; j<numOutputChannels; ++j, outBus += bufLength) {
				float *outFileBufPtr = outBufPos + j;
				if (outputTouched[j] == bufCounter) {
					for (int k=0; k<bufLength; ++k) {
						*outFileBufPtr = outBus[k];
						outFileBufPtr += numOutputChannels;
					}
				} else {
					for (int k=0; k<bufLength; ++k) {
						*outFileBufPtr = 0.f;
						outFileBufPtr += numOutputChannels;
					}
				}
			}
			bufFramesCalculated += bufLength;
			inBufPos += inBufStep;
			outBufPos += outBufStep;
			world->mBufCounter++;
			oscTime = nextTime;
		}

Bail:
		// write output
		sf_writef_float(world->hw->mNRTOutputFile, outputFileBuf, bufFramesCalculated);
	}

	if (cmdFile != stdin) fclose(cmdFile);
	sf_close(world->hw->mNRTOutputFile);
	world->hw->mNRTOutputFile = 0;

	if (world->hw->mNRTInputFile) {
		sf_close(world->hw->mNRTInputFile);
		world->hw->mNRTInputFile = 0;
	}

	free(packet.mData);
	World_Cleanup(world,true);
}
Beispiel #4
0
World* World_New(WorldOptions *inOptions)
{
#if (_POSIX_MEMLOCK - 0) >=  200112L
	if (inOptions->mMemoryLocking && inOptions->mRealTime)
	{
		bool lock_memory = false;

		rlimit limit;

		int failure = getrlimit(RLIMIT_MEMLOCK, &limit);
		if (failure)
			scprintf("getrlimit failure\n");
		else
		{
			if (limit.rlim_cur == RLIM_INFINITY and
				limit.rlim_max == RLIM_INFINITY)
				lock_memory = true;
			else
				scprintf("memory locking disabled due to resource limiting\n");

			if (lock_memory)
			{
				if (mlockall(MCL_FUTURE) != -1)
					scprintf("memory locking enabled.\n");
			}
		}
	}
#endif

	World *world = 0;

	try {
		static bool gLibInitted = false;
		if (!gLibInitted) {
			InterfaceTable_Init();
			initialize_library(inOptions->mUGensPluginPath);
			initializeScheduler();
			gLibInitted = true;
		}

		world = (World*)zalloc(1, sizeof(World));

		world->hw = (HiddenWorld*)zalloc(1, sizeof(HiddenWorld));

		world->hw->mAllocPool = new AllocPool(malloc, free, inOptions->mRealTimeMemorySize * 1024, 0);
		world->hw->mQuitProgram = new boost::sync::semaphore(0);
		world->hw->mTerminating = false;

		HiddenWorld *hw = world->hw;
		hw->mGraphDefLib = new HashTable<struct GraphDef, Malloc>(&gMalloc, inOptions->mMaxGraphDefs, false);
		hw->mNodeLib = new IntHashTable<Node, AllocPool>(hw->mAllocPool, inOptions->mMaxNodes, false);
		hw->mUsers = new Clients();
		hw->mMaxUsers = inOptions->mMaxLogins;
		hw->mAvailableClientIDs = new ClientIDs();
		for (int i = 0; i<hw->mMaxUsers; i++) {
			hw->mAvailableClientIDs->push_back(i);
		}
		hw->mClientIDdict = new ClientIDDict();
		hw->mHiddenID = -8;
		hw->mRecentID = -8;


		world->mNumUnits = 0;
		world->mNumGraphs = 0;
		world->mNumGroups = 0;

		world->mBufCounter = 0;
		world->mBufLength = inOptions->mBufLength;
		world->mSampleOffset = 0;
		world->mSubsampleOffset = 0.f;
		world->mNumAudioBusChannels = inOptions->mNumAudioBusChannels;
		world->mNumControlBusChannels = inOptions->mNumControlBusChannels;
		world->mNumInputs = inOptions->mNumInputBusChannels;
		world->mNumOutputs = inOptions->mNumOutputBusChannels;

		world->mVerbosity = inOptions->mVerbosity;
		world->mErrorNotification = 1;  // i.e., 0x01 | 0x02
		world->mLocalErrorNotification = 0;

		if (inOptions->mSharedMemoryID) {
			server_shared_memory_creator::cleanup(inOptions->mSharedMemoryID);
			hw->mShmem = new server_shared_memory_creator(inOptions->mSharedMemoryID, inOptions->mNumControlBusChannels);
			world->mControlBus = hw->mShmem->get_control_busses();
		} else {
			hw->mShmem = 0;
			world->mControlBus = (float*)zalloc(world->mNumControlBusChannels, sizeof(float));
		}

		world->mNumSharedControls = 0;
		world->mSharedControls = inOptions->mSharedControls;

		int numsamples = world->mBufLength * world->mNumAudioBusChannels;
		world->mAudioBus = (float*)zalloc(numsamples, sizeof(float));

		world->mAudioBusTouched = (int32*)zalloc(inOptions->mNumAudioBusChannels, sizeof(int32));
		world->mControlBusTouched = (int32*)zalloc(inOptions->mNumControlBusChannels, sizeof(int32));

		world->mNumSndBufs = inOptions->mNumBuffers;
		world->mSndBufs = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf));
		world->mSndBufsNonRealTimeMirror = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf));
		world->mSndBufUpdates = (SndBufUpdates*)zalloc(world->mNumSndBufs, sizeof(SndBufUpdates));

		GroupNodeDef_Init();

		int err = Group_New(world, 0, &world->mTopGroup);
		if (err) throw err;

		world->mRealTime = inOptions->mRealTime;

		world->ft = &gInterfaceTable;

		world->mNumRGens = inOptions->mNumRGens;
		world->mRGen = new RGen[world->mNumRGens];
		for (uint32 i=0; i<world->mNumRGens; ++i) {
			world->mRGen[i].init(server_timeseed());
		}

		world->mNRTLock = new SC_Lock();
		world->mDriverLock = new SC_Lock();

		if (inOptions->mPassword) {
			strncpy(world->hw->mPassword, inOptions->mPassword, 31);
			world->hw->mPassword[31] = 0;
		} else {
			world->hw->mPassword[0] = 0;
		}

#ifdef __APPLE__
		world->hw->mInputStreamsEnabled = inOptions->mInputStreamsEnabled;
		world->hw->mOutputStreamsEnabled = inOptions->mOutputStreamsEnabled;
#endif
		world->hw->mInDeviceName = inOptions->mInDeviceName;
		world->hw->mOutDeviceName = inOptions->mOutDeviceName;
		hw->mMaxWireBufs = inOptions->mMaxWireBufs;
		hw->mWireBufSpace = 0;

		world->mRendezvous = inOptions->mRendezvous;

		world->mRestrictedPath = inOptions->mRestrictedPath;

		sc_SetDenormalFlags();

		if (world->mRealTime) {
			hw->mAudioDriver = SC_NewAudioDriver(world);
			hw->mAudioDriver->SetPreferredHardwareBufferFrameSize(
					inOptions->mPreferredHardwareBufferFrameSize
			);
			hw->mAudioDriver->SetPreferredSampleRate(
					inOptions->mPreferredSampleRate
			);

			if (inOptions->mLoadGraphDefs) {
				World_LoadGraphDefs(world);
			}

			if (!hw->mAudioDriver->Setup()) {
				scprintf("could not initialize audio.\n");
				return 0;
			}
			if (!hw->mAudioDriver->Start()) {
				scprintf("start audio failed.\n");
				return 0;
			}

#ifdef __APPLE__
			SC::Apple::disableAppNap();
#endif


		} else {
			hw->mAudioDriver = 0;
		}

		if (!scsynth::asioThreadStarted()){
			scsynth::startAsioThread();
		}

	} catch (std::exception& exc) {
		scprintf("Exception in World_New: %s\n", exc.what());
		World_Cleanup(world,true);
		return 0;
	} catch (...) {
	}
	return world;
}
Beispiel #5
0
int main(int argc, char* argv[])
{
    setlinebuf(stdout);

#ifdef _WIN32
#ifdef SC_WIN32_STATIC_PTHREADS
    // initialize statically linked pthreads library
    pthread_win32_process_attach_np();
#endif

    // initialize winsock
    WSAData wsaData;
	int nCode;
    if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) {
		scprintf( "WSAStartup() failed with error code %d.\n", nCode );
        return 1;
    }
#endif

	int udpPortNum = -1;
	int tcpPortNum = -1;

	WorldOptions options = kDefaultWorldOptions;

	for (int i=1; i<argc;) {
		if (argv[i][0] != '-' || argv[i][1] == 0 || strchr("utaioczblndpmwZrNSDIOMHvRUhPL", argv[i][1]) == 0) {
			scprintf("ERROR: Invalid option %s\n", argv[i]);
			Usage();
		}
		int j = i;
		switch (argv[j][1]) {
			case 'u' :
				checkNumArgs(2);
				udpPortNum = atoi(argv[j+1]);
				break;
			case 't' :
				checkNumArgs(2);
				tcpPortNum = atoi(argv[j+1]);
				break;
			case 'a' :
				checkNumArgs(2);
				options.mNumAudioBusChannels = atoi(argv[j+1]);
				break;
			case 'i' :
				checkNumArgs(2);
				options.mNumInputBusChannels = atoi(argv[j+1]);
				break;
			case 'o' :
				checkNumArgs(2);
				options.mNumOutputBusChannels = atoi(argv[j+1]);
				break;
			case 'c' :
				checkNumArgs(2);
				options.mNumControlBusChannels = atoi(argv[j+1]);
				break;
			case 'z' :
				checkNumArgs(2);
				options.mBufLength = NEXTPOWEROFTWO(atoi(argv[j+1]));
				break;
			case 'Z' :
				checkNumArgs(2);
				options.mPreferredHardwareBufferFrameSize = NEXTPOWEROFTWO(atoi(argv[j+1]));
				break;
			case 'b' :
				checkNumArgs(2);
				options.mNumBuffers = NEXTPOWEROFTWO(atoi(argv[j+1]));
				break;
			case 'l' :
				checkNumArgs(2);
				options.mMaxLogins = NEXTPOWEROFTWO(atoi(argv[j+1]));
				break;
			case 'n' :
				checkNumArgs(2);
				options.mMaxNodes = NEXTPOWEROFTWO(atoi(argv[j+1]));
				break;
			case 'd' :
				checkNumArgs(2);
				options.mMaxGraphDefs = NEXTPOWEROFTWO(atoi(argv[j+1]));
				break;
			case 'p' :
				checkNumArgs(2);
				options.mPassword = argv[j+1];
				break;
			case 'm' :
				checkNumArgs(2);
				options.mRealTimeMemorySize = atoi(argv[j+1]);
				break;
			case 'w' :
				checkNumArgs(2);
				options.mMaxWireBufs = atoi(argv[j+1]);
				break;
			case 'r' :
				checkNumArgs(2);
				options.mNumRGens = atoi(argv[j+1]);
				break;
			case 'S' :
				checkNumArgs(2);
				options.mPreferredSampleRate = (uint32)atof(argv[j+1]);
				break;
			case 'D' :
				checkNumArgs(2);
				options.mLoadGraphDefs = atoi(argv[j+1]);
				break;
			case 'N' :
#ifdef NO_LIBSNDFILE
				scprintf("NRT mode not supported: scsynth compiled without libsndfile\n");
				exit(0);
#endif
// -N cmd-filename input-filename output-filename sample-rate header-format sample-format
				checkNumArgs(7);
				options.mRealTime = false;
				options.mNonRealTimeCmdFilename    = strcmp(argv[j+1], "_") ? argv[j+1] : 0;
				options.mNonRealTimeInputFilename  = strcmp(argv[j+2], "_") ? argv[j+2] : 0;
				options.mNonRealTimeOutputFilename = argv[j+3];
				options.mPreferredSampleRate = (uint32)atof(argv[j+4]);
				options.mNonRealTimeOutputHeaderFormat = argv[j+5];
				options.mNonRealTimeOutputSampleFormat = argv[j+6];
				break;
#ifdef __APPLE__
			case 'I' :
				checkNumArgs(2);
				options.mInputStreamsEnabled = argv[j+1];
				break;
			case 'O' :
				checkNumArgs(2);
				options.mOutputStreamsEnabled = argv[j+1];
				break;
            case 'M':
#endif
			case 'H' :
				checkNumArgs(2);
				options.mInDeviceName = argv[j+1];
#ifdef __APPLE__
				if (i+1>argc || argv[j+2][0]=='-')
				{
					options.mOutDeviceName = options.mInDeviceName;
				}
				else
				{
					// If there's a second argument then the user wants separate I/O devices
					options.mOutDeviceName = argv[j+2];
					++i;
				}
#else
				options.mOutDeviceName = options.mInDeviceName; // Non-Mac platforms always use same device
#endif
				break;
			case 'L' :
				checkNumArgs(1);
#if (_POSIX_MEMLOCK - 0) >=  200112L
				options.mMemoryLocking = true;
#else
				options.mMemoryLocking = false;
#endif
				break;
			case 'v' :
				checkNumArgs(2);
				options.mVerbosity = atoi(argv[j+1]);
				break;
			case 'R' :
				checkNumArgs(2);
				options.mRendezvous = atoi(argv[j+1]) > 0;
				break;
			case 'U' :
				checkNumArgs(2);
				options.mUGensPluginPath = argv[j+1];
				break;
			case 'P' :
				checkNumArgs(2);
				options.mRestrictedPath = argv[j+1];
				break;
			case 'h':
			default: Usage();
		}
	}
	if (udpPortNum == -1 && tcpPortNum == -1 && options.mRealTime) {
		scprintf("ERROR: There must be a -u and/or a -t options, or -N for nonrealtime.\n");
		Usage();
	}
	if (options.mNumInputBusChannels + options.mNumOutputBusChannels > options.mNumAudioBusChannels) {
		scprintf("ERROR: number of audio bus channels < inputs + outputs.\n");
		Usage();
	}

	struct World *world = World_New(&options);
	if (!world) return 1;

	if (!options.mRealTime) {
#ifdef NO_LIBSNDFILE
		return 1;
#else
		int exitCode = 0;
		try {
			World_NonRealTimeSynthesis(world, &options);
		} catch (std::exception& exc) {
			scprintf("%s\n", exc.what());
			exitCode = 1;
		}
		return exitCode;
#endif
	}

	if (udpPortNum >= 0) {
		if (!World_OpenUDP(world, udpPortNum)) {
			World_Cleanup(world);
			return 1;
		}
	}
	if (tcpPortNum >= 0) {
		if (!World_OpenTCP(world, tcpPortNum, options.mMaxLogins, 8)) {
			World_Cleanup(world);
			return 1;
		}
	}

	if(options.mVerbosity >=0){
#ifdef NDEBUG
		scprintf("SuperCollider 3 server ready.\n");
#else
		scprintf("SuperCollider 3 server ready (debug build).\n");
#endif
	}
	fflush(stdout);

	World_WaitForQuit(world);


#ifdef _WIN32
    // clean up winsock
    WSACleanup();

#ifdef SC_WIN32_STATIC_PTHREADS
    // clean up statically linked pthreads
    pthread_win32_process_detach_np();
#endif // SC_WIN32_STATIC_PTHREADS
#endif // _WIN32

	return 0;
}