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.

97 lines
3.2KB

  1. #!/usr/bin/python2.5
  2. #
  3. # Copyright 2012 Olivier Gillet.
  4. #
  5. # Author: Olivier Gillet (olivier@mutable-instruments.net)
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. #
  18. # -----------------------------------------------------------------------------
  19. import numpy
  20. waveforms = []
  21. SAMPLE_RATE = float(32000000 / 666)
  22. WAVETABLE_SIZE = 512
  23. def Dither(x, order=0, type=numpy.uint8):
  24. for i in xrange(order):
  25. x = numpy.hstack((numpy.zeros(1,), numpy.cumsum(x)))
  26. x = numpy.round(x)
  27. for i in xrange(order):
  28. x = numpy.diff(x)
  29. if any(x < numpy.iinfo(type).min) or any(x > numpy.iinfo(type).max):
  30. print 'Clipping occurred!'
  31. x[x < numpy.iinfo(type).min] = numpy.iinfo(type).min
  32. x[x > numpy.iinfo(type).max] = numpy.iinfo(type).max
  33. return x.astype(type)
  34. def Scale(array, min=1, max=254, center=True, dither=2):
  35. if center:
  36. array -= array.mean()
  37. mx = numpy.abs(array).max()
  38. array = (array + mx) / (2 * mx)
  39. array = array * (max - min) + min
  40. return Dither(array, order=dither)
  41. # Sine wave.
  42. numpy.random.seed(21)
  43. sine = -numpy.sin(numpy.arange(WAVETABLE_SIZE + 1) / float(WAVETABLE_SIZE) * 2 * numpy.pi)
  44. # Band limited waveforms.
  45. num_zones = 8
  46. bl_tri_tables = []
  47. bl_ntri_tables = []
  48. fill = numpy.fmod(numpy.arange(WAVETABLE_SIZE + 1), WAVETABLE_SIZE)
  49. wrap = numpy.fmod(numpy.arange(WAVETABLE_SIZE + 1) + WAVETABLE_SIZE / 2, WAVETABLE_SIZE)
  50. quadrature = numpy.fmod(numpy.arange(WAVETABLE_SIZE + 1) + WAVETABLE_SIZE / 4, WAVETABLE_SIZE)
  51. step = numpy.fmod(numpy.arange(WAVETABLE_SIZE + 1) + WAVETABLE_SIZE / 32, WAVETABLE_SIZE)
  52. for zone in range(num_zones):
  53. f0 = 440.0 * 2.0 ** ((18 + 16 * zone - 69) / 12.0)
  54. period = SAMPLE_RATE / f0
  55. m = 2 * numpy.floor(period / 2) + 1.0
  56. i = numpy.arange(-WAVETABLE_SIZE / 2, WAVETABLE_SIZE / 2) / float(WAVETABLE_SIZE)
  57. pulse = numpy.sin(numpy.pi * i * m) / (m * numpy.sin(numpy.pi * i) + 1e-9)
  58. pulse[WAVETABLE_SIZE / 2] = 1.0
  59. pulse = pulse[fill]
  60. square = numpy.cumsum(pulse - pulse[wrap])
  61. triangle = -numpy.cumsum(square[::-1] - square.mean()) / WAVETABLE_SIZE
  62. nes_triangle = 0
  63. for i in xrange(32):
  64. nes_triangle += (1 if i < 16 else -1) * pulse
  65. pulse = pulse[step]
  66. nes_triangle = -numpy.cumsum(nes_triangle)
  67. triangle = triangle[quadrature]
  68. if zone >= num_zones - 2:
  69. triangle = sine
  70. bl_tri_tables.append(('bandlimited_triangle_%d' % zone,
  71. Scale(triangle[quadrature])))
  72. nes_triangle = nes_triangle[quadrature]
  73. if zone >= num_zones - 2:
  74. nes_triangle = sine
  75. bl_ntri_tables.append(('bandlimited_nes_triangle_%d' % zone,
  76. Scale(nes_triangle[quadrature])))
  77. waveforms.extend(bl_tri_tables)
  78. waveforms.extend(bl_ntri_tables)