<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<?xml-stylesheet href="./_c74_tut.xsl" type="text/xsl"?>

<chapter name="MSP Sampling Tutorial 5: Waveshaping">
	<previous module="msp"  name="07_samplingchapter04"></previous>
	<next module="msp" name="07_samplingchapter06"></next>
	<parent name="00_mspindex">MSP Tutorials</parent>

<setdocpatch name="05sWaveshapingSynthesis" patch="05sWaveshapingSynthesis.maxpat"/>

<h1>
	Synthesis Tutorial 5: Waveshaping
</h1>

	<p>
		In this tutorial, we'll look at a latent (but very useful)
		attribute of samples, which is that they can be used as lookup
		tables to transform the shape of other waveforms. This process
		is called <i>waveshaping</i>, and is used in synthesis to generate
		complex spectra from a sinusoidal input. It's also the basic signal
		processing technique behind many types of amplitude-dependent distortion,
		and can be used to model the non-linearities of different kinds of
		amplifier.
	</p>


	<h2>
		Using a stored wavetable as a transfer function
	</h2>

	<p>
		Take a look at the tutorial patcher. The basic sound-generating
		circuit in the upper-left of the patcher should look familiar, with
		one new object (<o>lookup~</o>) inserted into the chain. We have
		a <o>cycle~</o> object going through an amplifier (<o>*~</o>) to
		the <o>ezdac~</o>.
	</p>

		<bullet>

		Turn on the <o>ezdac~</o> object and adjust the <o>number</o> box
		labeled <m>amplitude</m>. You should hear a sine wave at <m>220</m> Hz.
	</bullet>

	<p>
		The new object in this signal chain at first seems to be doing
		nothing, and in terms of what we hear, it isn't... yet.
		The <o>lookup~</o> object interprets a piece of sample memory
		stored in a <o>buffer~</o> object as a <i>transfer function</i>,
		with the beginning of the sample used representing input values
		of <m>-1</m> and the end of the sample used representing values
		of <m>1.</m> Incoming values are scaled across this <i>X</i> axis,
		and the resulting audio comes from the corresponding values along
		the <i>Y</i> axis.
	</p>

	<p>
		In our patch, the <o>buffer~</o> named <m>waveform</m> is serving as
		a <i>lookup table</i> (or transfer function) for the incoming sine
		wave. When the <o>cycle~</o> object generates a <m>-1</m>, for
		example, <i>whatever sample value</i> is at the beginning of
		the <o>buffer~</o> comes out of the <o>lookup~</o> object. When
		our <o>cycle~</o> hits <m>1</m>, the <o>lookup~</o> object reads
		from the end of the <o>buffer~</o> to find its outgoing sample.
	</p>

		<bullet>

		Double-click the <o>buffer~</o> object at the bottom of the tutorial
		patcher. Notice that the waveform loaded in is a simple ramp. Because
		our waveshape (the sample in the <o>buffer~</o> is a linear ramp with
		the beginning of the sample at <m>-1</m> and the end at <m>1</m>,
		our <o>cycle~</o> object sounds unchanged.
	</bullet><br/>

	<p>
		The <o>lookup~</o> object takes three possible arguments: the first
		is the name of the <o>buffer~</o> to use as its waveshape; the second
		and third are the start and end points (in <i>samples</i> to use
		within the <o>buffer~</o> as the boundaries of the transfer function.
		Because we want our <o>buffer~</o> to be exactly <m>512</m> samples
		long in our patcher, we created it with the argument of <m>10.66667</m>
		milliseconds. How did we get this number. At the right of the patcher,
		you can see the <o>sampstoms~</o> object, which allows us to convert
		from samples to milliseconds.
	</p>

	<h2>
		The <o>waveform~</o> object
	</h2>

	<p>
		Look at the graphical object at the top of the tutorial patcher.
		Notice that it contains the same shape that is loaded into our <o>buffer~</o>.
		The <o>waveform~</o> object allows us to view, select regions of, and
		directly modify the contents of a <o>buffer~</o> with a drawing tool.
	</p>

		<bullet>

		Using your mouse, doodle in the <o>waveform~</o> object's display.
		Notice how different shapes affect the output sound. Try drawing
		smooth curves, then jagged ones, then ones with lots of plateaus
		(straight horizontal lines). Notice that even slight variations
		in the shape have tremendous impact on the spectrum generated by
		the <o>lookup~</o> object.
	</bullet>

	<p>
		The <o>waveform~</o> object is operating in <m>draw</m> mode, where
		you can literally modify a sample loaded into a <o>buffer~</o> with
		your mouse. Other modes allow you to select regions, the boundaries
		of which can be used as Max messages for other objects.
	</p>

	<h2>
		Setting sample values with Max messages: <o>peek~</o>
	</h2>

		<bullet>

		Click on the <o>button</o> labeled <m>A</m> in the tutorial patcher.
		Our waveshape (and our sound) should return to normal.
	</bullet><br/>

	<p>
		The way we got the default waveshape in our tutorial patcher is through the logic controlled by the <o>uzi</o> below the <o>button</o> labeled <m>A</m>. The <o>uzi</o> object, you may recall, generates a lot of data instantly depending on its argument. The right outlet of the object generates a numeric ramp from <m>1</m> to its argument. We've subtracted <m>1</m> from that value to generate a stream of Max numbers from <m>0</m> to <m>511</m> when you click the <o>button</o>. These numbers are then sent to the middle and left inlets of a <o>peek~</o> object. The middle inlet receives a number that has been scaled into the range of <m>-1</m> to <m>1</m> (via the <o>scale</o> object), then the left inlet receives the number unchanged. The <o>peek~</o> object allows us to manually set the sample values within a <o>buffer~</o> via Max messages. The left inlet (which is "hot", and actually performs the operation) sets <i>which</i> sample we're changing to the most recent value received by the middle inlet. In section <m>A</m>, the <o>uzi</o> object generates a stream of numbers that fill our entire <o>buffer~</o> with an ascending ramp, e.g. </p>

	<p>
		Sample Value<br />
		0 -1.<br />
		1 -0.996086<br />
		2 -0.992172<br />
		3 -0.988258<br />
		4 -0.984344<br />
		5 -0.980431<br />
		...<br />
		508 0.988258<br />
		509 0.992172<br />
		510 0.996086<br />
		511 1.<br />
	</p>

	<h2>
		For the math geeks in the room
	</h2>

		<bullet>

		Click on the other <o>button</o> objects in the patcher
		(labeled <m>B</m>, <m>C</m>, and <m>D</m>). Notice how the
		waveshape in the <o>buffer~</o> changes, and note how it affects
		the sound. Each waveshape seems to <i>multiply</i> the frequency
		of the sound generated by the <o>cycle~</o> object. The logic
		at <m>B</m> makes our <m>220</m> Hz wave sound at <m>440</m>,
		<m>C</m> at <m>660</m>, and <m>D</m> at <m>880</m>.
	</bullet>

	<p>
		The equations that the <o>expr</o> objects are doing in these parts
		of the patch generate special types of transfer functions
		called <i>Chebyshev polynomials</i>. These functions are interesting
		in that they have the ability to transform sinusoidal input to
		different harmonic multiples. The four Chebyshev polynomials in our
		tutorial are:
	</p>

	<p>
		y = x (<o>uzi</o> object <m>A</m>, leaves the input unchanged)<br />
		y = 2*x^2-1 (<o>uzi</o> object <m>B</m>, doubles the frequency)<br />
		y = 4*x^3-3*x (<o>uzi</o> object <m>C</m>, triples the frequency)<br />
		y = 8*x^4-8*x^3+1 (<o>uzi</o> object <m>D</m>, quadruples the frequency)<br />
	</p>

	<p>
		In practice, what they do looks like this:
	</p>

<illustration><img src="images/samplingchapter05a.png"/></illustration>

	<caption>
		<i>Our four Chebyshev polynomials and their effect on a cosine input</i>
	</caption>

		<bullet>

		Click on the <m>read</m> messages in patcher area <m>E</m>. These will
		load 512-sample audio files into our waveshape <o>buffer~</o>. Notice
		their effect on the sound:
	</bullet>

<illustration><img src="images/samplingchapter05b.png"/></illustration>

	<caption>
		<i>Waveshaping through gtr512.aiff and blp512.aiff, respectively.</i>
	</caption>

		<bullet>

		Now that you know a bit more about the expected behavior of the
		waveshaping distortion, return to drawing in the <o>waveform~</o> object
		to see what kind of results you can achieve.
	</bullet>

	<h2>
		Summary
	</h2>

	<p>
		The <o>lookup~</o> object allows you to use a <o>buffer~</o> as a
		transfer function to perform a process called <i>waveshaping</i>
		on an input sound. Different shapes cause different distortions
		of the spectra and can create very complex timbres. The <o>waveform~</o>
		object allows you to directly view and modify the contents of an
		MSP <o>buffer~</o> using your mouse, and the <o>peek~</o> object
		allows you to set sample values programmatically with Max messages.
		Some transfer functions (such as Chebyshev polynomials) have special
		properties when used as a waveshaping function on a sinusoidal input.
	</p>

	<seealsolist>
		<seealso name="lookup~">Transfer function lookup table</seealso>

		<seealso name="waveform~">buffer~ viewer and editor</seealso>

		<seealso name="peek~">Read and write sample values</seealso>

<seealso name="sampstoms~">Convert time from samples to milliseconds</seealso>
	</seealsolist>

</chapter>


