Beispiel #1
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 #2
0
void SC_JackDriver::Run()
{
	jack_client_t* client = mClient;
	World* world = mWorld;

#ifdef SC_JACK_USE_DLL
	mDLL.Update(secondsSinceEpoch(getTime()));
#if SC_JACK_DEBUG_DLL
	static int tick = 0;
	if (++tick >= 10) {
		tick = 0;
		scprintf("DLL: t %.6f p %.9f sr %.6f e %.9f avg(e) %.9f inc %.9f\n",
				 mDLL.PeriodTime(), mDLL.Period(), mDLL.SampleRate(),
				 mDLL.Error(), mDLL.AvgError(), mOSCincrement * kOSCtoSecs);
	}
#endif
#else
	HostTime hostTime = getTime();

	double hostSecs = secondsSinceEpoch(hostTime);
	double sampleTime = (double)(jack_frame_time(client) + jack_frames_since_cycle_start(client));

	if (mStartHostSecs == 0) {
		mStartHostSecs = hostSecs;
		mStartSampleTime = sampleTime;
	} else {
		double instSampleRate = (sampleTime - mPrevSampleTime) / (hostSecs - mPrevHostSecs);
		double smoothSampleRate = mSmoothSampleRate;
		smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate);
		if (fabs(smoothSampleRate - mSampleRate) > 10.) {
			smoothSampleRate = mSampleRate;
		}
		mOSCincrement = (int64)(mOSCincrementNumerator / smoothSampleRate);
		mSmoothSampleRate = smoothSampleRate;
#if 0
		double avgSampleRate = (sampleTime - mStartSampleTime)/(hostSecs - mStartHostSecs);
		double jitter = (smoothSampleRate * (hostSecs - mPrevHostSecs)) - (sampleTime - mPrevSampleTime);
		double drift = (smoothSampleRate - mSampleRate) * (hostSecs - mStartHostSecs);
#endif
	}

	mPrevHostSecs = hostSecs;
	mPrevSampleTime = sampleTime;
#endif

	try {
		mFromEngine.Free();
		mToEngine.Perform();
		mOscPacketsToEngine.Perform();

		int numInputs = mInputList->mSize;
		int numOutputs = mOutputList->mSize;
		jack_port_t **inPorts = mInputList->mPorts;
		jack_port_t **outPorts = mOutputList->mPorts;
		sc_jack_sample_t **inBuffers = mInputList->mBuffers;
		sc_jack_sample_t **outBuffers = mOutputList->mBuffers;

		int numSamples = NumSamplesPerCallback();
		int bufFrames = mWorld->mBufLength;
		int numBufs = numSamples / bufFrames;

		float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames;
		float *outBuses = mWorld->mAudioBus;
		int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs;
		int32 *outTouched = mWorld->mAudioBusTouched;

		int minInputs = sc_min(numInputs, (int)mWorld->mNumInputs);
		int minOutputs = sc_min(numOutputs, (int)mWorld->mNumOutputs);

		int bufFramePos = 0;

		// cache I/O buffers
		for (int i = 0; i < minInputs; ++i) {
			inBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(inPorts[i], numSamples);
		}

		for (int i = 0; i < minOutputs; ++i) {
			outBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(outPorts[i], numSamples);
		}

		// main loop
#ifdef SC_JACK_USE_DLL
		int64 oscTime = mOSCbuftime = (int64)((mDLL.PeriodTime() - mMaxOutputLatency) * kSecondsToOSCunits + .5);
// 		int64 oscInc = mOSCincrement = (int64)(mOSCincrementNumerator / mDLL.SampleRate());
		int64 oscInc = mOSCincrement = (int64)((mDLL.Period() / numBufs) * kSecondsToOSCunits + .5);
		mSmoothSampleRate = mDLL.SampleRate();
		double oscToSamples = mOSCtoSamples = mSmoothSampleRate * kOSCtoSecs /* 1/pow(2,32) */;
#else
		int64 oscTime = mOSCbuftime = OSCTime(hostTime) - (int64)(mMaxOutputLatency * kSecondsToOSCunits + .5);
		int64 oscInc = mOSCincrement;
		double oscToSamples = mOSCtoSamples;
#endif

		for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames) {
			int32 bufCounter = mWorld->mBufCounter;
			int32 *tch;

			// copy+touch inputs
			tch = inTouched;
			for (int k = 0; k < minInputs; ++k) {
				sc_jack_sample_t *src = inBuffers[k] + bufFramePos;
				float *dst = inBuses + k * bufFrames;
				for (int n = 0; n < bufFrames; ++n) {
					*dst++ = *src++;
				}
				*tch++ = bufCounter;
			}

			// run engine
			int64 schedTime;
			int64 nextTime = oscTime + oscInc;

			while ((schedTime = mScheduler.NextTime()) <= 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 >= world->mBufLength) world->mSampleOffset = world->mBufLength-1;

				SC_ScheduledEvent event = mScheduler.Remove();
				event.Perform();
			}

			world->mSampleOffset = 0;
			world->mSubsampleOffset = 0.f;
			World_Run(world);

			// copy touched outputs
			tch = outTouched;
			for (int k = 0; k < minOutputs; ++k) {
				sc_jack_sample_t *dst = outBuffers[k] + bufFramePos;
				if (*tch++ == bufCounter) {
					float *src = outBuses + k * bufFrames;
					for (int n = 0; n < bufFrames; ++n) {
						*dst++ = *src++;
					}
				} else {
					for (int n = 0; n < bufFrames; ++n) {
						*dst++ = 0.0f;
					}
				}
			}

			// advance OSC time
			mOSCbuftime = oscTime = nextTime;
		}
	} catch (std::exception& exc) {
		scprintf("%s: exception in real time: %s\n", kJackDriverIdent, exc.what());
	} catch (...) {
		scprintf("%s: unknown exception in real time\n", kJackDriverIdent);
	}

	double cpuUsage = (double)jack_cpu_load(mClient);
	mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU);
	if (cpuUsage > mPeakCPU || --mPeakCounter <= 0) {
		mPeakCPU = cpuUsage;
		mPeakCounter = mMaxPeakCounter;
	}

	mAudioSync.Signal();
}