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.

100 lines
3.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. # Custom LFO waveshapes.
  30. import numpy
  31. def scale(x, min=0, max=255, center=True):
  32. mx = x.max()
  33. mn = x.min()
  34. x = (x - mn) / (mx - mn)
  35. x = numpy.round(x * (max - min) + min)
  36. target_type = numpy.uint8
  37. x[x < numpy.iinfo(target_type).min] = numpy.iinfo(target_type).min
  38. x[x > numpy.iinfo(target_type).max] = numpy.iinfo(target_type).max
  39. return x.astype(target_type)
  40. custom_lfos = []
  41. t = numpy.arange(0, 256) / 256.0
  42. ramp = t
  43. triangle = 2 * t * (t < 0.5) + (2.0 - 2 * t) * (t >= 0.5)
  44. square = (t < 0.5)
  45. bipolar_triangle = 2 * triangle - 1.0
  46. sine = numpy.sin(2 * numpy.pi * t)
  47. # Ramps (5)
  48. custom_lfos.append(ramp ** 4)
  49. custom_lfos.append(ramp)
  50. custom_lfos.append(triangle)
  51. custom_lfos.append(ramp[::-1])
  52. custom_lfos.append(ramp[::-1] ** 4)
  53. # Bump
  54. window = (1.0 - numpy.cos(4 * numpy.pi * t)) / 2.0
  55. custom_lfos.append(numpy.maximum(sine, 0.0) * window)
  56. custom_lfos.append(square.astype(float))
  57. sine_2 = numpy.sin(2 * numpy.pi * t) + 0.7 * numpy.sin(4 * numpy.pi * t)
  58. sine_3 = numpy.sin(2 * numpy.pi * t) + 0.7 * numpy.sin(6 * numpy.pi * t)
  59. sine_5 = numpy.sin(2 * numpy.pi * t) + 0.7 * numpy.sin(10 * numpy.pi * t)
  60. custom_lfos.append(sine ** 3)
  61. custom_lfos.append(sine)
  62. custom_lfos.append(sine_2)
  63. custom_lfos.append(sine_3)
  64. custom_lfos.append(sine_5)
  65. triangle_3 = numpy.cumsum(numpy.sign(numpy.diff(sine_3)))
  66. custom_lfos.append(numpy.array([0] + list(triangle_3)))
  67. for fold_amount in [1.0, 0.5]:
  68. rotate = (numpy.arange(0, 256) + 128) % 256
  69. fold = (1 + fold_amount) * bipolar_triangle[rotate]
  70. fold[fold > 1.0] = 2.0 - fold[fold > 1.0]
  71. fold[fold < -1.0] = -2.0 - fold[fold < -1.0]
  72. custom_lfos.append(-fold)
  73. spike = 2 ** (4 * triangle) - 1
  74. custom_lfos.append(spike)
  75. numpy.random.seed(999)
  76. custom_lfos.append(numpy.random.random((256, 1)).ravel())
  77. custom_lfos.append(sine)
  78. lfo_waveforms = numpy.zeros((257 * len(custom_lfos),), dtype=numpy.uint8)
  79. import pylab
  80. for i, values in enumerate(custom_lfos):
  81. values = scale(values)
  82. lfo_waveforms[i * 257: i * 257 + 256] = values
  83. lfo_waveforms[i * 257 + 256] = values[0]
  84. waveforms = [('lfo_waveforms', lfo_waveforms)]