# =============================================================================
# phaseshaper_elem.py -- Elementary phaseshapers and entities
# (section 2 of the paper)
#
# J.Kleimola, V.Lazzarini, J.Timoney, V.Valimaki,
# "PHASESHAPING OSCILLATOR ALGORITHMS FOR MUSICAL SOUND SYNTHESIS",
# SMC 2010, Barcelona, Spain, July 21-24, 2010.
#
# written using SciPy v0.7.1 and Matplotlib v0.99.1.1
# uses pylab for straight-forward matlab porting
# tab settings: 3
# =============================================================================
from scipy.signal import *
import matplotlib
import pylab

from phaseshapers import *		# phaseshaper implementations

f0 = 441.							# fundamental frequency
fs = 44100.							# sample rate
si = f0/fs							# phase increment
P = int(fs/f0)						# period
t = arange(0,4+si,si)			# time vector

# -----------------------------------------------------------------------------
# Synthesis
# -----------------------------------------------------------------------------

# -- synthesis parameters
a1 = 1.5		# scaling
a0 = 0		# offset
w1 = 0.5		# pulse width: varslope
w2 = 0.75	# pulse width: tilted triangle
m = 0.075	# ripple amount

# -- phaseshaped signals (implemented in phaseshapers.py)
phi = t % 1												# initial phase signal
ramp = g_ramp(phi,a1,a0)							# sect. 2.1
tri = g_tri(phi,a1,a0)								# sect. 2.2
vslope = phi + (phi-1)*(g_pulse(phi,w1,P))	# sect. 2.3
vtri = g_vtri(phi,w2,a1,a0,P)						# sect. 2.4
ripple = g_ripple(phi,m)							# sect. 2.5


# -----------------------------------------------------------------------------
# Plotting
# nothing really interesting here, we just plot the phase-aligned signals
# -----------------------------------------------------------------------------

fig = pylab.figure()
fig.canvas.set_window_title('Elementary Phaseshapers')
ticks = matplotlib.ticker.FixedLocator([0,0.5,1])

def preplot(id):
	id += 610
	p = pylab.subplot(id)
	p.grid(True)
	p.yaxis.set_major_locator(ticks)
	return p

def postplot(p, showticklabels=False):
	if not showticklabels:
		p.xaxis.set_ticklabels('')
	else:
		pylab.xlabel('Time (samples, f0=441 Hz, fs=44.1 kHz)')
	pylab.ylim(-0.1, 1.1)
	pylab.xlim(0,301)
	pylab.ylabel('Level')

# -- unipolar modulo counter
p1 = preplot(1)
p1.plot(phi, "k", lw=2)
postplot(p1)

# -- ramp
p2 = preplot(2)
p2.plot(ramp, "k", lw=2)
postplot(p2)

# -- triangle
p3 = preplot(3)
p3.plot(tri[50:351], "k", lw=2)
postplot(p3)

# -- pulse (variable slope ramp)
p4 = preplot(4)
p4.plot(vslope, "k", lw=2)
postplot(p4)

# -- tilted triangle
p5 = preplot(5)
d = int(w2*P)
p5.plot(vtri[d:d+301], "k", lw=2)
postplot(p5)

# -- ripples
p6 = preplot(6)
p6.plot(ripple, "k", lw=2)
postplot(p6,True)

pylab.subplots_adjust(left=0.17, bottom=0.10, right=0.80, top=0.93, wspace=0.20, hspace=0.11)
pylab.show()
