crudely merge mdaEPiano and mdaPiano
authorrekado <rekado@elephly.net>
Sun, 28 Jul 2013 03:42:18 +0000 (11:42 +0800)
committerrekado <rekado@elephly.net>
Sun, 28 Jul 2013 03:42:18 +0000 (11:42 +0800)
There are some differences in the types of certain variables that don't
seem very important.  This will be addressed in future commits.

src/mdaPiano.cpp
src/mdaPianoVoice.cpp

index a358988..419939a 100644 (file)
@@ -1,14 +1,13 @@
-/* ==================================================
- * LV2 port of the famous mda Piano VSTi
- * ==================================================
+/* ======================================================
+ * LV2 port of the popular mda Piano and mda EPiano VSTi
+ * ======================================================
  *
  * Port
  *   Author:    Ricardo Wurmus (rekado)
  *   Based on:  mda-vst-src-2010-02-14.zip
  *
- * mda Piano v1.0
+ * mda Piano / mda EPiano
  *   Copyright(c)1999-2000 Paul Kellett (maxim digital audio)
- *   Based on VST2 SDK (c)1996-1999 Steinberg Soft und Hardware GmbH, All Rights Reserved
  *
  * ==================================================
  */
@@ -24,6 +23,7 @@ mdaPiano::mdaPiano(double rate)
 
   sustain = 0;
 
+#ifdef PIANO
   static const char* sample_names[] =
     { "0c.raw", "0e.raw", "0g.raw"
     , "1c.raw", "1e.raw", "1g.raw"
@@ -31,12 +31,30 @@ mdaPiano::mdaPiano(double rate)
     , "3c.raw", "3e.raw", "3g.raw"
     , "4c.raw", "4e.raw", "4a.raw"
     };
+#elif defined EPIANO
+  static const char* sample_names[] =
+    { "0c-0.raw", "0c-1.raw", "0c-2.raw"
+    , "0g-0.raw", "0g-1.raw", "0g-2.raw"
+    , "1c-0.raw", "1c-1.raw", "1c-2.raw"
+    , "1g-0.raw", "1g-1.raw", "1g-2.raw"
+    , "2c-0.raw", "2c-1.raw", "2c-2.raw"
+    , "2g-0.raw", "2g-1.raw", "2g-2.raw"
+    , "3c-0.raw", "3c-1.raw", "3c-2.raw"
+    , "3g-0.raw", "3g-1.raw", "3g-2.raw"
+    , "4c-0.raw", "4c-1.raw", "4c-2.raw"
+    , "4g-0.raw", "4g-1.raw", "4g-2.raw"
+    , "5c-0.raw", "5c-1.raw", "5c-2.raw"
+    };
+#endif
 
   for (unsigned char i=0; i<NSAMPLES; ++i) {
     load_sample(&samples[i], sample_names[i]);
   }
 
   load_kgrp(kgrp);
