b48c0a84158ea8ac8e3fda044947bd82b8396a00
[software/lv2-mdametapiano.git] / src / mdaPianoVoice.cpp
1 #include "mdaPianoVoice.h"
2
3 mdaPianoVoice::mdaPianoVoice(double rate, short * samples, KGRP * master_kgrp) {
4 //set tuning
5 Fs = rate;
6 iFs = 1.0f/Fs;
7
8 waves = samples;
9 kgrp = master_kgrp;
10
11 default_preset[p_offset(p_envelope_decay)] = 0.500f;
12 default_preset[p_offset(p_envelope_release)] = 0.500f;
13 default_preset[p_offset(p_hardness_offset)] = 0.500f;
14 default_preset[p_offset(p_velocity_to_hardness)] = 0.500f;
15 default_preset[p_offset(p_muffling_filter)] = 0.803f;
16 default_preset[p_offset(p_velocity_to_muffling)] = 0.251f;
17 default_preset[p_offset(p_velocity_sensitivity)] = 0.376f;
18 default_preset[p_offset(p_stereo_width)] = 0.500f;
19 default_preset[p_offset(p_polyphony)] = 0.330f;
20 default_preset[p_offset(p_fine_tuning)] = 0.500f;
21 default_preset[p_offset(p_random_detuning)] = 0.246f;
22 default_preset[p_offset(p_stretch_tuning)] = 0.500f;
23
24 reset();
25 }
26
27
28 void mdaPianoVoice::reset() {
29 env = 0.0f;
30 dec = 0.99f;
31 muff = 160.0f;
32 volume = 0.2f;
33 sustain = 0;
34 cpos = 0;
35 m_key = LV2::INVALID_KEY;
36 }
37
38
39 float mdaPianoVoice::p_helper(unsigned short id, Param d) {
40 if (d == Default)
41 return default_preset[p_offset(id)];
42 else
43 return *p(id);
44 }
45
46
47 void mdaPianoVoice::on(unsigned char note, unsigned char velocity)
48 {
49 // store key that turned this voice on (used in 'get_key')
50 m_key = note;
51
52 float l=99.0f;
53 uint32_t k, s;
54
55 if(velocity>0)
56 {
57 // TODO: move this to mdaPiano.cpp
58 /*
59 if(activevoices < poly) //add a note
60 {
61 vl = activevoices;
62 activevoices++;
63 }
64 else //steal a note
65 {
66 for(v=0; v<poly; v++) //find quietest voice
67 {
68 if(voice[v].env < l) { l = voice[v].env; vl = v; }
69 }
70 }
71 */
72
73 k = (note - 60) * (note - 60);
74 l = fine + random * ((float)(k % 13) - 6.5f); //random & fine tune
75 if(note > 60) l += stretch * (float)k; //stretch
76
77 s = size;
78 if(velocity > 40) s += (uint32_t)(sizevel * (float)(velocity - 40));
79
80 k = 0;
81 while(note > (kgrp[k].high + s)) k++; //find keygroup
82
83 l += (float)(note - kgrp[k].root); //pitch
84 l = 22050.0f * iFs * (float)exp(0.05776226505 * l);
85 delta = (uint32_t)(65536.0f * l);
86 frac = 0;
87 pos = kgrp[k].pos;
88 end = kgrp[k].end;
89 loop = kgrp[k].loop;
90
91 env = (0.5f + velsens) * (float)pow(0.0078f * velocity, velsens); //velocity
92
93 l = 50.0f + *p(p_muffling_filter) * *p(p_muffling_filter) * muff + muffvel * (float)(velocity - 64); //muffle
94 if(l < (55.0f + 0.25f * (float)note)) l = 55.0f + 0.25f * (float)note;
95 if(l > 210.0f) l = 210.0f;
96 ff = l * l * iFs;
97 f0 = f1 = 0.0f;
98
99 if(note < 12) note = 12;
100 if(note > 108) note = 108;
101 l = volume * trim;
102 outr = l + l * width * (float)(note - 60);
103 outl = l + l - outr;
104
105 if(note < 44) note = 44; //limit max decay length
106 l = 2.0f * *p(p_envelope_decay);
107 if(l < 1.0f) l += 0.25f - 0.5f * *p(p_envelope_decay);
108 dec = (float)exp(-iFs * exp(-0.6 + 0.033 * (double)note - l));
109 }
110 else //note off
111 {
112 // TODO: move the loop to mdaPiano.cpp
113 //for(v=0; v<NVOICES; v++) if(voice[v].note==note) //any voices playing that note?
114 //{
115 release(0);
116 //}
117 }
118 }
119
120
121 void mdaPianoVoice::release(unsigned char velocity)
122 {
123 if(sustain==0) {
124 //no release on highest notes
125 if(note < 94 || note == SUSTAIN) {
126 dec = (float)exp(-iFs * exp(2.0 + 0.017 * (double)note - 2.0 * *p(p_envelope_release)));
127 }
128 } else {
129 note = SUSTAIN;
130 }
131
132 //Mark the voice to be turned off later. It may not be set to
133 //INVALID_KEY yet, because the release sound still needs to be
134 //rendered. m_key is finally set to INVALID_KEY by 'render' when
135 //env < SILENCE
136 m_key = SUSTAIN;
137 }
138
139
140 void mdaPianoVoice::render(uint32_t from, uint32_t to)
141 {
142 // abort if no key is pressed
143 // initially m_key is INVALID_KEY, so no sound will be rendered
144 if (m_key == LV2::INVALID_KEY)
145 return;
146
147 float x, l, r;
148 uint32_t i;
149
150 for (uint32_t frame = from; frame < to; ++frame) {
151 l = r = 0.0f;
152
153 frac += delta; //integer-based linear interpolation
154 pos += frac >> 16;
155 frac &= 0xFFFF;
156 if(pos > end) pos -= loop;
157
158 i = waves[pos];
159 i = (i << 7) + (frac >> 9) * (waves[pos + 1] - i) + 0x40400000;
160 x = env * (*(float *)&i - 3.0f); //fast int->float
161
162 /////////////////////
163 //TODO: This was used in processReplacing instead of the above
164 /*
165 //i = (i << 7) + (frac >> 9) * (waves[pos + 1] - i) + 0x40400000; //not working on intel mac !?!
166 i = waves[pos] + ((frac * (waves[pos + 1] - waves[pos])) >> 16);
167 x = env * (float)i / 32768.0f;
168 //x = env * (*(float *)&i - 3.0f); //fast int->float
169 */
170 /////////////////////
171
172 env = env * dec; //envelope
173 f0 += ff * (x + f1 - f0); //muffle filter
174 f1 = x;
175
176 l += outl * f0;
177 r += outr * f0;
178
179 //TODO: this was used in processReplacing
180 /////////////////////
181 /*
182 if(!(l > -2.0f) || !(l < 2.0f))
183 {
184 printf("what is this shit? %d, %f, %f\n", i, x, f0);
185 l = 0.0f;
186 }
187 if(!(r > -2.0f) || !(r < 2.0f))
188 {
189 r = 0.0f;
190 }
191 */
192 /////////////////////
193 comb[cpos] = l + r;
194 ++cpos &= 0x7F;
195 x = cdep * comb[cpos]; //stereo simulator
196
197 // TODO: processReplacing simply assigned instead of adding
198 // write to output
199 p(p_left)[frame] += l + x;
200 p(p_right)[frame] += r - x;
201 }
202 }
203
204
205 void mdaPianoVoice::update(Param par)
206 {
207 size = (uint32_t)(12.0f * p_helper(p_hardness_offset, par) - 6.0f);
208 sizevel = 0.12f * p_helper(p_velocity_to_hardness, par);
209 muffvel = p_helper(p_velocity_to_muffling, par) * p_helper(p_velocity_to_muffling, par) * 5.0f;
210
211 velsens = 1.0f + p_helper(p_velocity_sensitivity, par) + p_helper(p_velocity_sensitivity, par);
212 if(p_helper(p_velocity_sensitivity, par) < 0.25f) velsens -= 0.75f - 3.0f * p_helper(p_velocity_sensitivity, par);
213
214 fine = p_helper(p_fine_tuning, par) - 0.5f;
215 random = 0.077f * p_helper(p_random_detuning, par) * p_helper(p_random_detuning, par);
216 stretch = 0.000434f * (p_helper(p_stretch_tuning, par) - 0.5f);
217
218 cdep = p_helper(p_stereo_width, par) * p_helper(p_stereo_width, par);
219 trim = 1.50f - 0.79f * cdep;
220 width = 0.04f * p_helper(p_stereo_width, par); if(width > 0.03f) width = 0.03f;
221
222 poly = 8 + (uint32_t)(24.9f * p_helper(p_polyphony, par));
223 }