#!/usr/bin/env python

"""Acoustic Description Vector for Speech

Usage: s_slope [flags]
Flags: -f FFF opens file FFF for reading.
	-c XXX  selects column XXX (either a data name or an integer).
	-o FFF  sets the output file.
	-dt #.##   Sets the interval for calculating the output.

It takes a local spectrum,
bins it onto the Bark scale,
converts to perceptual loudness (via **E).
Then, it computes a measure of how far you can go
from each point before the spectrum changes too much.
"""

import math
import numpy
# from gmisclib import die
from gmisclib import cache as CC
from gmisclib import gpkmisc
from gmisclib import erb_scale

from gpk_voicing import percep_spec as PS
from gpk_voicing import fv_misc as FVM
from gpk_voicing import voice_misc as VM
SillyWidthException = FVM.SillyWidthException
NSV = 0.75

_wincache = {}
_WIN_CACHE_SIZE = 20
def win(n):
	key = n
	if len(_wincache) > _WIN_CACHE_SIZE:
		_wincache.pop()
	if key in _wincache:
		return _wincache[key]
	Norm = 1
	if not n > 0:
		raise SillyWidthException, n
	def inner_window(n, k, norm=2):
		assert k==0
		opn0 = VM.cont_kernel_c(n)
		w = opn0.P(0)
		# die.info("win.inner_window.w.shape=%s w0.shape=%s" % (w.shape, w0.shape))
		if norm > 0:
			numpy.divide(w, (numpy.absolute(w)**norm).sum()**(1.0/Norm), w)
		return w
	rv = VM.cont_kernel(n, 0, norm=Norm, kernel=inner_window)
	_wincache[key] = rv
	return rv


def avg_spec(b):
	ALPHA = -1.0
	E = 0.333
	f = erb_scale.erb_to_f(b)/1000.0
	bw = erb_scale.ebw(b)/100.0
	return (f**ALPHA * bw)**E


def feature_vec_guts(data, dt, Dt, do_irx=False,
		LF=1.0, fdif2=0.0, fdif2x=0.0, Nsv=NSV,
		cache_info=None, ps_cache_info=None
		):
	FORMANT_LOW = erb_scale.f_to_erb(200.0)
	FORMANT_HIGH = erb_scale.f_to_erb(6000.0)
	assert Dt > 0.0 and float(Dt)>0.0
	bmin = FORMANT_LOW - 0.5*FVM.DB
	bmax = FORMANT_HIGH + 0.5*FVM.DB
	width = 0.04 * LF / Dt
	if do_irx:
		width = max(1, int(round(width)))
	cs = win(width)
	css = cs.sum()
	f_kernel = numpy.array([-fdif2x, -fdif2, 1+2*fdif2+2*fdif2x, -fdif2, -fdif2x])

	if ps_cache_info is not None:
		ic_i = ps_cache_info
	else:
		ic_i = cache_info

	t0, neural, ectrs, nneural, nectrs =	\
		FVM.normalize_neural(data, dt, Dt, bmin=bmin, bmax=bmax, db=FVM.DB,
						do_mod=0, do_dissonance=False,
						PlompBouman=False,
						norm_kernel=cs/css, Nsv=Nsv, t_kernel=cs/css,
						f_kernel=f_kernel,
						cache_info=ic_i
						)
	o = []
	descr = []
	nsum = numpy.zeros((neural.shape[1],))
	nna = 0
	avss = 0.0
	for (i, e) in enumerate(ectrs):
		if e['type']=='band' and FORMANT_LOW < e['erb'] < FORMANT_HIGH:
			numpy.add(nsum, neural[i,:], nsum)
			avss += avg_spec(e['erb'])
			nna += 1
	dtmp = e.copy()
	del dtmp['erb']
	del dtmp['fc']
	dtmp['type'] = 'loudness'
	dtmp['width'] = width
	dtmp['Kentropy'] = gpkmisc.entropy(numpy.absolute(cs))
	dtmp['Fentropy'] = math.log(nna)
	dtmp['t_symmetry'] = 1
	dtmp['id'] = '%s:%d' % (dtmp['type'], width)
	descr.append(dtmp)
	o.append(nsum/nna)
	for (i, e) in enumerate(ectrs):
		if e['type']=='band' and FORMANT_LOW < e['erb'] < FORMANT_HIGH:
			tmp = neural[i,:] - nsum * (avg_spec(e['erb'])/avss)
			# pylab.plot(tmp)
			# print 'RMS', math.sqrt(Num.square(tmp).sum()/tmp.shape[0])
			dtmp = e.copy()
			dtmp['type'] = 'vowel'
			dtmp['width'] = width
			dtmp['Kentropy'] = gpkmisc.entropy(numpy.absolute(cs))
			dtmp['Fentropy'] = 0.0
			dtmp['t_symmetry'] = 1
			dtmp['a_scaling'] = 1
			# pylab.title('vowel %s' % dtmp['id'])
			# pylab.figure()
			o.append(tmp)
			dtmp['id'] = '%s:%d:%.1f' % (dtmp['type'], width, e['erb'])
			descr.append( dtmp )
	assert len(descr)==len(o), "Descriptor mismatch"
	return (o, descr, Dt, t0)


def feature_vec(data, dt, DT, LF=1.0, Nsv=NSV, fdif2=0.0, fdif2x=0.0,
			do_irx=False, cache_info=None, ps_cache_info=None):
	o = None
	ci = None
	if cache_info is not None:
		assert isinstance(cache_info, CC.cache_info)
		ci = cache_info.addinfo(dt, DT, LF, Nsv, fdif2, fdif2x, do_irx, 'fv201105-2')
		try:
			o = ci.load()
		except ci.Errors:
			pass
	if o is None:
		o = feature_vec_guts(data, dt, DT, LF=LF, Nsv=Nsv,
					do_irx=do_irx, fdif2=fdif2, fdif2x=fdif2x,
					cache_info=cache_info, ps_cache_info=ps_cache_info
					)
		if ci is not None:
			ci.bg_dump(o)
	return o




Opt_text = """
# RUN 1
# summarize_logs -uid UID -fromstart -best logS_advLImMDREf,-fv201102_4.av
# len(currentlist)= 26 tail= 0.0 nsamp= 26
# max(logS_advLImMDREf,-fv201102_4.av) = 376.74
#  samples used = 1 filename= logS_advLImMDREf,-fv201102_4.av
376.74 logp
# n= 39
26.031 Scale,vowel:.*:10.4
0.650176 Scale,vowel:.*:11.1
0.994825 Scale,vowel:.*:11.9
3.65683 Scale,vowel:.*:12.6
12.2741 Scale,vowel:.*:13.3
0.23901 Scale,vowel:.*:14.0
1.53292 Scale,vowel:.*:14.7
7.75427 Scale,vowel:.*:15.4
0.784154 Scale,vowel:.*:16.1
3.23822 Scale,vowel:.*:16.8
3.84116 Scale,vowel:.*:17.5
12.1566 Scale,vowel:.*:18.2
6.9634 Scale,vowel:.*:18.9
4.90421 Scale,vowel:.*:19.6
3.72337 Scale,vowel:.*:20.3
0.0150866 Scale,vowel:.*:21.0
6.29358 Scale,vowel:.*:21.8
3.50677 Scale,vowel:.*:22.5
1.94812 Scale,vowel:.*:23.2
17.1486 Scale,vowel:.*:23.9
1.76959 Scale,vowel:.*:24.6
1.27658 Scale,vowel:.*:25.3
0.439394 Scale,vowel:.*:26.0
0.185877 Scale,vowel:.*:26.7
12.2699 Scale,vowel:.*:6.2
10.2536 Scale,vowel:.*:6.9
5.84667 Scale,vowel:.*:7.6
3.5585 Scale,vowel:.*:8.3
0.405896 Scale,vowel:.*:9.0
2.4074 Scale,vowel:.*:9.7
2.94796 lf,lf
-0.302882 norm,fdif2
1.28682 norm,nsv
4.824 norm,tdif
0.16849 norm,tdif2
#
# RUN 2
#  summarize_logs -best -fromstart -uid UID logS_advLImMDREf,-fv201102_2.av
# len(currentlist)= 20 tail= 0.0 nsamp= 20
# max(logS_advLImMDREf,-fv201102_2.av) = 348.56
#  samples used = 1 filename= logS_advLImMDREf,-fv201102_2.av
348.56 logp
# n= 39
0.367388 Scale,vowel:.*:10.4
0.668657 Scale,vowel:.*:11.1
3.73234 Scale,vowel:.*:11.9
9.59746 Scale,vowel:.*:12.6
45.2418 Scale,vowel:.*:13.3
12.4549 Scale,vowel:.*:14.0
5.18612 Scale,vowel:.*:14.7
8.10955 Scale,vowel:.*:15.4
16.1181 Scale,vowel:.*:16.1
 8.2858 Scale,vowel:.*:16.8
 6.15389 Scale,vowel:.*:17.5
 2.11999 Scale,vowel:.*:18.2
 8.04381 Scale,vowel:.*:18.9
 3.69372 Scale,vowel:.*:19.6
 0.302413 Scale,vowel:.*:20.3
 3.42239 Scale,vowel:.*:21.0
 18.7842 Scale,vowel:.*:21.8
 7.25486 Scale,vowel:.*:22.5
 0.435129 Scale,vowel:.*:23.2
 2.46633 Scale,vowel:.*:23.9
 0.828264 Scale,vowel:.*:24.6
 0.604598 Scale,vowel:.*:25.3
 15.0723 Scale,vowel:.*:26.0
 2.12652 Scale,vowel:.*:26.7
 0.258391 Scale,vowel:.*:6.2
 3.00883 Scale,vowel:.*:6.9
 19.7981 Scale,vowel:.*:7.6
 0.098635 Scale,vowel:.*:8.3
 0.144953 Scale,vowel:.*:9.0
 21.9714 Scale,vowel:.*:9.7
 3.96667 lf,lf
 -0.523753 norm,fdif2
 0.703901 norm,nsv
 4.49354 norm,tdif
 -0.147517 norm,tdif2
4000 FORMANT_HIGH
"""

Scale = FVM.scale_xform(Opt_text,
			name="2011-04-17 optimization on mace and cayenne:/home/gpk/ItakuraSaitoDistance/IS-DTW/logS_advLImMDREf,-fv201102/{1,2}"
			)
