[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [sc-dev] Ugen creation q

On Tuesday, January 7, 2003, at 02:49 PM, Casey Basichis wrote:

Here are some questions in going through LFPulse, I
also looked at Latch which was clear.

//phase goes between 0 and 1?

^this.multiNew('audio', freq, iphase, width).madd(mul,
// This copies, the arguments to the variables in the

The SC classes don't "link" to the C code at all. Their only purpose is to write the .scsynthdef file. You just need to make sure that your C ugen has the same name and uses the same number of inputs and outputs as your SC class defines.

void LFPulse_next_a(LFPulse *unit, int inNumSamples)
	float *out = ZOUT(0);
	float *freq = ZIN(0); // Not sure what this does

IN,OUT, and their variations get pointers to the input and output data.
ZIN and ZOUT are predecremented by one in anticipation that you'll use preincrement indexing (*++ptr) which is the fastest way to stream through scalar data on powerpc. ZIN0 and ZOUT0 do not return pointers to data, but instead return a single floating point value. This is used when the input is only responded to at control rate.

The LFPulse_next_a function is used when the frequency control input is audio rate. The LFPulse_next_k function is used when the frequency control input is control rate.
that is why we have above: float *freq = ZIN(0);

	float nextDuty = ZIN0(2); // Not sure what this does
				  // ZIN0 means only get at each buffer?

The duty cycle is only updated at the end of the cycle. Otherwise you can get noisy stuttering if the duty cycle changes during the cycle.

	float duty = unit->mDuty;	
	float freqmul = unit->mFreqMul;
	float phase = unit->mPhase;
		float z;
		if (phase >= 1.f) {
			phase -= 1.f; // Keeps the phase in a 0-1 range?


			duty = unit->mDuty = nextDuty; // nextDuty, ZIN?

end of cycle. update the duty cycle.

			// output at least one sample from the opposite
			z = duty < 0.5 ? 1.f : 0.f; // This i dont get.

If the duty cycle is very small, it is possible that no impulse would be output at all if the phase never fell within the very thin region where the wave is supposed to be one. The code above guarantess that for small duty cycles we always output at least 1 sample of 1 at the end of the cycle. Conversely if the duty cycle is very large there might never be a zero output, and the above code guarantees that at least one zero is output.

		} else {
			z = phase < duty ? 1.f : 0.f; // I get this.
		phase += ZXP(freq) * freqmul; // increment freq
					      // (whatever that is) multiply by
					      // frequency add to phase?

The multiply converts the frequency to the proper phase increment.
ZXP is a macro that expands to *++(freq). The idea for using macros is that they are written in such a way that I can change them with a #define so that I can use another indexing scheme such as post increment without rewriting all of my code.

		ZXP(out) = z;

	unit->mPhase = phase;

--- james mccartney   james@xxxxxxxxxxxxxx   <http://www.audiosynth.com>
SuperCollider - a real time synthesis programming language for the PowerMac.