+#ifdef EPIANO
+  tweak_samples();
+#endif
 
   for(uint32_t i=0; i<NVOICES; ++i) {
     voices[i] = new mdaPianoVoice(rate, samples, kgrp);
@@ -117,6 +135,7 @@ void mdaPiano::handle_midi(uint32_t size, unsigned char* data) {
     case 0xB0:
       switch(data[1])
       {
+#ifdef PIANO
         case 0x01:  //mod wheel
         case 0x43:  //soft pedal
           {
@@ -126,6 +145,12 @@ void mdaPiano::handle_midi(uint32_t size, unsigned char* data) {
             }
             break;
           }
+#elif defined EPIANO
+        case 0x01: //mod wheel
+          //scale the mod value to cover the range [0..1]
+          *p(p_modulation) = scale_midi_to_f(data[2]);
+          break;
+#endif
 
         case 0x07:  //volume
           setVolume(0.00002f * (float)(data[2] * data[2]));
@@ -206,6 +231,7 @@ void mdaPiano::load_sample(Sample *s, const char* name) {
 
 // TODO: load keymapping from a file
 void mdaPiano::load_kgrp(KGRP *kgrp) {
+#ifdef PIANO
   kgrp[ 0].root = 36;  kgrp[ 0].high = 37;  kgrp[ 0].loop = 14774;
   kgrp[ 1].root = 40;  kgrp[ 1].high = 41;  kgrp[ 1].loop = 16268;
   kgrp[ 2].root = 43;  kgrp[ 2].high = 45;  kgrp[ 2].loop = 33541;
@@ -221,7 +247,76 @@ void mdaPiano::load_kgrp(KGRP *kgrp) {
   kgrp[12].root = 84;  kgrp[12].high = 85;  kgrp[12].loop = 6011;
   kgrp[13].root = 88;  kgrp[13].high = 89;  kgrp[13].loop = 3414;
   kgrp[14].root = 93;  kgrp[14].high = 999; kgrp[14].loop = 2399;
+#elif defined EPIANO
+  kgrp[ 0].root = 36;  kgrp[ 0].high = 39; //C1
+  kgrp[ 3].root = 43;  kgrp[ 3].high = 45; //G1
+  kgrp[ 6].root = 48;  kgrp[ 6].high = 51; //C2
+  kgrp[ 9].root = 55;  kgrp[ 9].high = 57; //G2
+  kgrp[12].root = 60;  kgrp[12].high = 63; //C3
+  kgrp[15].root = 67;  kgrp[15].high = 69; //G3
+  kgrp[18].root = 72;  kgrp[18].high = 75; //C4
+  kgrp[21].root = 79;  kgrp[21].high = 81; //G4
+  kgrp[24].root = 84;  kgrp[24].high = 87; //C5
+  kgrp[27].root = 91;  kgrp[27].high = 93; //G5
+  kgrp[30].root = 96;  kgrp[30].high =999; //C6
+
+  kgrp[0].loop = 4400;
+  kgrp[1].loop = 4903;
+  kgrp[2].loop = 6398;
+  kgrp[3].loop = 3938;
+  kgrp[4].loop = 1633; //was 1636
+  kgrp[5].loop = 5245;
+  kgrp[6].loop = 2937;
+  kgrp[7].loop = 2203; //was 2204
+  kgrp[8].loop = 6368;
+  kgrp[9].loop = 10452;
+  kgrp[10].loop = 5217; //was 5220
+  kgrp[11].loop = 3099;
+  kgrp[12].loop = 4284;
+  kgrp[13].loop = 3916;
+  kgrp[14].loop = 2937;
+  kgrp[15].loop = 4732;
+  kgrp[16].loop = 4733;
+  kgrp[17].loop = 2285;
+  kgrp[18].loop = 4098;
+  kgrp[19].loop = 4099;
+  kgrp[20].loop = 3609;
+  kgrp[21].loop = 2446;
+  kgrp[22].loop = 6278;
+  kgrp[23].loop = 2283;
+  kgrp[24].loop = 2689;
+  kgrp[25].loop = 4370;
+  kgrp[26].loop = 5225;
+  kgrp[27].loop = 2811;
+  kgrp[28].loop = 2811; //ghost
+  kgrp[29].loop = 4522;
+  kgrp[30].loop = 2306;
+  kgrp[31].loop = 2306; //ghost
+  kgrp[32].loop = 2169;
+#endif
 }
 
 
+#ifdef EPIANO
+void mdaPiano::tweak_samples() {
+  //extra xfade looping...
+  for(uint32_t k=0; k<28; k++)
+  {
+    long p0 = samples[k].size;
+    long p1 = samples[k].size - kgrp[k].loop;
+
+    float xf = 1.0f;
+    float dxf = -0.02f;
+
+    while(xf > 0.0f)
+    {
+      samples[k].buffer[p0] = (short)((1.0f - xf) * (float)samples[k].buffer[p0] + xf * (float)samples[k].buffer[p1]);
+      p0--;
+      p1--;
+      xf += dxf;
+    }
+  }
+}
+#endif
+
 static int _ = mdaPiano::register_class(p_uri);
index 116b5ba..9e46e6b 100644 (file)
@@ -8,6 +8,8 @@ mdaPianoVoice::mdaPianoVoice(double rate, Sample * master_samples, KGRP * master
   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;
@@ -20,6 +22,20 @@ mdaPianoVoice::mdaPianoVoice(double rate, Sample * master_samples, KGRP * master
   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);
@@ -40,29 +56,53 @@ void mdaPianoVoice::on(unsigned char key, unsigned char velocity) {
   update(Current);
 
   float l=99.0f;
+#ifdef PIANO
   uint32_t k, s;
+#elif defined EPIANO
+  long k, s;
+#endif
 
   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 += (uint32_t)(sizevel * (float)(velocity - 40));
+#endif
 
     k = 0;
     while(key > (kgrp[k].high + s)) k += SAMPLES_PER_NOTE; // find keygroup
+#ifdef EPIANO
+    if(velocity > 48) k++; // mid velocity sample
+    if(velocity > 80) k++; // high velocity sample
+#endif
     sample_index = k; // store sample index
 
     l += (float)(key - kgrp[k].root); // pitch
+#ifdef PIANO
     l = 22050.0f * iFs * (float)exp(0.05776226505 * l);
     delta = (uint32_t)(65536.0f * l);
+#elif defined EPIANO
+    l = 32000.0f * iFs * (float)exp(0.05776226505 * l);
+    delta = (long)(65536.0f * l);
+#endif
     frac = 0;
     pos = 0;
+
+#ifdef PIANO
     end = samples[sample_index].size;
+#elif defined EPIANO
+    end = samples[sample_index].size - 1;
+#endif
     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
@@ -70,10 +110,19 @@ void mdaPianoVoice::on(unsigned char key, unsigned char velocity) {
     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;
@@ -82,6 +131,13 @@ void mdaPianoVoice::on(unsigned char key, unsigned char velocity) {
     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);
@@ -92,20 +148,29 @@ void mdaPianoVoice::on(unsigned char key, unsigned char velocity) {
 void mdaPianoVoice::reset() {
   env = 0.0f;
   dec = 0.99f;
-  muff = 160.0f;
-  volume = 0.2f;
   sustain = 0;
+  volume = 0.2f;
+#ifdef PIANO
+  muff = 160.0f;
   cpos = 0;
+#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;
   }
@@ -125,7 +190,11 @@ void mdaPianoVoice::render(uint32_t from, uint32_t to) {
     return;
 
   float x, l, r;
+#ifdef PIANO
   uint32_t i;
+#elif defined EPIANO
+  long i;
+#endif
 
   update(Current);
   for (uint32_t frame = from; frame < to; ++frame) {
@@ -134,9 +203,10 @@ void mdaPianoVoice::render(uint32_t from, uint32_t to) {
 
     frac += delta;  // integer-based linear interpolation
     pos += frac >> 16;
-    frac &= 0xFFFF;
-    if(pos > end) pos -= loop;
+    frac &= 0xFFFF;  // why AND it with all ones?
+    if(pos > end) pos -= loop; // jump back to loop 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
@@ -155,16 +225,56 @@ void mdaPianoVoice::render(uint32_t from, uint32_t to) {
     // 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) {
+#ifdef PIANO
   size = (uint32_t)(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;
@@ -181,4 +291,30 @@ void mdaPianoVoice::update(Param par) {
   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;
+#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
+
+  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);
+  }
+
+  width = 0.03f * p_helper(p_stereo_width, par);
+  fine = p_helper(p_fine_tuning, par) - 0.5f;
+  random = 0.077f * p_helper(p_random_tuning, par) * p_helper(p_random_tuning, par);
+  overdrive = 1.8f * p_helper(p_overdrive, par);
+#endif
 }