Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # encoding: utf-8
- # cython: profile=False
- # filename: _dissc.pyx
- '''
- Steve: Microtonal spectum optimizer? Cython Version
- @author: Jordan
- '''
- import numpy as np
- cimport numpy as np
- cimport cython
- import math as m
- from libc.math cimport exp as cExp
- # DTYPE = np.float
- ctypedef np.float_t DTYPE_t
- np.seterr(divide='raise', over='raise', under='ignore', invalid='raise')
- """
- I define a timbre as the following 2d numpy array:
- [[f0, a0], [f1, a1], [f2, a2]...] where f describes the frequency
- of the given partial and a is its amplitude from 0 to 1. Phase is ignored.
- """
- # MUST BE MODIFIED TO PROVIDE UNSORTED OUTPUT
- #Calculates the dissonance of a timbre applied to a scale.
- cpdef dissTimbreScale(np.ndarray[DTYPE_t,ndim=2] t,np.ndarray[DTYPE_t,ndim=1] s):
- cdef DTYPE_t currDiss
- currDiss = 0.0
- cdef unsigned int i
- for i in range(s.size):
- currDiss += diss1Timbre(np.append(t[:,0],s[i]*t[:,0]), np.append(t[:,1],t[:,1]))
- return currDiss
- cdef inline DTYPE_t float_min(DTYPE_t a, DTYPE_t b): return a if a <= b else b
- cdef inline DTYPE_t float_abs(DTYPE_t a): return a if a >= 0 else -a
- # MODIFIED TO ACCEPT 2 1D UNSORTED INPUTS
- # Calculates the inherent dissonance of one timbres of the above form
- cpdef DTYPE_t diss1Timbre(np.ndarray[DTYPE_t,ndim=1] f, np.ndarray[DTYPE_t,ndim=1] a):
- cdef DTYPE_t runningDiss1
- runningDiss1 = 0.0
- cdef unsigned int length = f.size
- cdef unsigned int i
- cdef unsigned int j
- cdef DTYPE_t f1
- cdef DTYPE_t f2
- cdef DTYPE_t a1
- cdef DTYPE_t a2
- cdef DTYPE_t s
- for i in range(length):
- for j in range(i+1, length):
- if f[j] >= f[i]:
- f1 = f[i]
- f2 = f[j]
- a1 = float_abs(a[i])
- a2 = float_abs(a[j])
- else:
- f2 = f[i]
- f1 = f[j]
- a2 = float_abs(a[i])
- a1 = float_abs(a[j])
- s = 0.24/(0.021*f1 + 19)
- runningDiss1 += (float_min(a1,a2) * (cExp(-3.5*s*(f2-f1)) - cExp(-5.75*s*(f2-f1)) ) )
- return runningDiss1
- # MODIFIED TO USE pDTS(freqs, amps, scale, i)
- # Calculates the gradient of the dissonance curve (does not consider amplitudes)
- cpdef np.ndarray[DTYPE_t, ndim=1] gradTimbreScale(np.ndarray[DTYPE_t, ndim=2] t,np.ndarray[DTYPE_t,ndim=1] s):
- cdef np.ndarray[DTYPE_t, ndim=1] df
- df = np.array([])
- cdef unsigned int i
- for i in range(1, t.shape[0]):
- df = np.append(df,partialDerivativeTimbreScale(t[:,0],t[:,1],s,i))
- return df
- #MODIFIED TO ACCEPT ARGS (f, a, s, i)
- #Calculates an individual partial derivative of the dissonance curve
- cpdef DTYPE_t partialDerivativeTimbreScale(np.ndarray[DTYPE_t, ndim=1] f, np.ndarray[DTYPE_t, ndim=1] a, np.ndarray[DTYPE_t,ndim=1] s, unsigned int differentiatedFreq):
- length = f.size
- assert differentiatedFreq < length
- cdef np.ndarray[DTYPE_t, ndim=1] d
- d = np.array([])
- cdef unsigned int i
- for i in range(length):
- if i == differentiatedFreq:
- d = np.append(d,1)
- else:
- d = np.append(d,0)
- # Up to this point, all we need to go is add up all of the grad1Timbre( union([f, a, d], [f*s[i], a, d*s[i]]) )
- cdef DTYPE_t currGrad
- currGrad = 0.0
- for i in range(s.size):
- currGrad += grad1Timbre(np.append(f, f*s[i]), np.append(a, a), np.append(d, d*s[i]) )
- return currGrad
- #MODIFIED TO ACCEPT 3 1D INPUTS, MODIFIED TO ACCEPT UNSORTED
- #A component of partialDerivativeTimbreScale. Not all that useful by itself.
- cdef DTYPE_t grad1Timbre(np.ndarray[DTYPE_t,ndim=1] f, np.ndarray[DTYPE_t,ndim=1] a, np.ndarray[DTYPE_t,ndim=1] d):
- cdef DTYPE_t runningGrad1
- runningGrad1 = 0.0
- cdef unsigned int length = f.size
- cdef unsigned int i
- cdef unsigned int j
- cdef unsigned int ii
- cdef unsigned int jj
- # v Below: For Optimization Attempt
- cdef DTYPE_t sbase
- cdef DTYPE_t sbasesq
- cdef DTYPE_t df
- # ^ Above: For Optimization attempt
- for i in range(length):
- for j in range(i+1,length):
- if not( d[i] < 0.5 and d[j] < 0.5 ):
- if f[j] >= f[i]:
- (ii,jj) = (i,j)
- else:
- (ii,jj) = (j,i)
- if (d[ii] > .5) and (d[jj] < .5):
- # runningGrad1 += float_min(float_abs(a[ii]),float_abs(a[jj]))*gradF1(f[ii],f[jj])*d[ii]
- # Below: For Optimization Attempt
- sbase = 1./(0.021*f[ii] + 19)
- sbasesq = sbase*sbase
- df = f[jj]-f[ii]
- runningGrad1 += float_min(float_abs(a[ii]),float_abs(a[jj]))*(cExp(-0.84*df*sbase)*(0.01764*df*sbasesq + 0.84*sbase) - cExp(-1.38*df*sbase)*(0.02898*df*sbasesq + 1.38*sbase))*d[ii]
- elif (d[ii] < .5) and (d[jj] > .5):
- # runningGrad1 += float_min(float_abs(a[ii]),float_abs(a[jj]))*gradF2(f[ii],f[jj])*d[jj]
- # Below: For Optimization Attempt
- sbase = 1./(0.021*f[ii] + 19)
- df = f[jj]-f[ii]
- runningGrad1 += float_min(float_abs(a[ii]),float_abs(a[jj]))*(1.38*sbase*cExp(-1.38*df*sbase) - 0.84*sbase*cExp(-0.84*df*sbase))*d[jj]
- else:
- # runningGrad1 += float_min(float_abs(a[ii]),float_abs(a[jj]))*(d[ii]*gradF1(f[ii],f[jj]) + d[jj]*gradF2(f[ii],f[jj]))
- # Below: For Optimization Attempt
- sbase = 1./(0.021*f[ii] + 19)
- sbasesq = sbase*sbase
- df = f[jj]-f[ii]
- runningGrad1 += float_min(float_abs(a[ii]),float_abs(a[jj]))*(d[ii]*(cExp(-0.84*df*sbase)*(0.01764*df*sbasesq + 0.84*sbase) - cExp(-1.38*df*sbase)*(0.02898*df*sbasesq + 1.38*sbase)) + d[jj]*(1.38*sbase*cExp(-1.38*df*sbase) - 0.84*sbase*cExp(-0.84*df*sbase)))
- return runningGrad1
- # The following code is for calculating the amplitude gradients.
- # Calculates the gradient of the dissonance curve (does not consider amplitudes)
- cpdef np.ndarray[DTYPE_t, ndim=1] aGradTimbreScale(np.ndarray[DTYPE_t, ndim=2] t,np.ndarray[DTYPE_t,ndim=1] s):
- cdef np.ndarray[DTYPE_t, ndim=1] df
- df = np.array([])
- cdef unsigned int i
- for i in range(0, t.shape[0]):
- df = np.append(df,aPartialDerivativeTimbreScale(t[:,0],t[:,1],s,i))
- return df
- #Calculates the amplitude partial derivatives of the dissonance curve.
- cpdef DTYPE_t aPartialDerivativeTimbreScale(np.ndarray[DTYPE_t, ndim=1] f, np.ndarray[DTYPE_t, ndim=1] a, np.ndarray[DTYPE_t,ndim=1] s, unsigned int differentiatedAmp):
- length = f.size
- assert differentiatedAmp < length
- cdef np.ndarray[DTYPE_t, ndim=1] d
- d = np.array([])
- cdef unsigned int i
- for i in range(length):
- if i == differentiatedAmp:
- d = np.append(d,1)
- else:
- d = np.append(d,0)
- # Up to this point, all we need to go is add up all of the aGrad1Timbre( union([f, a, d], [f*s[i], a, d) )
- cdef DTYPE_t currGrad
- currGrad = 0.0
- for i in range(s.size):
- currGrad += aGrad1Timbre(np.append(f, f*s[i]), np.append(a, a), np.append(d, d) )
- return currGrad
- #A component of aPartialDerivativeTimbreScale. Not all that useful by itself.
- cdef DTYPE_t aGrad1Timbre(np.ndarray[DTYPE_t,ndim=1] f, np.ndarray[DTYPE_t,ndim=1] a, np.ndarray[DTYPE_t,ndim=1] d):
- cdef DTYPE_t runningGrad1
- runningGrad1 = 0.0
- cdef unsigned int length = f.size
- cdef unsigned int i
- cdef unsigned int j
- cdef unsigned int ii
- cdef unsigned int jj
- # v Below: For Optimization Attempt
- cdef DTYPE_t s
- # ^ Above: For Optimization attempt
- for i in range(length):
- for j in range(i+1,length):
- if not( d[i] < 0.5 and d[j] < 0.5 ):
- if f[j] >= f[i]:
- (ii,jj) = (i,j)
- else:
- (ii,jj) = (j,i)
- if ( d[ii] < 0.5 and d[jj] > 0.5 ):
- s = 0.24/(0.021*f[ii] + 19)
- runningGrad1 += float_dMinAbs(a[jj], a[ii]) * (cExp(-3.5*s*(f[jj]-f[ii])) - cExp(-5.75*s*(f[jj]-f[ii])) )
- elif( d[ii] > 0.5 and d[jj] < 0.5):
- s = 0.24/(0.021*f[ii] + 19)
- runningGrad1 += float_dMinAbs(a[ii], a[jj]) * (cExp(-3.5*s*(f[jj]-f[ii])) - cExp(-5.75*s*(f[jj]-f[ii])) )
- else:
- assert a[ii] == a[jj]
- s = 0.24/(0.021*f[ii] + 19)
- runningGrad1 += float_sign(a[ii]) * (cExp(-3.5*s*(f[jj]-f[ii])) - cExp(-5.75*s*(f[jj]-f[ii])) )
- return runningGrad1
- cdef inline DTYPE_t float_dMinAbs(DTYPE_t diffd, DTYPE_t notDiffd): return 0 if float_abs(notDiffd) < float_abs(diffd) else float_sign(diffd)
- cdef DTYPE_t float_sign(DTYPE_t t):
- if t > 0: return 1
- elif t < 0: return -1
- else: return 0
- # The following is solely for external use:
- # Calculates the dissonance of two partials of the form [f,a]
- cpdef DTYPE_t diss2Partials(np.ndarray[DTYPE_t,ndim=1] p1, np.ndarray[DTYPE_t,ndim=1] p2):
- cdef DTYPE_t f1 = p1[0]
- cdef DTYPE_t f2 = p2[0]
- cdef DTYPE_t a1 = float_abs(p1[1])
- cdef DTYPE_t a2 = float_abs(p2[1])
- cdef DTYPE_t s
- s = 0.24/(0.021*f1 + 19)
- return (float_min(a1,a2) * (cExp(-3.5*s*(f2-f1)) - cExp(-5.75*s*(f2-f1)) ) )
- # NEEDS FIXING
- # Calculates the dissonance of two timbres
- cpdef DTYPE_t diss2Timbres(np.ndarray[DTYPE_t,ndim=2] t1, np.ndarray[DTYPE_t,ndim=2] t2):
- return diss1Timbre(np.append(t1[:,0],t2[:,0]), np.append(t1[:,1],t2[:,1]) )
- #Modified to reflect adjusted derivative-multiplier for gradmatrices.
- cpdef np.ndarray[DTYPE_t,ndim=2] transpose(np.ndarray[DTYPE_t,ndim=2] t, DTYPE_t ratio):
- if t.shape[1] == 2:
- return np.dot(t, np.array([[ratio,0],[0,1]]))
- else:
- return np.dot(t, np.array([[ratio,0,0],[0,1,0],[0,0,ratio]]))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement