resonance.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import statistics
  2. import json
  3. clamp = lambda minimum, maximum, value : max(minimum, min(value, maximum))
  4. def compute_resonance(data, weights=[2/5, 2/5, 1/5]):
  5. assert(abs(sum(weights) - 1) < .01)
  6. data['mean'] = {'F': []}
  7. data['stdev'] = {'F': []}
  8. # Remove outliers (TODO: Make configurable)
  9. for i in range(4):
  10. mean = statistics.mean([
  11. phoneme['F'][i] for phoneme in data['phones']
  12. if phoneme['F'][i] != None
  13. ])
  14. stdev = statistics.stdev([
  15. phoneme['F'][i] for phoneme in data['phones']
  16. if phoneme['F'][i] != None
  17. ])
  18. data['mean']['F'].append(mean)
  19. data['stdev']['F'].append(stdev)
  20. for p in range(len(data['phones'])):
  21. if not data['phones'][p]['F'][i]:
  22. continue
  23. if abs(data['phones'][p]['F'][i] - mean) / stdev > 2:
  24. data['phones'][p]['outlier'] = True
  25. data['phones'][p]['F'][i] = None
  26. """statistics.mean([
  27. data['phones'][q]['F'][i] for q in range(i - , i + 2) if data['phones'][q]['F'][i] != None
  28. ])"""
  29. with open('stats.json') as f:
  30. stats = json.loads(f.read())
  31. for phone in data['phones']:
  32. if (not (phone.get('phoneme') and
  33. phone.get('expected') and
  34. stats.get(phone.get('phoneme')) and
  35. stats.get(phone.get('expected')))
  36. ): continue
  37. if not phone['phoneme'] and phone['expected'] in stats: continue
  38. phone['F_stdevs'] = [
  39. None if len(phone['F']) <= i or phone['F'][i] == None else
  40. (phone['F'][i] - stats[phone['expected']][i]['mean'])
  41. / stats[phone['expected']][i]['stdev']
  42. for i in list(range(4))
  43. ]
  44. for i in range(len(data['phones'])):
  45. currentPhone = data['phones'][i]
  46. isVowel = currentPhone['phoneme'] and len([
  47. value for value in list(currentPhone['phoneme'])
  48. if value in ["A", "E", "I", "O", "U", "Y"]
  49. ]) > 1
  50. if ('F_stdevs' in currentPhone and currentPhone['F_stdevs'][1] and
  51. currentPhone['F_stdevs'][2] and currentPhone['F_stdevs'][3]
  52. ):
  53. data['phones'][i]['resonance'] = clamp(0, 1,
  54. ( weights[0] * currentPhone['F_stdevs'][1]
  55. + weights[1] * currentPhone['F_stdevs'][2]
  56. + weights[2] * currentPhone['F_stdevs'][3]) / 3 + .5
  57. )
  58. pitch_sample = [
  59. phone['F'][0] for phone in data['phones']
  60. if phone.get('F') and phone['F'][0] and not phone.get('outlier')
  61. ]
  62. resonance_sample = [
  63. phone['resonance'] for phone in data['phones']
  64. if phone.get('resonance') and not phone.get('outlier')
  65. ]
  66. data['meanPitch'] = statistics.mean(pitch_sample)
  67. data['meanResonance'] = statistics.mean(resonance_sample)
  68. data['medianPitch'] = statistics.median(pitch_sample)
  69. data['medianResonance'] = statistics.median(resonance_sample)
  70. data['stdevPitch'] = statistics.stdev(pitch_sample)
  71. data['stdevResonance'] = statistics.stdev(resonance_sample)