You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

161 lines
5.3KB

  1. #!/usr/bin/python2.5
  2. #
  3. # Copyright 2014 Olivier Gillet.
  4. #
  5. # Author: Olivier Gillet (ol.gillet@gmail.com)
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining a copy
  8. # of this software and associated documentation files (the "Software"), to deal
  9. # in the Software without restriction, including without limitation the rights
  10. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. # copies of the Software, and to permit persons to whom the Software is
  12. # furnished to do so, subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice shall be included in
  15. # all copies or substantial portions of the Software.
  16. #
  17. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. # THE SOFTWARE.
  24. #
  25. # See http://creativecommons.org/licenses/MIT/ for more information.
  26. #
  27. # -----------------------------------------------------------------------------
  28. #
  29. # Lookup table definitions.
  30. import scipy.signal
  31. import numpy
  32. import pylab
  33. lookup_tables = []
  34. int16_lookup_tables = []
  35. """----------------------------------------------------------------------------
  36. Cosine table.
  37. ----------------------------------------------------------------------------"""
  38. size = 1024
  39. t = numpy.arange(0, size + size / 4 + 1) / float(size) * numpy.pi * 2
  40. lookup_tables.append(('sin', numpy.sin(t)))
  41. """----------------------------------------------------------------------------
  42. Raised cosine.
  43. ----------------------------------------------------------------------------"""
  44. size = 256
  45. t = numpy.arange(0, size + 1) / float(size)
  46. lookup_tables.append(('raised_cos', 1.0 - (numpy.cos(t * numpy.pi) + 1) / 2))
  47. """----------------------------------------------------------------------------
  48. XFade table
  49. ----------------------------------------------------------------------------"""
  50. size = 17
  51. t = numpy.arange(0, size) / float(size-1)
  52. t = 1.04 * t - 0.02
  53. t[t < 0] = 0
  54. t[t >= 1] = 1
  55. t *= numpy.pi / 2
  56. lookup_tables.append(('xfade_in', numpy.sin(t) * (2 ** -0.5)))
  57. lookup_tables.append(('xfade_out', numpy.cos(t) * (2 ** -0.5)))
  58. """----------------------------------------------------------------------------
  59. Grain window.
  60. ----------------------------------------------------------------------------"""
  61. size = 4096
  62. t = numpy.arange(0, size + 1) / float(size)
  63. lookup_tables.append(('window', 1.0 - (numpy.cos(t * numpy.pi) + 1) / 2))
  64. """----------------------------------------------------------------------------
  65. Sine window.
  66. ----------------------------------------------------------------------------"""
  67. def sum_window(window, steps):
  68. n = window.shape[0]
  69. start = 0
  70. stride = n / steps
  71. s = 0
  72. for i in xrange(steps):
  73. s = s + window[start:start+stride] ** 2
  74. start += stride
  75. return s
  76. window_size = 4096
  77. t = numpy.arange(0.0, window_size) / window_size
  78. # Perfect reconstruction for overlap of 2
  79. sine = numpy.sin(numpy.pi * t)
  80. # Perfect reconstruction for overlap of 4
  81. raised = (0.5 * numpy.cos(numpy.pi * t * 2) + 0.5) * numpy.sqrt(4.0 / 3.0)
  82. # Needs tweaks to provide good reconstruction
  83. power = (1.0 - (2 * t - 1.0) ** 2.0) ** 1.25
  84. compensation = sum_window(power, 2) ** 0.5
  85. compensation = numpy.array(list(compensation) * 2)
  86. power /= compensation
  87. lookup_tables.append(('sine_window_4096', power))
  88. """----------------------------------------------------------------------------
  89. Linear to dB, for display
  90. ----------------------------------------------------------------------------"""
  91. db = numpy.arange(0, 257)
  92. db[0] = 1
  93. db[db > 255] = 255
  94. db = numpy.log2(db / 16.0) * 32768 / 4
  95. int16_lookup_tables += [('db', db)]
  96. """----------------------------------------------------------------------------
  97. LPG cutoff
  98. ----------------------------------------------------------------------------"""
  99. TABLE_SIZE = 256
  100. cutoff = numpy.arange(0.0, TABLE_SIZE + 1) / TABLE_SIZE
  101. lookup_tables.append(('cutoff', 0.49 * 2 ** (-6 * (1 - cutoff))))
  102. """----------------------------------------------------------------------------
  103. Grain size table
  104. ----------------------------------------------------------------------------"""
  105. size = numpy.arange(0.0, TABLE_SIZE + 1) / TABLE_SIZE * 5
  106. lookup_tables.append(('grain_size', numpy.floor(512 * (2 ** size))))
  107. """----------------------------------------------------------------------------
  108. Quantizer for pitch.
  109. ----------------------------------------------------------------------------"""
  110. PITCH_TABLE_SIZE = 1025
  111. pitch = numpy.zeros((PITCH_TABLE_SIZE, ))
  112. notches = [-24, -12, -7, -4, -3, -1, -0.1, 0,
  113. 0.1, 1, 3, 4, 7, 12, 12, 24]
  114. n = len(notches) - 1
  115. for i in xrange(n):
  116. start_index = int(float(i) / n * PITCH_TABLE_SIZE)
  117. end_index = int(float(i + 1) / n * PITCH_TABLE_SIZE)
  118. length = end_index - start_index
  119. x = numpy.arange(0.0, length) / (length - 1)
  120. raised_cosine = 0.5 - 0.5 * numpy.cos(x * numpy.pi)
  121. xfade = 0.8 * raised_cosine + 0.2 * x
  122. pitch[start_index:end_index] = notches[i] + (notches[i + 1] - notches[i]) * xfade
  123. lookup_tables.append(('quantized_pitch', pitch))