#include "mdaPianoVoice.h" mdaPianoVoice::mdaPianoVoice(double rate, Sample * master_samples, KGRP * master_kgrp) { //set tuning Fs = rate; iFs = 1.0f/Fs; samples = master_samples; kgrp = master_kgrp; // TODO: load default values from ttl file #ifdef PIANO default_preset[p_offset(p_envelope_decay)] = 0.500f; default_preset[p_offset(p_envelope_release)] = 0.500f; default_preset[p_offset(p_hardness_offset)] = 0.500f; default_preset[p_offset(p_velocity_to_hardness)] = 0.500f; default_preset[p_offset(p_muffling_filter)] = 0.803f; default_preset[p_offset(p_velocity_to_muffling)] = 0.251f; default_preset[p_offset(p_velocity_sensitivity)] = 0.376f; default_preset[p_offset(p_stereo_width)] = 0.500f; default_preset[p_offset(p_polyphony)] = 0.330f; // unused default_preset[p_offset(p_fine_tuning)] = 0.500f; default_preset[p_offset(p_random_detuning)] = 0.246f; default_preset[p_offset(p_stretch_tuning)] = 0.500f; #elif defined EPIANO default_preset[p_offset(p_envelope_decay)] = 0.500f; default_preset[p_offset(p_envelope_release)] = 0.500f; default_preset[p_offset(p_hardness)] = 0.500f; default_preset[p_offset(p_treble_boost)] = 0.500f; default_preset[p_offset(p_modulation)] = 0.500f; default_preset[p_offset(p_lfo_rate)] = 0.650f; default_preset[p_offset(p_velocity_sensitivity)] = 0.250f; default_preset[p_offset(p_stereo_width)] = 0.500f; default_preset[p_offset(p_polyphony)] = 0.500f; // unused default_preset[p_offset(p_fine_tuning)] = 0.500f; default_preset[p_offset(p_random_tuning)] = 0.146f; default_preset[p_offset(p_overdrive)] = 0.000f; #endif reset(); update(Default); } float mdaPianoVoice::p_helper(unsigned short id, Param d) { if (d == Default) return default_preset[p_offset(id)]; else return *p(id); } void mdaPianoVoice::on(unsigned char key, unsigned char velocity) { // store key that turned this voice on (used in 'get_key') m_key = key; update(Current); float l=99.0f; long k, s; if(velocity > 0) { k = (key - 60) * (key - 60); l = fine + random * ((float)(k % 13) - 6.5f); //random & fine tune #ifdef PIANO if(key > 60) l += stretch * (float)k; //stretch #endif s = size; #ifdef PIANO if(velocity > 40) s += (long)(sizevel * (float)(velocity - 40)); #endif sample_index = 0; while (key > (kgrp[sample_index].high + s)) sample_index += SAMPLES_PER_NOTE; // find keygroup l += (float)(key - kgrp[sample_index].root); // pitch #ifdef PIANO l = 22050.0f * iFs * (float)exp(0.05776226505 * l); #elif defined EPIANO l = 32000.0f * iFs * (float)exp(0.05776226505 * l); #endif delta = (long)(65536.0f * l); frac = 0; pos = 0; #ifdef EPIANO if(velocity > 48) sample_index++; // mid velocity sample if(velocity > 80) sample_index++; // high velocity sample #endif end = samples[sample_index].size; loop = kgrp[sample_index].loop; #ifdef PIANO env = (0.5f + velsens) * (float)pow(0.0078f * velocity, velsens); //velocity l = 50.0f + *p(p_muffling_filter) * *p(p_muffling_filter) * muff + muffvel * (float)(velocity - 64); //muffle if(l < (55.0f + 0.25f * (float)key)) l = 55.0f + 0.25f * (float)key; if(l > 210.0f) l = 210.0f; ff = l * l * iFs; f0 = f1 = 0.0f; #elif defined EPIANO env = (3.0f + 2.0f * velsens) * (float)pow(0.0078f * velocity, velsens); // velocity // high notes quieter if(key > 60) { env *= (float)exp(0.01f * (float)(60 - key)); } #endif // note->pan if(key < 12) key = 12; if(key > 108) key = 108; #ifdef PIANO l = volume * trim; outr = l + l * width * (float)(key - 60); outl = l + l - outr; if(key < 44) key = 44; //limit max decay length l = 2.0f * *p(p_envelope_decay); if(l < 1.0f) l += 0.25f - 0.5f * *p(p_envelope_decay); dec = (float)exp(-iFs * exp(-0.6 + 0.033 * (double)key - l)); #elif defined EPIANO outr = volume + volume * width * (float)(key - 60); outl = volume + volume - outr; if(key < 44) key = 44; // limit max decay length dec = (float)exp(-iFs * exp(-1.0 + 0.03 * (double)key - 2.0f * *p(p_envelope_decay))); #endif } else { // some keyboards send note off events as 'note on' with velocity 0 release(0); } } void mdaPianoVoice::reset() { env = 0.0f; dec = 0.99f; sustain = 0; volume = 0.2f; #ifdef PIANO muff = 160.0f; cpos = 0; memset(comb, 0, sizeof(float) * 256); #elif defined EPIANO tl = tr = lfo0 = dlfo = 0.0f; lfo1 = 1.0f; #endif m_key = lvtk::INVALID_KEY; } void mdaPianoVoice::release(unsigned char velocity) { if(sustain==0) { #ifdef PIANO //no release on highest notes if(m_key < 94 || m_key == SUSTAIN) { dec = (float)exp(-iFs * exp(2.0 + 0.017 * (double)m_key - 2.0 * *p(p_envelope_release))); } #elif defined EPIANO dec = (float)exp(-iFs * exp(6.0 + 0.01 * (double)m_key - 5.0 * *p(p_envelope_release))); #endif } else { m_key = SUSTAIN; } //Mark the voice to be turned off later. It may not be set to //INVALID_KEY yet, because the release sound still needs to be //rendered. m_key is finally set to INVALID_KEY by 'render' when //env < SILENCE m_key = SUSTAIN; } void mdaPianoVoice::render(uint32_t from, uint32_t to) { // abort if no key is pressed // initially m_key is INVALID_KEY, so no sound will be rendered if (m_key == lvtk::INVALID_KEY) return; float x, l, r; long i; update(Current); for (uint32_t frame = from; frame < to; ++frame) { // initialize left and right output l = r = 0.0f; frac += delta; // integer-based linear interpolation pos += frac >> 16; frac &= 0xFFFF; // why AND it with all ones? if (pos >= end) { pos -= loop; // jump to loop point in sample } #ifdef PIANO i = samples[sample_index].buffer[pos]; i = (i << 7) + (frac >> 9) * (samples[sample_index].buffer[pos + 1] - i) + 0x40400000; x = env * (*(float *)&i - 3.0f); //fast int->float env = env * dec; //envelope f0 += ff * (x + f1 - f0); //muffle filter f1 = x; l += outl * f0; r += outr * f0; comb[cpos] = l + r; ++cpos &= 0x7F; x = cdep * comb[cpos]; //stereo simulator // write to output p(p_left)[frame] += l + x; p(p_right)[frame] += r - x; #elif defined EPIANO // alternative method (probably faster), said to not work on intel mac //i = samples[sample_index].buffer[pos]; //i = (i << 7) + (frac >> 9) * (samples[sample_index].buffer[pos + 1] - i) + 0x40400000; i = samples[sample_index].buffer[pos] + ((frac * (samples[sample_index].buffer[pos + 1] - samples[sample_index].buffer[pos])) >> 16); x = env * (float)i / 32768.0f; env = env * dec; // envelope // overdrive if(x>0.0f) { x -= overdrive * x * x; if(x < -env) x = -env; } l += outl * x; r += outr * x; // treble boost tl += tfrq * (l - tl); tr += tfrq * (r - tr); r += treb * (r - tr); l += treb * (l - tl); lfo0 += dlfo * lfo1; // LFO for tremolo and autopan lfo1 -= dlfo * lfo0; l += l * lmod * lfo1; r += r * rmod * lfo1; // TODO: worth making all these local variables? // write to output p(p_left)[frame] += l; p(p_right)[frame] += r; #endif } // turn off further processing when the envelope has rendered the voice silent if (env < SILENCE) { m_key = lvtk::INVALID_KEY; } #ifdef EPIANO if(fabs(tl)<1.0e-10) tl = 0.0f; // anti-denormal if(fabs(tr)<1.0e-10) tr = 0.0f; #endif } void mdaPianoVoice::update(Param par) { velsens = 1.0f + p_helper(p_velocity_sensitivity, par) + p_helper(p_velocity_sensitivity, par); if(p_helper(p_velocity_sensitivity, par) < 0.25f) { velsens -= 0.75f - 3.0f * p_helper(p_velocity_sensitivity, par); } fine = p_helper(p_fine_tuning, par) - 0.5f; #ifdef PIANO size = (long)(12.0f * p_helper(p_hardness_offset, par) - 6.0f); sizevel = 0.12f * p_helper(p_velocity_to_hardness, par); muffvel = p_helper(p_velocity_to_muffling, par) * p_helper(p_velocity_to_muffling, par) * 5.0f; stretch = 0.000434f * (p_helper(p_stretch_tuning, par) - 0.5f); cdep = p_helper(p_stereo_width, par) * p_helper(p_stereo_width, par); trim = 1.50f - 0.79f * cdep; width = 0.04f * p_helper(p_stereo_width, par); if(width > 0.03f) width = 0.03f; random = 0.077f * p_helper(p_random_detuning, par) * p_helper(p_random_detuning, par); #elif defined EPIANO size = (long)(12.0f * p_helper(p_hardness, par) - 6.0f); treb = 4.0f * p_helper(p_treble_boost, par) * p_helper(p_treble_boost, par) - 1.0f; // treble gain // treble frequency if(p_helper(p_treble_boost, par) > 0.5f) { tfrq = 14000.0f; } else { tfrq = 5000.0f; } tfrq = 1.0f - (float)exp(-iFs * tfrq); rmod = lmod = p_helper(p_modulation, par) + p_helper(p_modulation, par) - 1.0f; // lfo depth if(p_helper(p_modulation, par) < 0.5f) rmod = -rmod; dlfo = 6.283f * iFs * (float)exp(6.22f * p_helper(p_lfo_rate, par) - 2.61f); // lfo rate width = 0.03f * p_helper(p_stereo_width, par); overdrive = 1.8f * p_helper(p_overdrive, par); random = 0.077f * p_helper(p_random_tuning, par) * p_helper(p_random_tuning, par); #endif }