1#!/usr/bin/python2.5
2#
3# Copyright 2012 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# Waveform definitions.
30
31import numpy
32
33
34"""----------------------------------------------------------------------------
35Waveforms for vowel synthesis
36----------------------------------------------------------------------------"""
37
38SAMPLE_RATE = 96000
39
40waveforms = []
41# Create amplitude modulated sine/square tables for formants.
42sine_samples = []
43square_samples = []
44sine = numpy.sin(numpy.arange(16.0) / 16.0 * 2 * numpy.pi)
45for i, x in enumerate(sine):
46  gains = numpy.exp(0.184 * numpy.arange(16.0))
47  gains[0] = 0
48  values = gains * x * 4
49  values = numpy.round(values).astype(int)
50  amps = numpy.round(gains)
51  if (i >= 8):
52    amps = -amps
53  square_samples.extend(amps.astype(int))
54  sine_samples.extend(values)
55
56waveforms.extend([
57    ('formant_sine', sine_samples),
58    ('formant_square', square_samples)
59])
60
61
62"""----------------------------------------------------------------------------
63Band-limited waveforms
64----------------------------------------------------------------------------"""
65
66WAVETABLE_SIZE = 256
67
68# The Juno-6 / Juno-60 waveforms have a brighter harmonic content, which can be
69# recreated by adding to the signal a 1-pole high-pass filtered version of
70# itself.
71JUNINESS = 1.0
72
73
74def dither(x, order=0, type=numpy.int16):
75  for i in xrange(order):
76    x = numpy.hstack((numpy.zeros(1,), numpy.cumsum(x)))
77  x = numpy.round(x)
78  for i in xrange(order):
79    x = numpy.diff(x)
80  if any(x < numpy.iinfo(type).min) or any(x > numpy.iinfo(type).max):
81    print 'Clipping occurred!'
82  x[x < numpy.iinfo(type).min] = numpy.iinfo(type).min
83  x[x > numpy.iinfo(type).max] = numpy.iinfo(type).max
84  return x.astype(type)
85
86
87def scale(array, min=-32766, max=32766, center=True, dither_level=2):
88  if center:
89    array -= array.mean()
90  mx = numpy.abs(array).max()
91  array = (array + mx) / (2 * mx)
92  array = array * (max - min) + min
93  return dither(array, order=dither_level)
94
95
96# Sine wave.
97sine = -numpy.sin(numpy.arange(WAVETABLE_SIZE + 1) / float(WAVETABLE_SIZE) * \
98    2 * numpy.pi) * 127.5 + 127.5
99
100# Band limited waveforms.
101num_zones = 15
102bl_pulse_tables = []
103bl_tri_tables = []
104
105wrap = numpy.fmod(
106    numpy.arange(WAVETABLE_SIZE + 1) + WAVETABLE_SIZE / 2,
107    WAVETABLE_SIZE)
108
109quadrature = numpy.fmod(
110    numpy.arange(WAVETABLE_SIZE + 1) + WAVETABLE_SIZE / 4,
111    WAVETABLE_SIZE)
112
113fill = numpy.fmod(
114    numpy.arange(WAVETABLE_SIZE + 1),
115    WAVETABLE_SIZE)
116
117waveforms.append(('sine', scale(sine[quadrature])))
118
119for zone in range(num_zones):
120  f0 = 440.0 * 2.0 ** ((18 + 8 * zone - 69) / 12.0)
121  if zone == num_zones - 1:
122    f0 = SAMPLE_RATE / 2.0 - 1
123  else:
124    f0 = min(f0, SAMPLE_RATE / 2.0)
125  period = SAMPLE_RATE / f0
126  m = 2 * numpy.floor(period / 2) + 1.0
127  i = numpy.arange(-WAVETABLE_SIZE / 2, WAVETABLE_SIZE / 2) / \
128      float(WAVETABLE_SIZE)
129  pulse = numpy.sin(numpy.pi * i * m) / (m * numpy.sin(numpy.pi * i) + 1e-9)
130  pulse[WAVETABLE_SIZE / 2] = 1.0
131  pulse = pulse[fill]
132
133  bl_pulse_tables.append(('bandlimited_comb_%d' % zone,
134                          scale(pulse[quadrature])))
135
136waveforms.extend(bl_pulse_tables)
137waveforms.extend(bl_tri_tables)
138
139
140"""----------------------------------------------------------------------------
141Wavetables
142-----------------------------------------------------------------------------"""
143
144wavetable_data = []
145waves = map(ord, file('braids/data/waves.bin', 'rb').read())
146wavetable_data.append(('waves', waves))
147
148wave_map = map(ord, file('braids/data/map.bin', 'rb').read())
149wavetable_data.append(('map', wave_map))
150
151
152
153"""----------------------------------------------------------------------------
154???
155-----------------------------------------------------------------------------"""
156
157random_data = [
1585, 0, 132, 0, 20, 16, 20, 81, 16, 65, 8, 17, 4, 65, 17, 5,
1590, 69, 1, 88, 17, 25, 0, 132, 144, 0, 64, 80, 0, 21, 148, 0,
16065, 17, 5, 129, 4, 1, 68, 1, 65, 5, 65, 17, 21, 4, 20, 16,
1614, 128, 80, 0, 4, 64, 20, 21, 0, 4, 1, 20, 16, 9, 17, 68,
16217, 5, 17, 4, 1, 132, 0, 65, 16, 20, 81, 145, 1, 81, 17, 21,
16316, 21, 81, 1, 20, 16, 21, 68, 16, 16, 144, 5, 0, 132, 17, 4,
16465, 68, 129, 65, 20, 81, 129, 0, 4, 20, 65, 129, 17, 5, 80, 5,
16564, 64, 1, 132, 64, 65, 17, 68, 65, 64, 17, 5, 80, 0, 4, 1,
16620, 16, 25, 64, 4, 17, 4, 20, 16, 84, 20, 128, 5, 0, 132, 0,
16765, 80, 1, 65, 24, 81, 0, 129, 80, 129, 17, 5, 64, 1, 65, 64,
16816, 64, 16, 64, 17, 5, 64, 1, 65, 17, 5, 17, 132, 5, 80, 1,
16964, 20, 1, 16, 25, 81, 0, 80, 4, 129, 16, 5, 0, 4, 20, 16,
1704, 0, 8, 16, 4, 1, 20, 81, 16, 69, 1, 8, 21, 72, 0, 80,
1714, 65, 1, 0, 80, 1, 65, 0, 64, 80, 65, 17, 4, 20, 20, 129,
1721, 4, 21, 20, 16, 132, 17, 5, 16, 8, 1, 4, 4, 64, 0, 4,
1735, 17, 21, 81, 0, 5, 128, 0, 65, 64, 17, 4, 80, 16, 68, 0,
1744, 1, 1, 89, 17, 21, 64, 80, 1, 145, 0, 68, 20, 69, 1, 88,
17517, 25, 0, 132, 16, 65, 80, 1, 81, 1, 4, 21, 16, 21, 1, 16,
1769, 21, 20, 128, 4, 0, 69, 16, 20, 16, 21, 81, 65, 8, 20, 4,
17764, 64, 1, 132, 21, 145, 1, 64, 24, 64, 16, 4, 80, 65, 1, 9,
1785, 1, 4, 65, 4, 21, 64, 1, 81, 16, 16, 144, 17, 4, 1, 4,
1795, 65, 20, 128, 80, 9, 5, 1, 4, 1, 88, 0, 64, 8, 81, 80,
1801, 81, 17, 0, 145, 17, 69, 1, 4, 4, 17, 4, 9, 21, 20, 128,
18181, 84, 17, 64, 17, 68, 16, 8, 16, 20, 81, 0, 21, 20, 128, 144,
1825, 21, 0, 4, 1, 132, 64, 129, 1, 64, 80, 1, 65, 1, 5, 1,
1831, 9, 9, 81, 64, 17, 64, 20, 68, 1, 24, 0, 4, 5, 65, 69,
18465, 1, 68, 16, 8, 81, 4, 5, 65, 64, 65, 17, 8, 64, 0, 64,
18580, 1, 68, 0, 24, 5, 85, 4, 65, 64, 80, 16, 64, 64, 17, 64,
18620, 128, 80, 65, 1, 24, 69, 21, 1, 20, 65, 4, 129, 17, 5, 65,
1871, 68, 16, 68, 1, 24, 0, 20, 81, 0, 5, 65, 1, 64, 17, 21,
1884, 1, 1, 25, 81, 20, 64, 64, 16, 65, 80, 17, 0, 145, 1, 65,
1890, 64, 20, 16, 20, 80, 64, 65, 17, 88, 0, 64, 24, 0, 4, 5,
19065, 17, 0, 145, 17, 4, 65, 4, 145, 65, 4, 65, 0, 80, 17, 5,
19180, 0, 4, 1, 1, 89, 0, 64, 4, 65, 8, 81, 80, 0, 88, 0,
19264, 64, 0, 8, 17, 133, 65, 8, 64, 80, 64, 0, 24, 1, 5, 80,
19317, 5, 8, 21, 0, 20, 81, 0, 149, 5, 0, 132, 0, 20, 16, 20,
19481, 16, 65, 24, 16, 4, 65, 17, 5, 81, 1, 20, 17, 0, 88, 0,
19564, 20, 16, 9, 5, 1, 4, 1, 8, 81, 17, 5, 65, 24, 65, 16,
19664, 80, 0, 4, 64, 4, 128, 80, 65, 1, 8, 64, 5, 5, 65, 20,
197128, 80, 25, 16, 21, 81, 0, 21, 1, 16, 9, 64, 64, 16, 64, 20,
19884, 16, 16, 144, 20, 0, 21, 16, 68, 16, 65, 9, 16, 20, 81, 16,
1998, 25, 16, 20, 81, 0, 5, 17, 4, 1, 68, 1, 0, 80, 5, 0,
2004, 65, 132, 65, 4, 5, 65, 4, 129, 5, 0, 132, 1, 20, 81, 17,
2015, 65, 17, 0, 145, 16, 5, 0, 20, 145, 16, 69, 16, 132, 20, 20,
20265, 80, 17, 68, 1, 8, 20, 8, 25, 20, 81, 0, 68, 1, 0, 80,
20316, 65, 64, 1, 65, 1, 5, 20, 20, 129, 1, 65, 17, 21, 84, 4,
20464, 21, 1, 16, 9, 64, 68, 64, 65, 17, 8, 0, 20, 81, 16, 9,
20516, 4, 5, 129, 5, 0, 68, 1, 145, 1, 65, 17, 5, 80, 16, 64,
2061, 8, 16, 4, 1, 4, 20, 16, 20, 144, 64, 9, 21, 16, 4, 65,
20717, 5, 64, 0, 88, 0, 64, 8, 65, 17, 21, 81, 81, 16, 16, 144,
208144, 0, 4, 80, 1, 20, 64, 20, 24, 16, 4, 0, 20, 81, 16, 4,
20980, 0, 24, 81, 0, 129, 16, 5, 0, 20, 81, 17, 5, 17, 4, 128,
21080, 65, 1, 24, 16, 5, 20, 0, 20, 0, 4, 1, 68, 0, 24, 0,
2114, 80, 16, 4, 64, 9, 16, 4, 65, 17, 21, 9, 25, 80, 64, 65,
2121, 24, 81, 0, 129, 16, 81, 0, 21, 80, 24, 0, 20, 81, 1, 144,
21380, 89, 0, 64, 8, 16, 4, 5, 129, 20, 20, 128, 17, 5, 16, 88,
2140, 64, 8, 65, 17, 21, 81, 81, 16, 16, 144, 4, 0, 69, 16, 20,
21516, 21, 0, 20, 81, 1, 20, 16, 25, 1, 5, 80, 64, 89, 80, 16,
21664, 1, 5, 20, 20, 65, 16, 16, 144, 5, 0, 132, 1, 64, 80, 16,
21784, 20, 20, 64, 4, 129, 5, 4, 17, 84, 17, 69, 1, 24, 0, 4,
21821, 16, 20, 80, 17, 0, 145, 16, 5, 84, 0, 128, 5, 0, 132, 1,
2194, 65, 64, 65, 1, 5, 64, 16, 16, 144, 16, 5, 0, 4, 85, 16,
22017, 65, 0, 8, 0, 4, 5, 17, 4, 17, 68, 65, 64, 65, 17, 4,
22116, 1, 24, 81, 20, 64, 64, 16, 65, 144, 16, 5, 0, 4, 4, 64,
22216, 65, 4, 65, 20, 64, 16, 16, 144, 5, 0, 4, 85, 16, 17, 65,
2230, 24, 0, 20, 16, 9, 64, 21, 81, 1, 65, 1, 5, 0, 4, 5,
22480, 0, 68, 65, 16, 16, 80, 255
225]
226
227wavetable_data.append(('code', random_data))
228